class FMOperator(Oscillator): """A class to represent an FM operator""" def __init__( self, freq=440.0, level=1.0, phase=0.0, feedback=0, wave_type='sine', fm_type='DX', gate=Gate([0.0]), key_in=None ): Oscillator.__init__(self, key_in) self.freq = freq #frequency self.mixer = Mixer() #mixer to add modulators' outputs #sound generator if fm_type == 'LinearFM': self.generator = LinearFMGenerator( freq, level, phase, wave_type, self.mixer, key_in ) elif fm_type == 'DX': self.generator = DXGenerator( freq, level, phase, wave_type, self.mixer, key_in ) self.eg = ADSR(input=gate) #envelope generator #amplifier self.amp = Amplifier(input=self.generator, mod=self.eg) def add_modulator(self, mod, level=1.0): """Adds a modulator""" self.mixer.add_input(mod, level) def set_key_in(self, key_in): """Sets key input""" self.key_in = key_in self.generator.set_key_in(key_in) def set_eg_params(self, *args, **kwargs): """Sets parameters of the envelope""" self.eg.set_params(*args, **kwargs) def set_gate(self, gate): """Sets the gate input""" self.eg.set_input(gate) def set_keyboard(self, keyboard): """sets key and gate input from a keybord""" self.set_key_in(keyboard.key) self.set_gate(keyboard.gate) def output(self, t, **kwargs): """Returns the value of operators signal in time t""" return self.amp.output(t, **kwargs) def draw(self, ax, time=None, cycles=1, **kwargs): """ Draws the shape of the operators output signal along with its modulators and modulators' modulators etc. If 'time' is not provided, the shape will be drawn for 'cycles' cycles of operators carrier generator """ #draw the operators output signal Oscillator.draw(self, ax, time, cycles, **kwargs) #draw modulators' output signals if time is None: time = cycles / np.float64(self.freq) try: kwargs['alpha'] *= 0.5 except KeyError: kwargs['alpha'] = 0.5 self.mixer.draw(ax, time, **kwargs)
op4.set_eg_params(0.0, 0.11, 0.0, 0.05) op5.set_eg_params(0.0, 0.7, 0.2, 0.2) op6.set_eg_params(0.0, 0.7, 0.2, 0.4) #add keyboard kbd = MonoKeyboard() ops = [op1, op2, op3, op4, op5, op6] for op in ops: op.set_keyboard(kbd) #read a midi file kbd.read_midi('midi\\dangerzonebass.mid') #draw envelopes, keyboard outputs and the wave shape fig, (ax1, ax2, ax3) = plt.subplots(3, 1) for op in ops: op.eg.draw(ax2, 13, density=2000, alpha=0.5) kbd.gate.draw(ax2, 13, density=20000, alpha=0.5) kbd.key.draw(ax3, 13, density=2000) mixer.draw(ax1, 1.0 / 110, density=1000) #play the sound mixer.play(13) #show the outputs plt.show()