def fill(duration, point): """ fills the subsequence of the point with repetitions of its subsequence and sets the ``duration`` of each point. """ point['sequence'] = point['sequence'] * (point[DURATION_64] / (8 * duration)) | add({DURATION_64: duration}) return point
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_add_transformation(self): """ Ensure adding properties modifies the points """ from sebastian.core.transforms import add h1 = self.make_horizontal_sequence() from sebastian.core import DURATION_64 added = h1 | add({'octave': 4, DURATION_64: 8}) expected = [{'degree': degree, DURATION_64: 8, 'octave': 4} for degree in self.make_notes()] self.assertEqual(list(added), expected)
def test_add_transformation(self): """ Ensure adding properties modifies the points """ from sebastian.core.transforms import add h1 = self.make_horizontal_sequence() from sebastian.core import DURATION_64 added = h1 | add({'octave': 4, DURATION_64: 8}) expected = [{ 'degree': degree, DURATION_64: 8, 'octave': 4 } for degree in self.make_notes()] self.assertEqual(list(added), expected)
def test_play_notes_in_midi_pitches(self): """ Ensure that it plays in G major. """ from sebastian.core.transforms import degree_in_key, midi_pitch, add from sebastian.core.notes import Key, major_scale from sebastian.core import MIDI_PITCH, DURATION_64 h1 = self.make_horizontal_sequence() keyed = h1 | degree_in_key(Key("G", major_scale)) positioned = keyed | add({'octave': 4, DURATION_64: 8}) pitched = positioned | midi_pitch() self.assertEqual(pitched._elements, [ {'degree': 1, 'pitch': -1, DURATION_64: 8, MIDI_PITCH: 55, 'octave': 4}, {'degree': 2, 'pitch': 1, DURATION_64: 8, MIDI_PITCH: 57, 'octave': 4}, {'degree': 3, 'pitch': 3, DURATION_64: 8, MIDI_PITCH: 59, 'octave': 4}, {'degree': 1, 'pitch': -1, DURATION_64: 8, MIDI_PITCH: 55, 'octave': 4}, ])
def test_play_notes_in_midi_pitches(self): """ Ensure that it plays in G major. """ from sebastian.core.transforms import degree_in_key, midi_pitch, add from sebastian.core.notes import Key, major_scale from sebastian.core import MIDI_PITCH, DURATION_64 h1 = self.make_horizontal_sequence() keyed = h1 | degree_in_key(Key("G", major_scale)) positioned = keyed | add({'octave': 4, DURATION_64: 8}) pitched = positioned | midi_pitch() self.assertEqual(pitched._elements, [ { 'degree': 1, 'pitch': -1, DURATION_64: 8, MIDI_PITCH: 55, 'octave': 4 }, { 'degree': 2, 'pitch': 1, DURATION_64: 8, MIDI_PITCH: 57, 'octave': 4 }, { 'degree': 3, 'pitch': 3, DURATION_64: 8, MIDI_PITCH: 59, 'octave': 4 }, { 'degree': 1, 'pitch': -1, DURATION_64: 8, MIDI_PITCH: 55, 'octave': 4 }, ])
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") write_midi.write("ode_crescendo.mid", [crescendo])
def h2_end1(scale): return HSeq(scale[i] for i in [0, 4]) | add(quaver_point)
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") write_midi.write("ode_crescendo.mid", [crescendo]) write_lilypond.write("ode_crescendo.ly", crescendo | lilypond()) diminuendo = two_bars | dynamics("mf", "pppp")
def h1(scale): return HSeq(scale[i] for i in [5, 4, 3, 4]) | add(quaver_point)
def end(scale): return HSeq(scale[i] for i in [2, 1]) | add(quaver_point)
""" The main title theme to HBO's Game of Thrones by Ramin Djawadi """ from sebastian.core import Point, HSeq, OSequence from sebastian.core.transforms import midi_pitch, degree_in_key, add from sebastian.core.notes import Key, major_scale, minor_scale from sebastian.midi import write_midi C_Major = Key("C", major_scale) C_minor = Key("C", minor_scale) motive_degrees = HSeq(Point(degree=n) for n in [5, 1, 3, 4]) motive_rhythm_1 = HSeq(Point(duration_64=n) for n in [16, 16, 8, 8]) motive_rhythm_2 = HSeq( Point(duration_64=n) for n in [48, 48, 8, 8, 32, 32, 8, 8]) motive_1 = motive_degrees & motive_rhythm_1 motive_2 = (motive_degrees * 2) & motive_rhythm_2 # add key and octave seq1 = (motive_1 * 4) | add({"octave": 5}) | degree_in_key(C_minor) seq2 = (motive_1 * 4) | add({"octave": 5}) | degree_in_key(C_Major) seq3 = motive_2 | add({"octave": 4}) | degree_in_key(C_minor) seq = (seq1 + seq2 + seq3) | midi_pitch() | OSequence write_midi.write("game_of_thrones.mid", [seq], instruments=[49], tempo=350000)
def end(scale): return HSeq(scale[i] for i in [2, 1]) | add(quaver_point) def h2(scale): return HSeq(scale[i] for i in [0, 4, 3, 4]) | add(quaver_point) def h2_end1(scale): return HSeq(scale[i] for i in [0, 4]) | add(quaver_point) # there's two important quarter notes used at the ends of sections e1 = HSeq(scale[3]) | add(quarter_point) e2 = HSeq(scale[0]) | add(quarter_point) partA = h1(scale) + h1_end1(scale) + e1 + h1(scale) + end(scale) + e2 partB = h2(scale) + h2_end1(scale) + e1 + h2(scale) + end(scale) + e2 # here we see the basic structure of the song oseq = OSequence((partA * 2) + (partB * 2)) C_major = Key("C", major_scale) # note values filled-out for C major in octave 5 then MIDI pitches calculated seq = oseq | degree_in_key_with_octave(C_major, 5) | midi_pitch() # write to file: write_midi.write("shortning_bread_1.mid", [seq])
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 }")
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)
""" The main title theme to HBO's Game of Thrones by Ramin Djawadi """ from sebastian.core import Point, HSeq, OSequence from sebastian.core.transforms import midi_pitch, degree_in_key, add from sebastian.core.notes import Key, major_scale, minor_scale from sebastian.midi import write_midi C_Major = Key("C", major_scale) C_minor = Key("C", minor_scale) motive_degrees = HSeq(Point(degree=n) for n in [5, 1, 3, 4]) motive_rhythm_1 = HSeq(Point(duration_64=n) for n in [16, 16, 8, 8]) motive_rhythm_2 = HSeq(Point(duration_64=n) for n in [48, 48, 8, 8, 32, 32, 8, 8]) motive_1 = motive_degrees & motive_rhythm_1 motive_2 = (motive_degrees * 2) & motive_rhythm_2 # add key and octave seq1 = (motive_1 * 4) | add({"octave": 5}) | degree_in_key(C_minor) seq2 = (motive_1 * 4) | add({"octave": 5}) | degree_in_key(C_Major) seq3 = motive_2 | add({"octave": 4}) | degree_in_key(C_minor) seq = (seq1 + seq2 + seq3) | midi_pitch() | OSequence write_midi.write("game_of_thrones.mid", [seq], instruments=[49], tempo=350000)
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 }])
# 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]) # 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
from sebastian.core.transforms import midi_pitch, degree_in_key_with_octave, add from sebastian.core.notes import Key, major_scale from sebastian.midi import write_midi def alberti(triad): """ takes a VSeq of 3 notes and returns an HSeq of those notes in an alberti figuration. """ return HSeq(triad[i] for i in [0, 2, 1, 2]) # an abstract VSeq of 3 notes in root position (degree 1, 3 and 5) root_triad = VSeq(Point(degree=n) for n in [1, 3, 5]) quaver_point = Point({DURATION_64: 8}) # an OSequence with alberti figuration repeated 16 times using quavers alberti_osequence = OSequence(alberti(root_triad) * 16 | add(quaver_point)) C_major = Key("C", major_scale) # note values filled-out for C major in octave 5 then MIDI pitches calculated seq = alberti_osequence | degree_in_key_with_octave(C_major, 5) | midi_pitch() # write to file: write_midi.write("alberti.mid", [seq])
# invert assert (s1 | invert(50))._elements == [ {DURATION_64: 16, OFFSET_64: 16, MIDI_PITCH: 50}, {DURATION_64: 16, OFFSET_64: 32, MIDI_PITCH: 48} ] assert s1 | invert(100) | invert(100) == s1 s4 = HSeq([Point(degree=degree) for degree in [1, 2, 3, 2, 1]]) # add s5 = s4 | add({"octave": 4, DURATION_64: 8}) assert list(s5) == [ {'degree': 1, DURATION_64: 8, 'octave': 4}, {'degree': 2, DURATION_64: 8, 'octave': 4}, {'degree': 3, DURATION_64: 8, 'octave': 4}, {'degree': 2, DURATION_64: 8, 'octave': 4}, {'degree': 1, DURATION_64: 8, 'octave': 4} ] # degree_in_key s6 = s5 | degree_in_key(Key("C", major_scale)) assert list(s6) == [ {'degree': 1, DURATION_64: 8, 'octave': 4, 'pitch': -2},
def alberti(vseq, duration): """ takes a VSeq of 3 notes and returns an HSeq of those notes in an alberti figuration with each new note having the given duration. """ return HSeq(vseq[i] for i in [0, 2, 1, 2]) | add(Point({DURATION_64: duration}))
def silence(seq): return seq | add({'velocity':0})
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]) # 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())])
# 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]) # 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()
from sebastian.core import VSeq, HSeq, Point, OSequence from sebastian.core.transforms import midi_pitch, degree_in_key_with_octave, add from sebastian.core.notes import Key, major_scale from sebastian.midi import write_midi def alberti(triad): """ takes a VSeq of 3 notes and returns an HSeq of those notes in an alberti figuration. """ return HSeq(triad[i] for i in [0, 2, 1, 2]) # an abstract VSeq of 3 notes in root position (degree 1, 3 and 5) root_triad = VSeq(Point(degree=n) for n in [1, 3, 5]) quaver_point = Point({DURATION_64: 8}) # an OSequence with alberti figuration repeated 16 times using quavers alberti_osequence = OSequence(alberti(root_triad) * 16 | add(quaver_point)) C_major = Key("C", major_scale) # note values filled-out for C major in octave 5 then MIDI pitches calculated seq = alberti_osequence | degree_in_key_with_octave(C_major, 5) | midi_pitch() # write to file: write_midi.write("alberti.mid", [seq])