From e608f24907f3a4292a5af7b95c7be6f97d4432c4 Mon Sep 17 00:00:00 2001 From: Alperen Aga Date: Fri, 14 Oct 2022 00:27:32 +0300 Subject: [PATCH] Update Midi-Project (#21) Fix minor bugs Start separating files --- Main/Midi-Project/Midi-Project.py | 95 ++++++------------ Main/Midi-Project/midi/__init__.py | 3 + .../__pycache__/Midi_Functions.cpython-38.pyc | Bin 0 -> 2188 bytes .../midi/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 279 bytes .../basic_functions.cpython-38.pyc | Bin 0 -> 2189 bytes .../global_variables.cpython-38.pyc | Bin 0 -> 193 bytes .../midi/__pycache__/modules.cpython-38.pyc | Bin 0 -> 393 bytes Main/Midi-Project/midi/basic_functions.py | 47 +++++++++ Main/Midi-Project/midi/global_variables.py | 0 Main/Midi-Project/midi/modules.py | 4 + 10 files changed, 82 insertions(+), 67 deletions(-) create mode 100644 Main/Midi-Project/midi/__init__.py create mode 100644 Main/Midi-Project/midi/__pycache__/Midi_Functions.cpython-38.pyc create mode 100644 Main/Midi-Project/midi/__pycache__/__init__.cpython-38.pyc create mode 100644 Main/Midi-Project/midi/__pycache__/basic_functions.cpython-38.pyc create mode 100644 Main/Midi-Project/midi/__pycache__/global_variables.cpython-38.pyc create mode 100644 Main/Midi-Project/midi/__pycache__/modules.cpython-38.pyc create mode 100644 Main/Midi-Project/midi/basic_functions.py create mode 100644 Main/Midi-Project/midi/global_variables.py create mode 100644 Main/Midi-Project/midi/modules.py diff --git a/Main/Midi-Project/Midi-Project.py b/Main/Midi-Project/Midi-Project.py index 1eca0c0..45cb4f3 100644 --- a/Main/Midi-Project/Midi-Project.py +++ b/Main/Midi-Project/Midi-Project.py @@ -1,18 +1,11 @@ # @author: https://github.com/Alperencode # @date: 01 Aug 2022 +# @last update: 13 Oct 2022 -# Importing modules -from tkinter import * -from music21 import * -from tkinter import ttk,messagebox -import mido,time,threading,math,json,os,mido.backends.rtmidi +# Importing midi directory +from midi import * # Global variables -NOTES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] -PURE_NOTES = ['C', 'D', 'E', 'F', 'G', 'A', 'B'] -OTHER_NOTES = ['C#', 'D#', 'F#', 'G#', 'A#'] -MESSAGE_TYPES = ['note_on','note_off','pitchwheel','control_change'] -OCTAVES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] global_button_list = [] global_pitch_list = [] json_data = [] @@ -23,23 +16,11 @@ for _ in range(8): global_pitch_list.append([0,0,0,0,0,0,0,0,0,0,0,0]) -def converter(value, control): - """ - Range converter function to convert pitch value (-8192/8191) to cent value (-100/100) - control: True -> convert to cent value, False -> convert to pitch value - """ - if control: - new_value = (((value - (-8192)) * 200) / 16383) + (-100) - else: - new_value = (((value - (-100)) * 16383) / 200) + (-8192) - return int(new_value) - class NoteButton: """ This is the main class of the program which is basically responsible for sending the midi messages to the midi output. Detailed explanation has been provided in each function. """ - global output,app # Static variables # counter is used to keep track of the number of buttons created @@ -54,7 +35,7 @@ class NoteButton: pitch = [0,0,0,0,0,0,0,0,0,0,0,0] control_change = mido.Message('control_change', control=1, value=0) - def __init__(self,note_name,octave=5,velocity=64): + def __init__(self,note_name,octave=5,velocity=64,output=None, app=None): """ Initializing function of the class which takes 1 required argument and 2 optional arguments. note_name: name of the note @@ -70,39 +51,41 @@ def __init__(self,note_name,octave=5,velocity=64): self.__saved_pitch = 0 self.__entry_box_number = NoteButton.counter self.__entry_box = None + self.output = output + self.app = app # buttons are used to trigger 3 basic events: send note_on, wait for 100 miliseconds and send note_off # so command argument is used with lambda to trigger more than one function if note_name in PURE_NOTES: # Making note button white if the note is a pure note button = Button( - app,text=note_name, - command = lambda: (self.set_pitch(self.get_saved_pitch()), self.send_note_on(), self.send_pitch_wheel() , time.sleep(0.1), self.send_note_off()), + self.app,text=note_name, + command = lambda: (self.set_pitch(self.get_saved_pitch()), self.set_velocity(64), self.send_note_on(), self.send_pitch_wheel() , time.sleep(0.1), self.send_note_off()), width=10,height=15,bg="white",fg="#241f1f",activebackground="white",activeforeground="#241f1f",font=("Arial", 10, "bold")) else: # Making note button black if the note is not a pure note button = Button( - app,text=note_name, - command = lambda: (self.set_pitch(self.get_saved_pitch()), self.send_note_on(), self.send_pitch_wheel() , time.sleep(0.1), self.send_note_off()), + self.app,text=note_name, + command = lambda: (self.set_pitch(self.get_saved_pitch()), self.set_velocity(64),self.send_note_on(), self.send_pitch_wheel() , time.sleep(0.1), self.send_note_off()), width=4,height=7,bg="#241f1f",fg="white",activebackground="#241f1f",activeforeground="white",font=("Arial", 10, "bold")) # Placing label (note text) and entry box in the GUI if note_name in PURE_NOTES: NoteButton.label_counter += 1.5 - label = Label(app, text=note_name) + label = Label(self.app, text=note_name) label.place(x=10, y= 10 + (NoteButton.label_counter * 20)) - self.__entry_box = Entry(app, width=5) + self.__entry_box = Entry(self.app, width=5) self.__entry_box.place(x=50, y= 10 + (NoteButton.label_counter * 20)) self.__entry_box.bind('', lambda event: self.set_saved_pitch(self.__entry_box.get())) else: NoteButton.label_counter += 1.5 - label = Label(app, text=note_name) + label = Label(self.app, text=note_name) label.place(x=100, y= 10 + (NoteButton.label_counter * 20)) - self.__entry_box = Entry(app, width=5) + self.__entry_box = Entry(self.app, width=5) self.__entry_box.place(x=130, y= 10 + (NoteButton.label_counter * 20)) self.__entry_box.bind('', lambda event: self.set_saved_pitch(self.__entry_box.get())) @@ -193,29 +176,29 @@ def send_note_on(self): """ NoteButton.last_pressed_note = self.get_note_name() - output.send( NoteButton.control_change ) + self.output.send( NoteButton.control_change ) # Label will put an extra space if note is a pure note if self.get_note_name() in PURE_NOTES: - Label(app, text=f"Sending {self.get_note_name()} octave {self.get_octave()} with \n{self.__pitch_value} pitch and {self.get_velocity()} velocity",font=("Arial",12,"bold")).place(x=200, y=40) + Label(self.app, text=f"Sending {self.get_note_name()} octave {self.get_octave()} with \n{self.__pitch_value} pitch and {self.get_velocity()} velocity",font=("Arial",12,"bold")).place(x=200, y=40) else: - Label(app, text=f"Sending {self.get_note_name()} octave {self.get_octave()} with \n{self.__pitch_value} pitch and {self.get_velocity()} velocity",font=("Arial",12,"bold")).place(x=200, y=40) + Label(self.app, text=f"Sending {self.get_note_name()} octave {self.get_octave()} with \n{self.__pitch_value} pitch and {self.get_velocity()} velocity",font=("Arial",12,"bold")).place(x=200, y=40) # Sending midi signal - output.send( mido.Message('note_on', note=note_to_number(self.get_note_name(), self.get_octave()), velocity=self.get_velocity()) ) + self.output.send( mido.Message('note_on', note=note_to_number(self.get_note_name(), self.get_octave()), velocity=self.get_velocity()) ) def send_pitch_wheel(self): """Sending converted pitch value to the midi device""" sending_value = converter(self.get_pitch(), False) - output.send( mido.Message('pitchwheel', pitch=sending_value) ) + self.output.send( mido.Message('pitchwheel', pitch=sending_value) ) def send_note_off(self): """Sending note_off message to the midi device""" - output.send( mido.Message('note_off', note=note_to_number(self.get_note_name(), self.get_octave()), velocity=self.get_velocity()) ) - output.send( NoteButton.control_change ) + self.output.send( mido.Message('note_off', note=note_to_number(self.get_note_name(), self.get_octave()), velocity=self.get_velocity()) ) + self.output.send( NoteButton.control_change ) @staticmethod - def change_control(): + def change_control(output): """Sending control_change message to the midi device""" output.send(NoteButton.control_change) @@ -461,20 +444,6 @@ def default_labels(): save_new_button = Button(app, text="Save New", command=init_set_screen, width=7, height=1).place(x=495, y=250) -def note_to_number(note: str, octave: int): - """Converting passed note name and octave to Midi note number""" - note = NOTES.index(note) + 4 - note += (12 * octave) - - return note-16 - -def number_to_note(number: int): - """Converting passed Midi note number to note name and octave""" - note = NOTES[(number % 12)-4] - octave = math.floor((number+8)/12) - - return [note, octave] - def coming_note(msg): """ Core function for configuring incoming midi messages, @@ -532,7 +501,7 @@ def coming_note(msg): break elif msg.type == 'control_change': NoteButton.control_change = msg - threading.Thread(target=lambda: NoteButton.change_control()).start() + threading.Thread(target=lambda: NoteButton.change_control(output)).start() def close_program(): """ @@ -540,16 +509,8 @@ def close_program(): This function is also checking if there is any json file created to prevent overriding the old file. """ global app,note_bool,json_data - if json_data: - files = os.listdir() - json_files = [f for f in files if f.endswith('.json')] - if json_files: - last_number = int((json_files[-1].split(".")[0])[-1]) - with open(f"pitch_data{last_number+1}.json", "w") as fp: - json.dump(json_data, fp, indent=4) - else: - with open(f"pitch_data1.json", "w") as fp: - json.dump(json_data, fp, indent=4) + + save_json(json_data) app.destroy() note_bool = False @@ -609,7 +570,7 @@ def port_select_screen(): port_screen.mainloop() def main(): - global app,global_button_list + global app,global_button_list,output # Initializing the port selection window port_select_screen() @@ -624,10 +585,10 @@ def main(): # Creating the note buttons for item in PURE_NOTES: - global_button_list.append(NoteButton(item)) + global_button_list.append(NoteButton(item,output= output, app=app)) NoteButton.label_counter = 0 for item in OTHER_NOTES: - global_button_list.append(NoteButton(item)) + global_button_list.append(NoteButton(item, output= output, app=app)) # Initializing the main window label and widgets default_labels() diff --git a/Main/Midi-Project/midi/__init__.py b/Main/Midi-Project/midi/__init__.py new file mode 100644 index 0000000..7fc0552 --- /dev/null +++ b/Main/Midi-Project/midi/__init__.py @@ -0,0 +1,3 @@ +from midi.modules import * +from midi.global_variables import * +from midi.basic_functions import * diff --git a/Main/Midi-Project/midi/__pycache__/Midi_Functions.cpython-38.pyc b/Main/Midi-Project/midi/__pycache__/Midi_Functions.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0bb7ab63d1b0dbc0751c8c0251bcd17ae25e0332 GIT binary patch literal 2188 zcmah}TW=Fb6rP#g_1cbOLNK{gmTNI0fgsTWLTS^)frkcYob0+_ZPq{aGiR>nJC}{&;XHwFBf8i4 zJwwP}IC%Ffz~EE()4u^Y;WQ%aeMyaE5os}>wJhJFXtyHUw~cgs$He>tpX5_~n$Pf4%_0Ao7!k+$2QL^u&AsQgKMJEWFDO6D&%x*f zKhG~bCw_@v*L11Fmdug`y+S2)Us2baQ+d@RT*hpd}lc?U<4&tWh zQMk3o5G({6!9jrVke-W>MaUsw@Ln@*iG1AGtqB62+nw7>N&Hwy6~;}k9i*w?9^T-^K}&c+%)S0io=UvckcWfG z-PWd%@&sJc!?fv*004E){Riuns&>MdizjjljIW721L6&D+^%h;LZ-EiYGtjqEYcm7 zv}?^!ZSQW@R-e|_L_0}CmB>(}wa-N>iG$f{BNTB%)K-HquHo&o4`uR5G*qnx17oSL z?8XfhCUH8~eyWRxc9qm)^T1)aIYllBE7Ag!=RkufXZo`Zr2p-Q#3BENyvv{{B#e#$ zX%l3U>{CTwGO$?VV4Vh1_kqkVYqI|$@hDkH;J*m_a~F`+#uTqiQ+O@0jm(9t8in;BrOV~HNaCjV^e7Nh1w-Q9@ z(fN07G-rk6&x3>BAK-6z@Cm?+gM$M|2P=$K+0u@Ansx^_>Rc@L>c)1I?%biH7?Bi9 zlsGmWVbSedUNsW|2AIk3M>o?${U87V++O_G-ux1n;K zN#K4GXDtQYv1@U6ocuy~_E(GNp0OXs_HE@n%5+KB#%}sObmp(f4e|w9BVUvFBJ3&r z|2mGHVEF!f&&Kq?r&r-mv5=ea@NY-=X_vl)=KqRHyGws$-`TL0zH#OrrAZ82W<|`? zJt%5u25jz{rdvnJ%ioE@R5g-Td!dYHV|ivE8}p=dDutF-$CKvnL`ef8x&X@C)jf#T zfu?g3%hvC=)jAJUAhG$#SpZGa16@~QO)@~X$uFp#>REcc~`a#GOZL6>)bWUwc5pd|( z@)j<*fN%rAFX5`W&7iS^ahQ_|`((eNt{pJgi%e_3m z&(qDU!v>d~Z-y3Vb2_PQ>ub~McN5UmqkS^jwIQ_nd2lwOcl04b%AY3qd9oL(A_%0a z@@B2Bf!?C;)fVH+P^)66*U)>y=mP?&JLtSKi_#)E3#u^aRKYzK55d2JjcUwOTBF0L V^|IgXv(=&ErQ}FDV#s7Be*ybJPL2Qo literal 0 HcmV?d00001 diff --git a/Main/Midi-Project/midi/__pycache__/basic_functions.cpython-38.pyc b/Main/Midi-Project/midi/__pycache__/basic_functions.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9ecc5a2e443951074766879761a6c612104eaa87 GIT binary patch literal 2189 zcmah}&2JM&6rY*h_1cbOLJ0Y$EZ-QBK#*D}MJZ`w;Lre#lYXpRS(}}Sv&7zYXU7CA z=LFZPY7f1XO5upq|Du=v4Rfm0lcoLzT+;W(Nd!@=uC(vHdGq;x@4esJ;9#D>ceVW> z{5?a+UpRR8E5P6`{OR8yIN`KGR{NS7%^IZ1eAcvli=y9Z*uHJF<2y!Y{EX4A?;4%; zvqtCqoY8q$Z*zxdxXZIV$MbxE7x*AA@?-UaKLB$X;~xOuvAXLQV66+Q3cOf%{6Rj% zkMm)EqHg;|IB$fXm!b{?h@QeHs=#$*4kkaKIL`+Il(<>#WEv2?}zA4f)sEhUF*+WeiJ8bcsrb`{R z1gfm*y$-tv*8L8<4{D*q7C?Qb-8fOAmc%;SH#RnOz7?r(b9+;WhAxIltYp%tg_}WK z7d;BM_81Bag^j{N0qG$<7ey9D4h1If4bwKBtTRcdf~O+H%?BUac+MjH=~)np?9wiI zO*tJSJETiE>(UW&vu|7D1R}RPw-=N6sgNp)>s~8JQ^7sF!Ha{Y@Pe3o{hK_Mc*_xw z_9xrTbs^;mxTJ?=(;ET-&^Zqut(Gg=iDE9E$w_d&A@U5Uw<5ebt810=N_9!3 zTPkT)>yg@QuUD6!*H%O;Nh6iWNTk)zMKg(mnMxRmI26_8Ad0Ja`^;mRJQ1O)Hepa* z57H>CZM5T1MM<2_ww~*v!CfV_*t`(mmLiyh6={LVb6`Q5GyT~R@jv(wIZS{-?+O?S z5u>Ak+BlgYJ5=b&dD#zphz>J(3C8c03I>biVuJk$j4qXv z816WPI|4yY5pF}#uy_Q#Hh3-YGVo$4F@T1>pb)sz`OV9F@U37ydr;n3NU%v)_$(+33GPk`|3HxT|50Ar>4|iSl z?gfqX==?i3nzJJE=iXlL4~RF~`xL~hy}dms2P=wI$VBrhOP!SV6)dX-8c$f{!SxGRhTqe^Ox~#Y|ji-W1e(QrNC)5JZbh$BMBj+^I#mT z?m@QpG@X^$wtk;iYdlbaMD~%hAT-@JorFD(92Be0kSPMQZm$1GSF!5Y0^E}h zgCNwVSy}`+Nyq6lD^PhCyrog?sx2r*A+_6V1GU|llh~*dX$kls;)%9Z)D$|WHl+wS zP`3O87vRzICaxO6RkQ0sxP^I`l?sWnPbm4vYb)hipP&aGtv)EP><&f zo5$sf?><^wUHB4M+)7m+9YdRjL`-#?*S-^{;UYsr**ndIw;N&}Gn9^l$U>w;^cI_@ Q!w_+SPO>4l=w=800dcS@tpET3 literal 0 HcmV?d00001 diff --git a/Main/Midi-Project/midi/__pycache__/global_variables.cpython-38.pyc b/Main/Midi-Project/midi/__pycache__/global_variables.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8edea86310e09050e3c79fda71ba1290388efd95 GIT binary patch literal 193 zcmWIL<>g`kf~-=HWDxxrL?8o3AjbiSi&=m~3PUi1CZpdI z6B_Iq6yuUwoL!P%5R;x+l2Muz<69XYlvf`oSd1Omz)~o zo0ypw z92lC(-U@zwWzukANDxn?XtXCzNbrT*8K@hfwv_CxR+Pxv?R=swy%^T2P0d?SjjfCe zUVI@_3_*kZzVREjwqPtR`qPf1t<<| oQ47TuA#(O&^d7ilLq3zb={vC1;pp?*lexp;nH>koagNXNAO0C@0ssI2 literal 0 HcmV?d00001 diff --git a/Main/Midi-Project/midi/basic_functions.py b/Main/Midi-Project/midi/basic_functions.py new file mode 100644 index 0000000..f80da2c --- /dev/null +++ b/Main/Midi-Project/midi/basic_functions.py @@ -0,0 +1,47 @@ +from tkinter import * +from music21 import * +from tkinter import ttk,messagebox +import mido,time,threading,json,math,os,mido.backends.rtmidi + +NOTES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'] +PURE_NOTES = ['C', 'D', 'E', 'F', 'G', 'A', 'B'] +OTHER_NOTES = ['C#', 'D#', 'F#', 'G#', 'A#'] +MESSAGE_TYPES = ['note_on','note_off','pitchwheel','control_change'] +OCTAVES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +def note_to_number(note: str, octave: int): + """Converting passed note name and octave to Midi note number""" + note = NOTES.index(note) + 4 + note += (12 * octave) + + return note-16 + +def number_to_note(number: int): + """Converting passed Midi note number to note name and octave""" + note = NOTES[(number % 12)-4] + octave = math.floor((number+8)/12) + + return [note, octave] + +def converter(value, control): + """ + Range converter function to convert pitch value (-8192/8191) to cent value (-100/100) + control: True -> convert to cent value, False -> convert to pitch value + """ + if control: + new_value = (((value - (-8192)) * 200) / 16383) + (-100) + else: + new_value = (((value - (-100)) * 16383) / 200) + (-8192) + return int(new_value) + +def save_json(json_data): + if json_data: + files = os.listdir() + json_files = [f for f in files if f.endswith('.json')] + if json_files: + last_number = int((json_files[-1].split(".")[0])[-1]) + with open(f"pitch_data{last_number+1}.json", "w") as fp: + json.dump(json_data, fp, indent=4) + else: + with open(f"pitch_data1.json", "w") as fp: + json.dump(json_data, fp, indent=4) diff --git a/Main/Midi-Project/midi/global_variables.py b/Main/Midi-Project/midi/global_variables.py new file mode 100644 index 0000000..e69de29 diff --git a/Main/Midi-Project/midi/modules.py b/Main/Midi-Project/midi/modules.py new file mode 100644 index 0000000..bd372b0 --- /dev/null +++ b/Main/Midi-Project/midi/modules.py @@ -0,0 +1,4 @@ +from tkinter import * +from music21 import * +from tkinter import ttk,messagebox +import mido,time,threading,json,math,os,mido.backends.rtmidi \ No newline at end of file