Spaces:
Build error
Build error
from typing import Optional | |
import numpy as np | |
import torch | |
from torch import Tensor, tensor | |
from torchsynth.config import SynthConfig | |
from torchsynth.module import ( | |
ADSR, | |
VCA, | |
AudioMixer, | |
ControlRateUpsample, | |
MonophonicKeyboard, | |
SineVCO, | |
SquareSawVCO, | |
VCO, LFO, ModulationMixer, | |
) | |
from torchsynth.signal import Signal | |
from torchsynth.synth import AbstractSynth | |
# from configurations.read_configuration import get_conf_sample_rate | |
from melody_synth.non_random_LFOs import SinLFO, SawLFO, TriLFO, SquareLFO, RSawLFO | |
class TriangleVCO(VCO): | |
"""This is an expanded module that inherits VCO producing Triangle waves.""" | |
def oscillator(self, argument: Signal, midi_f0: Tensor) -> Signal: | |
return torch.arcsin(torch.sin(argument * 2)) * 2.0 / torch.pi | |
class AmpModTorchSynth(AbstractSynth): | |
"""This is an abstract class using the modules provided by 1B1Synth to assemble synthesizers that generate the | |
training set. (The implementation of this class references code in TorchSynth) """ | |
def __init__( | |
self, | |
synthconfig: Optional[SynthConfig] = None, | |
nebula: Optional[str] = "nebula", | |
*args, | |
**kwargs, | |
): | |
AbstractSynth.__init__(self, synthconfig=synthconfig, *args, **kwargs) | |
self.share_modules = [ | |
("keyboard", MonophonicKeyboard), | |
("adsr_1", ADSR), | |
("adsr_2", ADSR), | |
("upsample", ControlRateUpsample), | |
("vca", VCA), | |
("lfo_amp_sin", SinLFO), | |
("lfo_pitch_sin_1", SinLFO), | |
("lfo_pitch_sin_2", SinLFO), | |
( | |
"mixer", | |
AudioMixer, | |
{ | |
"n_input": 2, | |
"curves": [1.0, 1.0], | |
"names": ["vco_1", "vco_2"], | |
}, | |
) | |
] | |
def output(self) -> Tensor: | |
"""Synthesizes the signal as Tensor""" | |
midi_f0, note_on_duration = self.keyboard() | |
adsr1 = self.adsr_1(note_on_duration) | |
adsr1 = self.upsample(adsr1) | |
adsr2 = self.adsr_2(note_on_duration) | |
adsr2 = self.upsample(adsr2) | |
amp_modulation = self.lfo_amp_sin() | |
amp_modulation = self.upsample(amp_modulation) | |
pitch_modulation_1 = self.lfo_pitch_sin_1() | |
pitch_modulation_1 = self.upsample(pitch_modulation_1) | |
pitch_modulation_2 = self.lfo_pitch_sin_2() | |
pitch_modulation_2 = self.upsample(pitch_modulation_2) | |
vco_amp1 = adsr1 * (amp_modulation * 0.5 + 0.5) | |
vco_amp2 = adsr2 * (amp_modulation * 0.5 + 0.5) | |
vco_1_out = self.vco_1(midi_f0, pitch_modulation_1) | |
vco_1_out = self.vca(vco_1_out, vco_amp1) | |
vco_2_out = self.vco_2(midi_f0, pitch_modulation_2) | |
vco_2_out = self.vca(vco_2_out, vco_amp2) | |
return self.mixer(vco_1_out, vco_2_out) | |
def get_signal(self, amp_mod_depth, amp_waveform, duration_l, amp1, amp2): | |
"""Synthesizes the signal as Tensor""" | |
midi_f0, note_on_duration = self.keyboard() | |
adsr1 = self.adsr_1(note_on_duration) | |
adsr1 = self.upsample(adsr1) | |
adsr2 = self.adsr_2(note_on_duration) | |
adsr2 = self.upsample(adsr2) | |
amp_modulation = self.lfo_amp_sin() | |
amp_modulation = self.upsample(amp_modulation) | |
pitch_modulation_1 = self.lfo_pitch_sin_1() | |
pitch_modulation_1 = self.upsample(pitch_modulation_1) | |
pitch_modulation_2 = self.lfo_pitch_sin_2() | |
pitch_modulation_2 = self.upsample(pitch_modulation_2) | |
vco_amp1 = adsr1 * (amp_modulation * 0.5 + 0.5) | |
vco_amp2 = adsr2 * (amp_modulation * 0.5 + 0.5) | |
vco_1_out = self.vco_1(midi_f0, pitch_modulation_1) | |
vco_1_out = self.vca(vco_1_out, vco_amp1) | |
vco_2_out = self.vco_2(midi_f0, pitch_modulation_1) | |
vco_2_out = self.vca(vco_2_out, vco_amp2) | |
return self.mixer(vco_1_out, vco_2_out) | |
class DoubleSawSynth(AmpModTorchSynth): | |
"""In addition to the shared modules, this synthesizer uses two "SquareSawVCO" modules to generate square and | |
sawtooth waves""" | |
def __init__( | |
self, | |
synthconfig: Optional[SynthConfig] = None, | |
nebula: Optional[str] = "saw_square_voice", | |
*args, | |
**kwargs, | |
): | |
AmpModTorchSynth.__init__(self, synthconfig=synthconfig, *args, **kwargs) | |
# Register all modules as children | |
module_list = self.share_modules | |
module_list.append(("vco_1", SquareSawVCO)) | |
module_list.append(("vco_2", SquareSawVCO)) | |
self.add_synth_modules(module_list) | |
class SinSawSynth(AmpModTorchSynth): | |
"""In addition to the shared modules, this synthesizer uses a "SinVco" and a "SquareSawVCO" to generate | |
sine and sawtooth/square waves """ | |
def __init__( | |
self, | |
synthconfig: Optional[SynthConfig] = None, | |
nebula: Optional[str] = "sin_saw_voice", | |
*args, | |
**kwargs, | |
): | |
AmpModTorchSynth.__init__(self, synthconfig=synthconfig, *args, **kwargs) | |
# Register all modules as children | |
module_list = self.share_modules | |
module_list.append(("vco_1", SineVCO)) | |
module_list.append(("vco_2", SquareSawVCO)) | |
self.add_synth_modules(module_list) | |
class SinTriangleSynth(AmpModTorchSynth): | |
"""In addition to the shared modules, this synthesizer uses a "SinVco" and a "TriangleVCO" to generate | |
sine and triangle waves """ | |
def __init__( | |
self, | |
synthconfig: Optional[SynthConfig] = None, | |
nebula: Optional[str] = "sin_tri_voice", | |
*args, | |
**kwargs, | |
): | |
AmpModTorchSynth.__init__(self, synthconfig=synthconfig, *args, **kwargs) | |
# Register all modules as children | |
module_list = self.share_modules | |
module_list.append(("vco_1", SineVCO)) | |
module_list.append(("vco_2", TriangleVCO)) | |
self.add_synth_modules(module_list) | |
class TriangleSawSynth(AmpModTorchSynth): | |
"""In addition to the shared modules, this synthesizer uses a "TriangleVCO" and a "SquareSawVCO" to generate | |
triangle and sawtooth/square waves """ | |
def __init__( | |
self, | |
synthconfig: Optional[SynthConfig] = None, | |
nebula: Optional[str] = "triangle_saw_voice", | |
*args, | |
**kwargs, | |
): | |
AmpModTorchSynth.__init__(self, synthconfig=synthconfig, *args, **kwargs) | |
# Register all modules as children | |
module_list = self.share_modules | |
module_list.append(("vco_1", TriangleVCO)) | |
module_list.append(("vco_2", SquareSawVCO)) | |
self.add_synth_modules(module_list) | |
def amp_mod_with_duration(env, duration_l): | |
env_np = env.detach().numpy()[0] + 1e-30 | |
env_np_shift = np.hstack([[0], env_np[:-1]]) | |
env_np_sign = (env_np - env_np_shift)[:duration_l] + 1e-30 | |
env_np_sign_nor = np.around(env_np_sign / np.abs(env_np_sign)) | |
env_np_sign_nor_shift = np.hstack([[0], env_np_sign_nor[:-1]]) | |
extreme_points = (env_np_sign_nor - env_np_sign_nor_shift) | |
(max_loc,) = np.where(extreme_points == -2) | |
n_max = len(max_loc) | |
if n_max == 0: | |
return env | |
else: | |
last_max_loc = max_loc[n_max - 1] - 1 | |
# new_env = np.hstack([env_np[:last_max_loc], np.ones(len(env_np) - last_max_loc) * env_np[last_max_loc]]) | |
new_env = np.hstack([env_np[:last_max_loc], (env_np[last_max_loc:] * 0.8 + 0.2)]) | |
return tensor([new_env]) | |