def __init__(self, samplerate, numVoices = 16 ): numOscillators = SynthParameters.NUM_OSCILLATORS # Assemble voices self.voices = [] for _ in range(numVoices): oscillators = [] volumeEnvelopes = [] filters = [] filterEnvelopes = [] for _ in range(numOscillators): oscillators.append(Oscillator(samplerate=samplerate)) volumeEnvelopes.append(ADSR()) filters.append(Filter()) filterEnvelopes.append(ADSR()) self.voices.append(Voice(oscillators, volumeEnvelopes, filters, filterEnvelopes)) self.LFO = Oscillator(Waveform.SINE, 1, samplerate=samplerate) self.LFOToVolume = 0.0 self.LFOToFilter = 0.0
class Synth(object): def __init__(self, samplerate, numVoices = 16 ): numOscillators = SynthParameters.NUM_OSCILLATORS # Assemble voices self.voices = [] for _ in range(numVoices): oscillators = [] volumeEnvelopes = [] filters = [] filterEnvelopes = [] for _ in range(numOscillators): oscillators.append(Oscillator(samplerate=samplerate)) volumeEnvelopes.append(ADSR()) filters.append(Filter()) filterEnvelopes.append(ADSR()) self.voices.append(Voice(oscillators, volumeEnvelopes, filters, filterEnvelopes)) self.LFO = Oscillator(Waveform.SINE, 1, samplerate=samplerate) self.LFOToVolume = 0.0 self.LFOToFilter = 0.0 def noteOn(self, midiNote): # find free voice voice = self._getFreeVoice() # check if voice found if voice != None: """ print "Voice Id: " + str(voice.id) print "isActive() " + str(voice.isActive()) """ voice.reset() voice.midiNote = midiNote for volumeEnvelope in voice.volumeEnvelopes: volumeEnvelope.noteOn() for filterEnvelope in voice.filterEnvelopes: filterEnvelope.noteOn() def noteOff(self, midiNote): # find correct voice (with correct note) voice = None for v in self.voices: if v.midiNote == midiNote and v.isPressed(): voice = v break if voice != None: """ print "Voice Id: " + str(voice.id) print "isActive() " + str(voice.isActive()) """ for volumeEnvelope in voice.volumeEnvelopes: volumeEnvelope.noteOff() for filterEnvelope in voice.filterEnvelopes: filterEnvelope.noteOff() def getSample(self): sample = 0.0 # get LFO sample to only advance once lfoSample = self.LFO.getSample() # loop over active voices for voice in [voice for voice in self.voices if voice.isActive]: # broadcast filter LFO to all voices voice.filterLFOMod = clip(lfoSample * self.LFOToFilter, -1.0, 1.0) sample += voice.getSample() sample /= len(self.voices) / 4.0 sample *= (lfoSample * self.LFOToVolume + 1.0) * 0.5 # TODO: implement module for effects. Limit here by hand sample = clip(sample, -1.0, 1.0) return sample def setParameter(self, parameter, value): if parameter == SynthParameters.OSC_ALL_WAVEFORM: setter = partial(self._setParameterOscAllWaveform, value) elif parameter == SynthParameters.OSC_1_WAVEFORM: setter = partial(self._setParameterOsc1Waveform, value) elif parameter == SynthParameters.OSC_2_WAVEFORM: setter = partial(self._setParameterOsc2Waveform, value) elif parameter == SynthParameters.OSC_3_WAVEFORM: setter = partial(self._setParameterOsc3Waveform, value) elif parameter == SynthParameters.OSC_ALL_GAIN: setter = partial(self._setParameterOscAllGain, value) elif parameter == SynthParameters.OSC_1_GAIN: setter = partial(self._setParameterOsc1Gain, value) elif parameter == SynthParameters.OSC_2_GAIN: setter = partial(self._setParameterOsc2Gain, value) elif parameter == SynthParameters.OSC_3_GAIN: setter = partial(self._setParameterOsc3Gain, value) elif parameter == SynthParameters.OSC_ALL_DETUNE: setter = partial(self._setParameterOscAllDetune, value) elif parameter == SynthParameters.OSC_1_DETUNE: setter = partial(self._setParameterOsc1Detune, value) elif parameter == SynthParameters.OSC_2_DETUNE: setter = partial(self._setParameterOsc2Detune, value) elif parameter == SynthParameters.OSC_3_DETUNE: setter = partial(self._setParameterOsc3Detune, value) elif parameter == SynthParameters.OSC_ALL_CUTOFF: setter = partial(self._setParameterOscAllCutoff, value) elif parameter == SynthParameters.OSC_ALL_RESONANCE: setter = partial(self._setParameterOscAllResonance, value) elif parameter == SynthParameters.OSC_ALL_FILTER_ENVELOPE_AMOUNT: setter = partial(self._setParameterOscAllFilterEnvelopeAmount, value) elif parameter == SynthParameters.OSC_ALL_FILTER_ENEVELOPE_ATTACK: setter = partial(self._setParameterOscAllFilterEnvelopeAttack, value) elif parameter == SynthParameters.OSC_ALL_FILTER_ENEVELOPE_DECAY: setter = partial(self._setParameterOscAllFilterEnvelopeDecay, value) elif parameter == SynthParameters.OSC_ALL_FILTER_ENEVELOPE_SUSTAIN: setter = partial(self._setParameterOscAllFilterEnvelopeSustain, value) elif parameter == SynthParameters.OSC_ALL_FILTER_ENEVELOPE_RELEASE: setter = partial(self._setParameterOscAllFilterEnvelopeRelease, value) elif parameter == SynthParameters.OSC_ALL_VOLUME_ENEVELOPE_ATTACK: setter = partial(self._setParameterOscAllVolumeEnvelopeAttack, value) elif parameter == SynthParameters.OSC_1_VOLUME_ENEVELOPE_ATTACK: setter = partial(self._setParameterOsc1VolumeEnvelopeAttack, value) elif parameter == SynthParameters.OSC_2_VOLUME_ENEVELOPE_ATTACK: setter = partial(self._setParameterOsc2VolumeEnvelopeAttack, value) elif parameter == SynthParameters.OSC_3_VOLUME_ENEVELOPE_ATTACK: setter = partial(self._setParameterOsc3VolumeEnvelopeAttack, value) elif parameter == SynthParameters.OSC_ALL_VOLUME_ENEVELOPE_DECAY: setter = partial(self._setParameterOscAllVolumeEnvelopeDecay, value) elif parameter == SynthParameters.OSC_1_VOLUME_ENEVELOPE_DECAY: setter = partial(self._setParameterOsc1VolumeEnvelopeDecay, value) elif parameter == SynthParameters.OSC_2_VOLUME_ENEVELOPE_DECAY: setter = partial(self._setParameterOsc2VolumeEnvelopeDecay, value) elif parameter == SynthParameters.OSC_3_VOLUME_ENEVELOPE_DECAY: setter = partial(self._setParameterOsc3VolumeEnvelopeDecay, value) elif parameter == SynthParameters.OSC_ALL_VOLUME_ENEVELOPE_SUSTAIN: setter = partial(self._setParameterOscAllVolumeEnvelopeSustain, value) elif parameter == SynthParameters.OSC_ALL_VOLUME_ENEVELOPE_RELEASE: setter = partial(self._setParameterOscAllVolumeEnvelopeRelease, value) elif parameter == SynthParameters.OSC_1_VOLUME_ENEVELOPE_RELEASE: setter = partial(self._setParameterOsc1VolumeEnvelopeRelease, value) elif parameter == SynthParameters.OSC_2_VOLUME_ENEVELOPE_RELEASE: setter = partial(self._setParameterOsc2VolumeEnvelopeRelease, value) elif parameter == SynthParameters.OSC_3_VOLUME_ENEVELOPE_RELEASE: setter = partial(self._setParameterOsc3VolumeEnvelopeRelease, value) # Local parameters (local to Synth) elif parameter == SynthParameters.LFO_FREQUENCY: self.LFO.frequency = clip(value, 0.0001, float("inf")) return elif parameter == SynthParameters.LFO_TO_VOLUME: self.LFOToVolume = clip(value, -1.0, 1.0) return elif parameter == SynthParameters.LFO_TO_FILTER: self.LFOToFilter = clip(value, -1.0, 1.0) return # Parameter not implemented else: return for voice in self.voices: setter(voice) def _getFreeVoice(self): voice = None for v in self.voices: if not v.isActive(): voice = v break return voice # return next((voice for voice in self.voices if not voice.isActive()), None) """ Parameter setter functions """ # Oscillator def _setParameterOscAllWaveform(self, value, voice): for oscillator in voice.oscillators: oscillator.waveform = value def _setParameterOsc1Waveform(self, value, voice): voice.oscillators[0].waveform = value def _setParameterOsc2Waveform(self, value, voice): voice.oscillators[1].waveform = value def _setParameterOsc3Waveform(self, value, voice): voice.oscillators[2].waveform = value def _setParameterOscAllGain(self, value, voice): for oscillator in voice.oscillators: oscillator.gain = clip(value, 0.0, 1.0) def _setParameterOsc1Gain(self, value, voice): voice.oscillators[0].gain = clip(value, 0.0, 1.0) def _setParameterOsc2Gain(self, value, voice): voice.oscillators[1].gain = clip(value, 0.0, 1.0) def _setParameterOsc3Gain(self, value, voice): voice.oscillators[2].gain = clip(value, 0.0, 1.0) def _setParameterOscAllDetune(self, value, voice): for oscillator in voice.oscillators: oscillator.detune = value def _setParameterOsc1Detune(self, value, voice): voice.oscillators[0].detune = value def _setParameterOsc2Detune(self, value, voice): voice.oscillators[1].detune = value def _setParameterOsc3Detune(self, value, voice): voice.oscillators[2].detune = value # Volume envelope def _setParameterOscAllVolumeEnvelopeAttack(self, value, voice): for volumeEnvelope in voice.volumeEnvelopes: volumeEnvelope.stageValue[Stage.ATTACK] = clip(value, 0.01, float("inf")) def _setParameterOsc1VolumeEnvelopeAttack(self, value, voice): voice.volumeEnvelopes[0].stageValue[Stage.ATTACK] = clip(value, 0.01, float("inf")) def _setParameterOsc2VolumeEnvelopeAttack(self, value, voice): voice.volumeEnvelopes[1].stageValue[Stage.ATTACK] = clip(value, 0.01, float("inf")) def _setParameterOsc3VolumeEnvelopeAttack(self, value, voice): voice.volumeEnvelopes[2].stageValue[Stage.ATTACK] = clip(value, 0.01, float("inf")) def _setParameterOscAllVolumeEnvelopeDecay(self, value, voice): for volumeEnvelope in voice.volumeEnvelopes: volumeEnvelope.stageValue[Stage.DECAY] = clip(value, 0.01, float("inf")) def _setParameterOsc1VolumeEnvelopeDecay(self, value, voice): voice.volumeEnvelopes[0].stageValue[Stage.DECAY] = clip(value, 0.01, float("inf")) def _setParameterOsc2VolumeEnvelopeDecay(self, value, voice): voice.volumeEnvelopes[1].stageValue[Stage.DECAY] = clip(value, 0.01, float("inf")) def _setParameterOsc3VolumeEnvelopeDecay(self, value, voice): voice.volumeEnvelopes[2].stageValue[Stage.DECAY] = clip(value, 0.01, float("inf")) def _setParameterOscAllVolumeEnvelopeSustain(self, value, voice): for volumeEnvelope in voice.volumeEnvelopes: volumeEnvelope.stageValue[Stage.SUSTAIN] = clip(value, 0.0, 1.0) def _setParameterOscAllVolumeEnvelopeRelease(self, value, voice): for volumeEnvelope in voice.volumeEnvelopes: volumeEnvelope.stageValue[Stage.RELEASE] = clip(value, 0.01, float("inf")) def _setParameterOsc1VolumeEnvelopeRelease(self, value, voice): voice.volumeEnvelopes[0].stageValue[Stage.RELEASE] = clip(value, 0.01, float("inf")) def _setParameterOsc2VolumeEnvelopeRelease(self, value, voice): voice.volumeEnvelopes[1].stageValue[Stage.RELEASE] = clip(value, 0.01, float("inf")) def _setParameterOsc3VolumeEnvelopeRelease(self, value, voice): voice.volumeEnvelopes[2].stageValue[Stage.RELEASE] = clip(value, 0.01, float("inf")) # Filter envelope def _setParameterOscAllFilterEnvelopeAttack(self, value, voice): for filterEnvelope in voice.filterEnvelopes: filterEnvelope.stageValue[Stage.ATTACK] = clip(value, 0.01, float("inf")) def _setParameterOscAllFilterEnvelopeDecay(self, value, voice): for filterEnvelope in voice.filterEnvelopes: filterEnvelope.stageValue[Stage.DECAY] = clip(value, 0.01, float("inf")) def _setParameterOscAllFilterEnvelopeSustain(self, value, voice): for filterEnvelope in voice.filterEnvelopes: filterEnvelope.stageValue[Stage.SUSTAIN] = clip(value, 0.0, 1.0) def _setParameterOscAllFilterEnvelopeRelease(self, value, voice): for filterEnvelope in voice.filterEnvelopes: filterEnvelope.stageValue[Stage.RELEASE] = clip(value, 0.01, float("inf")) def _setParameterOscAllFilterEnvelopeAmount(self, value, voice): for filterEnvelopeAmount in voice.filterEnvelopesAmounts: filterEnvelopeAmount = clip(value, -1.0, 1.0) # Filter def _setParameterOscAllCutoff(self, value, voice): for filter in voice.filters: filter.cutoff = clip(value, 0.0, 0.999) def _setParameterOscAllResonance(self, value, voice): for filter in voice.filters: filter.resonance = clip(value, 0.0, 1.0)