def create_phrase(): p = Pat2Midi() n = Note2Midi() # vary the lag to create the rubato feeling lag_inc = NumberAnimation(frm=0, to=0.3, tween=['easeOutQuad']) lag_dec = NumberAnimation(frm=0.3, to=0, tween=['easeInOutCubic']) lag = SequentialAnimation([lag_inc, lag_dec], [1, 3], 2) # vary the volume over time to keep it interesting vol_inc1 = NumberAnimation(frm=Dyn.f, to=Dyn.ff, tween=['linear']) vol_dec1 = NumberAnimation(frm=Dyn.ff, to=Dyn.mf, tween=['linear']) vol_inc2 = NumberAnimation(frm=Dyn.mf, to=Dyn.f, tween=['linear']) vol_dec2 = NumberAnimation(frm=Dyn.f, to=Dyn.mp, tween=['linear']) vol_inc3 = NumberAnimation(frm=Dyn.mp, to=Dyn.mf, tween=['linear']) vol_dec3 = NumberAnimation(frm=Dyn.mf, to=Dyn.pp, tween=['linear']) vol = SequentialAnimation([vol_inc1, vol_dec1, vol_inc2, vol_dec2, vol_inc3, vol_dec3]) # and why not bounce a bit between legato and staccato while we're having fun? legato_to_staccato = NumberAnimation(frm=1, to=0.25, tween=['easeOutBounce']) staccato_to_legato = NumberAnimation(frm=0.1, to=1, tween=['easeOutBounce']) dur = SequentialAnimation([legato_to_staccato, staccato_to_legato]) # animate the tempo tempo_slowdown = NumberAnimation(frm=120, to=80, tween=['easeOutQuad']) # play some random cadenza notes = n.convert2( "a5 b5 c6 a5 e5 d5 c5 d5 e5 c5 a4 g#4 a4 b4 c5 a4 e4 d4 c4 d4 e4 c4 a3 g#3 a3 b3 c4 d4 e4 g#4 a4".split(" ")) notes2 = n.convert2( "d4 e4 f4 d4 a3 g3 f3 g3 a3 b3 c4 d4 c4 d4 e4 c4 g3 f3 e3 f3 g3 a3 b3 c4 a3 b3 c4 d4 e4 g#4 a4".split(" ")) notes.extend(notes2) properties_plain = { PP.NOTE: Pseq(notes, 1), PP.VOL: Pconst(100), PP.PLAYEDDUR: Pconst(0.95), PP.DUR: Pseq([Pconst(Dur.sixteenth_triplet, len(notes2) - 1), Pconst(Dur.half, 1)], 2), PP.LAG: Pconst(0), PP.TEMPO: Pconst(120) } properties_rubato = { PP.NOTE: Pseq(notes, 1), PP.VOL: Ptween(vol, 0, 0, len(notes), len(notes), None), PP.PLAYEDDUR: Ptween(dur, 0, 0, len(notes), len(notes), None), PP.DUR: Pseq([Pconst(Dur.sixteenth_triplet, len(notes2) - 1), Pconst(Dur.half, 1)], 2), PP.LAG: Ptween(lag, 0, 0, len(notes), len(notes), None), PP.TEMPO: Ptween(tempo_slowdown, 0, 0, len(notes), len(notes), None) } ph = Phrase(properties_plain) ph2 = Phrase(properties_rubato) p.add_phrases([ph, ph2], 0, 0, 0) p.write(outputfile)
def create_phrase(): n = Note2Midi() notes = ["c4", "e4", "g4", "c5", "b4", "g4", "f4", "d4", "c4"] from vectortween.NumberAnimation import NumberAnimation from vectortween.SequentialAnimation import SequentialAnimation increase = NumberAnimation(frm=Dyn.mp, to=Dyn.f) decrease = NumberAnimation(frm=Dyn.f, to=Dyn.ppp) swell_dim = SequentialAnimation([increase, decrease]) increasing_staccato = NumberAnimation(frm=1, to=0.5) properties1 = { # convert from note names to midi numbers PP.NOTE: Pseq(n.convert2(notes)), # last note is longer than the rest PP.DUR: Pseq([Pconst(Dur.eighth, len(notes) - 1), Pconst(Dur.whole, 1)]), # animate staccato PP.PLAYEDDUR: Ptween(increasing_staccato, 0, 0, len(notes), len(notes)), # volume should linearly go up from mp to f, then go down from f to ppp as the phrase progresses PP.VOL: Ptween(swell_dim, 0, 0, len(notes), len(notes), None), } properties2 = { # convert from (reversed) note names to midi numbers PP.NOTE: Pseq(n.convert2(notes[::-1])), # last note is longer than the rest PP.DUR: Pseq([Pconst(Dur.eighth, len(notes) - 1), Pconst(Dur.whole, 1)]), # animate staccato PP.PLAYEDDUR: Ptween(increasing_staccato, 0, 0, len(notes), len(notes)), # volume should linearly go up from mp to f, then go down from f to ppp as the phrase progresses PP.VOL: Ptween(swell_dim, 0, 0, len(notes), len(notes), None), } p1 = Phrase(properties1) p2 = Phrase(properties2) p2m = Pat2Midi() p2m.set_tempo(120) total_dur = p2m.add_phrases([p1, p2], start_time=1) print(total_dur) p2m.write(outputfile)
def create_phrase(): n = Note2Midi() a = NumberAnimation(frm=0, to=8000, tween=['easeOutElastic', 1, 0.02]) b = NumberAnimation(frm=8000, to=0, tween=['easeOutElastic', 1, 0.02]) c = NumberAnimation(frm=0, to=-8000, tween=['easeOutBounce', 0.1, 0.02]) d = NumberAnimation(frm=-8000, to=0, tween=['easeOutBounce', 0.1, 0.02]) s = SequentialAnimation([a, b, c, d], repeats=10) properties = { PP.NOTE: n.convert2(Pconst("a4", 1)), PP.DUR: Pconst(Dur.whole * 16, 1), # single note for 16 beats PP.PLAYEDDUR: Pconst(1), PP.ctrl_dur_key(MCC.PitchWheel): Pconst(0.03125, int((1 / 0.03125) * Dur.whole * 16)), PP.ctrl_val_key(MCC.PitchWheel): Ptween(s, 0, 0, int((1 / 0.03125) * Dur.whole * 16) - 1, int((1 / 0.03125) * Dur.whole * 16) - 1, None) } p = Phrase(properties) p2m = Pat2Midi() p2m.add_phrase(p, track=0, channel=0, start_time=0) p2m.write(outputfile)
def test_cc(self): properties = { PP.NOTE: Pconst(67, 5), PP.DUR: Pconst(1 / 2, 5), "D35": Pconst(1 / 4, 10), "V35": Pseq([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 10), "D34": Pconst(1 / 8, 20), "V34": Pseq([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ], 20) } p = Phrase(properties) result = [] for event in p: result.append(event) self.assertEqual(len(result), 5 + 10 + 20) self.assertEqual(result[-2]["V35"], 9) self.assertEqual(result[-2]["D35"], 4 * 1 / 4) self.assertEqual(result[-12]["V34"], 19) self.assertEqual(result[-12]["D34"], 4 * 1 / 8)
def phrase_for_section(self, section_id): """ :param section_id: integer :return: expremigen Phrase for section """ return Phrase(self.phrase_properties_for_section(section_id))
def test_defaults(self): n = Note2Midi() p = Phrase() result = [] for event in p: result.append(event) self.assertEqual(len(result), 1) self.assertEqual(result[0][PP.NOTE], n.lookup(Defaults.note)) self.assertEqual(result[0][PP.VOL], Defaults.vol) self.assertEqual(result[0][PP.DUR], 4 * Defaults.dur) self.assertEqual(result[0][PP.PLAYEDDUR], Defaults.playeddur) self.assertEqual(result[0][PP.LAG], Defaults.lag) self.assertEqual(result[0][PP.TEMPO], Defaults.tempo)
def __call__(self, kind=None, nanonotation=None, volumes=None, last_note_is_final=False): notes = self.nano.notes(nanonotation) durations = self.nano.dur(nanonotation) return Phrase({ PP.NOTE: self.note(notes), PP.VOL: self.volume(notes, volumes, None, None), PP.PLAYEDDUR: self.playeddur(notes, kind), PP.DUR: self.dur(durations), PP.LAG: self.lag(notes, last_note_is_final) })
def add_chords(pat2mid, track, channel): n = Note2Midi() notes = [C(["c3", "e3", "g3"]), C(["b2", "d3", "g3"]), C(["c3", "e3", "g3", "c4"])] from vectortween.NumberAnimation import NumberAnimation decrease = NumberAnimation(frm=Dyn.f, to=Dyn.p) properties = { PP.NOTE: Pseq(n.convert2(notes)), PP.DUR: Pseq([Pconst(Dur.whole, 2), Pconst(Dur.doublewhole, 1)]), PP.PLAYEDDUR: Pconst(1), PP.VOL: Ptween(decrease, 0, 0, len(notes), len(notes), None) } p = Phrase(properties) pat2mid.add_phrase(p, track=track, channel=channel, start_time=0) return pat2mid
def test_phrase(self): n = Note2Midi() properties = { PP.NOTE: Pseries(n.lookup("c4"), 1, 12), PP.VOL: Pconst(100, sys.maxsize), PP.DUR: Pconst(1 / 16, sys.maxsize), PP.PLAYEDDUR: Pconst(0.9, sys.maxsize), PP.LAG: Pconst(0, sys.maxsize) } p = Phrase(properties) result = [] for event in p: result.append(event) self.assertEqual(len(result), 12) self.assertEqual(result[1][PP.NOTE], n.lookup("c#4")) self.assertEqual(result[5][PP.VOL], 100) self.assertEqual(result[9][PP.DUR], 4 * 0.0625)
def test_addPhrase(self): n = Note2Midi() properties = { PP.NOTE: Pconst(n.lookup("f#3"), 3), PP.VOL: Pconst(Dyn.mf), PP.DUR: Pconst(Dur.quarter), PP.PLAYEDDUR: Pconst(0.9), PP.LAG: Pconst(0) } p = Phrase(properties) p2m = Pat2Midi() duration = p2m.add_phrase(p) self.assertEqual(duration, 3 * 4 * Dur.quarter) duration2 = p2m.add_phrase(p, start_time=duration) # just adding a single phrase returns the duration of that phrase only self.assertEqual(duration, duration2) # adding a list of phrases returns the total duration total_duration = p2m.add_phrases([p], start_time=duration + duration2) self.assertEqual(total_duration, 3 * duration)
def test_phrase2(self): n = Note2Midi() notes = ["c4", "e4", "g4", "c5", "b4", "g4", "f4", "d4", "c4"] from vectortween.NumberAnimation import NumberAnimation from vectortween.SequentialAnimation import SequentialAnimation increase = NumberAnimation(frm=Dyn.mp, to=Dyn.f) decrease = NumberAnimation(frm=Dyn.f, to=Dyn.ppp) swell_dim = SequentialAnimation([increase, decrease]) increasing_staccato = NumberAnimation(frm=1, to=0.8) properties = { # convert from note names to midi numbers PP.NOTE: Pseq(n.convert2(notes)), # last note is longer than the rest PP.DUR: Pseq([Pconst(Dur.quarter, len(notes) - 1), Pconst(Dur.whole, 1)]), # animate staccato PP.PLAYEDDUR: Ptween(increasing_staccato, 0, 0, len(notes), len(notes)), # volume should linearly go up from mp to f, then go down from f to ppp as the phrase progresses PP.VOL: Ptween(swell_dim, 0, 0, len(notes), len(notes), None), } p = Phrase(properties) result = [] for event in p: result.append(event) self.assertEqual(len(result), 9) # check that last note longer self.assertEqual(result[7][PP.DUR], 4 * 1 / 4) self.assertEqual(result[8][PP.DUR], 4 * 1) # check that volume increases then decreases self.assertLess(result[0][PP.VOL], result[4][PP.VOL]) self.assertLess(result[8][PP.VOL], result[4][PP.VOL]) self.assertLess(result[8][PP.VOL], result[0][PP.VOL]) # check that staccato increases for i in range(8): self.assertTrue( result[i][PP.PLAYEDDUR] > result[i + 1][PP.PLAYEDDUR]) self.assertEqual(result[8][PP.NOTE], n.lookup("c4"))
def add_melody(pat2mid, track, channel): n = Note2Midi() notes = ["c4", "e4", "g4", "c5", "b4", "g4", "f4", "d4", "c4"] from vectortween.NumberAnimation import NumberAnimation from vectortween.SequentialAnimation import SequentialAnimation increase = NumberAnimation(frm=Dyn.mp, to=Dyn.f) decrease = NumberAnimation(frm=Dyn.f, to=Dyn.ppp) swell_dim = SequentialAnimation([increase, decrease]) increasing_staccato = NumberAnimation(frm=1, to=0.5) properties = { # convert from note names to midi numbers PP.NOTE: Pseq(n.convert2(notes)), # last note is longer than the rest PP.DUR: Pseq([Pconst(Dur.quarter, len(notes) - 1), Pconst(Dur.whole, 1)]), # animate staccato PP.PLAYEDDUR: Ptween(increasing_staccato, 0, 0, len(notes), len(notes)), # volume should linearly go up from mp to f, then go down from f to ppp as the phrase progresses PP.VOL: Ptween(swell_dim, 0, 0, len(notes), len(notes), None), } p = Phrase(properties) pat2mid.set_tempo(60) pat2mid.add_phrase(p, track=track, channel=channel, start_time=0) return pat2mid
def add_phrase(self, phrase: Phrase, track=0, channel=0, start_time=0): """ :param phrase: a Phrase containing patterns and animations :param track: default: 0 :param channel: default: 0 :param start_time: time at which the phrase should be inserted default: 0 :return: total duration of the inserted phrase """ for event in phrase: # set tempo events only if they changed since last time # handle note events if PP.NOTE in event: if event[PP.TEMPO] != self.last_set_tempo[track]: self.midiFile.addTempo( track, start_time + phrase.generated_duration(), event[PP.TEMPO]) self.last_set_tempo[track] = event[PP.TEMPO] # set notes always if isinstance(event[PP.NOTE], Pchord): for n in event[PP.NOTE].notes: try: intnote = int(n) except ValueError: intnote = self.note2midi.lookup(n) if intnote == REST: continue self.midiFile.addNote( track=track, channel=channel, pitch=intnote, time=start_time + phrase.generated_duration() + event[PP.LAG], duration=event[PP.DUR] * event[PP.PLAYEDDUR], volume=int(event[PP.VOL]), annotation=None) else: try: intnote = int(event[PP.NOTE]) except ValueError: intnote = self.note2midi.lookup(event[PP.NOTE]) if intnote == REST: continue self.midiFile.addNote( track=track, channel=channel, pitch=intnote, time=start_time + phrase.generated_duration() + event[PP.LAG], duration=event[PP.DUR] * event[PP.PLAYEDDUR], volume=int(event[PP.VOL]), annotation=None) self.handle_control_changes(channel, event, phrase, start_time, track) # handle controller events (only if they changed since last time) else: self.handle_control_changes(channel, event, phrase, start_time, track) return phrase.generated_duration()