예제 #1
0
def pianofreqs(start='A0', stop='C8') -> np.ndarray:
    """
    Generate an array of the frequencies representing all the piano keys
    """
    n0 = int(n2m(start))
    n1 = int(n2m(stop)) + 1
    return m2f_np(np.arange(n0, n1, 1))
예제 #2
0
 def __init__(self, name='IV', written='3G', sounding='3C'):
     self._name = name
     self._written = written
     self._sounding = sounding
     self._written_midi = n2m(written)
     self._sounding_midi = n2m(sounding)
     self._flageolet_string = InstrumentString(self._sounding)
예제 #3
0
def asmidi(x) -> float:
    if isinstance(x, float):
        assert 0<=x<=128
        return x
    elif isinstance(x, str):
        return n2m(x)
    elif isinstance(x, int):
        assert 0 <= x < 128
        return float(x)
    elif hasattr(x, "pitch"):
        return x.pitch
    raise TypeError(f"Cannot interpret {x} as a midinote")
예제 #4
0
def asmidi(x: pitch_t) -> float:
    """
    Converts a notename to a midinote.
    """
    if isinstance(x, (int, float)):
        if x > 127:
            raise ValueError(
                "A midinote expected (< 128), but got a value of {x}!")
        return x
    elif isinstance(x, str):
        return n2m(x)
    try:
        return float(x)
    except TypeError:
        raise TypeError(f"could not convert {x} to a midi note")
예제 #5
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
예제 #6
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)
예제 #7
0
def piano_freqs(start='A0', stop='C8') -> numpy.ndarray:
    """
    generate an array of the frequencies representing all the piano keys
    """
    keys = range(int(n2m(start)), int(n2m(stop))+1)
    return numpy.fromiter((m2f(key) for key in keys), dtype=numpy.float64)
예제 #8
0
def regions_from_files(files,
                       key='auto',
                       offset='auto',
                       fillkeys=True,
                       relpath=True,
                       minkey=36,
                       skipbadestimations=True,
                       printregions=True,
                       offset_thresh=-55):
    """
    files: a list of soundfiles
    key: 'auto': read the file and determine the main pitch
         a function: it is called with the path, it returns a midinote
         an integer or string: the first note of the region, 
         all other samples are assigned chormatically
         a list of integers or strings: each file is assigned a specific key
    """
    if key == 'auto' and offset == 'auto':
        freqs_and_offsets = [
            estimate_freq_and_offset(f, minamp=offset_thresh) for f in files
        ]
        keys = [int(f2m(freq) + 0.5) for freq, _ in freqs_and_offsets]
        offsets = [o for f, o in freqs_and_offsets]
    elif key == 'auto':
        keys = [int(f2m(estimate_freq(f)) + 0.5) for f in files]
        offsets = [offset] * len(keys)
    elif offset == 'auto':
        keys = list(map(key, files))
        offsets = [estimate_offset(f) for f in files]
    else:
        if isinstance(key, int):
            keys = list(range(key, key + len(files)))
        elif isinstance(key, str):
            key = n2m(key)
            keys = list(range(key, key + len(files)))
        elif isinstance(key, collections.Callable):
            keys = list(map(key, files))
        else:
            keys = key
            assert len(keys) == len(files)
        offsets = [offset] * len(keys)
    if relpath:
        samples = [os.path.split(f)[1] for f in files]
    else:
        samples = files
    i = 0
    for f, key in zip(files, keys):
        if key < minkey:
            print("error in the frequency estimation: key of %s out of range"
                  "Trying another strategy" % f)
            key2 = int(estimate_freq(f, strategy='fft') + 0.5)
            if key2 < minkey:
                print("    no luck...")
                if not skipbadestimations:
                    raise RuntimeError(
                        "could not estimate the frequency of %s, aborting" % f)
                else:
                    print("estimation failed, skipping...")
                    key2 = -1
            if key2 >= minkey:
                keys[i] = key2
        i += 1
    rows = sorted(zip(samples, keys, offsets),
                  key=lambda sample_key_offset: sample_key_offset[1])
    regions = []
    if not fillkeys:
        raise ValueError("XXX fix this")
        # for sample, key, offset in samples_and_keys:
        #     regions.append("<region> sample=%s key=%d offset=%d" %
        #                    (sample, key, offset))
    else:
        samples, keys, offsets = list(zip(*rows))
        from .iterlib import pairwise
        avgs = [int((key1 + key0) / 2. + 0.5) for key0, key1 in pairwise(keys)]
        lokeys = [keys[0] - (avgs[0] - keys[0])] + avgs
        centers = keys
        hikeys = avgs + [keys[-1] + (keys[-1] - avgs[-1])]
        hikeys = [max(center, k - 1) for k, center in zip(hikeys, centers)]
        for sample, offset, center, lokey, hikey in zip(
                samples, offsets, centers, lokeys, hikeys):
            assert lokey <= center <= hikey
            if offset is None:
                offset = 0
            region = ("<region> sample=%s offset=%d pitch_keycenter=%d "
                      "lokey=%d hikey=%d" %
                      (sample, offset, center, lokey, hikey))
            regions.append(region)
    if printregions:
        print("\n".join(regions))
    return regions
예제 #9
0
 def sound2note(self, note):
     midinote = n2m(note)
     dx = midinote - self._sounding_midi
     if dx >= 0:
         written = self._written_midi + dx
         return m2n(written)
예제 #10
0
 def note2sound(self, note):
     midinote = n2m(note)
     dx = midinote - self._written_midi
     if dx >= 0:
         sounding = self._sounding_midi + dx
         return m2n(sounding)
예제 #11
0
def normalize_note(note):
    return m2n(n2m(note))