Skip to content

Commit 317ea53

Browse files
committed
Update Midi-Project (#21)
Fix minor bugs Start separating files
1 parent 44358d0 commit 317ea53

File tree

5 files changed

+76
-67
lines changed

5 files changed

+76
-67
lines changed

Main/Midi-Project/Midi-Project.py

Lines changed: 28 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
# @author: https://github.com/Alperencode
22
# @date: 01 Aug 2022
3+
# @last update: 13 Oct 2022
34

4-
# Importing modules
5-
from tkinter import *
6-
from music21 import *
7-
from tkinter import ttk,messagebox
8-
import mido,time,threading,math,json,os,mido.backends.rtmidi
5+
# Importing midi directory
6+
from midi import *
97

108
# Global variables
11-
NOTES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
12-
PURE_NOTES = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
13-
OTHER_NOTES = ['C#', 'D#', 'F#', 'G#', 'A#']
14-
MESSAGE_TYPES = ['note_on','note_off','pitchwheel','control_change']
15-
OCTAVES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
169
global_button_list = []
1710
global_pitch_list = []
1811
json_data = []
@@ -23,23 +16,11 @@
2316
for _ in range(8):
2417
global_pitch_list.append([0,0,0,0,0,0,0,0,0,0,0,0])
2518

26-
def converter(value, control):
27-
"""
28-
Range converter function to convert pitch value (-8192/8191) to cent value (-100/100)
29-
control: True -> convert to cent value, False -> convert to pitch value
30-
"""
31-
if control:
32-
new_value = (((value - (-8192)) * 200) / 16383) + (-100)
33-
else:
34-
new_value = (((value - (-100)) * 16383) / 200) + (-8192)
35-
return int(new_value)
36-
3719
class NoteButton:
3820
"""
3921
This is the main class of the program which is basically responsible for sending the midi messages to the midi output.
4022
Detailed explanation has been provided in each function.
4123
"""
42-
global output,app
4324

4425
# Static variables
4526
# counter is used to keep track of the number of buttons created
@@ -54,7 +35,7 @@ class NoteButton:
5435
pitch = [0,0,0,0,0,0,0,0,0,0,0,0]
5536
control_change = mido.Message('control_change', control=1, value=0)
5637

57-
def __init__(self,note_name,octave=5,velocity=64):
38+
def __init__(self,note_name,octave=5,velocity=64,output=None, app=None):
5839
"""
5940
Initializing function of the class which takes 1 required argument and 2 optional arguments.
6041
note_name: name of the note
@@ -70,39 +51,41 @@ def __init__(self,note_name,octave=5,velocity=64):
7051
self.__saved_pitch = 0
7152
self.__entry_box_number = NoteButton.counter
7253
self.__entry_box = None
54+
self.output = output
55+
self.app = app
7356

7457
# buttons are used to trigger 3 basic events: send note_on, wait for 100 miliseconds and send note_off
7558
# so command argument is used with lambda to trigger more than one function
7659
if note_name in PURE_NOTES:
7760
# Making note button white if the note is a pure note
7861
button = Button(
79-
app,text=note_name,
80-
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()),
62+
self.app,text=note_name,
63+
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()),
8164
width=10,height=15,bg="white",fg="#241f1f",activebackground="white",activeforeground="#241f1f",font=("Arial", 10, "bold"))
8265
else:
8366
# Making note button black if the note is not a pure note
8467
button = Button(
85-
app,text=note_name,
86-
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()),
68+
self.app,text=note_name,
69+
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()),
8770
width=4,height=7,bg="#241f1f",fg="white",activebackground="#241f1f",activeforeground="white",font=("Arial", 10, "bold"))
8871

8972
# Placing label (note text) and entry box in the GUI
9073
if note_name in PURE_NOTES:
9174
NoteButton.label_counter += 1.5
9275

93-
label = Label(app, text=note_name)
76+
label = Label(self.app, text=note_name)
9477
label.place(x=10, y= 10 + (NoteButton.label_counter * 20))
9578

96-
self.__entry_box = Entry(app, width=5)
79+
self.__entry_box = Entry(self.app, width=5)
9780
self.__entry_box.place(x=50, y= 10 + (NoteButton.label_counter * 20))
9881
self.__entry_box.bind('<Return>', lambda event: self.set_saved_pitch(self.__entry_box.get()))
9982
else:
10083
NoteButton.label_counter += 1.5
10184

102-
label = Label(app, text=note_name)
85+
label = Label(self.app, text=note_name)
10386
label.place(x=100, y= 10 + (NoteButton.label_counter * 20))
10487

105-
self.__entry_box = Entry(app, width=5)
88+
self.__entry_box = Entry(self.app, width=5)
10689
self.__entry_box.place(x=130, y= 10 + (NoteButton.label_counter * 20))
10790
self.__entry_box.bind('<Return>', lambda event: self.set_saved_pitch(self.__entry_box.get()))
10891

@@ -193,29 +176,29 @@ def send_note_on(self):
193176
"""
194177

195178
NoteButton.last_pressed_note = self.get_note_name()
196-
output.send( NoteButton.control_change )
179+
self.output.send( NoteButton.control_change )
197180

198181
# Label will put an extra space if note is a pure note
199182
if self.get_note_name() in PURE_NOTES:
200-
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)
183+
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)
201184
else:
202-
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)
185+
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)
203186

204187
# Sending midi signal
205-
output.send( mido.Message('note_on', note=note_to_number(self.get_note_name(), self.get_octave()), velocity=self.get_velocity()) )
188+
self.output.send( mido.Message('note_on', note=note_to_number(self.get_note_name(), self.get_octave()), velocity=self.get_velocity()) )
206189

