music-composition/chords2midi/midify.py

154 lines
3.8 KiB
Python

def main() :
True
class Chord() :
pitches = None
## [0-9]?[a-gA-G][bMmd]?
# octave
# note
# flat/Major chord/minor chord/deminutive chord
def __init__(self, s) :
note = Note(s)
self.pitches = note.pitch
if note.mod == "M" :
raise Exception("not impl")
elif note.mod == "m" :
raise Exception("not impl")
elif note.mod == "d" :
raise Exception("not impl")
elif note.mod == "" :
pass
else :
raise Exception(f"invalid note mod '{note.mod}'")
class Note():
octave = None
offset = None
s = None
pitch = None
mod = None
# [0-9]?[a-gA-G][b]?
# octave (default 4)
# note (case insensitive)
def __init__(self, s):
assert(s)
self.s = s
self.octave = 4
self.offset = 0
if s[0].isnumeric() :
self.octave = int(s[0])
s = s[1:]
note = s[0].lower()
self.mod = s[1:]
assert(note >= 'a' and note <= 'g')
self.offset = ord(note) - ord('a') - 2
if self.offset < 0 :
self.offset += 7
# de gab
# c f
self.offset += len([j for j in [1,2,4,5,6] if self.offset >= j])
if self.mod == "b" and note in "degab" :
self.mod = ""
self.offset -= 1
self.pitch = 12 * self.octave + self.offset
class Writer():
writer = None
def __init__(self, writer):
self.writer = writer
def chord(self, chord, duration=1, track=0, channel=0, volume=100):
return self.chords([chord], duration, track, channel, volume)
def chords(self, chords, duration=1, track=0, channel=0, volume=100):
for chord in chords:
chord = Chord(chord)
for pitch in chord.pitches :
self.writer.pitch(pitch, duration, track, channel, volume)
class MIDIWriter():
time = 0
driver = None
def __init__(self, driver):
self.driver = driver
def pitch(self, pitch, duration, track, channel, volume):
self.pitches([pitch], duration, track, channel, volume)
def pitches(self, pitches, duration, track, channel, volume):
for pitch in pitches :
self.driver.pitch(self.time, pitch, duration, track, channel, volume)
self.time += 1
def flush(self, path):
self.driver.write(path)
class MIDIDriver():
def pitch(self, time, pitches, duration, track, channel, volume):
raise Exception("not impl")
def write(self, path) :
raise Exception("not impl")
class MIDIDriverStream(MIDIDriver):
stream = None
buff = None
def __init__(self, stream=None) :
super().__init__()
self.stream = stream
self.buff = ""
def pitch(self, time, pitch, duration, track, channel, volume):
if self.buff :
self.buff += "\n"
self.buff += f't={time}, p={pitch}, d={duration}'
def write(self, path) :
print(self.buff, file=self.stream)
self.buff = ""
class MIDIDriverStdout(MIDIDriverStream):
def __init__(self) :
super().__init__()
class MIDIDriverImpl(MIDIDriver):
midi = None
bpm = None
def __init__(self, bpm=60):
self.bpm = bpm
self.__set_midi__()
super().__init__()
def __set_midi__(self) :
import midiutil
ttime = 0 # ?
tempo = self.bpm
self.midi = midiutil.MIDIFile(1)
for track in range(11) :
self.midi.addTempo(track, ttime, tempo)
def pitch(self, time, pitch, duration, track, channel, volume):
assert(track >= 0 and track <= 10)
self.midi.addNote(
track=track,
channel=channel,
pitch=int(pitch),
time=time,
duration=duration,
volume=volume,
)
def write(self, path) :
with open(path, "wb") as f :
self.midi.writeFile(f)
self.__set_midi__()
if __name__ == "__main__":
main()