def get_music(a, b, key='C', mode='major'): midi_out = StringIO() scale = build_scale(key, mode, octaves=1) matcher = SequenceMatcher(None, a, b) tone = key.lower() melodies = [tone] for tag, i1, i2, j1, j2 in matcher.get_opcodes(): next_note = None if tag == 'replace': next_note = 'r' elif tag == 'equal': next_note = tone elif tag == 'delete': tone = tone_down(tone, scale) next_note = tone elif tag == 'insert': tone = tone_up(tone, scale) next_note = tone melodies += [next_note] * ((i2 - i1) or 1) s = SMF([parse(" ".join(melodies))]) s.write(midi_out) return midi_out
def test_write_midi_multi_tacks(self): """ Writing out test.mid to ensure midi processing works. This isn't really a test. """ from sebastian.core import OSequence, Point from sebastian.core import OFFSET_64, MIDI_PITCH, DURATION_64 test1 = OSequence([ Point({OFFSET_64: o, MIDI_PITCH: m, DURATION_64: d}) for (o, m, d) in [ (0, 60, 16), (16, 72, 16), (32, 64, 16), (48, 55, 16), ] ]) test2 = OSequence([ Point({OFFSET_64: o, MIDI_PITCH: m, DURATION_64: d}) for (o, m, d) in [ (0, 55, 16), (16, 55, 16), (32, 64, 16), (48 + 16, 55, 16 * 10), ] ]) from sebastian.midi.write_midi import SMF from io import BytesIO out_fd = BytesIO(bytearray()) expected_bytes = b"""MThd\x00\x00\x00\x06\x00\x01\x00\x03\x00\x10MTrk\x00\x00\x00&\x00\xffX\x04\x04\x02\x18\x08\x00\xffY\x02\x00\x00\x00\xffQ\x03\x07\xa1 \x00\xff\x03\ttest song\x00\xff/\x00MTrk\x00\x00\x00'\x00\xc0\x00\x00\x90<@\x10\x80<\x00\x00\x90H@\x10\x80H\x00\x00\x90@@\x10\x80@\x00\x00\x907@\x10\x807\x00\x00\xff/\x00MTrk\x00\x00\x00(\x00\xc1\x10\x00\x917@\x10\x817\x00\x00\x917@\x10\x817\x00\x00\x91@@\x10\x81@\x00\x10\x917@\x81 \x817\x00\x00\xff/\x00""" s = SMF([test1, test2], instruments=[0, 16]) s.write(out_fd, title="test song") actual_bytes = out_fd.getvalue() self.assertEqual(expected_bytes, actual_bytes)
def test_write_midi(self): """ Writing out test.mid to ensure midi processing works. This isn't really a test. """ from sebastian.core import OSequence, Point from sebastian.core import OFFSET_64, MIDI_PITCH, DURATION_64 test = OSequence([ Point({OFFSET_64: o, MIDI_PITCH: m, DURATION_64: d}) for (o, m, d) in [ (0, 60, 16), (16, 72, 16), (32, 64, 16), (48, 55, 16), (64, 74, 16), (80, 62, 16), (96, 50, 16), (112, 48, 16), (128, 36, 16), (144, 24, 16), (160, 40, 16), (176, 55, 16), (192, 26, 16), (208, 38, 16), (224, 50, 16), (240, 48, 16) ] ]) from sebastian.midi.write_midi import SMF from io import BytesIO out_fd = BytesIO(bytearray()) expected_bytes = b'MThd\x00\x00\x00\x06\x00\x01\x00\x02\x00\x10MTrk\x00\x00\x00%\x00\xffX\x04\x04\x02\x18\x08\x00\xffY\x02\x00\x00\x00\xffQ\x03\x07\xa1 \x00\xff\x03\x08untitled\x00\xff/\x00MTrk\x00\x00\x00\x87\x00\xc0\x00\x00\x90<@\x10\x80<\x00\x00\x90H@\x10\x80H\x00\x00\x90@@\x10\x80@\x00\x00\x907@\x10\x807\x00\x00\x90J@\x10\x80J\x00\x00\x90>@\x10\x80>\x00\x00\x902@\x10\x802\x00\x00\x900@\x10\x800\x00\x00\x90$@\x10\x80$\x00\x00\x90\x18@\x10\x80\x18\x00\x00\x90(@\x10\x80(\x00\x00\x907@\x10\x807\x00\x00\x90\x1a@\x10\x80\x1a\x00\x00\x90&@\x10\x80&\x00\x00\x902@\x10\x802\x00\x00\x900@\x10\x800\x00\x00\xff/\x00' s = SMF([test], instruments=None) s.write(out_fd) actual_bytes = out_fd.getvalue() self.assertEqual(expected_bytes, actual_bytes)
def separate_files(): for num, pattern in enumerate(patterns): sequence = parse(pattern) f = open("in_c_%s.mid" % (num + 1), "w") s = SMF([sequence]) s.write(f) f.close()
def test_velocity_from_note_with_invalid_velocities(self): from sebastian.core import OSequence, Point from sebastian.core import OFFSET_64, MIDI_PITCH, DURATION_64 test = OSequence([ Point({ OFFSET_64: o, MIDI_PITCH: m, DURATION_64: d }) for (o, m, d) in [(0, 60, 16), (16, 72, 16), (32, 64, 16)] ]) test[0]['velocity'] = -1 test[1]['velocity'] = 300 from sebastian.midi.write_midi import SMF from io import BytesIO out_fd = BytesIO(bytearray()) expected_bytes = b'MThd\x00\x00\x00\x06\x00\x01\x00\x02\x00\x10MTrk\x00\x00\x00&\x00\xffX\x04\x04\x02\x18\x08\x00\xffY\x02\x00\x00\x00\xffQ\x03\x07\xa1 \x00\xff\x03\ttest song\x00\xff/\x00MTrk\x00\x00\x00\x1f\x00\xc0\x00\x00\x90<\x00\x10\x80<\x00\x00\x90H\xff\x10\x80H\x00\x00\x90@@\x10\x80@\x00\x00\xff/\x00' s = SMF([test]) s.write(out_fd, title="test song") actual_bytes = out_fd.getvalue() self.assertEqual(expected_bytes, actual_bytes)
def one_file(): seq = OSequence([]) for num, pattern in enumerate(patterns): seq = seq + parse(pattern) * 10 f = open("in_c_all.mid", "w") s = SMF([seq]) s.write(f) f.close()
def performance(): tracks = [] for track_num in range(8): # 8 tracks seq = OSequence([]) for pattern in patterns: seq += parse(pattern) * random.randint(2, 5) # repeat 2-5 times tracks.append(seq | transpose(random.choice([-12, 0, 12]))) # transpose -1, 0 or 1 octaves f = open("in_c_performance.mid", "w") s = SMF(tracks) s.write(f) f.close()
def test_write_midi(self): """ Writing out test.mid to ensure midi processing works. This isn't really a test. """ from sebastian.core import OSequence, Point from sebastian.core import OFFSET_64, MIDI_PITCH, DURATION_64 test = OSequence([ Point({ OFFSET_64: o, MIDI_PITCH: m, DURATION_64: d }) for (o, m, d) in [(0, 60, 16), (16, 72, 16), (32, 64, 16), (48, 55, 16), (64, 74, 16), (80, 62, 16), (96, 50, 16), (112, 48, 16), (128, 36, 16), (144, 24, 16), (160, 40, 16), (176, 55, 16), (192, 26, 16), (208, 38, 16), (224, 50, 16), (240, 48, 16)] ]) from sebastian.midi.write_midi import SMF from io import BytesIO out_fd = BytesIO(bytearray()) expected_bytes = b'MThd\x00\x00\x00\x06\x00\x01\x00\x02\x00\x10MTrk\x00\x00\x00%\x00\xffX\x04\x04\x02\x18\x08\x00\xffY\x02\x00\x00\x00\xffQ\x03\x07\xa1 \x00\xff\x03\x08untitled\x00\xff/\x00MTrk\x00\x00\x00\x87\x00\xc0\x00\x00\x90<@\x10\x80<\x00\x00\x90H@\x10\x80H\x00\x00\x90@@\x10\x80@\x00\x00\x907@\x10\x807\x00\x00\x90J@\x10\x80J\x00\x00\x90>@\x10\x80>\x00\x00\x902@\x10\x802\x00\x00\x900@\x10\x800\x00\x00\x90$@\x10\x80$\x00\x00\x90\x18@\x10\x80\x18\x00\x00\x90(@\x10\x80(\x00\x00\x907@\x10\x807\x00\x00\x90\x1a@\x10\x80\x1a\x00\x00\x90&@\x10\x80&\x00\x00\x902@\x10\x802\x00\x00\x900@\x10\x800\x00\x00\xff/\x00' s = SMF([test], instruments=None) s.write(out_fd) actual_bytes = out_fd.getvalue() self.assertEqual(expected_bytes, actual_bytes)
def test_write_midi_multi_tacks(self): """ Writing out test.mid to ensure midi processing works. This isn't really a test. """ from sebastian.core import OSequence, Point from sebastian.core import OFFSET_64, MIDI_PITCH, DURATION_64 test1 = OSequence([ Point({ OFFSET_64: o, MIDI_PITCH: m, DURATION_64: d }) for (o, m, d) in [ (0, 60, 16), (16, 72, 16), (32, 64, 16), (48, 55, 16), ] ]) test2 = OSequence([ Point({ OFFSET_64: o, MIDI_PITCH: m, DURATION_64: d }) for (o, m, d) in [ (0, 55, 16), (16, 55, 16), (32, 64, 16), (48 + 16, 55, 16 * 10), ] ]) from sebastian.midi.write_midi import SMF from io import BytesIO out_fd = BytesIO(bytearray()) expected_bytes = b"""MThd\x00\x00\x00\x06\x00\x01\x00\x03\x00\x10MTrk\x00\x00\x00&\x00\xffX\x04\x04\x02\x18\x08\x00\xffY\x02\x00\x00\x00\xffQ\x03\x07\xa1 \x00\xff\x03\ttest song\x00\xff/\x00MTrk\x00\x00\x00'\x00\xc0\x00\x00\x90<@\x10\x80<\x00\x00\x90H@\x10\x80H\x00\x00\x90@@\x10\x80@\x00\x00\x907@\x10\x807\x00\x00\xff/\x00MTrk\x00\x00\x00(\x00\xc1\x10\x00\x917@\x10\x817\x00\x00\x917@\x10\x817\x00\x00\x91@@\x10\x81@\x00\x10\x917@\x81 \x817\x00\x00\xff/\x00""" s = SMF([test1, test2], instruments=[0, 16]) s.write(out_fd, title="test song") actual_bytes = out_fd.getvalue() self.assertEqual(expected_bytes, actual_bytes)
def test_velocity_from_note_with_invalid_velocities(self): from sebastian.core import OSequence, Point from sebastian.core import OFFSET_64, MIDI_PITCH, DURATION_64 test = OSequence([ Point({OFFSET_64: o, MIDI_PITCH: m, DURATION_64: d}) for (o, m, d) in [ (0, 60, 16), (16, 72, 16), (32, 64, 16) ] ]) test[0]['velocity'] = -1 test[1]['velocity'] = 300 from sebastian.midi.write_midi import SMF from io import BytesIO out_fd = BytesIO(bytearray()) expected_bytes = b'MThd\x00\x00\x00\x06\x00\x01\x00\x02\x00\x10MTrk\x00\x00\x00&\x00\xffX\x04\x04\x02\x18\x08\x00\xffY\x02\x00\x00\x00\xffQ\x03\x07\xa1 \x00\xff\x03\ttest song\x00\xff/\x00MTrk\x00\x00\x00\x1f\x00\xc0\x00\x00\x90<\x00\x10\x80<\x00\x00\x90H\xff\x10\x80H\x00\x00\x90@@\x10\x80@\x00\x00\xff/\x00' s = SMF([test]) s.write(out_fd, title="test song") actual_bytes = out_fd.getvalue() self.assertEqual(expected_bytes, actual_bytes)
#!/usr/bin/env python from sebastian.lilypond.interp import parse from sebastian.midi.write_midi import SMF rh = parse(r""" \relative c'' { g16 fis g8 ~ g16 d16 e fis g a b cis d16 cis d8 ~ d16 a16 b cis d e fis d g16 fis g8 ~ g16 fis16 e d cis e a, g fis e d cis d fis a, g fis a d,8 }""") lh = parse(r""" \relative c { g8 b'16 a b8 g g, g' fis,8 fis'16 e fis8 d fis, d' e,8 e'16 d e8 g a, cis' d, fis16 e fis8 d d, }""") # operator overloading FTW! seq = rh // lh if __name__ == "__main__": f = open("var1.mid", "w") s = SMF([seq]) s.write(f) f.close()
def get_music(series, key='C', mode='major', octaves=2, instruments=None, period=12): ''' Returns music generated from an inserted series. Parameters ---------- series : an array that could be an 2d-array. key : Musical key. Can be setted as a parameter while building scale. Key should be written as "C", for C and "C#" for C sharp and "Cb" for C flat. mode : Music mode. 'major', 'minor' and 'pentatonic' are accetable parameters. More options of modes on `build_scale`. octaves : Number of available scales for musical construction. As higher are the octaves higher pitch differeneces will occur while representing your data. instruments : list of MIDI instruments. General MIDI Level 1 Instrument Patch Map can be found at: http://en.wikipedia.org/wiki/General_MIDI Gran Piano is the default usage value '[0]' if any instruments are declared. Fewer examples: [0] Acoustic Grand Piano [18] Rock Organ [23] Tango Accordion [32] Acoustic Bass [73] Flute period : int parameter of chord_scaled function. Returns ------- midi_out : BytesIO object. It can be written on a file or used by your way. Example ------- >>> data = np.random.random(10).reshape(2,5) array([[ 0.13536875, 0.42212475, 0.26360219, 0.30153336, 0.62150923], [ 0.49384405, 0.32503762, 0.85549822, 0.80212442, 0.70702405]]) >>> get_music(data, octaves=2, instruments=(0,23)) <io.BytesIO instance at 0x7f98201c9d40> ''' midi_out = BytesIO() series = np.array(series) scale = build_scale(key, mode, octaves) melodies = [] if len(series.shape) == 1: if all(np.isnan(series)): melody = [] melodies.append(melody) else: snotes = note_number(series, scale) melody = parse(' '.join([note_name(x, scale) for x in snotes])) melodies.append(melody) else: for i in range(series.shape[0]): if all(np.isnan(series[i])): melody = [] melodies.append(melody) else: snotes = note_number(series[i], scale) melody = parse(' '.join([note_name(x, scale) for x in snotes])) melodies.append(melody) # chords = chord_scaled(series, scale, period) # Transform it to a MIDI file with chords. # s = SMF([melody, chords], instruments=[0, 23]) if instruments is None: s = SMF(melodies) else: s = SMF(melodies, instruments) s.write(midi_out) return midi_out