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
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
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)
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)
def sound2note(self, note): midinote = n2m(note) dx = midinote - self._sounding_midi if dx >= 0: written = self._written_midi + dx return m2n(written)
def note2sound(self, note): midinote = n2m(note) dx = midinote - self._written_midi if dx >= 0: sounding = self._sounding_midi + dx return m2n(sounding)
def normalize_note(note): return m2n(n2m(note))