class MidiThread(threading.Thread): def __init__(self,timeline): super().__init__() self.stopped = False self.MC = MidiControl() self.timeline = timeline def run(self): print('running') while not self.isStopped(): res = self.MC.test_inp() if res: #print(res) n = res[1] if n > 120: n = n - 128 if n < 10: timeline.integrate_midi(n) #print(n) print('stopped') def isStopped(self): return self.stopped def stop(self): self.stopped = True self.MC.quit()
class BackingTrackPlayerApp(App): def __init__(self, **kwargs): super().__init__(**kwargs) self.mc = MidiControl() def build(self): self.title = 'Backing Track Player V1.0' self.use_kivy_settings = False Window.bind(on_dropfile=self._dropfile_action) return Builder.load_string(kv) def _dropfile_action(self, window, path): self.root.set_backing_track(path.decode()) def on_start(self): names = self.mc.get_midi_ports() self.root.ids.midi_devices.values = names m_input = self.config.getdefault('MIDI', 'input', 'None') ch = self.config.get('MIDI', 'channel') song = self.config.get('Track', 'song') if m_input in names: self.root.set_backing_track( song ) # before set midi ports - so errors can show in track area self.mc.set_midi_port(m_input) self.mc.midi_channel = int(ch) self.root.ids.midi_devices.text = m_input self.root.ids.midi_ch.text = str(int(ch) + 1) Clock.schedule_interval(self.mc.read_midi_callback, .1) def open_settings(self, *largs): # kivy control panel will not open pass def build_config(self, config): config.setdefaults('MIDI', {'input': 'None', 'channel': 'None'}) config.setdefaults('Track', {'song': 'None'}) def get_application_config(self, defaultpath='%(appdir)s/%(appname)s.ini'): if platform == 'macosx': # mac will not write into app folder s = '~/.%(appname)s.ini' else: s = defaultpath return super().get_application_config(defaultpath=s) def on_stop(self): if self.mc.midi_in_port and self.mc.midi_channel is not None and self.root.track_path: self.config.set('MIDI', 'input', self.mc.midi_in_port.name) self.config.set('MIDI', 'channel', self.mc.midi_channel) self.config.set('Track', 'song', self.root.track_path) self.config.write()
def __init__(self,timeline): super().__init__() self.stopped = False self.MC = MidiControl() self.timeline = timeline
def __init__(self, **kwargs): super().__init__(**kwargs) self.mc = MidiControl()
class BackingTrackPlayerApp(App): def __init__(self, **kwargs): super().__init__(**kwargs) self.mc = MidiControl() def build(self): self.title = 'Backing Track Player V1.01' self.use_kivy_settings = False Window.minimum_width = window_width Window.minimum_height = window_height # Window.size = 800, 375 Window.bind(on_dropfile=self._dropfile_action) Window.bind(on_request_close=self.window_request_close) return Builder.load_string(kv) def _dropfile_action(self, _, path): self.root.ids.sm.get_screen('play_screen').set_backing_track( path.decode()) def on_start(self): names = self.mc.get_midi_ports() self.root.ids.midi_devices.values = names m_input = self.config.getdefault('MIDI', 'input', 'None') ch = self.config.get('MIDI', 'channel') song = self.config.get('Track', 'song') if not Path(song).exists( ): # if track that was in config file was no longer exists... song = 'None' self.root.ids.sm.get_screen('play_screen').set_backing_track(song) # before set midi ports - so errors can show in track area if m_input in names: self.mc.set_midi_port(m_input) self.mc.midi_channel = int(ch) self.root.ids.midi_devices.text = m_input self.root.ids.midi_ch.text = str(int(ch) + 1) Clock.schedule_interval(self.mc.read_midi_callback, .1) def open_settings(self, *largs): # kivy control panel will not open pass def build_config(self, config): config.setdefaults('MIDI', {'input': 'None', 'channel': 'None'}) config.setdefaults('Track', {'song': 'None'}) config.setdefaults( 'Window', { 'width': window_width, 'height': window_height, 'top': window_top, 'left': window_left }) def get_application_config(self, defaultpath='%(appdir)s/%(appname)s.ini'): if platform == 'win' or platform == 'macosx': # mac will not write into app folder s = self.user_data_dir + '/%(appname)s.ini' # puts ini in AppData on Windows else: s = defaultpath return super().get_application_config(defaultpath=s) def window_request_close(self, _): # Window.size is automatically adjusted for density, must divide by density when saving size config = self.config config.set('Window', 'width', int(Window.size[0] / Metrics.density)) config.set('Window', 'height', int(Window.size[1] / Metrics.density)) config.set('Window', 'top', Window.top) config.set('Window', 'left', Window.left) self.config.write() return False def on_stop(self): p = self.root.ids.sm.get_screen('play_screen').track_path if p: self.config.set('Track', 'song', p) self.config.write() if self.mc.midi_in_port and self.mc.midi_channel is not None: self.config.set('MIDI', 'input', self.mc.midi_in_port.name) self.config.set('MIDI', 'channel', self.mc.midi_channel) self.config.write()
def setup_midi(self): self.midi_control = MidiControl(self)
class Backend: """ entire backend for sol """ def __init__(self,xmlfile=None,gui=None,ports=(7007,7008)): self.xmlfile = xmlfile self.library = Library(xmlfile) self.cur_clip = Clip('',[-1,-1],"no clip loaded") self.cur_song = None self.cur_rec = None self.cur_col = -1 self.search = SearchR(self.library.clips) self.osc_client = ControlR(self,port=ports[0]) self.osc_server = ServeR(gui,port=ports[1]) self.record = RecordR(self) self.last_save_file = None self.cur_time = RefObj("cur_time") self.cur_clip_pos = RefObj("cur_clip_pos",0.0) def update_time(_,msg): # this is the driving force behind the (audio) backend :o) try: self.cur_time.value = int(msg) except: pass def update_song_info(_,msg): if self.cur_song: self.cur_song.vars['total_len'] = int(msg) self.osc_server.map("/pyaud/pos/frame",update_time) self.osc_server.map("/pyaud/info/song_len",update_song_info) self.osc_server.map("/activeclip/video/position/values",self.cur_clip_pos.update_generator('float')) ### MIDI CONTROL # basically, here are the descriptions that map to functions # then in the midi config it reads the keys and figures out # what keys to set to which functions # which are then mapped thru the osc server to figure out # what to do with the note value (different types of notes) self.desc_to_fun = { 'clip_play' : self.osc_client.play , 'clip_pause' : self.osc_client.pause , 'clip_reverse' : self.osc_client.reverse , 'clip_random' : self.osc_client.random_play , 'clip_clear' : self.osc_client.clear , } # can also auto-gen some of these for cue select etc def gen_selector(i): index = i def fun_tor(): self.select_clip(self.library.clip_collections[self.cur_col][index]) return fun_tor for i in range(C.NO_Q): self.desc_to_fun['clip_{}'.format(i)] = gen_selector(i) # no clue how im going to add midi out.. for now self.midi_control = None #self.load_last() def setup_midi(self): self.midi_control = MidiControl(self) def save_data(self,savefile=None): if not os.path.exists('./savedata'): os.makedirs('./savedata') if not savefile: if not self.last_save_file: filename = os.path.splitext(self.xmlfile)[0] filename = filename.split('/')[-1] savefile = "./savedata/{}".format(filename) else: savefile = self.last_save_file ######## savedata = {'xmlfile':self.xmlfile,'library':self.library, 'current_clip':self.cur_clip,'current_collection':self.cur_col} ######## with open(savefile,'wb') as f: dill.dump(savedata,f) with open('./savedata/last_save','w') as last_save: last_save.write(savefile) print('successfully saved',savefile) self.last_save_file = savefile return savefile # success def load_data(self,savefile): if os.path.exists(savefile): with open(savefile,'rb') as save: savedata = dill.load(save) ######## loaddata = {'xmlfile':'self.xmlfile','library':'self.library', 'current_clip':'self.cur_clip','current_collection':'self.cur_col'} ######## for key in loaddata: if key in savedata: exec("{} = savedata[key]".format(loaddata[key])) self.search = SearchR(self.library.clips) print('successfully loaded',savefile) self.last_save_file = savefile def load_composition(self,fname): if fname == self.xmlfile: # add any new clips self.library.update_from_xml(fname) print('updated library from',fname) else: self.xmlfile = fname self.library = Library(fname) self.cur_clip = Clip('',[-1,-1],"no clip loaded") self.cur_col = -1 print('loaded library from',fname) self.search = SearchR(self.library.clips) def load_last(self): if os.path.exists('./savedata/last_save'): with open('./savedata/last_save') as last_save: fname = last_save.read() self.load_data(fname) if self.midi_control is not None: self.load_last_midi() #self.record.load_last() dangerous (have to implement dependency on audio track 2 do this) def load_last_midi(self): if os.path.exists('./savedata/last_midi'): with open('./savedata/last_midi','r') as last_midi: fname = last_midi.read() self.midi_control.map_midi(fname) def change_clip(self,newclip): if self.cur_clip is not None: self.cur_clip.last_pos = self.cur_clip_pos.value self.cur_clip = newclip self.osc_client.select_clip(newclip) def select_clip(self,newclip): # function to be overwritten : ) self.change_clip(newclip)