def display(self, format="png"): """ Return an object that can be used to display this sequence. This is used for IPython Notebook. :param format: "png" or "svg" """ from sebastian.core.transforms import lilypond seq = HSeq(self) | lilypond() if format == "png": suffix = ".preview.png" args = ["lilypond", "--png", "-dno-print-pages", "-dpreview"] elif format == "svg": suffix = ".preview.svg" args = ["lilypond", "-dbackend=svg", "-dno-print-pages", "-dpreview"] f = tempfile.NamedTemporaryFile(suffix=suffix) basename = f.name[:-len(suffix)] args.extend(["-o"+basename, "-"]) p = sp.Popen(args, stdin=sp.PIPE) p.communicate(write_lilypond.output(seq)) if p.returncode != 0: # there was an error return None if not ipython: return f.read() if format == "png": return Image(data=f.read(), filename=f.name, format="png") else: return SVG(data=f.read(), filename=f.name)
def test_lilypond_transform(self): """ Ensure that it plays in G major. """ from sebastian.core.transforms import midi_pitch, add, lilypond from sebastian.core import DURATION_64 from sebastian.core import HSeq, Point h1 = HSeq([Point(pitch=pitch) for pitch in [0, 1, 2, 3, 4, 11, -4, -11]]) positioned = h1 | add({'octave': 4, DURATION_64: 8}) pitched = positioned | midi_pitch() pitched[3]['octave'] = 5 pitched[4]['octave'] = 3 lilyed = pitched | lilypond() import pprint pprint.pprint(list(lilyed)) self.assertEqual(lilyed._elements, [ {'duration_64': 8, 'lilypond': 'd8', 'midi_pitch': 50, 'octave': 4, 'pitch': 0}, {'duration_64': 8, 'lilypond': 'a8', 'midi_pitch': 57, 'octave': 4, 'pitch': 1}, {'duration_64': 8, 'lilypond': 'e8', 'midi_pitch': 52, 'octave': 4, 'pitch': 2}, {'duration_64': 8, 'lilypond': "b'8", 'midi_pitch': 59, 'octave': 5, 'pitch': 3}, {'duration_64': 8, 'lilypond': 'fis,8', 'midi_pitch': 54, 'octave': 3, 'pitch': 4}, {'duration_64': 8, 'lilypond': 'fisis8', 'midi_pitch': 55, 'octave': 4, 'pitch': 11}, {'duration_64': 8, 'lilypond': 'bes8', 'midi_pitch': 58, 'octave': 4, 'pitch': -4}, {'duration_64': 8, 'lilypond': 'beses8', 'midi_pitch': 57, 'octave': 4, 'pitch': -11} ])
def test_write(self): import tempfile pitches = HSeq({"pitch": n} for n in [-2, 0, 2, -3]) seq = pitches | add({"octave": 5, DURATION_64: 16}) | lilypond() f = tempfile.NamedTemporaryFile(suffix=".ly", delete=False) write(f.name, seq) with open(f.name) as g: self.assertEqual(g.read(), "{ c'4 d'4 e'4 f'4 }")
def test_display_skipped_on_empty(self): """ If all lilypond output is empty, ensure we don't call lilypond """ empty = HSeq({"fake":n} for n in xrange(2)) seq = empty | lilypond() displayed = seq.display() self.assertIsInstance(displayed, HSeq)
def test_display_skipped_on_empty(self): """ If all lilypond output is empty, ensure we don't call lilypond """ empty = HSeq({"fake": n} for n in range(2)) seq = empty | lilypond() displayed = seq.display() self.assertTrue(isinstance(displayed, HSeq))
def test_lilypond_transform_rhythms(self): """ Ensure points without pitches can render to lilypond """ from sebastian.core.transforms import lilypond from sebastian.core import DURATION_64 from sebastian.core import HSeq, Point h1 = HSeq([Point({DURATION_64: 64}), Point({DURATION_64: 0}), Point()]) h2 = h1 | lilypond() self.assertEqual(h2._elements[0]['lilypond'], r"\xNote c'1") self.assertEqual(h2._elements[1]['lilypond'], '') self.assertEqual(h2._elements[2]['lilypond'], '')
def test_lilypond_transform_rhythms(self): """ Ensure points without pitches can render to lilypond """ from sebastian.core.transforms import lilypond from sebastian.core import DURATION_64 from sebastian.core import HSeq, Point h1 = HSeq([ Point({DURATION_64: 64}), Point({DURATION_64: 0}), Point() ]) h2 = h1 | lilypond() self.assertEqual(h2._elements[0]['lilypond'], r"\xNote c'1") self.assertEqual(h2._elements[1]['lilypond'], '') self.assertEqual(h2._elements[2]['lilypond'], '')
def display(self, format="png"): """ Return an object that can be used to display this sequence. This is used for IPython Notebook. :param format: "png" or "svg" """ from sebastian.core.transforms import lilypond seq = HSeq(self) | lilypond() lily_output = write_lilypond.lily_format(seq) if not lily_output.strip(): #In the case of empty lily outputs, return self to get a textual display return self if format == "png": suffix = ".preview.png" args = ["lilypond", "--png", "-dno-print-pages", "-dpreview"] elif format == "svg": suffix = ".preview.svg" args = [ "lilypond", "-dbackend=svg", "-dno-print-pages", "-dpreview" ] f = tempfile.NamedTemporaryFile(suffix=suffix) basename = f.name[:-len(suffix)] args.extend(["-o" + basename, "-"]) #Pass shell=True so that if your $PATH contains ~ it will #get expanded. This also changes the way the arguments get #passed in. To work correctly, pass them as a string p = sp.Popen(" ".join(args), stdin=sp.PIPE, shell=True) stdout, stderr = p.communicate("{ %s }" % lily_output) if p.returncode != 0: # there was an error #raise IOError("Lilypond execution failed: %s%s" % (stdout, stderr)) return None if not ipython: return f.read() if format == "png": return Image(data=f.read(), filename=f.name, format="png") else: return SVG(data=f.read(), filename=f.name)
def display(self, format="png"): """ Return an object that can be used to display this sequence. This is used for IPython Notebook. :param format: "png" or "svg" """ from sebastian.core.transforms import lilypond seq = HSeq(self) | lilypond() lily_output = write_lilypond.lily_format(seq) if not lily_output.strip(): #In the case of empty lily outputs, return self to get a textual display return self if format == "png": suffix = ".preview.png" args = ["lilypond", "--png", "-dno-print-pages", "-dpreview"] elif format == "svg": suffix = ".preview.svg" args = ["lilypond", "-dbackend=svg", "-dno-print-pages", "-dpreview"] f = tempfile.NamedTemporaryFile(suffix=suffix) basename = f.name[:-len(suffix)] args.extend(["-o" + basename, "-"]) #Pass shell=True so that if your $PATH contains ~ it will #get expanded. This also changes the way the arguments get #passed in. To work correctly, pass them as a string p = sp.Popen(" ".join(args), stdin=sp.PIPE, shell=True) stdout, stderr = p.communicate("{ %s }" % lily_output) if p.returncode != 0: # there was an error #raise IOError("Lilypond execution failed: %s%s" % (stdout, stderr)) return None if not ipython: return f.read() if format == "png": return Image(data=f.read(), filename=f.name, format="png") else: return SVG(data=f.read(), filename=f.name)
def write(filename, seq): with open(filename, "w") as f: f.write("{ ") for point in seq: f.write(point["lilypond"]) f.write(" ") f.write("}\n") if __name__ == "__main__": from sebastian.core import DURATION_64 from sebastian.core import HSeq, Point from sebastian.core.notes import Key, major_scale from sebastian.core.transforms import degree_in_key, add, lilypond seq = HSeq(Point(degree=n) for n in [1, 2, 3, 4]) seq = seq | add({DURATION_64: 16, "octave": 5}) C_major = Key("C", major_scale) seq = seq | degree_in_key(C_major) | lilypond() write("test.ly", seq)
def test_lilypond_transform(self): """ Ensure that it plays in G major. """ from sebastian.core.transforms import midi_pitch, add, lilypond from sebastian.core import DURATION_64 from sebastian.core import HSeq, Point h1 = HSeq( [Point(pitch=pitch) for pitch in [0, 1, 2, 3, 4, 11, -4, -11]]) positioned = h1 | add({'octave': 4, DURATION_64: 8}) pitched = positioned | midi_pitch() pitched[3]['octave'] = 5 pitched[4]['octave'] = 3 lilyed = pitched | lilypond() import pprint pprint.pprint(list(lilyed)) self.assertEqual(lilyed._elements, [{ 'duration_64': 8, 'lilypond': 'd8', 'midi_pitch': 50, 'octave': 4, 'pitch': 0 }, { 'duration_64': 8, 'lilypond': 'a8', 'midi_pitch': 57, 'octave': 4, 'pitch': 1 }, { 'duration_64': 8, 'lilypond': 'e8', 'midi_pitch': 52, 'octave': 4, 'pitch': 2 }, { 'duration_64': 8, 'lilypond': "b'8", 'midi_pitch': 59, 'octave': 5, 'pitch': 3 }, { 'duration_64': 8, 'lilypond': 'fis,8', 'midi_pitch': 54, 'octave': 3, 'pitch': 4 }, { 'duration_64': 8, 'lilypond': 'fisis8', 'midi_pitch': 55, 'octave': 4, 'pitch': 11 }, { 'duration_64': 8, 'lilypond': 'bes8', 'midi_pitch': 58, 'octave': 4, 'pitch': -4 }, { 'duration_64': 8, 'lilypond': 'beses8', 'midi_pitch': 57, 'octave': 4, 'pitch': -11 }])
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") write_midi.write("ode_crescendo.mid", [crescendo]) write_lilypond.write("ode_crescendo.ly", crescendo | lilypond()) diminuendo = two_bars | dynamics("mf", "pppp") write_midi.write("ode_diminuendo.mid", [diminuendo]) write_lilypond.write("ode_diminuendo.ly", diminuendo | lilypond())
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") write_midi.write("ode_crescendo.mid", [crescendo]) write_lilypond.write("ode_crescendo.ly", crescendo | lilypond()) diminuendo = two_bars | dynamics("mf", "pppp") write_midi.write("ode_diminuendo.mid", [diminuendo]) write_lilypond.write("ode_diminuendo.ly", diminuendo | lilypond())
# 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]) # put that sequence into C major, octave 4 quavers C_MAJOR = Key("C", major_scale) seq7 = seq6 | add({"octave": 4, DURATION_64: 8}) | degree_in_key(C_MAJOR) # convert to MIDI pitch and play player.play([OSequence(seq7 | midi_pitch())]) # sequence of first four degree of a scale seq8 = HSeq(Point(degree=n) for n in [1, 2, 3, 4]) # add duration and octave seq8 = seq8 | add({DURATION_64: 16, "octave": 5}) # put into C major seq8 = seq8 | degree_in_key(C_MAJOR) # annotate with lilypond seq8 = seq8 | lilypond() # write out lilypond file write("example.ly", seq8)
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]) # put that sequence into C major, octave 4 quavers C_MAJOR = Key("C", major_scale) seq7 = seq6 | add({"octave": 4, DURATION_64: 8}) | degree_in_key(C_MAJOR) # convert to MIDI pitch and play player.play([OSequence(seq7 | midi_pitch())]) # sequence of first four degree of a scale seq8 = HSeq(Point(degree=n) for n in [1, 2, 3, 4]) # add duration and octave seq8 = seq8 | add({DURATION_64: 16, "octave": 5}) # put into C major seq8 = seq8 | degree_in_key(C_MAJOR) # annotate with lilypond seq8 = seq8 | lilypond() # write out lilypond file write("example.ly", seq8)
def test_output(self): pitches = HSeq({"pitch": n} for n in [-2, 0, 2, -3]) seq = pitches | add({"octave": 5, DURATION_64: 16}) | lilypond() self.assertEqual(output(seq), "{ c'4 d'4 e'4 f'4 }")