Definition of Pulse train generator There are many ways to implement pulse generator. Here, PulseGen is based on SinGen. For a perfect
| 138 | |
| 139 | |
| 140 | class PulseGen(torch.nn.Module): |
| 141 | """ Definition of Pulse train generator |
| 142 | |
| 143 | There are many ways to implement pulse generator. |
| 144 | Here, PulseGen is based on SinGen. For a perfect |
| 145 | """ |
| 146 | def __init__(self, samp_rate, pulse_amp = 0.1, |
| 147 | noise_std = 0.003, voiced_threshold = 0): |
| 148 | super(PulseGen, self).__init__() |
| 149 | self.pulse_amp = pulse_amp |
| 150 | self.sampling_rate = samp_rate |
| 151 | self.voiced_threshold = voiced_threshold |
| 152 | self.noise_std = noise_std |
| 153 | self.l_sinegen = SineGen(self.sampling_rate, harmonic_num=0, \ |
| 154 | sine_amp=self.pulse_amp, noise_std=0, \ |
| 155 | voiced_threshold=self.voiced_threshold, \ |
| 156 | flag_for_pulse=True) |
| 157 | |
| 158 | def forward(self, f0): |
| 159 | """ Pulse train generator |
| 160 | pulse_train, uv = forward(f0) |
| 161 | input F0: tensor(batchsize=1, length, dim=1) |
| 162 | f0 for unvoiced steps should be 0 |
| 163 | output pulse_train: tensor(batchsize=1, length, dim) |
| 164 | output uv: tensor(batchsize=1, length, 1) |
| 165 | |
| 166 | Note: self.l_sine doesn't make sure that the initial phase of |
| 167 | a voiced segment is np.pi, the first pulse in a voiced segment |
| 168 | may not be at the first time step within a voiced segment |
| 169 | """ |
| 170 | with torch.no_grad(): |
| 171 | sine_wav, uv, noise = self.l_sinegen(f0) |
| 172 | |
| 173 | # sine without additive noise |
| 174 | pure_sine = sine_wav - noise |
| 175 | |
| 176 | # step t corresponds to a pulse if |
| 177 | # sine[t] > sine[t+1] & sine[t] > sine[t-1] |
| 178 | # & sine[t-1], sine[t+1], and sine[t] are voiced |
| 179 | # or |
| 180 | # sine[t] is voiced, sine[t-1] is unvoiced |
| 181 | # we use torch.roll to simulate sine[t+1] and sine[t-1] |
| 182 | sine_1 = torch.roll(pure_sine, shifts=1, dims=1) |
| 183 | uv_1 = torch.roll(uv, shifts=1, dims=1) |
| 184 | uv_1[:, 0, :] = 0 |
| 185 | sine_2 = torch.roll(pure_sine, shifts=-1, dims=1) |
| 186 | uv_2 = torch.roll(uv, shifts=-1, dims=1) |
| 187 | uv_2[:, -1, :] = 0 |
| 188 | |
| 189 | loc = (pure_sine > sine_1) * (pure_sine > sine_2) \ |
| 190 | * (uv_1 > 0) * (uv_2 > 0) * (uv > 0) \ |
| 191 | + (uv_1 < 1) * (uv > 0) |
| 192 | |
| 193 | # pulse train without noise |
| 194 | pulse_train = pure_sine * loc |
| 195 | |
| 196 | # additive noise to pulse train |
| 197 | # note that noise from sinegen is zero in voiced regions |