Example #1
0
def verifyCounterpointVerbose(melody1: stream.Stream,
                              melody2: stream.Stream) -> bool:

    rval = True

    melody1 = melody1.flat.notes
    melody2 = melody2.flat.notes
    final = melody1[-1]

    if melody1.duration != melody2.duration:
        print("Durations do not match up")
        return False

    if melody2.flat.notes[-1].pitch.pitchClass != final.pitch.pitchClass:
        print("Don't end on same note:", melody1[-1], melody2[-1])
        rval = False

    if not (melody2[0].pitch.pitchClass == final.pitch.pitchClass
            or interval.pitch.Interval(melody2[0], final).name == 'P5'):
        print(
            "Melody 2 starts on {}, not on the final or a P5 to the final {}.",
            melody2[0].name, final)
        rval = False

    badVerticalIntervalList = []
    badHorIntM1 = []
    badHorIntM2 = []
    for i in range(len(melody1)):
        #check that all the intervals are okay
        if Interval(melody1[i],
                    melody2[i]).name not in allowedVerticalIntervals:
            badVerticalIntervalList.append(
                (i + 1, Interval(melody1[i], melody2[i])))
            rval = False

        if i != 0 and Interval(
                melody2[i - 1],
                melody2[i]).name not in allowedHorizontalIntervals:
            badHorIntM2.append((i - 1, i, Interval(melody2[i - 1],
                                                   melody2[i])))

    if not len(badVerticalIntervalList) == 0:
        print("Bad vertical intervals:")
    for v in badVerticalIntervalList:
        print(v)

    if not len(badHorIntM2) == 0:
        print("Bad vertical intervals:")
    for v in badHorIntM1:
        print(v)

    return rval
Example #2
0
def add_step_information(notes, keySignatures):
  """
  This function will populate the step information into Mupix note objects, it
  is required because music21 will not keep key signature information in
  measure other than the measure the key is defined in when reading musicXML.
  The maintainers of music21 don't believe this is an issue and won't fix it,
  so this and others must exist.

  :param [notes]: A list of Mupix NoteObjects.
  :type [notes]: List

  :param [keySignatures]: A list of Mupix KeySignatureObjects.
  :type [keySignatures]: List

  :return [List]: The original list of Mupix NoteObjects (in order) with step information included.
  :rtype: List
  """
  for key in keySignatures:
    key_name = key.step.upper() if key.mode == "major" else key.step.lower()

    for note in notes:
      if note.part == key.part and note.measure == key.measure:
        note.step = Interval(noteStart=Note(Key(key_name).asKey().tonic), noteEnd=note._music21_object).semitones % 12

  return notes
Example #3
0
def calculate_ambitus(item):
    """
    Calculate the ambitus of a phrase, monomodal section, piece, etc.

    Parameters
    ----------
    item
        The item for which to calculate the ambitus. This can be of
        any type, but it must have the attributes `lowest_note` and
        `note_of_final` defined.
    """
    if item.note_of_final is None:
        return AmbitusType.UNDEFINED

    interval = Interval(item.note_of_final, item.lowest_note)
    if 0 >= interval.semitones >= -4:
        return AmbitusType.AUTHENTIC
    elif -5 >= interval.semitones > -12:
        return AmbitusType.PLAGAL
    elif interval.semitones == -12:
        # TODO: which ambitus should this have?
        return AmbitusType.PLAGAL
    else:
        raise Exception(  # pragma: no cover
            "Check the logic in the ambitus calculation! "
            "We expect the lowest note to be less than an octave "
            "below the main final.")
Example #4
0
def split_voices(lead, current):
    """
    Given two sequential notes, if the lead note contains more voices than current, then duplicate
    the notes in current to match lead, producing continuous voice lines
        :param lead: Leading note
        :param current: Current node
    """
    num_lead = get_number_of_voices(lead)
    num_current = get_number_of_voices(current)
    if current.isNote:
        return [
            Note(current.pitch, quarterLength=current.duration.quarterLength)
            for i in range(num_lead)
        ]
    if num_lead == num_current:
        return [
            Note(pitch, quarterLength=current.duration.quarterLength)
            for pitch in current.pitches
        ]
    if current.isChord and len(current.pitches) == 0:
        raise RuntimeError(
            "The system was able to parse the file, but detected an illegal construct: empty chord"
        )
    middle = map(itemgetter(0), [
        sorted([(c, abs(Interval(e, c).cents)) for c in current.pitches],
               key=itemgetter(1))[0] for e in lead.pitches[1:-1]
    ])
    return [
        Note(pitch, quarterLength=current.duration.quarterLength)
        for pitch in chain(current.pitches[0:1], middle, current.pitches[-1:])
    ]
