def record_midi_wav(mid_): # write mid_ to file with open("test.mid", "wb") as bin_file: mid_.writeFile(bin_file) s = Server().boot().start() # create app synth midi_reader = Notein() amp = MidiAdsr(midi_reader['velocity']) pit = MToF(midi_reader['pitch']) osc = SineLoop(freq=pit, feedback=0, mul=amp).mix(1) rev = STRev(osc, revtime=1, cutoff=4000, bal=0.2).out() # create recorder rec = Record(rev, buffering=2, filename='beat.wav', quality=0.4) clean = Clean_objects(12, rec) clean.start() midi_reader = MidiFile('test.mid') # makeshift infinite loop for message in midi_reader.play(): s.addMidiEvent(*message.bytes()) s.stop()
#useful for debugging show = False if "-v" in argv: show = True #Pyo server/objects s = Server().boot() s.start() wav = SineLoop(freq=2 * Pi * 261.626) notes = dict() notes['a'] = 220 notes['b'] = 246.942 notes['c'] = 261.626 notes['d'] = 293.665 notes['e'] = 329.628 notes['f'] = 349.228 notes['g'] = 391.995 notes['highA'] = 440 try: main() except KeyboardInterrupt: pass wav.stop() #otherOut.stop() s.stop() cls() print "Stopped theremin" exit()
class MusebotBase(object): ''' This class includes the functionality required by all Musebots, namely the ability to parse the config file, communicate with the server, and gracefully start up and shut down as per the Musebot communication spec. ''' class Heartbeat: def __init__(self, config={}): self._del = 1 # 1 beat per second self._msg = [config['id']] self._osc = OscDataSend('s', config['mc_listen_port'], '/agent/alive', host=config['mc_hostname']) def beat(self): while True: self._osc.send(self._msg) sleep(self._del) if not serverBooted(): break def start(self, run_as_deamon=True): self._thread = Thread(target=self.beat) self._thread.daemon = run_as_deamon # True => die when main thread dies self._thread.start() def __init__(self, config_path='config.txt'): self.parse_config_file(config_path) # init members & properties self._server = Server().boot() # do first self._heartbeat = MusebotBase.Heartbeat(self._config) self._osc_listeners = {} self._osc_recv = OscDataReceive(self.port, '/', self.osc_listener_callback) # register osc listeners self.register_osc_listener('/agent/gain', self.gain) self.register_osc_listener('/agent/kill', self.shutdown) self.register_osc_listener('/agent/quit', self.shutdown) self.register_osc_listener('/agent/off', self.shutdown) def parse_config_file(self, config): with open(config) as f: self._config = {} for line in f: k,v = line.split() if k in {'mc_listen_port', 'my_listen_port', 'output_channels'}: self._config[k] = int(v) else: self._config[k] = v def run(self): '''Implemented in user code''' pass def start(self): self._heartbeat.start() self.run() def register_osc_listener(self, address, func): self._osc_listeners[address] = func self._osc_recv.addAddress(address) def osc_listener_callback(self, address, *args): if address in self._osc_listeners: self._osc_listeners[address](args) ############################################################################ # osc callbacks # def shutdown(self, *args): print(self.id+' shutting down!') self._server.stop() self._server.closeGui() def gain(self, gain, *args): self._server.amp = float(gain[0]) ############################################################################ # properties # @property def server(self): return self._server @property def config(self): return deepcopy(self._config) @property def id(self): return self.config['id'] @property def port(self): return self.config['my_listen_port'] @property def hostname(self): return self.config['mc_hostname'] @property def hostport(self): return self.config['mc_listen_port'] @property def heartbeat(self): return self._heartbeat
class MidiCube: def __init__(self, pers_mgr=PersistenceManager()): self.inputs = {} self.outputs = {} self.reg_mgr = RegistrationManager() self.pers_mgr = pers_mgr def reg(self): return self.reg_mgr.cur_reg def add_input(self, device: MidiInputDevice): device.cube = self self.inputs[device.get_identifier()] = device #Add Binding callback def callback(msg: mido.Message): for binding in self.reg().bindings: binding.apply(msg.copy(), self, device) device.add_listener(MidiListener(-1, callback)) def add_output(self, device: MidiOutputDevice): device.cube = self self.outputs[device.get_identifier()] = device print('Added output: ' + device.get_identifier()) def load_devices(self): for name in mido.get_input_names(): device = mido.open_input(name) self.add_input(PortInputDevice(device)) for name in mido.get_output_names(): device = mido.open_output(name) self.add_output(PortOutputDevice(device)) def init(self): #Boot server self.server = Server(audio='jack') self.server.deactivateMidi() self.server.boot().start() #Init devices for device in self.outputs.values(): device.init() #Load Registrations self.pers_mgr.load(self) print("Loaded Registrations") def cb(r): for o in self.outputs.values(): o.on_reg_change() self.reg_mgr.add_listener(cb) #Init devices for device in self.outputs.values(): device.on_reg_change() def close(self, save=True): for key, inport in self.inputs.items(): try: inport.close() except: pass for key, outport in self.outputs.items(): try: outport.close() except: pass if save: self.pers_mgr.save(self) print("Saved registrations!") self.server.stop() def create_menu(self): #Option list options = [ midicube.menu.SimpleMenuOption(self.__bind_device_menu, "Bind Devices", ""), midicube.menu.SimpleMenuOption(self.__setup_device_menu, "Set Up Devices", ""), midicube.menu.SimpleMenuOption(self.__delete_binding_menu, "Delete Bindings", ""), midicube.menu.SimpleMenuOption(self.__registration_menu, "Registrations", "") ] menu = midicube.menu.OptionMenu(options, history=True) return menu def __bind_device_menu(self): #Callback def enter(): self.reg().bindings.append( DeviceBinding(in_device.curr_value(), out_device.curr_value(), in_channel.curr_value(), out_channel.curr_value())) #out_device.curr_value().bind(in_device.curr_value(), in_channel.curr_value(), out_channel.curr_value()) return None #Options in_device = midicube.menu.ValueMenuOption(enter, "Input Device", [*self.inputs.keys()]) out_device = midicube.menu.ValueMenuOption(enter, "Output Device", [*self.outputs.keys()]) in_channel = midicube.menu.ValueMenuOption(enter, "Input Channel", range(-1, 16)) out_channel = midicube.menu.ValueMenuOption(enter, "Output Channel", range(-1, 16)) #Menu return midicube.menu.OptionMenu( [in_device, out_device, in_channel, out_channel]) def __setup_device_menu(self): #Callback def enter(): return device.curr_value().create_menu() #Options device = midicube.menu.ValueMenuOption(enter, "Device", [*self.outputs.values()]) #Menu return midicube.menu.OptionMenu([device]) def __delete_binding_menu(self): #Callback def enter(): if binding.curr_value() != None: self.reg().bindings.remove(binding.curr_value()) return None #Options binding = midicube.menu.ValueMenuOption(enter, "Delete Bindings", self.reg().bindings) #Menu return midicube.menu.OptionMenu([binding]) def __registration_menu(self): #TODO Refresh menu when registrations are changed #Callbacks def select_reg(): self.reg_mgr.select(registration.curr_value()) return None def save_reg_menu(): reg = self.reg() def save_reg(name): reg.name = name self.reg_mgr.add_registration(reg) return None return midicube.menu.InputMenu(save_reg, "Save as", reg.name) def overwrite_reg_menu(): reg = self.reg() def overwrite_name(name): def overwrite_reg(new_name): del self.reg_mgr.registrations[name] reg.name = new_name self.reg_mgr.add_registration(reg) return midicube.menu.InputMenu(overwrite_reg, "New Name", reg.name) return midicube.menu.InputMenu(overwrite_name, "Overwrite", reg.name) def delete_reg(): del self.reg_mgr.registrations[self.reg().name] return None #Options registration = midicube.menu.ValueMenuOption( select_reg, "Select Registration", [*self.reg_mgr.registrations.values()]) save = midicube.menu.SimpleMenuOption(save_reg_menu, "Save Registration", "") overwrite = midicube.menu.SimpleMenuOption(overwrite_reg_menu, "Overwrite Registration", "") delete = midicube.menu.SimpleMenuOption(delete_reg, "Delete Registration", "") #Menu return midicube.menu.OptionMenu( [registration, save, overwrite, delete])
run = True server = Server().boot() server.start() met = Metro(.125, 12).play() players.append(Player(met, notes1)) players.append(Player(met, notes2)) players.append(Player(met, notes3)) while run: for event in pygame.event.get(): if event.type == pygame.KEYUP: for player in players: player.note_off(chr(event.key)) if event.key == ESC: run = False break if event.key == PLUS: met.time = min(.5, met.time + .01) if event.key == MINUS: met.time = max(.07, met.time - .01) if event.type == pygame.KEYDOWN: for player in players: player.note_on(chr(event.key)) server.stop()
class MusicPlayer: """Playback engine for sequencer samples and sounds""" NUM_PAGES = 8 NUM_ROWS = 8 NUM_COLS = 8 NUM_TRACKS = 3 NUM_BEATS = NUM_PAGES * NUM_COLS SECONDS_PER_MIN = 60.0 # Parameters for GUI to build sliders MIN_TEMPO = 40.0 MAX_TEMPO = 240.0 MIN_VOLUME = 0.0 MAX_VOLUME = 1.0 MIN_REVERB = 0.0 MAX_REVERB = 1.0 # Instrument descriptive constants WAVETABLE_A = 0 WAVETABLE_B = 1 DRUM_KIT = 2 def __init__(self): """Constructor for music_player""" """Make sure to call add_gui once initialized""" self.instruments = [] #instrument/track volume is here self.tempo = 120.0 #BPM (for now) self.global_volume = 0.75 #between 0 and 1 self.page_index = 0 #1st page self.play_all = False self.playhead_index = 0 self.beat_index = 0 self.server = Server(duplex=0) """Set proper output device for latency-free playback on Windows""" """Source: https://groups.google.com/d/msg/pyo-discuss/9fvFiGbch3c/tzJTfbpLUY8J""" if platform.system() == "Windows": out_devices = pa_get_output_devices() od_index = 0 for od in out_devices[0]: if "Primary Sound Driver" in od: pai = int(out_devices[1][od_index]) self.server.setOutputDevice(pai) break od_index += 1 self.server.boot() self.server.start() metronome_time = self.SECONDS_PER_MIN / self.tempo self.metronome = Metro(time=metronome_time) self.metronome_callback = TrigFunc(self.metronome, function=self.step) # Create instruments wavetable_a = WaveInstrument(self, WaveInstrument.BASS) wavetable_b = WaveInstrument(self, WaveInstrument.LEAD) drums = DrumInstrument(self) self.instruments.append(wavetable_a) self.instruments.append(wavetable_b) self.instruments.append(drums) self.mixer_setup() def mixer_setup(self): # Combine all tracks in mixer self.track_mixer = Mixer(outs=1) for inst_index in range(0, len(self.instruments)): instrument = self.instruments[inst_index] generator = instrument.get_generator() self.track_mixer.addInput(inst_index, generator) self.track_mixer.setAmp(inst_index, 0, instrument.get_volume()) # Prepare master output self.master_out = Mixer(outs=1, chnls=2) self.master_out.addInput(0, self.track_mixer[0]) self.master_out.setAmp(0, 0, self.global_volume) self.master_out.out() def add_gui(self, gui): """ Sets the GUI that this music player must instruct to update playhead. Must be called right after constructor before operation. Arguments: gui: GUI object monitoring this player """ self.gui = gui def terminate(self): """Terminate MusicPlayer server in preparation for shutdown""" self.server.stop() self.server.shutdown() def step(self): """ Step the music player through next beat """ # Set GUI to reflect current beat self.gui.update_playhead() # Play step for instruments for instrument in self.instruments: instrument.play_step() # For next iteration, increment playhead and beat indices self.playhead_index = (self.playhead_index + 1) % self.NUM_COLS if (self.play_all == True): self.beat_index = (self.beat_index + 1) % self.NUM_BEATS elif (self.play_all == False): self.beat_index = (self.page_index * self.NUM_COLS) +\ self.playhead_index def add_network_handler(self, network_handler): self.network_handler = network_handler """playback methods""" def play(self): self.metronome.play() def pause(self): for instrument in self.instruments: instrument.pause() self.metronome.stop() def set_session(self, session): """used to load a session into the music player""" # Reload pertinent MusicPlayer variables self.set_tempo(session.tempo) # Reconstruct each instrument from session data self.instruments = [] instrument_data = session.instrument_data for data in instrument_data: volume = data.volume reverb_mix = data.reverb_mix notes = data.notes if isinstance(data, WaveInstrumentData): wavetype = data.wavetype wave_instrument = WaveInstrument(self, wavetype, volume, reverb_mix, notes) self.instruments.append(wave_instrument) elif isinstance(data, DrumInstrumentData): drum_instrument = DrumInstrument(self, volume, reverb_mix, notes) self.instruments.append(drum_instrument) # Reload mixer to reflect new instruments self.mixer_setup() """ Modifiers """ def set_note(self, note): instrument = self.instruments[note.track_id] instrument.set_note(note) def set_global_volume(self, volume): self.global_volume = volume self.master_out.setAmp(0, 0, volume) def set_volume(self, track_id, volume): self.instruments[track_id].set_volume(volume) self.track_mixer.setAmp(track_id, 0, volume) def set_reverb(self, track_id, reverb): self.instruments[track_id].set_reverb(reverb) def set_tempo(self, new_tempo): new_time = self.SECONDS_PER_MIN / new_tempo self.metronome.setTime(new_time) self.tempo = new_tempo """getter methods""" def get_session(self): """Get descriptive MusicPlayer session to restore later""" session = Session(self, self.instruments) return session """getter methods for GUI""" def get_names(self, track_id): return self.instruments[track_id].get_names() def get_reverb(self, track_id): return self.instruments[track_id].get_reverb() def get_volume(self, track_id): return self.instruments[track_id].get_volume() def get_global_volume(self): return self.global_volume def get_tempo(self): return self.tempo def get_note(self, track_id, page_index, position, pitch): pass def get_current_page(self, track_id): instrument = self.instruments[track_id] notes = instrument.get_page(self.page_index) return notes