-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathgcode_midi_2.py
More file actions
124 lines (98 loc) · 4.42 KB
/
gcode_midi_2.py
File metadata and controls
124 lines (98 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import mido
import os
import math
from song import Note
FILENAME = "/home/pi/Dark_World_Theme.mid"
OUTPUT_FOLDER = "~/3D Printing/"
OUTPUT_NAME = 'DarkWorldTheme-'
# MIDI takes a number from 0 to 127 to represent the notes for the following frequencies
NOTES = [8.18, 8.66, 9.18, 9.72, 10.30, 10.91, 11.56, 12.25, 12.98, 13.75, 14.57, 15.43, 16.35,
17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.50, 25.96, 27.50, 29.14, 30.87, 32.70,
34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 51.91, 55.00, 58.27, 61.74, 65.41,
69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.83, 110.00, 116.54, 123.47,
130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08,
246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00,
466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61,
880.00, 932.33, 987.77, 1046.50, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98,
1567.98, 1661.22, 1760.00, 1864.66, 1975.53, 2093.00, 2217.46, 2349.32, 2489.02,
2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520.00, 3729.31, 3951.07, 4186.01,
4434.92, 4698.64, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 6644.88, 7040.00,
7458.62, 7902.13, 8372.02, 8869.84, 9397.27, 9956.06, 10548.08, 11175.30, 11839.82,
12543.85, 13289.75]
# The speed offset of the printer. Adjusting this will 'tune' the printer
VELOCITY_MULT = 5
AXIS = 'Y'
MIN = 0
MAX = 150
START = (MIN + MAX)//2
START_INSTRUCTIONS = "G26\nG21\nG90\nG28\nG1 {}{} F{}\nG4 P1000\n".format(AXIS, START, (600*VELOCITY_MULT))
END_INSTRUCTIONS = "\nG4 P1000\nG1 {}{} F{}\n".format(AXIS, START, int(600*VELOCITY_MULT))
def main():
notes = notes_from_file(FILENAME)
for channel in notes:
print(channel, len(notes[channel]))
full_export(notes, OUTPUT_FOLDER, OUTPUT_NAME)
def notes_from_file(filename):
mid = mido.MidiFile(FILENAME)
tpb = mid.ticks_per_beat
tps = 8000*tpb
notes = {}
start_times = {}
for track in mid.tracks:
for note in track:
if hasattr(note, 'channel') and note.channel not in notes:
notes[note.channel] = []
for track in mid.tracks:
abstime = 0
for note in track:
abstime += note.time / tps
if note.type == 'note_on' and note.velocity != 0:
start_times[note.channel] = abstime
elif note.type =='note_off' or (note.type == 'note_on' and note.velocity == 0):
notes[note.channel].append(Note(note.note, int(start_times[note.channel]*1000), int((abstime - start_times[note.channel])*1000)))
elif note.type == 'set_tempo':
tps = 1000000/note.tempo*tpb
return notes
def convert_notes(notes):
gcode = ''
pos = START
new_positions = []
i = 0
current_time = 0
for note in notes:
# Calculate distance and velocity
velocity = NOTES[note.note] * VELOCITY_MULT
distance = velocity * note.length / 60000 # notes are in miliseconds
# Try to go towards max Y. If it doesn't fit, go towards min Y. If neither fit, go back and forth as much as required.
while distance > 0:
if pos + distance <= MAX:
pos += distance
new_positions.append(pos)
distance = 0
elif pos - distance >= MIN:
pos -= distance
new_positions.append(pos)
distance = 0
elif pos + distance - MAX < distance - pos + MIN:
new_positions.append(MAX)
distance -= MAX - pos
pos = MAX
else:
new_positions.append(MIN)
distance -= pos - MIN
pos = MIN
# Write GCode to string
gcode += "G4 P{}\n".format(note.time - current_time)
for new_pos in new_positions:
gcode += "G1 {}{} F{}\n".format(AXIS, int(new_pos), int(velocity))
# Prepare for next note
new_positions.clear()
current_time = note.time + note.length
return gcode
def full_export(notes, folder, filename):
for track in notes:
export_gcode(os.path.join(folder, filename + str(track) + '.gcode'), convert_notes(notes[track]))
def export_gcode(filename, gcode):
with open(filename, 'w') as file:
file.write(START_INSTRUCTIONS + gcode + END_INSTRUCTIONS)
#main()