def chord_scaled(arr, scale, period=12): ''' Scales an note's array ''' remainder = arr.size % period if remainder: fill = period - remainder arr = np.append(arr, np.zeros(fill) * np.nan) arr_scaled = np.int32([np.nansum(row) / len(row) for row in arr.reshape((-1, period))]) root_scaled = [note_on_classes(note, arr, scale) for note in arr_scaled] root = [] third = [] fifth = [] for note in root_scaled: root.append(note_name(note, scale)) third.append(note_name(note, scale)) fifth.append(note_name(note, scale)) seq1 = parse(" ".join(root)) seq2 = parse(" ".join(third)) seq3 = parse(" ".join(fifth)) # chords = (seq1 * period) // (seq2 * period) // (seq3 * period) chords = seq1 // seq2 // seq3 # return (chords | add({DURATION_64: chords[0][DURATION_64] * period})) return (chords | stretch(period))
def play_rand_song_uno(self, counts=20): alpha = parse(self.gen_rand_snippet(counts)) beta = parse(self.gen_rand_snippet(counts)) gamma = parse(self.gen_rand_snippet(counts)) delta = parse(self.gen_rand_snippet(counts)) player.play([alpha, beta]) player.play([alpha, gamma]) player.play([beta, gamma]) player.play([alpha])
def eq(self, lilypond, answer): """ The first is a lilypond fragment. The second is the intended interpretation, a sequence of (offset, pitch, duration) tuples where offset and duration are in multiples of a 64th note and pitch is MIDI note number. """ print "\nTEST: %s" % lilypond result = parse(lilypond) i = -1 # so available in else clause of for for i, event in enumerate(answer): r = result[i].tuple(OFFSET_64, MIDI_PITCH, DURATION_64) if event != r: print "%s != %s" % (event, r) print "\x1B[31mFAIL\x1B[0m" break else: print "%s == %s" % (event, r) else: if len(answer) != len(result): print "\x1B[31mFAIL (different length)\x1B[0m" for j in range(i + 1, len(result)): print "!= %s" % (result[j].tuple(OFFSET_64, MIDI_PITCH, DURATION_64), ) else: print "\x1B[32mSUCCESS\x1B[0m"
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 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 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 eq(self, lilypond, answer): """ The first is a lilypond fragment. The second is the intended interpretation, a sequence of (offset, pitch, duration) tuples where offset and duration are in multiples of a 64th note and pitch is MIDI note number. """ result = parse(lilypond) self.assertEqual(len(answer), len(result)) for i, event in enumerate(answer): r = result[i].tuple(OFFSET_64, MIDI_PITCH, DURATION_64) self.assertEqual(event, r)
def deduce_rosetta_stone(): octave = parse("c cis d dis e f fis g gis a ais b") | midi_to_pitch() pitches = [] try: for point in octave: print point pitches.append(point['pitch']) #pitches = [point['pitch'] for point in octave] except Exception as e: pass return pitches
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 play_music(self, x, y): ''' Generate sounds from data to be used for each coordinate. x and y are the coordinates of any image point. ''' scale = build_scale('C', mode='major', octaves=1) notes = note_number(self.data, scale) note = notes[y,x] melody = parse(note_name(note, scale)) midi_out = StringIO() write('Oc.midi', [melody]) os.system('fluidsynth --audio-driver=alsa /usr/share/sounds/sf2/FluidR3_GM.sf2 Oc.midi')
def play_music(self, x, y): ''' Generate sounds from data to be used for each coordinate. x and y are the coordinates of any image point. ''' scale = build_scale('C', mode='major', octaves=1) notes = note_number(self.data, scale) note = notes[y,x] melody = parse(note_name(note, scale)) midi_out = StringIO() write('Oc.midi', [melody]) pygame.mixer.init() music = pygame.mixer.Sound('Oc.midi') pygame.mixer.music.load('Oc.midi') pygame.mixer.music.play()
def test(lilypond, answer): print "\nTEST: %s" % lilypond result = parse(lilypond) i = -1 # so available in else clause of for for i, event in enumerate(answer): r = result[i].tuple(OFFSET_64, MIDI_PITCH, DURATION_64) if event != r: print "%s != %s" % (event, r) print "\x1B[31mFAIL\x1B[0m" break else: print "%s == %s" % (event, r) else: if len(answer) != len(result): print "\x1B[31mFAIL (different length)\x1B[0m" for j in range(i + 1, len(result)): print "!= %s" % (result[j].tuple(OFFSET_64, MIDI_PITCH, DURATION_64), ) else: print "\x1B[32mSUCCESS\x1B[0m"
#!/usr/bin/env python from sebastian.lilypond.interp import parse from sebastian.lilypond.write_lilypond import write from sebastian.midi import write_midi, player from sebastian.core import OSequence, HSeq, Point, DURATION_64 from sebastian.core.transforms import transpose, reverse, add, degree_in_key, midi_pitch, lilypond from sebastian.core.notes import Key, major_scale # construct sequences using lilypond syntax seq1 = parse("c d e") seq2 = parse("e f g") # concatenate seq3 = seq1 + seq2 # transpose and reverse seq4 = seq3 | transpose(12) | reverse() # merge seq5 = seq3 // seq4 # play MIDI player.play([seq5]) # write to MIDI write_midi.write("seq5.mid", [seq5]) # contruct a horizontal sequence of scale degrees seq6 = HSeq(Point(degree=degree) for degree in [1, 2, 3, 2, 1])
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
#!/usr/bin/env python """ Generate ode to joy in the entire dynamic range "pppppp" -> "ffff". Also generate a crescendo from "ppp" to "ff" and a dimininuendo from "mf" to "ppp". This will output numerous midi files, as well as three lilypond (*.ly) files with dynamic notation. """ from sebastian.lilypond.interp import parse from sebastian.core.transforms import dynamics, lilypond, midi_to_pitch, add from sebastian.midi import write_midi from sebastian.lilypond import write_lilypond # construct sequences using lilypond syntax melody = parse("e4 e f g g f e d c c d e") A = parse("e4. d8 d2") Aprime = parse("d4. c8 c2") two_bars = melody + A + melody + Aprime two_bars = two_bars | midi_to_pitch() two_bars = two_bars | add({"octave": 5}) velocities = [ "pppppp", "ppppp", "pppp", "ppp", "pp", "p", "mp", "mf", "f", "ff", "fff", "ffff" ] for d in velocities: two_bars_with_dynamics = two_bars | dynamics(d) write_midi.write("ode_%s.mid" % (d, ), [two_bars_with_dynamics]) two_bars_ff_lily = two_bars | dynamics("ff") | lilypond()
#!/usr/bin/env python """ Generate ode to joy in the entire dynamic range "pppppp" -> "ffff". Also generate a crescendo from "ppp" to "ff" and a dimininuendo from "mf" to "ppp". This will output numerous midi files, as well as three lilypond (*.ly) files with dynamic notation. """ from sebastian.lilypond.interp import parse from sebastian.core.transforms import dynamics, lilypond, midi_to_pitch, add from sebastian.midi import write_midi from sebastian.lilypond import write_lilypond # construct sequences using lilypond syntax melody = parse("e4 e f g g f e d c c d e") A = parse("e4. d8 d2") Aprime = parse("d4. c8 c2") two_bars = melody + A + melody + Aprime two_bars = two_bars | midi_to_pitch() two_bars = two_bars | add({"octave": 5}) velocities = ["pppppp", "ppppp", "pppp", "ppp", "pp", "p", "mp", "mf", "f", "ff", "fff", "ffff"] for d in velocities: two_bars_with_dynamics = two_bars | dynamics(d) write_midi.write("ode_%s.mid" % (d,), [two_bars_with_dynamics]) two_bars_ff_lily = two_bars | dynamics("ff") | lilypond() write_lilypond.write("ode_ff.ly", two_bars_ff_lily) crescendo = two_bars | dynamics("ppp", "ff")
#!/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()
#!/usr/bin/env python from sebastian.lilypond.interp import parse from sebastian.midi import write_midi # construct sequences using lilypond syntax seq1 = parse("e4. d c r") seq2 = parse("g4. f4 f8 e4.") seq2a = parse("r4.") seq2b = parse("r4 g8") seq3 = parse("c'4 c'8 b a b c'4 g8 g4") seq3a = parse("g8") seq3b = parse("f8") # concatenate mice = (seq1 * 2) + (seq2 + seq2a) + (seq2 + seq2b) + ( (seq3 + seq3a) * 2) + (seq3 + seq3b) + seq1 # write to MIDI write_midi.write("mice.mid", [mice])
def play_rand_song_dos(self, counts=20): alpha = parse(self.gen_rand_snippet(counts)) beta = parse(self.gen_rand_snippet(counts)) gamma = parse(self.gen_rand_snippet(counts)) delta = parse(self.gen_rand_snippet(counts)) player.play([alpha+(alpha//beta)+(alpha//beta//gamma)+(alpha//beta//gamma//delta)])