class UtilsTests(unittest.TestCase): test_get_note = {'C': 60,'C': 0, 'G': 127, 'E': 64, 'A#': 70}; test_get_note_number = {0: 60, 1:85,2:122,3:99,4:16,5:41,6:90,7:55,8:44,9:21,10:70,11:83}; test_get_midi_number = {0:['C',-1],60:['C',4],12:['C',0],120:['C',9],127:['G',9]}; test_normalize_scale = [['G', 'C##', 'Bb', 'B##b', 'A#', 'D', 'B#'],['C','D', 'G', 'A#']]; test_calc_scale_cases = []; def setUp(self): self.utils = Utils(); utils_for_tests = UtilsForTests(); self.test_calc_scale_cases = utils_for_tests.loadTestCorpus('test_corpus/test_calc_scale_corpus'); def test_getNote(self): for note, midi_note in self.test_get_note.iteritems(): self.assertEqual(note, self.utils.getNote(midi_note)); def test_getNoteNumber(self): for note_number, midi_note in self.test_get_note_number.iteritems(): self.assertEqual(note_number, self.utils.getNoteNumber(midi_note)); def test_getMidiNumber(self): for midi_note, note_octave in self.test_get_midi_number.iteritems(): self.assertEqual(midi_note, self.utils.getMidiNumber(note_octave[0],note_octave[1])); def test_getNoteAndOctave(self): for midi_note, note_octave in self.test_get_midi_number.iteritems(): self.assertEqual(note_octave[0], self.utils.getNoteAndOctave(midi_note)[0]); self.assertEqual(note_octave[1], self.utils.getNoteAndOctave(midi_note)[1]); def test_normalizeScale(self): norm_scale = self.utils.normalizeScale(self.test_normalize_scale[0]); self.assertSequenceEqual(norm_scale, self.test_normalize_scale[1]); def test_calcScale(self): for case in self.test_calc_scale_cases: scale = self.utils.calcScale(case[1],case[0]); self.assertListEqual(scale, case[2]);
class Gui(Frame): transpose = 0; scale_to_map = []; mapped_scale = {}; auto_mode = False; button_state_map = {}; event_types = (NOTE_ON, NOTE_OFF); button_color_state_map_black = {True:'#00CCA9',False:'#2b3633'}; button_color_state_map_white = {True:'#00CCA9',False:'#FFFFCD'}; def __init__(self,Master=None,*pos,**kw): self.utils = Utils(); self.cache = ScaleCache(); self.mapper = Mapper(); self.load_init_button_states(); ############### GUI ############### apply(Frame.__init__,(self,Master),kw) self._Frame4 = Frame(self) self._Frame4.pack(expand='yes',fill='both',side='left') self._Frame3 = Frame(self,background='#016678') self._Frame3.pack(expand='yes',fill='both',side='left') self._Frame29 = Frame(self._Frame4,background='#016678') self._Frame29.pack(expand='yes',fill='both',side='top') self._ListboxNote = Listbox(self._Frame29,background='#014455' ,foreground='#CCFFDE',height='4',highlightthickness='0' ,selectborderwidth='5',selectmode='extended',width='6') self._ListboxNote.pack(expand='yes',fill='both',side='left') self._Frame28 = Frame(self._Frame4,background='#016678') self._Frame28.pack(expand='yes',fill='both',side='top') self._ListboxScale = Listbox(self._Frame28,background='#014455' ,foreground='#CCFFDE',height='5',highlightthickness='0' ,selectmode='extended',width='6') self._ListboxScale.pack(expand='yes',fill='both',side='left') self._Frame17 = Frame(self._Frame3) self._Frame17.pack(expand='yes',fill='both',side='top') self._LabelStatus = Label(self._Frame17,background='#FFFFCD' ,relief='groove',state='disabled',text='This is test text.') self._LabelStatus.pack(expand='yes',fill='both',side='top') self._Frame11 = Frame(self._Frame3,background='#016678') self._Frame11.pack(expand='yes',fill='both',side='top') self._Frame10 = Frame(self._Frame3,background='#016678') self._Frame10.pack(side='top') self._Frame19 = Frame(self._Frame3) self._Frame19.pack(side='top') self._Frame18 = Frame(self._Frame3) self._Frame18.pack(expand='yes',fill='both',side='top') self._Frame32 = Frame(self._Frame11,background='#016678') self._Frame32.pack(side='left') self._MenuInput = Menubutton(self._Frame32,activebackground='#3b3c3c' ,activeforeground='#CCFFDE',background='#FFFFCD',menu='_MenuInputs' ,text='Input',width='10') self._MenuInput.pack(expand='yes',fill='both',side='top') self._Frame33 = Frame(self._Frame11,background='#016678') self._Frame33.pack(expand='yes',fill='x',side='left') self._ButtonScanMidi = Button(self._Frame33,activebackground='#3b3c3c' ,activeforeground='#CCFFDE',background='#2b3633' ,command=self._on__ButtonScanMidi_command,foreground='#CCFFDE' ,text='Scan') self._ButtonScanMidi.pack(expand='yes',fill='x',side='top') self._Frame31 = Frame(self._Frame11,background='#016678') self._Frame31.pack(expand='yes',fill='both',side='left') self._MenuOutput = Menubutton(self._Frame31,activebackground='#3b3c3c' ,activeforeground='#CCFFDE',background='#FFFFCD',text='Output' ,width='10') self._MenuOutput.pack(expand='yes',fill='x',side='top') self._Frame22 = Frame(self._Frame10,background='#016678',width='1') self._Frame22.pack(expand='yes',fill='both',side='left') self._Frame24 = Frame(self._Frame10,background='#016678' ,highlightbackground='Black',width='20') self._Frame24.pack(expand='yes',fill='both',side='left') self._ButtonCSharp = Button(self._Frame24,activebackground='#3b3c3c' ,activeforeground='#CCFFDE',background='#2b3633' ,command=self._on__ButtonCSharp_command,foreground='#CCFFDE' ,height='2',relief='flat',text='C#',width='1') self._ButtonCSharp.pack(expand='yes',side='left') self._Frame13 = Frame(self._Frame10,background='#016678',width='10') self._Frame13.pack(expand='yes',fill='both',side='left') self._Frame14 = Frame(self._Frame10) self._Frame14.pack(expand='yes',fill='both',side='left') self._ButtonDSharp = Button(self._Frame14,activebackground='#3b3c3c' ,activeforeground='#CCFFDE',background='#2b3633' ,command=self._on__ButtonDSharp_command,foreground='#CCFFDE' ,height='2',text='D#',width='1') self._ButtonDSharp.pack(expand='yes',fill='both',side='left') self._Frame7 = Frame(self._Frame10,background='#016678',width='50') self._Frame7.pack(expand='yes',fill='both',side='left') self._Frame8 = Frame(self._Frame10,background='#016678') self._Frame8.pack(expand='yes',fill='both',side='left') self._ButtonFSharp = Button(self._Frame8,activebackground='#3b3c3c' ,activeforeground='#CCFFDE',background='#2b3633' ,command=self._on__ButtonFSharp_command,foreground='#CCFFDE' ,height='2',text='F#',width='1') self._ButtonFSharp.pack(expand='yes',fill='both',side='left') self._Frame15 = Frame(self._Frame10,background='#016678',width='10') self._Frame15.pack(expand='yes',fill='both',side='left') self._Frame26 = Frame(self._Frame10) self._Frame26.pack(expand='yes',fill='both',side='left') self._ButtonGSharp = Button(self._Frame26,activebackground='#3b3c3c' ,activeforeground='#CCFFDE',background='#2b3633' ,command=self._on__ButtonGSharp_command,foreground='#CCFFDE' ,height='2',text='G#',width='1') self._ButtonGSharp.pack(expand='yes',fill='both',side='left') self._Frame12 = Frame(self._Frame10,background='#016678',width='10') self._Frame12.pack(expand='yes',fill='both',side='left') self._Frame16 = Frame(self._Frame10) self._Frame16.pack(expand='yes',fill='both',side='left') self._ButtonASharp = Button(self._Frame16,activebackground='#3b3c3c' ,activeforeground='#CCFFDE',background='#2b3633' ,command=self._on__ButtonASharp_command,foreground='#CCFFDE' ,height='2',text='A#',width='1') self._ButtonASharp.pack(expand='yes',fill='both',side='left') self._Frame30 = Frame(self._Frame10,background='#016678') self._Frame30.pack(expand='yes',fill='both',side='left') self._Frame21 = Frame(self._Frame19,background='#016678',width='20') self._Frame21.pack(expand='yes',fill='both',side='left') self._ButtonC = Button(self._Frame21,activebackground='#ffffff' ,activeforeground='#2b3633',background='#FFFFCD',borderwidth='3' ,command=self._on__ButtonC_command,height='2',text='C') self._ButtonC.pack(expand='yes',fill='both',side='left') self._Frame25 = Frame(self._Frame19) self._Frame25.pack(expand='yes',fill='both',side='left') self._ButtonD = Button(self._Frame25,activebackground='#ffffff' ,activeforeground='#2b3633',background='#FFFFCD' ,command=self._on__ButtonD_command,text='D') self._ButtonD.pack(expand='yes',fill='both',side='left') self._Frame20 = Frame(self._Frame19) self._Frame20.pack(expand='yes',fill='both',side='left') self._ButtonE = Button(self._Frame20,activebackground='#ffffff' ,activeforeground='#2b3633',background='#FFFFCD' ,command=self._on__ButtonE_command,text='E') self._ButtonE.pack(expand='yes',fill='both',side='right') self._Frame1 = Frame(self._Frame19) self._Frame1.pack(expand='yes',fill='both',side='left') self._ButtonF = Button(self._Frame1,activebackground='#ffffff' ,activeforeground='#2b3633',background='#FFFFCD' ,command=self._on__ButtonF_command,text='F') self._ButtonF.pack(expand='yes',fill='both',side='right') self._Frame27 = Frame(self._Frame19) self._Frame27.pack(expand='yes',fill='both',side='left') self._ButtonG = Button(self._Frame27,activebackground='#ffffff' ,activeforeground='#2b3633',background='#FFFFCD' ,command=self._on__ButtonG_command,text='G') self._ButtonG.pack(expand='yes',fill='both',side='left') self._Frame2 = Frame(self._Frame19) self._Frame2.pack(expand='yes',fill='both',side='left') self._ButtonA = Button(self._Frame2,activebackground='#ffffff' ,activeforeground='#2b3633',background='#FFFFCD' ,command=self._on__ButtonA_command,text='A') self._ButtonA.pack(expand='yes',fill='both',side='right') self._Frame6 = Frame(self._Frame19) self._Frame6.pack(expand='yes',fill='both',side='left') self._ButtonB = Button(self._Frame6,activebackground='#ffffff' ,activeforeground='#2b3633',background='#FFFFCD' ,command=self._on__ButtonB_command,text='B') self._ButtonB.pack(expand='yes',fill='both',side='right') self._Frame5 = Frame(self._Frame19,background='#016678') self._Frame5.pack(expand='yes',fill='both',side='left') self._Frame23 = Frame(self._Frame18,background='#016678') self._Frame23.pack(expand='yes',fill='both',side='left') self._ScaleTrans = Scale(self._Frame23,background='#016678' ,bigincrement=1,borderwidth='0',command=self._on__ScaleTrans_command ,foreground='#2b3633',from_=-12,highlightbackground='#3b3c3c' ,highlightcolor='#3b3c3c',highlightthickness='0' ,label='Transpose(cents)',orient='horizontal',resolution=1 ,sliderlength='50',tickinterval=0,to=12) self._ScaleTrans.pack(expand='yes',fill='x',side='left') self._Frame9 = Frame(self._Frame18,background='#016678') self._Frame9.pack(expand='yes',fill='both',side='left') self._ButtonAutoMode = Button(self._Frame9,activebackground='#ffffff' ,activeforeground='#2b3633',background='#FFFFCD',text='Magic mode' ,width='7') self._ButtonAutoMode.pack(expand='yes',side='bottom') self._Frame34 = Frame(self._Frame18,background='#016678') self._Frame34.pack(expand='yes',fill='both',side='left') self._ButtonQuit = Button(self._Frame34,activebackground='#BB1167' ,background='#CD0045',command=self._on__ButtonQuit_command ,text='Quit') self._ButtonQuit.pack(expand='yes',side='left') ############### GUI ############### self._MenuInput.menu = Menu(self._MenuInput, tearoff = 0 ); self._MenuInput["menu"] = self._MenuInput.menu; self._MenuOutput.menu = Menu(self._MenuOutput, tearoff = 0 ); self._MenuOutput["menu"] = self._MenuOutput.menu; self.midi_in = None; self.midi_out = None; self.check_midi_ports(); self._ButtonAutoMode.config(command=self.process_auto_mode_change); self.showMessage("Loading..."); for note in self.utils.getNotes(): self._ListboxNote.insert(END, note); for scale in self.utils.getAvailableScales(): self._ListboxScale.insert(END, scale); self.current_scale = [10]; self.current_note = [0]; self.process_note_change(self.current_note); self.showMessage("Ready to work, sir!"); self.current_note = (); self.current_scale = (); self.poll_lists(); # start polling the list def process_auto_mode_change(self): if self.auto_mode: self.auto_mode = False; else: self.auto_mode = True; self.showMessage("Magic Mode!"); def check_midi_ports(self): if self.midi_in is not None: self.midi_in.close_port(); if self.midi_out is not None: self.midi_out.close_port(); self.midi_in = rtmidi.MidiIn(); self.midi_out = rtmidi.MidiOut(); ports_in = self.midi_in.ports; ports_out = self.midi_out.ports; self._MenuInput.menu.delete(0,END); self._MenuOutput.menu.delete(0,END); if len(ports_in) == 0: self._MenuInput.config(text="No input devices"); else: for port_index in range(0, len(ports_in)): self._MenuInput.menu.add_command(label=ports_in[port_index], command=lambda port_index=port_index: self.midi_in_device_select_callback(port_index)); self.midi_in_device_select_callback(0); if len(ports_out) == 0: self._MenuInput.config(text="No output devices"); else: for port_index in range(0, len(ports_out)): self._MenuOutput.menu.add_command(label=ports_out[port_index], command=lambda port_index=port_index: self.midi_out_device_select_callback(port_index)); self.midi_out_device_select_callback(0); def midi_out_device_select_callback(self, port_index): self.midi_out.close_port(); self.midi_out.open_port(port_index); self.updateMenuTitle(port_index, self._MenuOutput, self._MenuOutput.menu); def midi_in_device_select_callback(self, port_index): self.midi_in.close_port(); self.midi_in.open_port(port_index); self.midi_in.callback = self.midi_callback self.updateMenuTitle(port_index, self._MenuInput, self._MenuInput.menu); def updateMenuTitle(self, index, menu_button, menu): menu_button.config(text=menu.entrycget(index, "label")); def poll_lists(self): now_note = self._ListboxNote.curselection(); now_scale = self._ListboxScale.curselection(); if len(now_note) != 0 and now_note != self.current_note: self.process_note_change(now_note) self.current_note = now_note if len(now_scale) != 0 and now_scale != self.current_scale: self.process_scale_change(now_scale) self.current_scale = now_scale self.after(250, self.poll_lists) def midi_callback(self, message, time_stamp): event_types = (NOTE_ON, NOTE_OFF) if (message[0] & 0xF0) in event_types: self.showCurrentNote(message); if self.auto_mode: if(message[1] < 60): note_scale = self.utils.getNoteAndOctave(message[1]); if len(self._ListboxScale.curselection()) == 0: self.showMessage("Select scale first!"); else: scale = self.utils.getAvailableScales()[self._ListboxScale.curselection()[0]]; self.mapped_scale = self.cache.getScaleFromCache(note_scale[0],scale); self.showMessage("Magic mode scale:%s-%s"%(note_scale[0],scale)); self.midi_out.send_message(message); else: self.send_modif_massage(message); else: self.send_modif_massage(message); else: self.midi_out.send_message(message); def send_modif_massage(self, message): note_octave = self.utils.getNoteAndOctave(message[1]); message[1] = self.utils.getMidiNumber(self.mapped_scale[note_octave[0]], note_octave[1]); message[1] += self.transpose; self.midi_out.send_message(message); def showCurrentNote(self, message): note_octave = self.utils.getNoteAndOctave(message[1]); note_name = note_octave[0]; octave = note_octave[1]; if (message[0] & 0xF0) in self.event_types: self.showMessage("Note: %s, Octave: %s, Vel: %s"%(note_name,octave,message[2])); def _on__ButtonScanMidi_command(self,Event=None): self.check_midi_ports(); def process_note_change(self, note): if len(note) != 0 and len(self.current_scale) != 0: note_name = notes.int_to_note(note[0]); scale_name = self.utils.getAvailableScales()[self.current_scale[0]]; self.scale_to_map = self.mapper.getScaleToMap(note_name, scale_name); self.mapped_scale = self.cache.getScaleFromCache(note_name, scale_name); self.show_scale_to_buttons(); self.auto_mode = False; self.showMessage(note_name + " - " + scale_name); def process_scale_change(self, scale): if len(scale) != 0 and len(self.current_note) != 0: note_name = notes.int_to_note(self.current_note[0]); scale_name = self.utils.getAvailableScales()[scale[0]]; self.scale_to_map = self.mapper.getScaleToMap(note_name, scale_name); self.mapped_scale = self.cache.getScaleFromCache(note_name, scale_name); self.show_scale_to_buttons(); self.auto_mode = False; self.showMessage(note_name + " - " + scale_name); def show_scale_to_buttons(self): for note in self.utils.getNotes(): button_name = note.replace('#','Sharp'); button_name = "self._Button" + button_name; if note in self.scale_to_map: self.button_state_map[note] = True if '#' in note: button_color = self.button_color_state_map_black[True]; else: button_color = self.button_color_state_map_white[True]; else: self.button_state_map[note] = False if '#' in note: button_color = self.button_color_state_map_black[False]; else: button_color = self.button_color_state_map_white[False]; eval(button_name + ".configure(bg = '" + button_color + "')"); def load_init_button_states(self): for note in self.utils.getNotes(): self.button_state_map[note] = False; def process_button_change(self, note): new_state = self.update_scale_to_map(note); self.button_state_map[note] = new_state; self.set_custom_mapped_scale(); #self.searchForScale(self.scale_to_map) self.auto_mode = False; return new_state; def searchForScale(self, scale_to_search): for note in self.utils.getNotes(): for scale in self.utils.getAvailableScales(): if set(scale_to_search) == set(self.mapper.getScaleToMap(note, scale)): print note,scale; print hash(set(scale_to_search)) print hash(set(self.mapper.getScaleToMap(note, scale))) def update_scale_to_map(self, note): if self.button_state_map[note] is True: self.scale_to_map.remove(note); return False; else: self.scale_to_map.append(note); return True; def set_custom_mapped_scale(self): if len(self.scale_to_map) != 0: self.mapped_scale = self.mapper.getCustomMap(self.scale_to_map); self.showMessage("Cutom scale: \n"); def showMessage(self, message): self._LabelStatus.config(text = message); def _on__ButtonASharp_command(self,Event=None): new_state = self.process_button_change('A#'); self._ButtonASharp.configure(bg = self.button_color_state_map_black[new_state]); def _on__ButtonA_command(self,Event=None): new_state = self.process_button_change('A'); self._ButtonA.configure(bg = self.button_color_state_map_white[new_state]); def _on__ButtonB_command(self,Event=None): new_state = self.process_button_change('B'); self._ButtonB.configure(bg = self.button_color_state_map_white[new_state]); def _on__ButtonCSharp_command(self,Event=None): new_state = self.process_button_change('C#'); self._ButtonCSharp.configure(bg = self.button_color_state_map_black[new_state]); def _on__ButtonC_command(self,Event=None): new_state = self.process_button_change('C'); self._ButtonC.configure(bg = self.button_color_state_map_white[new_state]); def _on__ButtonDSharp_command(self,Event=None): new_state = self.process_button_change('D#'); self._ButtonDSharp.configure(bg = self.button_color_state_map_black[new_state]); def _on__ButtonD_command(self,Event=None): new_state = self.process_button_change('D'); self._ButtonD.configure(bg = self.button_color_state_map_white[new_state]); def _on__ButtonE_command(self,Event=None): new_state = self.process_button_change('E'); self._ButtonE.configure(bg = self.button_color_state_map_white[new_state]); def _on__ButtonFSharp_command(self,Event=None): new_state = self.process_button_change('F#'); self._ButtonFSharp.configure(bg = self.button_color_state_map_black[new_state]); def _on__ButtonF_command(self,Event=None): new_state = self.process_button_change('F'); self._ButtonF.configure(bg = self.button_color_state_map_white[new_state]); def _on__ButtonGSharp_command(self,Event=None): new_state = self.process_button_change('G#'); self._ButtonGSharp.configure(bg = self.button_color_state_map_black[new_state]); def _on__ButtonG_command(self,Event=None): new_state = self.process_button_change('G'); self._ButtonG.configure(bg = self.button_color_state_map_white[new_state]); def _on__ButtonQuit_command(self,Event=None): if self.midi_in is not None: self.midi_in.close_port(); if self.midi_out is not None: self.midi_out.close_port(); exit(0); def _on__ScaleTrans_command(self,Event=None): self.transpose = self._ScaleTrans.get();
class MainForm(QtGui.QMainWindow): NOTE_OFF = 0x80 NOTE_ON = 0x90 def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.utils = Utils(); self.cache = ScaleCache(); self.mapper = Mapper(); self.scale_to_map = []; self.mapped_scale = {}; self.transpose = 0; self.autoScale = False; self.ui = Ui_MainWindow(); self.ui.setupUi(self); self.loadAvailableScales(); self.loadInitScale(); self.midi_in = None; self.midi_out = None; self.check_midi_ports(); self.ui.statusBar.showMessage("Ready for rock'N'roll!",1000 * 20); def loadAvailableScales(self): for scale in self.utils.getAllAvailableScales(): self.ui.listWidgetScales.addItem(scale); def loadInitScale(self): self.ui.listWidgetNotes.setCurrentRow(0); self.ui.listWidgetScales.setCurrentRow(0); result = self.cache.getScaleFromCache(str(self.ui.listWidgetNotes.item(0).text()),str(self.ui.listWidgetScales.item(0).text())); self.setNewScale(result); @QtCore.pyqtSlot(str) def on_listWidgetScales_currentTextChanged(self, scale): currNote = self.ui.listWidgetNotes.currentItem(); if currNote is not None: result = self.cache.getScaleFromCache(str(currNote.text()), str(scale)); self.setNewScale(result); self.ui.statusBar.showMessage("Mapped scale: %s-%s"%(str(currNote.text()),str(scale)), 1000 * 5); @QtCore.pyqtSlot(str) def on_listWidgetNotes_currentTextChanged(self, note): currScale = self.ui.listWidgetScales.currentItem(); if currScale is not None: result = self.cache.getScaleFromCache(str(note), str(currScale.text())); self.setNewScale(result); self.autoScale = False; self.ui.pushButtonMagic.setChecked(False); self.ui.statusBar.showMessage("Mapped scale: %s-%s"%(str(note),str(currScale.text())), 1000 * 5); def setNewScale(self, scales): self.scale_to_map = scales['scale_to_map']; self.mapped_scale = scales['mapped_scale']; self.showOnKeys(); def showOnKeys(self): for key in self.utils.getNotes(): replacedKey = key.replace('#','S'); if key in self.scale_to_map: new_state = True; else: new_state = False; eval('self.ui.pushButton' + replacedKey + ".setChecked(" + str(new_state) + ")"); def setNewKeyState(self, key, state): if state: self.scale_to_map.append(key); self.mapped_scale = self.mapper.getMap(self.scale_to_map); else: if key in self.scale_to_map: self.scale_to_map.remove(key); if len(self.scale_to_map) != 0: self.mapped_scale = self.mapper.getMap(self.scale_to_map); self.autoScale = False; self.ui.pushButtonMagic.setChecked(False); self.ui.statusBar.showMessage("Custom scale: " + str(self.scale_to_map), 1000 * 5); @QtCore.pyqtSlot(bool) def on_pushButtonC_clicked(self, status): self.setNewKeyState('C', status); @QtCore.pyqtSlot(bool) def on_pushButtonCS_clicked(self, status): self.setNewKeyState('C#', status); @QtCore.pyqtSlot(bool) def on_pushButtonD_clicked(self, status): self.setNewKeyState('D', status); @QtCore.pyqtSlot(bool) def on_pushButtonDS_clicked(self, status): self.setNewKeyState('D#', status); @QtCore.pyqtSlot(bool) def on_pushButtonE_clicked(self, status): self.setNewKeyState('E', status); @QtCore.pyqtSlot(bool) def on_pushButtonF_clicked(self, status): self.setNewKeyState('F', status); @QtCore.pyqtSlot(bool) def on_pushButtonFS_clicked(self, status): self.setNewKeyState('F#', status); @QtCore.pyqtSlot(bool) def on_pushButtonG_clicked(self, status): self.setNewKeyState('G', status); @QtCore.pyqtSlot(bool) def on_pushButtonGS_clicked(self, status): self.setNewKeyState('G#', status); @QtCore.pyqtSlot(bool) def on_pushButtonA_clicked(self, status): self.setNewKeyState('A', status); @QtCore.pyqtSlot(bool) def on_pushButtonAS_clicked(self, status): self.setNewKeyState('A#', status); @QtCore.pyqtSlot(bool) def on_pushButtonB_clicked(self, status): self.setNewKeyState('B', status); @QtCore.pyqtSlot(int) def on_spinBoxTranspose_valueChanged(self, value): self.transpose = value; @QtCore.pyqtSlot() def on_pushButtonScan_clicked(self): self.check_midi_ports(); def check_midi_ports(self): if self.midi_in is not None: self.midi_in.close_port(); if self.midi_out is not None: self.midi_out.close_port(); self.midi_in = rtmidi.MidiIn(); self.midi_out = rtmidi.MidiOut(); ports_in = self.midi_in.ports; ports_out = self.midi_out.ports; self.ui.listWidgetInput.clear(); self.ui.listWidgetOutput.clear(); if len(ports_in) == 0: self.ui.listWidgetInput.addItem("No input devices"); else: for port_index in range(0, len(ports_in)): self.ui.listWidgetInput.addItem(ports_in[port_index]); self.on_listWidgetInput_currentRowChanged(0); if len(ports_out) == 0: self.ui.listWidgetOutput.addItem("No input devices"); else: for port_index in range(0, len(ports_out)): self.ui.listWidgetOutput.addItem(ports_out[port_index]); self.on_listWidgetOutput_currentRowChanged(0); self.ui.statusBar.showMessage("Scan completed!",1000*5); @QtCore.pyqtSlot(bool) def on_pushButtonMagic_clicked(self, state): self.autoScale = state; self.ui.statusBar.showMessage("Magic mode: %s"%(state),1000*5); @QtCore.pyqtSlot() def on_pushButtonPanic_clicked(self): message = [self.NOTE_OFF,0,0]; for i in range(0, 127): message[1] = i; self.midi_out.send_message(message); @QtCore.pyqtSlot(int) def on_listWidgetInput_currentRowChanged(self, port): self.midi_in.close_port(); self.midi_in.open_port(port); self.midi_in.callback = self.midi_callback self.ui.statusBar.showMessage("%s port opened!"%(self.ui.listWidgetInput.item(port).text()),1000*5); @QtCore.pyqtSlot(int) def on_listWidgetOutput_currentRowChanged(self, port): self.midi_out.close_port(); self.midi_out.open_port(port); self.ui.statusBar.showMessage("%s port opened!"%(self.ui.listWidgetOutput.item(port).text()),1000*5); def midi_callback(self, message, time_stamp): event_types = (self.NOTE_ON, self.NOTE_OFF) if (message[0] & 0xF0) in event_types: if self.autoScale: if(message[1] < 60): note_scale = self.utils.getNoteAndOctave(message[1]); scale = str(self.ui.listWidgetScales.currentItem().text()); result = self.cache.getScaleFromCache(note_scale[0], scale); self.scale_to_map = result['scale_to_map']; self.mapped_scale = result['mapped_scale']; #self.ui.statusBar.showMessage("Magic mode scale:%s-%s"%(note_scale[0],scale),1000*5); self.midi_out.send_message(message); else: self.send_modif_massage(message); else: self.send_modif_massage(message); else: self.midi_out.send_message(message); def send_modif_massage(self, message): note_octave = self.utils.getNoteAndOctave(message[1]); message[1] = self.utils.getMidiNumber(self.mapped_scale[note_octave[0]], note_octave[1]); message[1] += self.transpose; self.midi_out.send_message(message); @QtCore.pyqtSlot() def on_pushButtonExit_clicked(self): self.closeOpenPorts(); self.close(); def closeOpenPorts(self): if self.midi_in is not None: self.midi_in.close_port(); if self.midi_out is not None: self.midi_out.close_port(); def __exit__(self): self.closeOpenPorts();