예제 #1
0
def _sumtone_find_source(pitch,
                         maxdist=0.5,
                         intervals: List[U[int, float]] = None,
                         minnote: pitch_t = 'A0',
                         maxnote: pitch_t = 'C8',
                         difftonegap=0.):
    """
    pitch: a note str or a midinote
    maxdist: the max. distance between the given note and #
                 the produced sumtone
    intervals: allowed intervals for the source pitches
    minnote, maxnote: the range to look for sumtones

    Returns: a list of pairs (note1:str, note2:str) representing
             notes which produce
             the given pitch as a sumtone
             (or an empty list if no pairs are found)
    """
    intervals = intervals or [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    m0 = asmidi(pitch)
    midimin = int(n2m(minnote)) if isinstance(minnote, str) else int(minnote)
    midimax = int(n2m(maxnote)) if isinstance(maxnote, str) else int(maxnote)
    minValidFreq = 1
    results = []
    for interval in intervals:
        for midi1 in range(midimin, midimax):
            midi2 = midi1 + interval
            if midi2 > midimax:
                continue
            sumFreq = m2f(midi1) + m2f(midi2)
            if sumFreq <= minValidFreq:
                continue
            diffFreq = abs(m2f(midi1) - m2f(midi2))
            if diffFreq < 20 or (abs(f2m(diffFreq) - f2m(sumFreq)) <
                                 difftonegap):
                continue
            midiError = abs(f2m(sumFreq) - m0)
            if midiError <= maxdist:
                results.append((midiError, (midi1, midi2)))
    if not results:
        return []
    results.sort()  # secondary sort by minimal difference
    pairs = list(set(midipair for diff, midipair in results))
    pairs.sort()  # primary sort by pitch
    out = [(m2n(m1), m2n(m2)) for m1, m2 in pairs]
    assert all(isinstance(n0, str) and isinstance(n1, str) for n0, n1 in out)
    return out
예제 #2
0
    def sound2harmonic(self, note, kind='all', tolerance=0.5):
        """
        find the harmonics in this string which can produce the given sound as result.

        note: the note to produce (a string note)
        kind: kind of harmonic. One of [4, 3M, 3m, natural, all]
        tolerance: the acceptable difference between the desired note and the result
                   (in semitones)
        """
        midinote = n2m(note)
        if kind == '4' or kind == 4:
            f0 = midinote - 24
            out = self.sound2note(m2n(f0))
        elif kind == '3M' or kind == 3:
            f0 = midinote - 28
            out = self.sound2note(m2n(f0))
        elif kind == '3m':
            f0 = midinote - 31
            out = self.sound2note(m2n(f0))
        elif kind in ('n', 'natural'):
            fundamental = m2f(self._sounding_midi)
            harmonics = [f2m(fundamental * harmonic) for harmonic in range(12)]
            acceptable_harmonics = []
            for harmonic in harmonics:
                if abs(harmonic - midinote) <= tolerance:
                    acceptable_harmonics.append(harmonic)
            if len(acceptable_harmonics) > 0:
                # now find the position of the node in the string
                results = []
                nodes = []
                for harmonic in acceptable_harmonics:
                    fret = self._flageolet_string.ratio2fret(
                        m2f(harmonic) / fundamental)
                    nodes.append(fret)
                for node in nodes:
                    for fret_pos in node.frets_pos:
                        results.append(fret_pos[1])  # we only append the pitch
                out = [self.sound2note(result) for result in results]
            else:
                out = None
        elif kind == 'all':
            out = []
            for kind in ('4 3M 3m n'.split()):
                out.append(
                    self.sound2harmonic(note, kind=kind, tolerance=tolerance))
            return out
        return kind, out
예제 #3
0
def makePitch(pitch: pitch_t, divsPerSemitone:int=4) -> str:
    if isinstance(pitch, (int, float)):
        notename = pt.m2n(pitch)
    elif isinstance(pitch, str):
        notename = pitch
    else:
        raise TypeError(f"Expected a midinote or a notename, got {pitch} (type: {type(pitch)})")
    return notenameToLily(notename, divsPerSemitone=divsPerSemitone)
예제 #4
0
 def sound2note(self, note, strings=None):
     if strings is None:
         strings = (self.i, self.ii, self.iii, self.iv)
     notes = note.split()
     if len(notes) > 1:
         midinotes = [n2m(n) for n in notes]
         midinotes.sort(reverse=True)
         notes = [m2n(m) for m in midinotes]
         lines = []
         for strings in _window((self.i, self.ii, self.iii, self.iv),
                                len(notes)):
             for string, note in zip(strings, notes):
                 lines.append(self.sound2note(note, [string]))
             lines.append('\n')
         return ''.join(lines)
     else:
         lines = []
         for string in strings:
             out = string.sound2note(note)
             if out:
                 lines.append("%s --> %s\n" % (string._name, out))
         return ''.join(lines)
예제 #5
0
 def sound2note(self, note):
     midinote = n2m(note)
     dx = midinote - self._sounding_midi
     if dx >= 0:
         written = self._written_midi + dx
         return m2n(written)
예제 #6
0
 def note2sound(self, note):
     midinote = n2m(note)
     dx = midinote - self._written_midi
     if dx >= 0:
         sounding = self._sounding_midi + dx
         return m2n(sounding)
예제 #7
0
def normalize_note(note):
    return m2n(n2m(note))