def edit_scale(pad, verbose): global config rbank = int((pad - 1) / _PADS) rsubpad = pad - (_PADS * rbank) - 1 menu = qprompt.Menu() x = 0 for y in Scale._SCALE_PATTERNS: menu.add(str(x), y) x = x + 1 stype = menu.show(hdr="Pad %d (Bank %s-%d):" % (pad, chr(65 + rbank), rsubpad + 1), msg="Scale", returns="desc") root = qprompt.ask_int("Note", vld=list(range(0, 128)), dft=config[1][rbank][rsubpad]['note']) count = qprompt.ask_int("Count", vld=[0] + list(range(1, _PTOTAL + 2 - pad)), dft=0) scale = Scale.build_scale(Note.from_midi_num(root), stype) scale_lst = [] for note in scale: scale_lst.append(note.midi_note_number()) if count: while len(scale_lst) < count: root = scale_lst.pop() scale = Scale.build_scale(Note.from_midi_num(root), stype) for note in scale: scale_lst.append(note.midi_note_number()) else: count = len(scale_lst) if pad + count > _PTOTAL: count = _PTOTAL + 1 - pad for note in scale_lst[:count]: bank = int((pad - 1) / _PADS) subpad = pad - (_PADS * bank) - 1 config[1][bank][subpad]['note'] = note if verbose: print("Setting Pad %d (Bank %s-%d) to %d (%s)" % (pad, chr(65 + bank), subpad + 1, note, Note.from_midi_num(note))) pad = pad + 1
def test_scale_builder_e_maj(): s = Scale.build_scale(Note('E', 4), 'maj') expected = [ Note('E', 4), Note('F', 4, '#'), Note('G', 4, '#'), Note('A', 4), Note('B', 4), Note('C', 5, '#'), Note('D', 5, '#'), Note('E', 5) ] assert s == expected
def test_scale_builder_c_flat_nat_min(): s = Scale.build_scale(Note('C', 5, 'b'), 'natural minor') expected = [ Note('C', 5, 'b'), Note('D', 5, 'b'), Note('E', 5, 'bb'), Note('F', 5, 'b'), Note('G', 5, 'b'), Note('A', 5, 'bb'), Note('B', 5, 'bb'), Note('C', 6, 'b') ] assert s == expected
def test_scale_builder_b_sharp_nat_min(): s = Scale.build_scale(Note('B', 4, '#'), 'nat min') expected = [ Note('B', 4, '#'), Note('C', 5, '##'), Note('D', 5, '#'), Note('E', 5, '#'), Note('F', 5, '##'), Note('G', 5, '#'), Note('A', 5, '#'), Note('B', 5, '#') ] assert s == expected
def test_scale_builder_b_nat_min(): s = Scale.build_scale(Note('B', 4), 'natural minor') expected = [ Note('B', 4), Note('C', 5, '#'), Note('D', 5), Note('E', 5), Note('F', 5, '#'), Note('G', 5), Note('A', 5), Note('B', 5) ] assert s == expected
def test_scale_builder_a_nat_min(): s = Scale.build_scale(Note('A', 4), 'nat min') expected = [ Note('A', 4), Note('B', 4), Note('C', 5), Note('D', 5), Note('E', 5), Note('F', 5), Note('G', 5), Note('A', 5) ] assert s == expected
def test_scale_builder_b_flat_min(): s = Scale.build_scale(Note('B', 4, 'b'), 'min') expected = [ Note('B', 4, 'b'), Note('C', 5), Note('D', 5, 'b'), Note('E', 5, 'b'), Note('F', 5), Note('G', 5, 'b'), Note('A', 5), Note('B', 5, 'b') ] assert s == expected
def test_scale_builder_f_sharp_min(): s = Scale.build_scale(Note('F', 4, '#'), 'minor') expected = [ Note('F', 4, '#'), Note('G', 4, '#'), Note('A', 4), Note('B', 4), Note('C', 5, '#'), Note('D', 5), Note('E', 5, '#'), Note('F', 5, '#') ] assert s == expected
def test_scale_builder_c_flat_maj(): s = Scale.build_scale(Note('C', 5, 'b'), 'maj') expected = [ Note('C', 5, 'b'), Note('D', 5, 'b'), Note('E', 5, 'b'), Note('F', 5, 'b'), Note('G', 5, 'b'), Note('A', 5, 'b'), Note('B', 5, 'b'), Note('C', 6, 'b') ] assert s == expected
def edit_scale(pad, verbose): global config rbank = int((pad - 1) / _PADS) rsubpad = pad - (_PADS * rbank) - 1 ptype = config[1][rbank][rsubpad]['type'] if ptype == "BANK": qprompt.error("Pad %d (Bank %s-%d) is configured as a BANK" % (pad, chr(65 + rbank), rsubpad + 1)) return menu = qprompt.Menu() x = 0 for y in Scale._SCALE_PATTERNS: menu.add(str(x), y) x = x + 1 stype = menu.show(hdr="Pad %d (Bank %s-%d):" % (pad, chr(65 + rbank), rsubpad + 1), msg="Scale", returns="desc") root = qprompt.ask_int("Note", vld=list(range(0, 128)), dft=config[1][rbank][rsubpad]['note']) count = qprompt.ask_int("Count", vld=[0] + list(range(1, _PTOTAL + 2 - pad)), dft=0) same = qprompt.ask_yesno(msg="Config all as per Pad %d?" % pad, dft='N') scale = Scale.build_scale(Note.from_midi_num(root), stype) scale_lst = [] for note in scale: scale_lst.append(note.midi_note_number()) if count: while len(scale_lst) < count: root = scale_lst.pop() scale = Scale.build_scale(Note.from_midi_num(root), stype) for note in scale: scale_lst.append(note.midi_note_number()) else: count = len(scale_lst) if pad + count > _PTOTAL: count = _PTOTAL + 1 - pad for note in scale_lst[:count]: bank = int((pad - 1) / _PADS) subpad = pad - (_PADS * bank) - 1 if same and ptype == "NOTE": config[1][bank][subpad]['type'] = config[1][rbank][rsubpad]['type'] config[1][bank][subpad]['channel'] = config[1][rbank][rsubpad][ 'channel'] config[1][bank][subpad]['trigger'] = config[1][rbank][rsubpad][ 'trigger'] config[1][bank][subpad]['aftertouch'] = config[1][rbank][rsubpad][ 'aftertouch'] if same and ptype == "PROG": config[1][bank][subpad]['type'] = config[1][rbank][rsubpad]['type'] config[1][bank][subpad]['channel'] = config[1][rbank][rsubpad][ 'channel'] if ptype == "NOTE": config[1][bank][subpad]['note'] = note else: config[1][bank][subpad]['program'] = note if verbose: print("Setting Pad %d (Bank %s-%d) to %d (%s)" % (pad, chr(65 + bank), subpad + 1, note, Note.from_midi_num(note))) pad = pad + 1
def edit_scale(pad, verbose): global config rbank = int((pad - 1) / _PADS) rsubpad = pad - (_PADS * rbank) - 1 menu = qprompt.Menu() menu.add("0", "Note") menu.add("1", "Midi-CC") menu.add("2", "Program") ptype = menu.show(msg="Apply Scale to:", returns="desc", dft="0") menu = qprompt.Menu() x = 0 for y in Scale._SCALE_PATTERNS: menu.add(str(x), y) x = x + 1 stype = menu.show(hdr="Pad %d (Bank %s-%d):" % (pad, chr(65 + rbank), rsubpad + 1), msg="Scale", returns="desc") same = None if ptype == "Note": root = qprompt.ask_int("Note", vld=list(range(0, 128)), dft=config[1][rbank][rsubpad]['note']) same = qprompt.ask_yesno(msg="Config all as per Pad %d?" % pad, dft='N') elif ptype == "Midi-CC": root = qprompt.ask_int("Midi-CC Value", vld=list(range(0, 128)), dft=config[1][rbank][rsubpad]['midicc']) else: root = qprompt.ask_int("Program Value", vld=list(range(0, 128)), dft=config[1][rbank][rsubpad]['prog']) count = qprompt.ask_int("Count", vld=[0] + list(range(1, _PTOTAL + 2 - pad)), dft=0) scale = Scale.build_scale(Note.from_midi_num(root), stype) scale_lst = [] for note in scale: scale_lst.append(note.midi_note_number()) if count: while len(scale_lst) < count: root = scale_lst.pop() scale = Scale.build_scale(Note.from_midi_num(root), stype) for note in scale: scale_lst.append(note.midi_note_number()) else: count = len(scale_lst) if pad + count > _PTOTAL: count = _PTOTAL + 1 - pad for note in scale_lst[:count]: bank = int((pad - 1) / _PADS) subpad = pad - (_PADS * bank) - 1 if same and ptype == "Note": config[1][bank][subpad]['trigger'] = config[1][rbank][rsubpad][ 'trigger'] if ptype == "Note": config[1][bank][subpad]['note'] = note elif ptype == "Midi-CC": config[1][bank][subpad]['midicc'] = note else: config[1][bank][subpad]['prog'] = note if verbose: print("Setting Pad %d (Bank %s-%d) to %d (%s)" % (pad, chr(65 + bank), subpad + 1, note, Note.from_midi_num(note))) pad = pad + 1
from uno_synth import * # Requires: # https://github.com/charlottepierce/music_essentials from music_essentials import Note, Scale # build initial patch (basic triangle sound) data = Patch.build({}) # now add a 'C Scale' to the sequence scale = Scale.build_scale(Note.from_note_string("C4"), "major") step = 1 # describe each step in full for note in scale: data = data + Seq.build({ "step": step, "count": 1, "elements": [{ "element": { "type": 2, "port": 0, "channel": 0 }, "data": { "note": Note.midi_note_number(note), "velocity": 127, "length": 1, }
def test_non_note_tonic_str(): with pytest.raises(TypeError): Scale.build_scale('dlsfk', 'major')
def test_unsupported_scale_type(): with pytest.raises(ValueError): Scale.build_scale(Note('C', 4), 'scale')
def test_non_note_tonic_int(): with pytest.raises(TypeError): Scale.build_scale(1, 'major')