def __init__(self, original_figure: str = None, spotify_figure: str = None, figure: str = None, bass: str = None, root: str = None, kind: str = None): # This is the original figure, which is kept because it is needed to create a SpotifyChord equivalent to THIS # SpotifyChordSymbol self.original_figure = original_figure if spotify_figure == 'NC': self.bass = None self.root = None self.structure = 'NC' elif figure: assert root self.bass = Pitch(bass[1:]) if bass else None if self.bass: self.bass.octave = None self.root = Pitch(root) self.root.octave = None self.structure = figure else: assert root and kind chord_symbol = ChordSymbol(bass=bass[1:], root=root, kind=kind) self.bass = Pitch(bass[1:]) if bass else None if self.bass: self.bass.octave = None self.root = Pitch(root) self.root.octave = None self.structure = chord_symbol.figure
def testPitchEquality(self): ''' Test updating accidental display. ''' data = [ ('a', 'b', False), ('a', 'a', True), ('a#', 'a', False), ('a#', 'b-', False), ('a#', 'a-', False), ('a##', 'a#', False), ('a#4', 'a#4', True), ('a-3', 'a-4', False), ('a#3', 'a#4', False), ] for x, y, match in data: p1 = Pitch(x) p2 = Pitch(y) self.assertEqual(p1 == p2, match) # specific case of changing octave p1 = Pitch('a#') p2 = Pitch('a#') self.assertEqual(p1, p2) p1.octave = 4 p2.octave = 3 self.assertNotEqual(p1, p2) p1.octave = 4 p2.octave = 4 self.assertEqual(p1, p2)
def notate_note(note): if note['pitch'] == 'rest': n = Rest() else: if isinstance(note['pitch'], list): pitches = [] for pitch_number in note['pitch']: p = Pitch(pitch_number) # Force all flats if p.accidental.name == 'sharp': p = p.getEnharmonic() pitches.append(p) n = Chord(notes=pitches) else: p = Pitch(note['pitch']) # Force all flats if p.accidental.name == 'sharp': p = p.getEnharmonic() n = Note(p) d = Duration() if note['duration'] == 0: d.quarterLength = .125 d = d.getGraceDuration() else: # music21 docs say `fill` is for testing. I can't remember why I chose # to use it originally. It works. But not for tuplets. Maybe this blog # post contains a better solution: # http://music21-mit.blogspot.com/2015/09/durations-and-durationtuples.html d.fill(note['durations']) n.duration = d return n
def notate_score(musician_names, instrument_names, music): score = Score() for musician_name, instrument_name in zip(musician_names, instrument_names): instrument = get_instrument(instrument_name) instrument.partName = instrument.instrumentName instrument.partAbbreviation = instrument.instrumentAbbreviation parts = [] part = Part() parts.append(part) part.insert(0, instrument) score.insert(0, part) score.insert(0, StaffGroup(parts)) notes = music[musician_name] for pitches in notes: if not pitches or pitches == 'stop': note = Rest() elif len(pitches) == 1: pitch = Pitch(pitches[0] + 60) note = Note(pitch) else: note = Chord(notes=[Pitch(p + 60) for p in pitches]) duration = Duration() duration.fill([4.0]) note.duration = duration part.append(note) score.show('musicxml', '/Applications/Sibelius 7.5.app')
def generate_closed_chord(self, root_note: PitchInit, anchor_note: PitchInit = "C4", max_notes: int = 5, bass_note: Optional[PitchInit] = None, include_root: bool = True): if isinstance(root_note, str): root_note = Pitch(root_note) if isinstance(anchor_note, str): anchor_note = Pitch(anchor_note) if isinstance(bass_note, str): bass_note = Pitch(bass_note) if max_notes < 2: raise ValueError("Not really a chord with only one or no notes.") chord_heap = [] third = root_note.transpose(self.third_quality.interval) fifth = root_note.transpose(self.fifth_quality.interval) harmonies = [root_note.transpose(harm.interval) for harm in self.harmonies] heappush(chord_heap, (9, third)) for harmony in harmonies: heappush(chord_heap, (7, harmony)) heappush(chord_heap, (1, fifth)) if include_root: heappush(chord_heap, (3, root_note)) if self.upper_quality is not None: heappush(chord_heap, (9, (root_note.transpose(self.upper_quality.interval)))) while len(chord_heap) > max_notes: heappop(chord_heap) chord_base = Chord(note for _, note in chord_heap) chord_base.sortDiatonicAscending(inPlace=True) chord_base = move_chord(chord_base, anchor_note) chord_base = chord_base.closedPosition() inversions = all_inversions(chord_base) inversions = [move_chord(c, anchor_note) for c in inversions] best_option = min(inversions, key=lambda x: chord_mad(x, anchor_note)) if bass_note is not None: bass_note = move_pitch(bass_note, anchor_note.transpose(-12)) best_option.add(bass_note, runSort=True) return best_option
def split(figure): _figure = figure.replace('bpedal', '-pedal') root = match(r'[A-Ga-g][#-]*', _figure).group() _figure = _figure.replace(root, '', 1) root_pitch = Pitch(root) root = str(root_pitch) bass = search(r'/[A-Ga-g][#-]*', _figure) structure = _figure.replace(bass.group(), '', 1) if bass else _figure if bass: bass_pitch = Pitch(bass.group()[1:]) bass = '/' + str(bass_pitch) return root, structure.strip(), bass if bass else ''
def write_notation_cell(music, path, event_index): score = Score() metadata = Metadata() metadata.title = '' metadata.composer = '' score.insert(0, metadata) layout = ScoreLayout() layout.scalingMillimeters = 1.25 layout.scalingTenths = 40 score.insert(0, layout) for musician in music: instrument_name = musician['instrument'] instrument = get_instrument(instrument_name) instrument.partName = instrument.instrumentName if instrument.instrumentName is 'Violoncello': instrument.partName = 'Cello' instrument.partAbbreviation = instrument.instrumentAbbreviation parts = [] part = Part() parts.append(part) part.insert(0, instrument) score.insert(0, part) # score.insert(0, StaffGroup(parts)) for event in musician['music']: pitches = event['pitches'] dur = event['duration'] # if not pitches or pitches == 'stop': # note = Rest() if len(pitches) == 1: pitch = Pitch(pitches[0] + 60) note = Note(pitch) else: note = Chord(notes=[Pitch(p + 60) for p in pitches]) duration = Duration() duration.fill([dur]) note.duration = duration part.append(note) file_path = os.path.join(path, str(event_index).zfill(2)) musicxml_file_path = file_path + '.xml' png_output_file_path = file_path + '.png' score.write('musicxml', musicxml_file_path) write_png_with_musescore(musicxml_file_path, png_output_file_path, dpi=600)
def make_music21_note( pitch_number=None, duration=1.0, staccato=False, tenuto=False, accent=False, falloff=False, plop=False, scoop=False, doit=False, breath_mark=False, ): if pitch_number == None or pitch_number == 'rest': n = Rest() elif isinstance(pitch_number, list): pitches = [Pitch(p) for p in pitch_number] for p in pitches: if p.accidental.name is 'natural': p.accidental = None n = Chord(pitches) else: p = Pitch(pitch_number) if p.accidental.name is 'natural': p.accidental = None n = Note(p) d = Duration() d.quarterLength = duration n.duration = d if staccato: n.articulations.append(Staccato()) if tenuto: n.articulations.append(Tenuto()) if accent: n.articulations.append(Accent()) if falloff: n.articulations.append(Falloff()) if plop: n.articulations.append(Plop()) if scoop: n.articulations.append(Scoop()) if doit: n.articulations.append(Doit()) if breath_mark: n.articulations.append(BreathMark()) return n
def plot_instrument_ranges(sounds): inst_info = {(snd.short_name, snd.low_no, snd.high_no, snd.section): None for snd in sounds}.keys() color_map = { Section.PERCUSSION: "orange", Section.WOODWINDS: "green", Section.BRASS: "red", Section.STRINGS: "blue", } names, lows, highs, sections = zip(*inst_info) fig, ax = plt.subplots(figsize=(6, 6)) ax.barh( y=list(range(len(names))), left=lows, width=[high - low for (low, high) in zip(lows, highs)], tick_label=names, color=[color_map[sec] for sec in sections], ) # grid at Cs and Gs xticks = sorted(list(range(24, 111, 12)) + list(range(19, 111, 12))) ax.set_xticks(xticks) ax.set_xticklabels([Pitch(no) for no in xticks], rotation=0) ax.grid(axis="x", which="major") ax.set_title("Instrument Ranges") plt.tight_layout() plt.show()
def transposed_to( self, pitch: Pitch = Pitch()) -> Tuple['SpotifyChord', Optional[Interval]]: if self.is_no_chord(): return self, None tr_int = interval.notesToInterval(self.root, pitch) return self.transposed_by(tr_int), tr_int
def testCopyAndDeepcopy(self): ''' Test copying all objects defined in this module ''' for part in sys.modules[self.__module__].__dict__: match = False for skip in ['_', '__', 'Test', 'Exception']: if part.startswith(skip) or part.endswith(skip): match = True if match: continue name = getattr(sys.modules[self.__module__], part) # noinspection PyTypeChecker if callable(name) and not isinstance(name, types.FunctionType): try: # see if obj can be made w/ args obj = name() except TypeError: continue copy.copy(obj) copy.deepcopy(obj) p1 = Pitch('C#3') p2 = copy.deepcopy(p1) self.assertIsNot(p1, p2) self.assertIsNot(p1.accidental, p2.accidental)
def get_offset_from_key(key): tonic, mode = key.split(' ') tonic = tonic.replace('b', '-') if mode == 'major': k = Key(tonic) else: k = Key(tonic.lower()).relative return Pitch('C').midi - k.getTonic().midi
def testUpdateAccidentalDisplaySimple(self): '''Test updating accidental display. ''' past = [Pitch('A#3'), Pitch('C#'), Pitch('C')] a = Pitch('c') a.accidental = Accidental('natural') a.accidental.displayStatus = True self.assertEqual(a.name, 'C') self.assertTrue(a.accidental.displayStatus) a.updateAccidentalDisplay(pitchPast=past, overrideStatus=True) self.assertFalse(a.accidental.displayStatus) b = copy.deepcopy(a) self.assertFalse(b.accidental.displayStatus) self.assertEqual(b.accidental.name, 'natural')
def main(): parser = get_cmd_line_parser(description=__doc__) ParserArguments.filename(parser) ParserArguments.tempo(parser) ParserArguments.framerate(parser) ParserArguments.set_defaults(parser) ParserArguments.best(parser) args = parser.parse_args() defaults.framerate = args.framerate song = Stream() roots = 'ABCDEFG' scales = [scale.MajorScale, scale.MinorScale, scale.WholeToneScale, scale.ChromaticScale] print('Choosing a random scale from Major, Minor, Whole Tone, Chromatic.') rscale = random.choice(scales)(Pitch(random.choice(roots))) print('Using: %s' % rscale.name) print('Generating a score...') random_note_count = 50 random_note_speeds = [0.5, 1] print('100 Random 1/8th and 1/4th notes in rapid succession...') for i in range(random_note_count): note = Note(random.choice(rscale.pitches)) note.duration.quarterLength = random.choice(random_note_speeds) song.append(note) scale_practice_count = 4 print('Do the scale up and down a few times... maybe %s' % scale_practice_count) rev = rscale.pitches[:] rev.reverse() updown_scale = rscale.pitches[:] updown_scale.extend(rev[1:-1]) print('updown scale: %s' % updown_scale) for count, pitch in enumerate(cycle(updown_scale)): print(' note %s, %s' % (count, pitch)) song.append(Note(pitch)) if count >= scale_practice_count * len(updown_scale): break print('Composition finished:') song.show('txt') if args.best: print('Audifying the song to file "{}"...') wave = audify_to_file(song, args.tempo, args.filename, verbose=True) else: wave = audify_basic(song, args.tempo, verbose=True) print('Writing Song to file "{}"...'.format(args.filename)) with wav_file_context(args.filename) as fout: fout.write_frames(wave.frames) return 0
def testQuarterToneA(self): p1 = Pitch('D#~') # environLocal.printDebug([p1, p1.accidental]) self.assertEqual(str(p1), 'D#~') # test generation of raw musicxml output xmlOut = m21ToXml.GeneralObjectExporter().parse(p1).decode('utf-8') match = '<step>D</step><alter>1.5</alter><octave>4</octave>' xmlOut = xmlOut.replace(' ', '') xmlOut = xmlOut.replace('\n', '') self.assertNotEqual(xmlOut.find(match), -1) s = stream.Stream() for pStr in ['A~', 'A#~', 'A`', 'A-`']: p = Pitch(pStr) self.assertEqual(str(p), pStr) n = note.Note() n.pitch = p s.append(n) self.assertEqual(len(s), 4) match = [e.pitch.ps for e in s] self.assertEqual(match, [69.5, 70.5, 68.5, 67.5]) s = stream.Stream() alterList = [ None, 0.5, 1.5, -1.5, -0.5, 'half-sharp', 'one-and-a-half-sharp', 'half-flat', 'one-and-a-half-flat', '~' ] sc = scale.MajorScale('c4') for x in range(1, 10): n = note.Note(sc.pitchFromDegree(x % sc.getDegreeMaxUnique())) n.quarterLength = 0.5 n.pitch.accidental = Accidental(alterList[x]) s.append(n) match = [str(n.pitch) for n in s.notes] self.assertEqual(match, [ 'C~4', 'D#~4', 'E-`4', 'F`4', 'G~4', 'A#~4', 'B`4', 'C-`4', 'D~4' ]) match = [e.pitch.ps for e in s] self.assertEqual( match, [60.5, 63.5, 62.5, 64.5, 67.5, 70.5, 70.5, 58.5, 62.5])
def valid_voicing(s): """Verifies a string of 4 space-separated pitches as a valid voicing.""" pitchStrings = s.split() if len(pitchStrings) != 4: msg = "The voicing should have exactly 4 notes" raise argparse.ArgumentTypeError(msg) b, t, a, s = [Pitch(p) for p in pitchStrings] if not b <= t <= a <= s: msg = "The notes of the given voicing should be ordered BTAS" raise argparse.ArgumentTypeError(msg) return tuple(pitchStrings)
def __init__(self): self.names = ['vln', 'gtr'] self.vln = vln = Violin() self.gtr = gtr = AcousticGuitar() self.l = [vln, gtr] self.d = {} for name, inst in zip(self.names, self.l): inst.nickname = name self.d[name] = inst # lowest, highest notes ranges = [ ('G3', 'B6'), # Violin ('E2', 'G5') # Guitar ] for r, i in zip(ranges, self.l): i.lowest_note = Pitch(r[0]) i.highest_note = Pitch(r[1]) i.all_notes = list(frange(i.lowest_note.ps, i.highest_note.ps + 1)) i.all_notes_24 = list( frange(i.lowest_note.ps, i.highest_note.ps + 1, 0.5))
def voiceNote(noteName, pitchRange): """Generates voicings for a note in a given pitch range. Returns a list of `Pitch` objects with the same name as the note that also fall within the voice's range. """ lowerOctave = pitchRange[0].octave upperOctave = pitchRange[1].octave for octave in range(lowerOctave, upperOctave + 1): n = Pitch(noteName + str(octave)) if pitchRange[0] <= n <= pitchRange[1]: yield n
def __init__(self, spotify_figure: str = None, figure: str = None, bass: str = None, root: str = None, kind: str = None, chord: Chord = None): if spotify_figure == 'NC': self.bass = None self.root = None self.chord = Chord() self.structure = 'NC' elif chord: assert root and figure self.bass = Pitch(bass[1:]) if bass else None self.root = Pitch(root) self.chord = chord self.structure = spotify_figure if spotify_figure else figure elif figure: assert root chord_symbol = ChordSymbol(figure=figure) self.chord = Chord(chord_symbol.pitches) self.bass = Pitch(bass[1:]) if bass else None if self.bass: self.bass.octave = None self.root = Pitch(root) self.root.octave = None self.structure = figure else: assert root and kind chord_symbol = ChordSymbol(bass=bass, root=root, kind=kind) self.chord = Chord(chord_symbol.pitches) self.bass = Pitch(bass) if bass else None if self.bass: self.bass.octave = None self.root = Pitch(root) self.root.octave = None self.structure = chord_symbol.figure
def testUpdateAccidentalDisplaySeries(self): '''Test updating accidental display. ''' def proc(_pList, past): for p in _pList: p.updateAccidentalDisplay(pitchPast=past) past.append(p) def compare(past, _result): # environLocal.printDebug(['accidental compare']) for i in range(len(_result)): p = past[i] if p.accidental is None: pName = None pDisplayStatus = None else: pName = p.accidental.name pDisplayStatus = p.accidental.displayStatus targetName = _result[i][0] targetDisplayStatus = _result[i][1] self.assertEqual( pName, targetName, f'name error for {i}: {pName} instead of desired {targetName}' ) self.assertEqual( pDisplayStatus, targetDisplayStatus, f'{i}: {p} display: {pDisplayStatus}, target {targetDisplayStatus}' ) # alternating, in a sequence, same pitch space pList = [ Pitch('a#3'), Pitch('a3'), Pitch('a#3'), Pitch('a3'), Pitch('a#3') ] result = [('sharp', True), ('natural', True), ('sharp', True), ('natural', True), ('sharp', True)] proc(pList, []) compare(pList, result) # alternating, in a sequence, different pitch space pList = [ Pitch('a#2'), Pitch('a6'), Pitch('a#1'), Pitch('a5'), Pitch('a#3') ] result = [('sharp', True), ('natural', True), ('sharp', True), ('natural', True), ('sharp', True)] proc(pList, []) compare(pList, result) # alternating, after gaps pList = [ Pitch('a-2'), Pitch('g3'), Pitch('a5'), Pitch('a#5'), Pitch('g-3'), Pitch('a3') ] result = [('flat', True), (None, None), ('natural', True), ('sharp', True), ('flat', True), ('natural', True)] proc(pList, []) compare(pList, result) # repeats of the same: show at different registers pList = [ Pitch('a-2'), Pitch('a-2'), Pitch('a-5'), Pitch('a#5'), Pitch('a#3'), Pitch('a3'), Pitch('a2') ] result = [('flat', True), ('flat', False), ('flat', True), ('sharp', True), ('sharp', True), ('natural', True), ('natural', True)] proc(pList, []) compare(pList, result) # the always- 'unless-repeated' setting # first, with no modification, repeated accidentals are not shown pList = [Pitch('a-2'), Pitch('a#3'), Pitch('a#5')] result = [('flat', True), ('sharp', True), ('sharp', True)] proc(pList, []) compare(pList, result) # second, with status set to always pList = [Pitch('a-2'), Pitch('a#3'), Pitch('a#3')] pList[2].accidental.displayType = 'always' result = [('flat', True), ('sharp', True), ('sharp', True)] proc(pList, []) compare(pList, result) # status set to always pList = [Pitch('a2'), Pitch('a3'), Pitch('a5')] pList[2].accidental = Accidental('natural') pList[2].accidental.displayType = 'always' result = [(None, None), (None, None), ('natural', True)] proc(pList, []) compare(pList, result) # first use after other pitches in different register # note: this will force the display of the accidental pList = [Pitch('a-2'), Pitch('g3'), Pitch('a-5')] result = [('flat', True), (None, None), ('flat', True)] proc(pList, []) compare(pList, result) # first use after other pitches in different register # note: this will force the display of the accidental pList = [Pitch('a-2'), Pitch('g3'), Pitch('a-2')] # pairs of accidental, displayStatus result = [('flat', True), (None, None), ('flat', True)] proc(pList, []) compare(pList, result) # accidentals, first usage, not first pitch pList = [Pitch('a2'), Pitch('g#3'), Pitch('d-2')] result = [(None, None), ('sharp', True), ('flat', True)] proc(pList, []) compare(pList, result)
def midi_to_name(midi): return Pitch(midi).nameWithOctave
def freq_to_midi(freq): base_pitch = Pitch() current_interval = Interval( integer_interval_from(freq, base_pitch.frequency)) return base_pitch.transpose(current_interval).midi
def get_mapping(samples, starting_point): if isinstance(starting_point, str): starting_point = Pitch(starting_point).midi mapping = {s: i + starting_point for i, s in enumerate(samples)} mapping[' '] = 0 return mapping
Rule.SEVENTH_UNPREPARED: Cost.BAD, Rule.SEVENTH_UNRESOLVED: Cost.VERYBAD, Rule.LEADINGTONE_UNRESOLVED: Cost.VERYBAD, # voicing rules Rule.VERTICAL_NOT_DOUBLINGROOT: Cost.NOTIDEAL, Rule.VERTICAL_SEVENTH_MISSINGNOTE: Cost.MAYBEBAD, } def applyRule(rule): """Given a rule enum, provide the cost of breaking that rule.""" return _ruleCostMapping[rule] voice_ranges = { PartEnum.SOPRANO: (Pitch("C4"), Pitch("G5")), PartEnum.ALTO: (Pitch("G3"), Pitch("D5")), PartEnum.TENOR: (Pitch("C3"), Pitch("G4")), PartEnum.BASS: (Pitch("E2"), Pitch("C4")), } verticalHorizontalMapping = { IntervalV.ALTO_SOPRANO: (PartEnum.SOPRANO, PartEnum.ALTO), IntervalV.TENOR_SOPRANO: (PartEnum.TENOR, PartEnum.SOPRANO), IntervalV.TENOR_ALTO: (PartEnum.TENOR, PartEnum.ALTO), IntervalV.BASS_SOPRANO: (PartEnum.BASS, PartEnum.SOPRANO), IntervalV.BASS_ALTO: (PartEnum.BASS, PartEnum.ALTO), IntervalV.BASS_TENOR: (PartEnum.BASS, PartEnum.TENOR), }
def tensors_to_stream(outputs, config, metadata=None): cur_measure_number = 0 parts = {} for part_name in outputs.keys(): if part_name == 'extra': continue part = Part(id=part_name) parts[part_name] = part last_time_signature = None cur_time_signature = '4/4' for step in range(outputs['soprano'].shape[0]): extra = outputs['extra'][step] if extra[indices_extra['has_time_signature_3/4']].item() == 1: cur_time_signature = '3/4' elif extra[indices_extra['has_time_signature_4/4']].item() == 1: cur_time_signature = '4/4' elif extra[indices_extra['has_time_signature_3/2']].item() == 1: cur_time_signature = '3/2' cur_time_pos = extra[indices_extra['time_pos']].item() has_fermata = extra[indices_extra['has_fermata']].item() == 1 if cur_time_pos == 1.0 or cur_measure_number == 0: for part_name, part in parts.items(): part.append(Measure(number=cur_measure_number)) if cur_measure_number == 0: if part_name in ['soprano', 'alto']: part[-1].append(clef.TrebleClef()) else: part[-1].append(clef.BassClef()) key = int( torch.argmax( outputs['extra'][0, indices_extra['has_sharps_0']: indices_extra['has_sharps_11'] + 1], dim=0).item()) if key >= 6: key -= 12 part[-1].append(KeySignature(key)) part[-1].append(MetronomeMark(number=90)) cur_measure_number += 1 if last_time_signature is None or cur_time_signature != last_time_signature: for part in parts.values(): part[-1].append(TimeSignature(cur_time_signature)) last_time_signature = cur_time_signature for part_name, part in parts.items(): idx = torch.argmax(outputs[part_name][step]).item() if idx == indices_parts['is_continued']: try: last_element = part[-1].flat.notesAndRests[-1] cur_element = deepcopy(last_element) if last_element.tie is not None and last_element.tie.type == 'stop': last_element.tie = Tie('continue') else: last_element.tie = Tie('start') cur_element.tie = Tie('stop') except IndexError: logging.debug( 'Warning: "is_continued" on first beat. Replaced by rest.' ) cur_element = Rest(quarterLength=config.time_grid) part[-1].append(cur_element) elif idx == indices_parts['is_rest']: part[-1].append(Rest(quarterLength=config.time_grid)) else: pitch = Pitch() part[-1].append(Note(pitch, quarterLength=config.time_grid)) # Set pitch value AFTER appending to measure in order to avoid unnecessary accidentals pitch.midi = idx + min_pitches[part_name] - len(indices_parts) if has_fermata: for part in parts.values(): fermata = Fermata() fermata.type = 'upright' part[-1][-1].expressions.append(fermata) score = Score() if metadata is not None: score.append(Metadata()) score.metadata.title = f"{metadata.title} ({metadata.number})" score.metadata.composer = f"Melody: {metadata.composer}\nArrangement: BachNet ({datetime.now().year})" for part in parts.values(): part[-1].rightBarline = 'light-heavy' score.append(parts['soprano']) if 'alto' in parts: score.append(parts['alto']) score.append(parts['tenor']) score.append(parts['bass']) score.stripTies(inPlace=True, retainContainers=True) return score
def main1(): all_pitches = MajorScale(tonic="C").getPitches("C1", "C8") pitch2index = {p: ix for ix, p in enumerate(all_pitches)} C2 = Pitch("C2") C3 = Pitch("C3") C4 = Pitch("C4") C5 = Pitch("C5") C6 = Pitch("C6") def get_next_triplets(triplet: Triplet) -> Set[Triplet]: next_triplets = set() for i, pitch in enumerate(triplet.pitches): # TODO: improve construct_graph to accept negative values here for diff in [1]: # TODO: make this a utility function moved_pitch = all_pitches[pitch2index[pitch] + diff] if moved_pitch in triplet.pitches: continue next_pitches = tuple( p if i != j else moved_pitch for j, p in enumerate(triplet.pitches) ) if ( not C2 <= next_pitches[0] <= C4 or not C3 <= next_pitches[1] <= C5 or not C4 <= next_pitches[2] <= C6 ): continue next_triplets.add(Triplet(next_pitches)) return next_triplets init_pitches = (Pitch("C2"), Pitch("C3"), Pitch("C4")) init_triplet = Triplet(init_pitches) _, edges = construct_graph(init_triplet, get_next_triplets, 48) G = nx.DiGraph() G.add_edges_from(edges) plot_hierarchical_graph(G) # blocking progression = [] chord = init_triplet while chord: progression.append(chord) successors = list(G.successors(chord)) if successors: chord = successors[len(successors) // 2] else: chord = None print(progression) sounds, _ = midi.initialize() _ = query_sound(sounds, Section.STRINGS, Instrument.BASSES, Articulation.SPICCATO) celli = query_sound( sounds, Section.STRINGS, Instrument.CELLI, Articulation.SPICCATO ) violas = query_sound( sounds, Section.STRINGS, Instrument.VIOLAS, Articulation.SPICCATO ) violins = query_sound( sounds, Section.STRINGS, Instrument.VIOLINS_1, Articulation.SPICCATO ) _ = query_sound(sounds, Section.BRASS, Instrument.TUBA, Articulation.STACCATISSIMO) trombones = query_sound( sounds, Section.BRASS, Instrument.TENOR_TROMBONES_A3, Articulation.STACCATISSIMO ) trumpets = query_sound( sounds, Section.BRASS, Instrument.TRUMPETS_A3, Articulation.STACCATISSIMO ) horns = query_sound( sounds, Section.BRASS, Instrument.HORNS_A4, Articulation.STACCATISSIMO ) strings = (celli, violas, violins) brass = (trombones, trumpets, horns) dt = 0.175 dur = 0.125 p = Player() for measure, triplet in enumerate(progression): for beat in range(4): for note, snd in zip(triplet.pitches, strings): p.schedule(snd, Pitch(note).midi, (beat + measure * 4) * dt, dur, 100) for note, snd in zip(triplet.pitches, brass): p.schedule(snd, Pitch(note).midi, measure * 4 * dt, dur * 2, 100) p.schedule(snd, Pitch(note).midi, (measure * 4 + 3.25) * dt, dur * 0.5, 100) p.play()
import copy import argparse import itertools from fractions import Fraction from music21.note import Note from music21.pitch import Pitch from music21.chord import Chord from music21.roman import RomanNumeral from music21.key import Key from music21.meter import TimeSignature from music21.clef import BassClef, TrebleClef from music21.instrument import Piano from music21.stream import Part, Score, Voice SOPRANO_RANGE = (Pitch("C4"), Pitch("G5")) ALTO_RANGE = (Pitch("G3"), Pitch("C5")) TENOR_RANGE = (Pitch("C3"), Pitch("G4")) BASS_RANGE = (Pitch("E2"), Pitch("C4")) def voiceNote(noteName, pitchRange): """Generates voicings for a note in a given pitch range. Returns a list of `Pitch` objects with the same name as the note that also fall within the voice's range. """ lowerOctave = pitchRange[0].octave upperOctave = pitchRange[1].octave for octave in range(lowerOctave, upperOctave + 1): n = Pitch(noteName + str(octave))
def __post_init__(self): self.low_no = Pitch(self.low).midi self.high_no = Pitch(self.high).midi
def getPitchFromString(p): """Cached method. Calls music21.pitch.Pitch().""" cachedGetPitchFromString.append(p) return Pitch(p)
from music21.instrument import fromString as get_instrument from music21.clef import BassClef timestamp = datetime.datetime.utcnow() metadata = Metadata() metadata.title = 'The Title' metadata.composer = 'Jonathan Marmor' metadata.date = timestamp.strftime('%Y/%m/%d') score = Score() score.insert(0, metadata) part = Part() parts = [part] oboe = get_instrument('oboe') part.insert(0, oboe) score.insert(0, part) score.insert(0, StaffGroup(parts)) for dur in [[1, .5], [.25], [.25, 2]]: pitch = Pitch(60) note = Note(pitch) duration = Duration() duration.fill(dur) note.duration = duration part.append(note) score.show('musicxml', '/Applications/Sibelius 7.5.app')