def test_detect_all_251s(self): from sidewinder import detect_numeral_pattern # mistyChart = sidewinder.Chart(progression=self.misty_numerals, key=self.misty_key) shorthand_string = 'FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, Am7, D7, Gm7, C7, FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, FM6, Eb9, FM7, Cm7, F7b9, BbM7, BbM7, Cbm7, E7, G7, Am7, D7b9, Gm7, C7, FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, FM6, FM6' mistyChart = sidewinder.Chart(progression=shorthand_string, key=self.misty_key) # in F numerals = mistyChart.get_numeral_representation(key=mistyChart.key) twofiveone = ['IIm7', 'V7', 'IM7'] two_five_ones = detect_numeral_pattern(numerals, pattern=twofiveone, transposing='True', original_key=mistyChart.key) # original key results chords_ = [c.replace(' ', '') for c in shorthand_string.split(',')] expect = [ idx for idx, equal in enumerate([(i, j, k) == ( 'Gm7', 'C7', 'FM7') for i, j, k in zip(chords_, chords_[1:], chords_[2:])]) if equal ] found = [hit['start_index'] for hit in two_five_ones['hits']] assert expect == found # transposed results expect_transposed = [(1, 'Bb'), (15, 'Bb'), (39, 'Bb')] found_transposed = [(hit['start_index'], hit['key']) for hit in two_five_ones['transposed_hits']] assert expect_transposed == found_transposed
def test_smooth_voice_leading(self): mistyChart = sidewinder.Chart(progression=self.misty_numerals, key=self.misty_key) mistyChart.set_durations(durations=self.misty_durs) from sidewinder.utilities import notes_durations_to_track, track_to_midi from sidewinder.voicings.voicings import voice_chords from sidewinder.voicings.voice_leading import smooth_voice_leading print( '=== testing smooth voice leading - please manually inspect the generated midi file: ===' ) voiced_chords = voice_chords(mistyChart.progressionShorthandList, voicing_type='rootless', type='B') smooth_voiced_chords = smooth_voice_leading(voiced_chords) assert track_to_midi(notes_durations_to_track(smooth_voiced_chords, mistyChart.durations), name='midi_out\\smooth_voice_test_SVL', timestamp=False) is not None assert track_to_midi(notes_durations_to_track(voiced_chords, mistyChart.durations), name='midi_out\\smooth_voice_test_default', timestamp=False) is not None
def test_shorthand_string_to_shorthand_list(self): shorthand_string = 'FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, Am7, D7, Gm7, C7, FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, FM6, Eb9, FM7, Cm7, F7b9, BbM7, BbM7, Cbm7, E7, G7, Am7, D7b9, Gm7, C7, FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, FM6, FM6' mistyChart = sidewinder.Chart(progression=shorthand_string, key=self.misty_key) cond1 = (mistyChart.progressionShorthandList[0] == 'FM7') cond2 = (mistyChart.progressionShorthandList[1] == 'Cm7') assert (cond1 & cond2)
def test_numeral_and_key_to_shorthand_list(self): mistyChart = sidewinder.Chart(progression=self.misty_numerals, key=self.misty_key) #print(mistyChart.__dict__) cond1 = (mistyChart.progressionShorthandList[0] == 'FM7') cond2 = (mistyChart.progressionShorthandList[1] == 'Cm7') assert (cond1 & cond2)
def test_shorthand_list_and_given_key_to_numerals_list(self): shorthand_string = 'FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, Am7, D7, Gm7, C7, FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, FM6, Eb9, FM7, Cm7, F7b9, BbM7, BbM7, Cbm7, E7, G7, Am7, D7b9, Gm7, C7, FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, FM6, FM6' shorthand_list = shorthand_string.replace(' ', '').split(',') test_key = self.misty_key mistyChart = sidewinder.Chart(progression=shorthand_list, key=test_key) numerals = mistyChart.get_numeral_representation(key=test_key) cond1 = (numerals[1] == 'Vm7') assert (cond1)
def test_shorthand_string_to_shorthand_tuples_list(self): shorthand_string = 'FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, Am7, D7, Gm7, C7, FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, FM6, Eb9, FM7, Cm7, F7b9, BbM7, BbM7, Cbm7, E7, G7, Am7, D7b9, Gm7, C7, FM7, Cm7, F7, BbM7, Bbm9, Eb7, FM7, Dm7, Gm7, C7, FM6, FM6' mistyChart = sidewinder.Chart(progression=shorthand_string, key=self.misty_key) cond1a = (mistyChart.progressionShorthandTuplesList[0][0] == 'F') cond1b = (mistyChart.progressionShorthandTuplesList[0][1] == 'M7') cond2a = (mistyChart.progressionShorthandTuplesList[1][0] == 'C') cond2b = (mistyChart.progressionShorthandTuplesList[1][1] == 'm7') assert (cond1a & cond1b & cond2a & cond2b)
def test_generate_walking_bassline_midi(self): mistyChart = sidewinder.Chart(progression=self.misty_numerals, key=self.misty_key) from sidewinder.utilities import notes_durations_to_track, track_to_midi from sidewinder.melodies.basslines import create_walking_bassline bassline_track = create_walking_bassline( mistyChart.progressionShorthandList, self.misty_durs) assert track_to_midi(bassline_track, name='midi_out\\walking_bassline_test', timestamp=False) is not None
def test_difficult_shorthand_string_to_parsed_shorthand_list(self): shorthand_string = 'Fmaj7, co7, Ebm7b5, ' mistyChart = sidewinder.Chart(progression=shorthand_string, key=self.misty_key) cond1a = (mistyChart.progressionShorthandTuplesList[0][0] == 'F') cond1b = (mistyChart.progressionShorthandTuplesList[0][1] == 'M7') cond2a = (mistyChart.progressionShorthandTuplesList[1][0] == 'C') cond2b = (mistyChart.progressionShorthandTuplesList[1][1] == 'o7') cond3a = (mistyChart.progressionShorthandTuplesList[2][0] == 'Eb') cond3b = (mistyChart.progressionShorthandTuplesList[2][1] == 'm7b5') assert (cond1a & cond1b & cond2a & cond2b & cond3a & cond3b)
def test_basic_voiced_chord_midi_output(self): mistyChart = sidewinder.Chart(progression=self.misty_numerals, key=self.misty_key) mistyChart.set_durations(durations=self.misty_durs) from sidewinder.utilities import notes_durations_to_track, track_to_midi from sidewinder.voicings.voicings import voice_chords # TO-DO: refactor the below into a Chart method? print( '=== testing basic voiced chord midi out - please manually inspect the generated midi file: ===' ) voiced_chords = voice_chords(mistyChart.progressionShorthandList, voicing_type='rootless', type='A') assert track_to_midi(notes_durations_to_track(voiced_chords, mistyChart.durations), timestamp=False) is not None
def main(): misty_numerals = 'IM7, v-7, I7, IVM7, iv-9, bVII7, IM7, vi-7, ii-7, V7, iii-7, VI7, ii-7, V7, \ IM7, v-7, I7, IVM7, iv-9, bVII7, IM7, vi-7, ii-7, V7, I6, bVII9, IM7, \ v-7, I7b9, IVM7, IVM7,\ bv-7, VII7, II7, iii-7, VI7b9, ii-7, V7, \ IM7, v-7, I7, IVM7, iv-9, bVII7, IM7, vi-7, ii-7, V7, I6, I6' misty_durs = [ 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 2, 2, 2, 1, 1, 1, 1 ] mistyChart = sidewinder.Chart(progression=misty_numerals, key='F') mistyChart.set_durations(durations=misty_durs) twofiveone = ['IIm7', 'V7', 'IM7'] two_five_ones = detect_numeral_pattern( mistyChart.get_numeral_representation(), pattern=twofiveone, transposing='True', original_key=mistyChart.key) print(two_five_ones) tfo_durs = [[ mistyChart.durations[tf['start_index']], mistyChart.durations[tf['start_index'] + 1], mistyChart.durations[tf['start_index'] + 2] ] for tf in two_five_ones['hits']] # from random import choices # # asc = [1,2,3,4,5,4,3,1] # asc = [1,2,4,'b7','b9'] # p = choices(asc, weights=[1,2,2,2,1], k=32) # print(p) # melody = get_scale_patterns('chromatic', p=p, keys=['F'], pattern_as_chromatic=True) # print(melody['F'][0]) # add a selection of melody to a selection of bars in the Composition arps = [[from_shorthand(chord)[i] for i in (0, 1, 2, 3, 2, 1, 0, 1)] for chord in mistyChart.progressionShorthandList] notes_ = [] note_durations = [] for arp, chord_dur in zip(arps, mistyChart.durations): if chord_dur == 1: note_durations += [8 for _ in range(8)] notes_ += [arp[i] for i in range(8)] elif chord_dur == 2: note_durations += [8 for _ in range(4)] notes_ += [arp[i] for i in range(4)] assert len(notes_) == len(note_durations) t = Track() for i, _ in enumerate(note_durations): t.add_notes(notes_[i], note_durations[i]) # use the db to add/overlay a 251 lick in the right place start_index = two_five_ones['hits'][0][ 'start_index'] # refers to index in chord progression (not bar) key = two_five_ones['hits'][0]['key'] durs = tfo_durs[0] # [1,1,1] # chords_ = mistyChart.progressionShorthandList[start_index:start_index+len(twofiveone)] ### now search db for a 251 in F w/ duratons 1,1,1 then place at start_index db = TinyDB( r'C:\Users\Sam\Documents\Sidewinder\local files\jazz-licks-db-260720-new.json' ) # set-up / connection # candidate_licks = find_partial_matches(db, {'tags':'251'}) # gives db id's (doc_id) # searching should be better, done on actual chord metadata candidate_licks = find_by_chords_durations(db, chords=['Gm7', 'C7', 'FM7'], durations=[1, 1, 1]) # candidate_licks = [load_entry(db, doc_id) for doc_id in candidate_licks] # instantiate from db lick251 = load_entry(db, candidate_licks[0]) # for doc_id in candidate_licks[-15:]: # print(db.get(doc_id=doc_id)) # print(candidate_licks[0].chords) # candidate_licks[0].to_midi() notes_ = [nc[2] for bar in lick251.passage for nc in bar] notes_ = [nc[0] if bool(nc) else None for nc in notes_] durations_ = [nc[1] for bar in lick251.passage for nc in bar] # [start of Misty ... 251 lick notes_,durations_ ... rest of Misty] start_bar = 8 # could compute using start_index and misty_durs t2 = Track_from_list(t[:start_bar - 1]) for n, d in zip(notes_, durations_): t2.add_notes(n, d) for bar in Track_from_list( t[start_bar - 1 + 4:] ): # known that the lick is 4 bars, could probably compute from lick251.passage t2 + bar track_to_midi(t2, name='midi_out\\test251_lick_add')
def test_set_mismatched_length_durations_SHORT(self): mistyChart = sidewinder.Chart(progression=self.misty_numerals, key=self.misty_key) mistyChart.set_durations(durations=self.misty_durs[:2]) assert self.misty_durs[:2] == mistyChart.durations[:2]
def test_set_mismatched_length_durations_LONG(self): mistyChart = sidewinder.Chart(progression=self.misty_numerals, key=self.misty_key) mistyChart.set_durations(durations=self.misty_durs * 2) assert self.misty_durs == mistyChart.durations[:len(self.misty_durs)]
def test_create_representation_of_chart_with_durations(self): mistyChart = sidewinder.Chart(progression=self.misty_numerals, key=self.misty_key) mistyChart.set_durations(durations=self.misty_durs) assert self.misty_durs == mistyChart.durations