Example #5
0
def png_to_smart_track(png_file_name: str,
                       track_name: str,
                       track_duration: int,
                       threshold: int = 0) -> SmartTrack:
    res = SmartTrack(name=track_name, duration=track_duration)
    arr = Converter.png_to_array(png_file_name)
    d, m = divmod(track_duration, len(arr[0]))
    if m is not 0:
        raise ValueError(
            f'target track duration {track_duration} is not a multiple of png file width {len(arr[0])}')
    for pitch, row in enumerate(arr):
        seq = SmartSequence(duration=track_duration)
        crt_interval = None
        for i, v in enumerate(row):
            if v <= threshold:
                if crt_interval:
                    crt_interval.end += d
                else:
                    crt_interval = Interval(start=d * i, end=d * (i + 1))
            else:
                if crt_interval:
                    seq.append(crt_interval)
                    crt_interval = None
        if crt_interval:
            seq.append(crt_interval)
        res.put_sequence(pitch, seq)
    return res
Example #6
0
def get_ambitus(*, note_of_final, lowest_note):
    if note_of_final is None:
        return AmbitusType.UNDEFINED

    interval = Interval(note_of_final, lowest_note)
    if 0 >= interval.semitones >= -4:
        return AmbitusType.AUTHENTIC
    elif -5 >= interval.semitones > -12:
        return AmbitusType.PLAGAL
    else:
        raise Exception(  # pragma: no cover
            "Check the logic in the ambitus calculation! "
            "We expect the lowest note to be less than an octave "
            "below the main final.")
Example #7
0
def get_contour(note1, note2):
    if note1.isRest and note2.isRest:
        return 's'
    elif note1.isRest and not note2.isRest:
        return 'u'
    elif not note1.isRest and note2.isRest:
        return 'd'
    else:
        interval = Interval(note1, note2)
        cents = interval.cents
        if cents == 0:
            return 's'
        if cents > 0:
            return 'u'
        return 'd'
Example #8
0
def generateMelody(cf: stream.Stream):
    cflist = list(cf.flat.notes)
    posslist = []
    for note in cflist:
        newlist = []
        for intstr in allowedVerticalIntervals:
            next = note.transpose(Interval(intstr))
            #only attach pitches in the mode
            pitches = music21.scale.Scale.extractPitchList(
                music21.key.Key("C", "major").getScale())
            if next.pitch.pitchClass in [p.pitchClass for p in pitches]:
                newlist.append(next)
        posslist.append(newlist)

    return posslist
Example #9
0
 def __init__(self, note1, note2):
     assert isinstance(note1, Note)
     assert isinstance(note2, Note)
     self.note1 = note1
     self.note2 = note2
     self.interval = Interval(self.note1, self.note2)
     self.pc1 = self.note1.name
     self.pc2 = self.note2.name
     self.semitones = abs(self.interval.semitones)
     self.direction = self.interval.direction
     if self.direction == Direction.ASCENDING:
         self.bottom_pc = self.pc1
         self.top_pc = self.pc2
     else:
         self.bottom_pc = self.pc2
         self.top_pc = self.pc1
Example #10
0
def transposeKeys(keys, newTonic):
    """Transpose a list of keys relative to a new tonic."""
    referenceKey = Key(keys[0])
    newTonicKey = Key(newTonic, mode=referenceKey.mode)
    intervalDiff = Interval(referenceKey.tonic, newTonicKey.tonic)
    transposedKeys = [newTonicKey.tonicPitchNameWithCase]
    for k in keys[1:]:
        localKey = Key(k)
        newLocalTonic = localKey.tonic.transpose(intervalDiff)
        newLocalKey = Key(newLocalTonic, mode=localKey.mode)
        if abs(newLocalKey.sharps) >= 7:
            newLocalKey = Key(newLocalTonic.getEnharmonic(),
                              mode=localKey.mode)
        transposedKeys.append(newLocalKey.tonicPitchNameWithCase)
    transposedKeys = [k.replace("-", "b") for k in transposedKeys]
    return transposedKeys
Example #11
0
def has_framing_interval(notes, interval_name):
    return Interval(notes[0], notes[-1]).name == interval_name
Example #12
0
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 chord_transpose(chord, transposition):
    new_scs = chord.transposed_by(Interval(transposition))
    return new_scs
Example #14
0
def get_interval(note1, note2):
    if note1.isRest or note2.isRest:
        return 'rest'
    return str(Interval(note1, note2).cents)
def _get_transposed_pitch(pitch, interv):
    return pitch.transpose(Interval(interv), inPlace=False)
Example #16
0
    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),
}


perfectUnison = Interval("P1")

cachedGetChordFromPitches = []
cachedGetKeyFromString = []
cachedGetPitchFromString = []
cachedGetLeadingTone = []
cachedGetVerticalIntervalsFromPitches = []
cachedGetInterval = []
cachedIsTriad = []
cachedVoiceChord = []
cachedProgressionCost = []
cachedChordCost = []


@lru_cache(maxsize=None)
def getChordFromPitches(pitches):
Example #17
0
def getInterval(p1, p2):
    """Cached method. Calls music21.interval.Interval()."""
    cachedGetInterval.append((p1, p2))
    pitch1 = getPitchFromString(p1)
    pitch2 = getPitchFromString(p2)
    return Interval(noteStart=pitch1, noteEnd=pitch2)
Example #18
0
def transpose_to_c_tonic(score):
    tonic = score.analyze('key').tonic
    transpos_interval = Interval(tonic, Pitch('C'))

    score.transpose(transpos_interval, inPlace=True)