207190
def send_pitch_wheel(self):
208191
"""Sending converted pitch value to the midi device"""
209192
sending_value = converter(self.get_pitch(), False)
210-
output.send( mido.Message('pitchwheel', pitch=sending_value) )
193+
self.output.send( mido.Message('pitchwheel', pitch=sending_value) )
211194

212195
def send_note_off(self):
213196
"""Sending note_off message to the midi device"""
214-
output.send( mido.Message('note_off', note=note_to_number(self.get_note_name(), self.get_octave()), velocity=self.get_velocity()) )
215-
output.send( NoteButton.control_change )
197+
self.output.send( mido.Message('note_off', note=note_to_number(self.get_note_name(), self.get_octave()), velocity=self.get_velocity()) )
198+
self.output.send( NoteButton.control_change )
216199

217200
@staticmethod
218-
def change_control():
201+
def change_control(output):
219202
"""Sending control_change message to the midi device"""
220203
output.send(NoteButton.control_change)
221204

@@ -461,20 +444,6 @@ def default_labels():
461444

462445
save_new_button = Button(app, text="Save New", command=init_set_screen, width=7, height=1).place(x=495, y=250)
463446

464-
def note_to_number(note: str, octave: int):
465-
"""Converting passed note name and octave to Midi note number"""
466-
note = NOTES.index(note) + 4
467-
note += (12 * octave)
468-
469-
return note-16
470-
471-
def number_to_note(number: int):
472-
"""Converting passed Midi note number to note name and octave"""
473-
note = NOTES[(number % 12)-4]
474-
octave = math.floor((number+8)/12)
475-
476-
return [note, octave]
477-
478447
def coming_note(msg):
479448
"""
480449
Core function for configuring incoming midi messages,
@@ -532,24 +501,16 @@ def coming_note(msg):
532501
break
533502
elif msg.type == 'control_change':
534503
NoteButton.control_change = msg
535-
threading.Thread(target=lambda: NoteButton.change_control()).start()
504+
threading.Thread(target=lambda: NoteButton.change_control(output)).start()
536505

537506
def close_program():
538507
"""
539508
Closes the program and saves json data if there is any.
540509
This function is also checking if there is any json file created to prevent overriding the old file.
541510
"""
542511
global app,note_bool,json_data
543-
if json_data:
544-
files = os.listdir()
545-
json_files = [f for f in files if f.endswith('.json')]
546-
if json_files:
547-
last_number = int((json_files[-1].split(".")[0])[-1])
548-
with open(f"pitch_data{last_number+1}.json", "w") as fp:
549-
json.dump(json_data, fp, indent=4)
550-
else:
551-
with open(f"pitch_data1.json", "w") as fp:
552-
json.dump(json_data, fp, indent=4)
512+
513+
save_json(json_data)
553514
app.destroy()
554515
note_bool = False
555516

@@ -609,7 +570,7 @@ def port_select_screen():
609570
port_screen.mainloop()
610571

611572
def main():
612-
global app,global_button_list
573+
global app,global_button_list,output
613574

614575
# Initializing the port selection window
615576
port_select_screen()
@@ -624,10 +585,10 @@ def main():
624585

625586
# Creating the note buttons
626587
for item in PURE_NOTES:
627-
global_button_list.append(NoteButton(item))
588+
global_button_list.append(NoteButton(item,output= output, app=app))
628589
NoteButton.label_counter = 0
629590
for item in OTHER_NOTES:
630-
global_button_list.append(NoteButton(item))
591+
global_button_list.append(NoteButton(item, output= output, app=app))
631592

632593
# Initializing the main window label and widgets
633594
default_labels()

Main/Midi-Project/midi/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from midi.modules import *
2+
from midi.global_variables import *
3+
from midi.basic_functions import *
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
def note_to_number(note: str, octave: int):
2+
"""Converting passed note name and octave to Midi note number"""
3+
note = NOTES.index(note) + 4
4+
note += (12 * octave)
5+
6+
return note-16
7+
8+
def number_to_note(number: int):
9+
"""Converting passed Midi note number to note name and octave"""
10+
note = NOTES[(number % 12)-4]
11+
octave = math.floor((number+8)/12)
12+
13+
return [note, octave]
14+
15+
def converter(value, control):
16+
"""
17+
Range converter function to convert pitch value (-8192/8191) to cent value (-100/100)
18+
control: True -> convert to cent value, False -> convert to pitch value
19+
"""
20+
if control:
21+
new_value = (((value - (-8192)) * 200) / 16383) + (-100)
22+
else:
23+
new_value = (((value - (-100)) * 16383) / 200) + (-8192)
24+
return int(new_value)
25+
26+
def save_json(json_data):
27+
if json_data:
28+
files = os.listdir()
29+
json_files = [f for f in files if f.endswith('.json')]
30+
if json_files:
31+
last_number = int((json_files[-1].split(".")[0])[-1])
32+
with open(f"pitch_data{last_number+1}.json", "w") as fp:
33+
json.dump(json_data, fp, indent=4)
34+
else:
35+
with open(f"pitch_data1.json", "w") as fp:
36+
json.dump(json_data, fp, indent=4)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
NOTES = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
2+
PURE_NOTES = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
3+
OTHER_NOTES = ['C#', 'D#', 'F#', 'G#', 'A#']
4+
MESSAGE_TYPES = ['note_on','note_off','pitchwheel','control_change']
5+
OCTAVES = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Main/Midi-Project/midi/modules.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from tkinter import *
2+
from music21 import *
3+
from tkinter import ttk,messagebox
4+
import mido,time,threading,json,math,os,mido.backends.rtmidi

0 commit comments

Comments
 (0)