Changeset 088760e for python/lib


Ignore:
Timestamp:
Oct 31, 2018, 10:26:52 PM (6 years ago)
Author:
Paul Brossier <piem@piem.org>
Branches:
feature/constantq
Children:
c03d191
Parents:
45c2c5c (diff), 7a54b37 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into feature/constantq

Location:
python/lib
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • python/lib/aubio/__init__.py

    r45c2c5c r088760e  
    11#! /usr/bin/env python
     2# -*- coding: utf8 -*-
     3
     4"""
     5aubio
     6=====
     7
     8Provides a number of classes and functions for music and audio signal
     9analysis.
     10
     11How to use the documentation
     12----------------------------
     13
     14Documentation of the python module is available as docstrings provided
     15within the code, and a reference guide available online from `the
     16aubio homepage <https://aubio.org/documentation>`_.
     17
     18The docstrings examples are written assuming `aubio` and `numpy` have been
     19imported with:
     20
     21>>> import aubio
     22>>> import numpy as np
     23"""
    224
    325import numpy
     
    931
    1032class fvec(numpy.ndarray):
    11     """a numpy vector holding audio samples"""
     33    """fvec(input_arg=1024)
     34    A vector holding float samples.
    1235
    13     def __new__(cls, input_arg=1024, **kwargs):
     36    If `input_arg` is an `int`, a 1-dimensional vector of length `input_arg`
     37    will be created and filled with zeros. Otherwise, if `input_arg` is an
     38    `array_like` object, it will be converted to a 1-dimensional vector of
     39    type :data:`float_type`.
     40
     41    Parameters
     42    ----------
     43    input_arg : `int` or `array_like`
     44        Can be a positive integer, or any object that can be converted to
     45        a numpy array with :func:`numpy.array`.
     46
     47    Examples
     48    --------
     49    >>> aubio.fvec(10)
     50    array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)
     51    >>> aubio.fvec([0,1,2])
     52    array([0., 1., 2.], dtype=float32)
     53    >>> a = np.arange(10); type(a), type(aubio.fvec(a))
     54    (<class 'numpy.ndarray'>, <class 'numpy.ndarray'>)
     55    >>> a.dtype, aubio.fvec(a).dtype
     56    (dtype('int64'), dtype('float32'))
     57
     58    Notes
     59    -----
     60
     61    In the Python world, `fvec` is simply a subclass of
     62    :class:`numpy.ndarray`. In practice, any 1-dimensional `numpy.ndarray` of
     63    `dtype` :data:`float_type` may be passed to methods accepting
     64    `fvec` as parameter. For instance, `sink()` or `pvoc()`.
     65
     66    See Also
     67    --------
     68    cvec : a container holding spectral data
     69    numpy.ndarray : parent class of :class:`fvec`
     70    numpy.zeros : create a numpy array filled with zeros
     71    numpy.array : create a numpy array from an existing object
     72    """
     73    def __new__(cls, input_arg=1024):
    1474        if isinstance(input_arg, int):
    1575            if input_arg == 0:
    1676                raise ValueError("vector length of 1 or more expected")
    17             return numpy.zeros(input_arg, dtype=float_type, **kwargs)
     77            return numpy.zeros(input_arg, dtype=float_type, order='C')
    1878        else:
    19             return numpy.array(input_arg, dtype=float_type, **kwargs)
     79            np_input = numpy.array(input_arg, dtype=float_type, order='C')
     80            if len(np_input.shape) != 1:
     81                raise ValueError("input_arg should have shape (n,)")
     82            if np_input.shape[0] == 0:
     83                raise ValueError("vector length of 1 or more expected")
     84            return np_input
  • python/lib/aubio/cmd.py

    r45c2c5c r088760e  
    102102    subparser.add_input()
    103103    subparser.add_buf_hop_size()
     104    subparser.add_silence()
     105    subparser.add_release_drop()
    104106    subparser.add_time_format()
    105107    subparser.add_verbose_help()
     
    138140
    139141def parser_add_subcommand_cut(subparsers):
    140     # quiet subcommand
     142    # cut subcommand
    141143    subparser = subparsers.add_parser('cut',
    142144            help='slice at timestamps')
     
    207209                action="store", dest="silence", default=-70,
    208210                help="silence threshold")
     211
     212    def add_release_drop(self):
     213        self.add_argument("-d", "--release-drop",
     214                metavar = "<value>", type=float,
     215                action="store", dest="release_drop", default=10,
     216                help="release drop threshold")
    209217
    210218    def add_minioi(self, default="12ms"):
     
    248256                action = "store", dest = "cut_until_nslices", default = None,
    249257                help="how many extra slices should be added at the end of each slice")
     258        self.add_argument("--create-first",
     259                action = "store_true", dest = "create_first", default = False,
     260                help="always include first slice")
    250261
    251262# some utilities
     
    380391        self.parse_options(args, self.valid_opts)
    381392        self.notes = aubio.notes(**self.options)
     393        if args.silence is not None:
     394            self.notes.set_silence(args.silence)
     395        if args.release_drop is not None:
     396            self.notes.set_release_drop(args.release_drop)
    382397        super(process_notes, self).__init__(args)
    383398    def __call__(self, block):
     
    500515def main():
    501516    parser = aubio_parser()
    502     args = parser.parse_args()
     517    if sys.version_info[0] != 3:
     518        # on py2, create a dummy ArgumentParser to workaround the
     519        # optional subcommand issue. See https://bugs.python.org/issue9253
     520        # This ensures that:
     521        #  - version string is shown when only '-V' is passed
     522        #  - help is printed if  '-V' is passed with any other argument
     523        #  - any other argument get forwarded to the real parser
     524        parser_root = argparse.ArgumentParser(add_help=False)
     525        parser_root.add_argument('-V', '--version', help="show version",
     526                action="store_true", dest="show_version")
     527        args, extras = parser_root.parse_known_args()
     528        if args.show_version == False: # no -V, forward to parser
     529            args = parser.parse_args(extras, namespace=args)
     530        elif len(extras) != 0: # -V with other arguments, print help
     531            parser.print_help()
     532            sys.exit(1)
     533    else: # in py3, we can simply use parser directly
     534        args = parser.parse_args()
    503535    if 'show_version' in args and args.show_version:
    504536        sys.stdout.write('aubio version ' + aubio.version + '\n')
  • python/lib/aubio/cut.py

    r45c2c5c r088760e  
    102102    s = source(source_uri, samplerate, hopsize)
    103103    if samplerate == 0:
    104         samplerate = s.get_samplerate()
     104        samplerate = s.samplerate
    105105        options.samplerate = samplerate
    106106
     
    151151                timestamps, timestamps_end = timestamps_end,
    152152                output_dir = options.output_directory,
    153                 samplerate = options.samplerate)
     153                samplerate = options.samplerate,
     154                create_first = options.create_first)
    154155
    155156def main():
  • python/lib/aubio/midiconv.py

    r45c2c5c r088760e  
    22""" utilities to convert midi note number to and from note names """
    33
    4 __all__ = ['note2midi', 'midi2note', 'freq2note']
     4__all__ = ['note2midi', 'midi2note', 'freq2note', 'note2freq']
    55
    66import sys
     7from ._aubio import freqtomidi, miditofreq
     8
    79py3 = sys.version_info[0] == 3
    810if py3:
     
    1416
    1517def note2midi(note):
    16     " convert note name to midi note number, e.g. [C-1, G9] -> [0, 127] "
     18    """Convert note name to midi note number.
     19
     20    Input string `note` should be composed of one note root
     21    and one octave, with optionally one modifier in between.
     22
     23    List of valid components:
     24
     25    - note roots: `C`, `D`, `E`, `F`, `G`, `A`, `B`,
     26    - modifiers: `b`, `#`, as well as unicode characters
     27      `𝄫`, `♭`, `♮`, `♯` and `𝄪`,
     28    - octave numbers: `-1` -> `11`.
     29
     30    Parameters
     31    ----------
     32    note : str
     33        note name
     34
     35    Returns
     36    -------
     37    int
     38        corresponding midi note number
     39
     40    Examples
     41    --------
     42    >>> aubio.note2midi('C#4')
     43    61
     44    >>> aubio.note2midi('B♭5')
     45    82
     46
     47    Raises
     48    ------
     49    TypeError
     50        If `note` was not a string.
     51    ValueError
     52        If an error was found while converting `note`.
     53
     54    See Also
     55    --------
     56    midi2note, freqtomidi, miditofreq
     57    """
    1758    _valid_notenames = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11}
    1859    _valid_modifiers = {
     
    2566    _valid_octaves = range(-1, 10)
    2667    if not isinstance(note, str_instances):
    27         raise TypeError("a string is required, got %s (%s)" % (note, str(type(note))))
     68        msg = "a string is required, got {:s} ({:s})"
     69        raise TypeError(msg.format(str(type(note)), repr(note)))
    2870    if len(note) not in range(2, 5):
    29         raise ValueError("string of 2 to 4 characters expected, got %d (%s)" \
    30                          % (len(note), note))
     71        msg = "string of 2 to 4 characters expected, got {:d} ({:s})"
     72        raise ValueError(msg.format(len(note), note))
    3173    notename, modifier, octave = [None]*3
    3274
     
    5294        raise ValueError("%s is not a valid octave" % octave)
    5395
    54     midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]
     96    midi = 12 + octave * 12 + _valid_notenames[notename] \
     97            + _valid_modifiers[modifier]
    5598    if midi > 127:
    5699        raise ValueError("%s is outside of the range C-2 to G8" % note)
     
    58101
    59102def midi2note(midi):
    60     " convert midi note number to note name, e.g. [0, 127] -> [C-1, G9] "
     103    """Convert midi note number to note name.
     104
     105    Parameters
     106    ----------
     107    midi : int [0, 128]
     108        input midi note number
     109
     110    Returns
     111    -------
     112    str
     113        note name
     114
     115    Examples
     116    --------
     117    >>> aubio.midi2note(70)
     118    'A#4'
     119    >>> aubio.midi2note(59)
     120    'B3'
     121
     122    Raises
     123    ------
     124    TypeError
     125        If `midi` was not an integer.
     126    ValueError
     127        If `midi` is out of the range `[0, 128]`.
     128
     129    See Also
     130    --------
     131    note2midi, miditofreq, freqtomidi
     132    """
    61133    if not isinstance(midi, int_instances):
    62134        raise TypeError("an integer is required, got %s" % midi)
    63135    if midi not in range(0, 128):
    64         raise ValueError("an integer between 0 and 127 is excepted, got %d" % midi)
    65     _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
     136        msg = "an integer between 0 and 127 is excepted, got {:d}"
     137        raise ValueError(msg.format(midi))
     138    _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
     139            'A', 'A#', 'B']
    66140    return _valid_notenames[midi % 12] + str(int(midi / 12) - 1)
    67141
    68142def freq2note(freq):
    69     " convert frequency in Hz to nearest note name, e.g. [0, 22050.] -> [C-1, G9] "
    70     from aubio import freqtomidi
    71     return midi2note(int(freqtomidi(freq)))
     143    """Convert frequency in Hz to nearest note name.
     144
     145    Parameters
     146    ----------
     147    freq : float [0, 23000[
     148        input frequency, in Hz
     149
     150    Returns
     151    -------
     152    str
     153        name of the nearest note
     154
     155    Example
     156    -------
     157    >>> aubio.freq2note(440)
     158    'A4'
     159    >>> aubio.freq2note(220.1)
     160    'A3'
     161    """
     162    nearest_note = int(freqtomidi(freq) + .5)
     163    return midi2note(nearest_note)
     164
     165def note2freq(note):
     166    """Convert note name to corresponding frequency, in Hz.
     167
     168    Parameters
     169    ----------
     170    note : str
     171        input note name
     172
     173    Returns
     174    -------
     175    freq : float [0, 23000[
     176        frequency, in Hz
     177
     178    Example
     179    -------
     180    >>> aubio.note2freq('A4')
     181    440
     182    >>> aubio.note2freq('A3')
     183    220.1
     184    """
     185    midi = note2midi(note)
     186    return miditofreq(midi)
  • python/lib/aubio/slicing.py

    r45c2c5c r088760e  
    77
    88def slice_source_at_stamps(source_file, timestamps, timestamps_end=None,
    9                            output_dir=None, samplerate=0, hopsize=256):
    10     """ slice a sound file at given timestamps """
     9                           output_dir=None, samplerate=0, hopsize=256,
     10                           create_first=False):
     11    """Slice a sound file at given timestamps.
     12
     13    This function reads `source_file` and creates slices, new smaller
     14    files each starting at `t` in `timestamps`, a list of integer
     15    corresponding to time locations in `source_file`, in samples.
     16
     17    If `timestamps_end` is unspecified, the slices will end at
     18    `timestamps_end[n] = timestamps[n+1]-1`, or the end of file.
     19    Otherwise, `timestamps_end` should be a list with the same length
     20    as `timestamps` containing the locations of the end of each slice.
     21
     22    If `output_dir` is unspecified, the new slices will be written in
     23    the current directory. If `output_dir` is a string, new slices
     24    will be written in `output_dir`, after creating the directory if
     25    required.
     26
     27    The default `samplerate` is 0, meaning the original sampling rate
     28    of `source_file` will be used. When using a sampling rate
     29    different to the one of the original files, `timestamps` and
     30    `timestamps_end` should be expressed in the re-sampled signal.
     31
     32    The `hopsize` parameter simply tells :class:`source` to use this
     33    hopsize and does not change the output slices.
     34
     35    If `create_first` is True and `timestamps` does not start with `0`, the
     36    first slice from `0` to `timestamps[0] - 1` will be automatically added.
     37
     38    Parameters
     39    ----------
     40    source_file : str
     41        path of the resource to slice
     42    timestamps : :obj:`list` of :obj:`int`
     43        time stamps at which to slice, in samples
     44    timestamps_end : :obj:`list` of :obj:`int` (optional)
     45        time stamps at which to end the slices
     46    output_dir : str (optional)
     47        output directory to write the slices to
     48    samplerate : int (optional)
     49        samplerate to read the file at
     50    hopsize : int (optional)
     51        number of samples read from source per iteration
     52    create_first : bool (optional)
     53        always create the slice at the start of the file
     54
     55    Examples
     56    --------
     57    Create two slices: the first slice starts at the beginning of the
     58    input file `loop.wav` and lasts exactly one second, starting at
     59    sample `0` and ending at sample `44099`; the second slice starts
     60    at sample `44100` and lasts until the end of the input file:
     61
     62    >>> aubio.slice_source_at_stamps('loop.wav', [0, 44100])
     63
     64    Create one slice, from 1 second to 2 seconds:
     65
     66    >>> aubio.slice_source_at_stamps('loop.wav', [44100], [44100 * 2 - 1])
     67
     68    Notes
     69    -----
     70    Slices may be overlapping. If `timestamps_end` is `1` element
     71    shorter than `timestamps`, the last slice will end at the end of
     72    the file.
     73    """
    1174
    1275    if timestamps is None or len(timestamps) == 0:
    1376        raise ValueError("no timestamps given")
    1477
    15     if timestamps[0] != 0:
     78    if timestamps[0] != 0 and create_first:
    1679        timestamps = [0] + timestamps
    1780        if timestamps_end is not None:
     
    1982
    2083    if timestamps_end is not None:
    21         if len(timestamps_end) != len(timestamps):
     84        if len(timestamps_end) == len(timestamps) - 1:
     85            timestamps_end = timestamps_end + [_max_timestamp]
     86        elif len(timestamps_end) != len(timestamps):
    2287            raise ValueError("len(timestamps_end) != len(timestamps)")
    2388    else:
     
    49114        vec, read = _source.do_multi()
    50115        # if the total number of frames read will exceed the next region start
    51         if len(regions) and total_frames + read >= regions[0][0]:
     116        while len(regions) and total_frames + read >= regions[0][0]:
    52117            #print "getting", regions[0], "at", total_frames
    53118            # get next region
     
    76141                    # write remaining samples from current region
    77142                    _sink.do_multi(vec[:, start:remaining], remaining - start)
    78                     #print "closing region", "remaining", remaining
     143                    #print("closing region", "remaining", remaining)
    79144                    # close this file
    80145                    _sink.close()
     
    83148                _sink.do_multi(vec[:, start:read], read - start)
    84149        total_frames += read
     150        # remove old slices
     151        slices = list(filter(lambda s: s['end_stamp'] > total_frames,
     152            slices))
    85153        if read < hopsize:
    86154            break
  • python/lib/gen_code.py

    r45c2c5c r088760e  
    483483
    484484  if (err > 0) {{
    485     PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}");
     485    if (PyErr_Occurred() == NULL) {{
     486      PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}");
     487    }} else {{
     488      // change the RuntimeError into ValueError
     489      PyObject *type, *value, *traceback;
     490      PyErr_Fetch(&type, &value, &traceback);
     491      PyErr_Restore(PyExc_ValueError, value, traceback);
     492    }}
    486493    return NULL;
    487494  }}
  • python/lib/gen_external.py

    r45c2c5c r088760e  
    7878        cpp_cmd = os.environ.get('CC', 'cc').split()
    7979        cpp_cmd += ['-E']
    80     cpp_cmd += ['-x', 'c']  # force C language (emcc defaults to c++)
     80    if 'emcc' in cpp_cmd:
     81        cpp_cmd += ['-x', 'c'] # emcc defaults to c++, force C language
    8182    return cpp_cmd
    8283
     
    8586    ''' return a dense and preprocessed  string of all c declarations implied by aubio.h
    8687    '''
     88    cpp_output = get_cpp_output(header=header, usedouble=usedouble)
     89    return filter_cpp_output (cpp_output)
     90
     91
     92def get_cpp_output(header=header, usedouble=False):
     93    ''' find and run a C pre-processor on aubio.h '''
    8794    cpp_cmd = get_preprocessor()
    8895
     
    105112    cpp_output = proc.stdout.read()
    106113    err_output = proc.stderr.read()
     114    if err_output:
     115        print("Warning: preprocessor produced errors or warnings:\n%s" \
     116                % err_output.decode('utf8'))
    107117    if not cpp_output:
    108         raise Exception("preprocessor output is empty:\n%s" % err_output)
    109     elif err_output:
    110         print("Warning: preprocessor produced warnings:\n%s" % err_output)
     118        raise_msg = "preprocessor output is empty! Running command " \
     119                + "\"%s\" failed" % " ".join(cpp_cmd)
     120        if err_output:
     121            raise_msg += " with stderr: \"%s\"" % err_output.decode('utf8')
     122        else:
     123            raise_msg += " with no stdout or stderr"
     124        raise Exception(raise_msg)
    111125    if not isinstance(cpp_output, list):
    112126        cpp_output = [l.strip() for l in cpp_output.decode('utf8').split('\n')]
    113127
    114     cpp_output = filter(lambda y: len(y) > 1, cpp_output)
     128    return cpp_output
     129
     130def filter_cpp_output(cpp_raw_output):
     131    ''' prepare cpp-output for parsing '''
     132    cpp_output = filter(lambda y: len(y) > 1, cpp_raw_output)
    115133    cpp_output = list(filter(lambda y: not y.startswith('#'), cpp_output))
    116134
Note: See TracChangeset for help on using the changeset viewer.