Changeset 633400d for python


Ignore:
Timestamp:
Dec 5, 2018, 10:34:39 PM (6 years ago)
Author:
Paul Brossier <piem@piem.org>
Branches:
feature/cnn, feature/crepe, feature/pitchshift, feature/timestretch, fix/ffmpeg5, master
Children:
283a619a
Parents:
5b46bc3 (diff), f19db54 (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/pitchshift

Location:
python
Files:
18 added
3 deleted
40 edited

Legend:

Unmodified
Added
Removed
  • python/README.md

    r5b46bc3 r633400d  
    1 Python aubio module
    2 ===================
     1aubio
     2=====
    33
    4 This module wraps the aubio library for Python using the numpy module.
     4aubio is a collection of tools for music and audio analysis.
    55
    6 Using the Python aubio module
    7 -----------------------------
     6This package integrates the aubio library with [NumPy] to provide a set of
     7efficient tools to process and analyse audio signals, including:
    88
    9 After installing python-aubio, you will be able to import the aubio module:
     9- read audio from any media file, including videos and remote streams
     10- high quality phase vocoder, spectral filterbanks, and linear filters
     11- Mel-Frequency Cepstrum Coefficients and standard spectral descriptors
     12- detection of note attacks (onset)
     13- pitch tracking (fundamental frequency estimation)
     14- beat detection and tempo tracking
    1015
    11     $ python
    12     [...]
    13     >>> import aubio
    14     >>> help(aubio.miditofreq)
     16aubio works with both Python 2 and Python 3.
    1517
    16 Finding some inspiration
    17 ------------------------
     18Links
     19-----
    1820
    19 Some examples are available in the `python/demos` directory. These scripts are
    20 small programs written in python and using python-aubio.
     21- [module documentation][doc_python]
     22- [installation instructions][doc_python_install]
     23- [aubio manual][manual]
     24- [aubio homepage][homepage]
     25- [issue tracker][bugtracker]
    2126
    22 For instance, `demo_source.py` reads a media file.
     27Demos
     28-----
    2329
    24     $ ./python/demos/demo_source.py /path/to/sound/sample.wav
     30Some examples are available in the [`python/demos`][demos_dir] folder. Each
     31script is a command line program which accepts one ore more argument.
    2532
    26 and `demo_timestretch_online.py` stretches the original file into a new one:
     33**Notes**: installing additional modules is required to run some of the demos.
    2734
    28     $ ./python/demo/demo_timestretch_online.py loop.wav stretched_loop.wav 0.92`
     35### Analysis
    2936
    30 Note: you might need to install additional modules to run some of the demos.
    31 Some demos use [matplotlib](http://matplotlib.org/) to draw plots, others use
    32 [PySoundCard](https://github.com/bastibe/PySoundCard) to play and record
    33 sounds.
     37- `demo_source.py` uses aubio to read audio samples from media files
     38- `demo_onset_plot.py` detects attacks in a sound file and plots the results
     39  using [matplotlib]
     40- `demo_pitch.py` looks for fundamental frequency in a sound file and plots the
     41  results using [matplotlib]
     42- `demo_spectrogram.py`, `demo_specdesc.py`, `demo_mfcc.py` for spectral
     43  analysis.
    3444
    35 Testing the Python module
    36 -------------------------
     45### Real-time
    3746
    38 To run the all the python tests, use the script:
     47- `demo_pyaudio.py` and `demo_tapthebeat.py` use [pyaudio]
     48- `demo_pysoundcard_play.py`, `demo_pysoundcard.py` use [PySoundCard]
     49- `demo_alsa.py` uses [pyalsaaudio]
    3950
    40     $ ./python/tests/run_all_tests
     51### Others
    4152
    42 Each test script can also be called one at a time. For instance:
     53- `demo_timestretch.py` can change the duration of an input file and write the
     54  new sound to disk,
     55- `demo_wav2midi.py` detects the notes in a file and uses [mido] to write the
     56  results into a MIDI file
    4357
    44     $ ./python/tests/test_note2midi.py -v
     58### Example
    4559
    46 Install in a virtualenv
    47 -----------------------
     60Use `demo_timestretch_online.py` to slow down `loop.wav`, write the results in
     61`stretched_loop.wav`:
    4862
    49 You should be able to install python-aubio directly from the top source
    50 directory of aubio.
     63    $ python demo_timestretch_online.py loop.wav stretched_loop.wav 0.92
    5164
    52 First, create a virtualenv to hold the required python module:
    53 
    54     $ virtualenv pyaubio
    55     $ source pyaubio/bin/activate
    56 
    57 Now install and build the python extension using:
    58 
    59     $ pip install .
    60 
    61 Install requirements
    62 --------------------
    63 
    64 Before compiling this module, you must have compiled libaubio.
    65 
    66 A simple way to do this is with pip:
    67 
    68     $ pip install -r requirements.txt
    69 
    70 For more information about how this module works, please refer to the [Python/C
    71 API Reference Manual] (http://docs.python.org/c-api/index.html) and the
    72 [Numpy/C API Reference](http://docs.scipy.org/doc/numpy/reference/c-api.html).
    73 
    74 Compiling python aubio
    75 ----------------------
    76 
    77 To build the aubio Python module, run the following command from the top source
    78 directory of aubio:
    79 
    80     $ ./setup.py build
    81 
    82 Note: if libaubio was previously built using waf, the script will use it.
    83 Otherwise, the entire library will be built inside the python extension.
    84 
    85 To find out more about `setup.py` options:
    86 
    87     $ ./setup.py --help
    88 
    89 Installing
     65Built with
    9066----------
    9167
    92 To install the Python module:
     68The core of aubio is written in C for portability and speed. In addition to
     69[NumPy], aubio can be optionally built to use one or more of the following
     70libraries:
    9371
    94     $ ./setup.py install
     72- media file reading:
    9573
    96 Alternatively, you may want to use the Python module without installing it by
    97 setting your PYTHONPATH, for instance as follows:
     74    - [ffmpeg] / [avcodec] to decode and read audio from almost any format,
     75    - [libsndfile] to read audio from uncompressed sound files,
     76    - [libsamplerate] to re-sample audio signals,
     77    - [CoreAudio] to read all media formats supported by macOS, iOS, and tvOS.
    9878
    99     $ export PYTHONPATH=$PYTHONPATH:$PWD/`ls -rtd build/lib.* | head -1`:$PWD/tests
     79- hardware acceleration:
    10080
     81    - [Atlas] and [Blas], for accelerated vector and matrix computations,
     82    - [fftw3], to compute fast Fourier Transforms of any size,
     83    - [Accelerate] for accelerated FFT and matrix computations (macOS/iOS),
     84    - [Intel IPP], accelerated vector computation and FFT implementation.
     85
     86[ffmpeg]: https://ffmpeg.org
     87[avcodec]: https://libav.org
     88[libsndfile]: http://www.mega-nerd.com/libsndfile/
     89[libsamplerate]: http://www.mega-nerd.com/SRC/
     90[CoreAudio]: https://developer.apple.com/reference/coreaudio
     91[Atlas]: http://math-atlas.sourceforge.net/
     92[Blas]: https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms
     93[fftw3]: http://fftw.org
     94[Accelerate]: https://developer.apple.com/reference/accelerate
     95[Intel IPP]: https://software.intel.com/en-us/intel-ipp
     96
     97[demos_dir]:https://github.com/aubio/aubio/tree/master/python/demos
     98[pyaudio]:https://people.csail.mit.edu/hubert/pyaudio/
     99[PySoundCard]:https://github.com/bastibe/PySoundCard
     100[pyalsaaudio]:https://larsimmisch.github.io/pyalsaaudio/
     101[mido]:https://mido.readthedocs.io
     102
     103[manual]: https://aubio.org/manual/latest/
     104[doc_python]: https://aubio.org/manual/latest/python.html
     105[doc_python_install]: https://aubio.org/manual/latest/python_module.html
     106[homepage]: https://aubio.org
     107[NumPy]: https://www.numpy.org
     108[bugtracker]: https://github.com/aubio/aubio/issues
     109[matplotlib]:https://matplotlib.org/
  • python/demos/demo_bpm_extract.py

    r5b46bc3 r633400d  
    44from numpy import median, diff
    55
    6 def get_file_bpm(path, params = None):
     6def get_file_bpm(path, params=None):
    77    """ Calculate the beats per minute (bpm) of a given file.
    88        path: path to the file
     
    1111    if params is None:
    1212        params = {}
    13     try:
    14         win_s = params['win_s']
    15         samplerate = params['samplerate']
    16         hop_s = params['hop_s']
    17     except KeyError:
    18         """
    19         # super fast
    20         samplerate, win_s, hop_s = 4000, 128, 64
    21         # fast
    22         samplerate, win_s, hop_s = 8000, 512, 128
    23         """
    24         # default:
    25         samplerate, win_s, hop_s = 44100, 1024, 512
     13    # default:
     14    samplerate, win_s, hop_s = 44100, 1024, 512
     15    if 'mode' in params:
     16        if params.mode in ['super-fast']:
     17            # super fast
     18            samplerate, win_s, hop_s = 4000, 128, 64
     19        elif params.mode in ['fast']:
     20            # fast
     21            samplerate, win_s, hop_s = 8000, 512, 128
     22        elif params.mode in ['default']:
     23            pass
     24        else:
     25            raise ValueError("unknown mode {:s}".format(params.mode))
     26    # manual settings
     27    if 'samplerate' in params:
     28        samplerate = params.samplerate
     29    if 'win_s' in params:
     30        win_s = params.win_s
     31    if 'hop_s' in params:
     32        hop_s = params.hop_s
    2633
    2734    s = source(path, samplerate, hop_s)
     
    4552            break
    4653
    47     # Convert to periods and to bpm
    48     if len(beats) > 1:
    49         if len(beats) < 4:
    50             print("few beats found in {:s}".format(path))
    51         bpms = 60./diff(beats)
    52         b = median(bpms)
    53     else:
    54         b = 0
    55         print("not enough beats found in {:s}".format(path))
    56     return b
     54    def beats_to_bpm(beats, path):
     55        # if enough beats are found, convert to periods then to bpm
     56        if len(beats) > 1:
     57            if len(beats) < 4:
     58                print("few beats found in {:s}".format(path))
     59            bpms = 60./diff(beats)
     60            return median(bpms)
     61        else:
     62            print("not enough beats found in {:s}".format(path))
     63            return 0
     64
     65    return beats_to_bpm(beats, path)
    5766
    5867if __name__ == '__main__':
    59     import sys
    60     for f in sys.argv[1:]:
    61         bpm = get_file_bpm(f)
     68    import argparse
     69    parser = argparse.ArgumentParser()
     70    parser.add_argument('-m', '--mode',
     71            help="mode [default|fast|super-fast]",
     72            dest="mode", default='default')
     73    parser.add_argument('sources',
     74            nargs='+',
     75            help="input_files")
     76    args = parser.parse_args()
     77    for f in args.sources:
     78        bpm = get_file_bpm(f, params = args)
    6279        print("{:6s} {:s}".format("{:2f}".format(bpm), f))
  • python/demos/demo_filter.py

    r5b46bc3 r633400d  
    11#! /usr/bin/env python
    22
     3import sys
     4import os.path
     5import aubio
    36
    4 def apply_filter(path):
    5     from aubio import source, sink, digital_filter
    6     from os.path import basename, splitext
    77
     8def apply_filter(path, target):
    89    # open input file, get its samplerate
    9     s = source(path)
     10    s = aubio.source(path)
    1011    samplerate = s.samplerate
    1112
    1213    # create an A-weighting filter
    13     f = digital_filter(7)
     14    f = aubio.digital_filter(7)
    1415    f.set_a_weighting(samplerate)
    15     # alternatively, apply another filter
    1616
    1717    # create output file
    18     o = sink("filtered_" + splitext(basename(path))[0] + ".wav", samplerate)
     18    o = aubio.sink(target, samplerate)
    1919
    2020    total_frames = 0
    2121    while True:
     22        # read from source
    2223        samples, read = s()
     24        # filter samples
    2325        filtered_samples = f(samples)
     26        # write to sink
    2427        o(filtered_samples, read)
     28        # count frames read
    2529        total_frames += read
    26         if read < s.hop_size: break
     30        # end of file reached
     31        if read < s.hop_size:
     32            break
    2733
     34    # print some info
    2835    duration = total_frames / float(samplerate)
    29     print ("read {:s}".format(s.uri))
    30     print ("applied A-weighting filtered ({:d} Hz)".format(samplerate))
    31     print ("wrote {:s} ({:.2f} s)".format(o.uri, duration))
     36    input_str = "input: {:s} ({:.2f} s, {:d} Hz)"
     37    output_str = "output: {:s}, A-weighting filtered ({:d} frames total)"
     38    print(input_str.format(s.uri, duration, samplerate))
     39    print(output_str.format(o.uri, total_frames))
    3240
    3341if __name__ == '__main__':
    34     import sys
    35     for f in sys.argv[1:]:
    36         apply_filter(f)
     42    usage = "{:s} <input_file> [output_file]".format(sys.argv[0])
     43    if not 1 < len(sys.argv) < 4:
     44        print(usage)
     45        sys.exit(1)
     46    if len(sys.argv) < 3:
     47        input_path = sys.argv[1]
     48        basename = os.path.splitext(os.path.basename(input_path))[0] + ".wav"
     49        output_path = "filtered_" + basename
     50    else:
     51        input_path, output_path = sys.argv[1:]
     52    # run function
     53    apply_filter(input_path, output_path)
  • python/demos/demo_filterbank.py

    r5b46bc3 r633400d  
    11#! /usr/bin/env python
    22
    3 from aubio import filterbank, fvec
    4 from pylab import loglog, show, xlim, ylim, xlabel, ylabel, title
    5 from numpy import vstack, arange
     3"""Create a filterbank from a list of frequencies.
    64
     5This demo uses `aubio.filterbank.set_triangle_bands` to build a set of
     6triangular filters from a list of frequencies.
     7
     8The filterbank coefficients are then modified before being displayed."""
     9
     10import aubio
     11import numpy as np
     12import matplotlib.pyplot as plt
     13
     14# sampling rate and size of the fft
     15samplerate = 48000
    716win_s = 2048
    8 samplerate = 48000
    917
     18# define a list of custom frequency
    1019freq_list = [60, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 24000]
     20# number of filters to create
    1121n_filters = len(freq_list) - 2
    1222
    13 f = filterbank(n_filters, win_s)
    14 freqs = fvec(freq_list)
     23# create a new filterbank
     24f = aubio.filterbank(n_filters, win_s)
     25freqs = aubio.fvec(freq_list)
    1526f.set_triangle_bands(freqs, samplerate)
    1627
     28# get the coefficients from the filterbank
    1729coeffs = f.get_coeffs()
    18 coeffs[4] *= 5.
    19 
     30# apply a gain to fifth band
     31coeffs[4] *= 6.
     32# load the modified coeffs into the filterbank
    2033f.set_coeffs(coeffs)
    2134
    22 times = vstack([arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
    23 title('Bank of filters built using a simple list of boundaries\nThe middle band has been amplified by 2.')
    24 loglog(times.T, f.get_coeffs().T, '.-')
    25 xlim([50, samplerate/2])
    26 ylim([1.0e-6, 2.0e-2])
    27 xlabel('log frequency (Hz)')
    28 ylabel('log amplitude')
    29 
    30 show()
     35# display the band gains in a loglog plot
     36freqs = np.vstack([np.arange(win_s // 2 + 1) * samplerate / win_s] * n_filters)
     37plt.title('filterbank built from a list of frequencies\n'
     38          'The 5th band has been amplified by a factor 6.')
     39plt.loglog(freqs.T, f.get_coeffs().T, '.-')
     40plt.xlim([50, samplerate/2])
     41plt.ylim([1.0e-6, 2.0e-2])
     42plt.xlabel('log frequency (Hz)')
     43plt.ylabel('log amplitude')
     44plt.show()
  • python/demos/demo_pitch_sinusoid.py

    r5b46bc3 r633400d  
    3838pointer += partition
    3939pointer += partition
    40 freqs[ pointer : pointer + partition ] = 400 + 5 * np.random.random(sin_length/8)
     40freqs[ pointer : pointer + partition ] = 400 + 5 * np.random.random(sin_length//8)
    4141
    4242a = build_sinusoid(sin_length, freqs, samplerate)
  • python/demos/demo_source_simple.py

    r5b46bc3 r633400d  
    11#! /usr/bin/env python
    2 import sys, aubio
     2
     3"""A simple example using aubio.source."""
     4
     5import sys
     6import aubio
    37
    48samplerate = 0  # use original source samplerate
    5 hop_size = 256 # number of frames to read in one block
    6 s = aubio.source(sys.argv[1], samplerate, hop_size)
     9hop_size = 256  # number of frames to read in one block
     10src = aubio.source(sys.argv[1], samplerate, hop_size)
    711total_frames = 0
    812
    9 while True: # reading loop
    10     samples, read = s()
    11     total_frames += read
    12     if read < hop_size: break # end of file reached
     13while True:
     14    samples, read = src()  # read hop_size new samples from source
     15    total_frames += read   # increment total number of frames
     16    if read < hop_size:    # end of file reached
     17        break
    1318
    1419fmt_string = "read {:d} frames at {:d}Hz from {:s}"
    15 print (fmt_string.format(total_frames, s.samplerate, sys.argv[1]))
    16 
     20print(fmt_string.format(total_frames, src.samplerate, src.uri))
  • python/demos/demo_timestretch.py

    r5b46bc3 r633400d  
    1313
    1414win_s = 1024
    15 hop_s = win_s / 8 # 87.5 % overlap
     15hop_s = win_s // 8 # 87.5 % overlap
    1616
    1717warmup = win_s // hop_s - 1
  • python/demos/demo_timestretch_online.py

    r5b46bc3 r633400d  
    1212import numpy as np
    1313
    14 win_s = 1024
    15 hop_s = win_s / 8 # 87.5 % overlap
     14win_s = 512
     15hop_s = win_s // 8 # 87.5 % overlap
    1616
    1717warmup = win_s // hop_s - 1
     
    9393    old_grain.phas = np.copy(cur_grain.phas)
    9494
     95    # until end of file
     96    if read < hop_s: break
     97    # increment block counter
    9598    block_read += 1
    96     if read < hop_s: break
    9799
    98100for t in range(warmup + 2): # purge the last frames from the phase vocoder
  • python/ext/aubio-types.h

    r5b46bc3 r633400d  
    2828#include "aubio.h"
    2929#else
    30 #include "aubio/aubio.h"
     30#include <aubio/aubio.h>
    3131#endif
    3232
     
    4545#define AUBIO_NPY_SMPL_STR "float32"
    4646#define AUBIO_NPY_SMPL_CHR "f"
     47#endif
     48
     49#ifndef PATH_MAX
     50#ifdef MAX_PATH
     51#define PATH_MAX MAX_PATH
     52#else
     53#define PATH_MAX 1024
     54#endif
    4755#endif
    4856
  • python/ext/aubiomodule.c

    r5b46bc3 r633400d  
    33#include "py-musicutils.h"
    44
     5// this dummy macro is used to convince windows that a string passed as -D flag
     6// is just that, a string, and not a double.
     7#define REDEFINESTRING(x) #x
     8#define DEFINEDSTRING(x) REDEFINESTRING(x)
     9
    510static char aubio_module_doc[] = "Python module for the aubio library";
    611
    712static char Py_alpha_norm_doc[] = ""
    8 "alpha_norm(fvec, integer) -> float\n"
    9 "\n"
    10 "Compute alpha normalisation factor on vector, given alpha\n"
     13"alpha_norm(vec, alpha)\n"
     14"\n"
     15"Compute `alpha` normalisation factor of vector `vec`.\n"
     16"\n"
     17"Parameters\n"
     18"----------\n"
     19"vec : fvec\n"
     20"   input vector\n"
     21"alpha : float\n"
     22"   norm factor\n"
     23"\n"
     24"Returns\n"
     25"-------\n"
     26"float\n"
     27"   p-norm of the input vector, where `p=alpha`\n"
    1128"\n"
    1229"Example\n"
    1330"-------\n"
    1431"\n"
    15 ">>> b = alpha_norm(a, 9)";
     32">>> a = aubio.fvec(np.arange(10)); alpha = 2\n"
     33">>> aubio.alpha_norm(a, alpha), (sum(a**alpha)/len(a))**(1./alpha)\n"
     34"(5.338539123535156, 5.338539126015656)\n"
     35"\n"
     36"Note\n"
     37"----\n"
     38"Computed as:\n"
     39"\n"
     40".. math::\n"
     41"  l_{\\alpha} = \n"
     42"       \\|\\frac{\\sum_{n=0}^{N-1}{{x_n}^{\\alpha}}}{N}\\|^{1/\\alpha}\n"
     43"";
    1644
    1745static char Py_bintomidi_doc[] = ""
    18 "bintomidi(float, samplerate = integer, fftsize = integer) -> float\n"
    19 "\n"
    20 "Convert bin (float) to midi (float), given the sampling rate and the FFT size\n"
     46"bintomidi(fftbin, samplerate, fftsize)\n"
     47"\n"
     48"Convert FFT bin to frequency in midi note, given the sampling rate\n"
     49"and the size of the FFT.\n"
     50"\n"
     51"Parameters\n"
     52"----------\n"
     53"fftbin : float\n"
     54"   input frequency bin\n"
     55"samplerate : float\n"
     56"   sampling rate of the signal\n"
     57"fftsize : float\n"
     58"   size of the FFT\n"
     59"\n"
     60"Returns\n"
     61"-------\n"
     62"float\n"
     63"   Frequency converted to midi note.\n"
    2164"\n"
    2265"Example\n"
    2366"-------\n"
    2467"\n"
    25 ">>> midi = bintomidi(float, samplerate = 44100, fftsize = 1024)";
     68">>> aubio.bintomidi(10, 44100, 1024)\n"
     69"68.62871551513672\n"
     70"";
    2671
    2772static char Py_miditobin_doc[] = ""
    28 "miditobin(float, samplerate = integer, fftsize = integer) -> float\n"
    29 "\n"
    30 "Convert midi (float) to bin (float), given the sampling rate and the FFT size\n"
     73"miditobin(midi, samplerate, fftsize)\n"
     74"\n"
     75"Convert frequency in midi note to FFT bin, given the sampling rate\n"
     76"and the size of the FFT.\n"
     77"\n"
     78"Parameters\n"
     79"----------\n"
     80"midi : float\n"
     81"   input frequency, in midi note\n"
     82"samplerate : float\n"
     83"   sampling rate of the signal\n"
     84"fftsize : float\n"
     85"   size of the FFT\n"
     86"\n"
     87"Returns\n"
     88"-------\n"
     89"float\n"
     90"   Frequency converted to FFT bin.\n"
     91"\n"
     92"Examples\n"
     93"--------\n"
     94"\n"
     95">>> aubio.miditobin(69, 44100, 1024)\n"
     96"10.216779708862305\n"
     97">>> aubio.miditobin(75.08, 32000, 512)\n"
     98"10.002175331115723\n"
     99"";
     100
     101static char Py_bintofreq_doc[] = ""
     102"bintofreq(fftbin, samplerate, fftsize)\n"
     103"\n"
     104"Convert FFT bin to frequency in Hz, given the sampling rate\n"
     105"and the size of the FFT.\n"
     106"\n"
     107"Parameters\n"
     108"----------\n"
     109"fftbin : float\n"
     110"   input frequency bin\n"
     111"samplerate : float\n"
     112"   sampling rate of the signal\n"
     113"fftsize : float\n"
     114"   size of the FFT\n"
     115"\n"
     116"Returns\n"
     117"-------\n"
     118"float\n"
     119"   Frequency converted to Hz.\n"
    31120"\n"
    32121"Example\n"
    33122"-------\n"
    34123"\n"
    35 ">>> bin = miditobin(midi, samplerate = 44100, fftsize = 1024)";
    36 
    37 static char Py_bintofreq_doc[] = ""
    38 "bintofreq(float, samplerate = integer, fftsize = integer) -> float\n"
    39 "\n"
    40 "Convert bin number (float) in frequency (Hz), given the sampling rate and the FFT size\n"
     124">>> aubio.bintofreq(10, 44100, 1024)\n"
     125"430.6640625\n"
     126"";
     127
     128static char Py_freqtobin_doc[] = ""
     129"freqtobin(freq, samplerate, fftsize)\n"
     130"\n"
     131"Convert frequency in Hz to FFT bin, given the sampling rate\n"
     132"and the size of the FFT.\n"
     133"\n"
     134"Parameters\n"
     135"----------\n"
     136"midi : float\n"
     137"   input frequency, in midi note\n"
     138"samplerate : float\n"
     139"   sampling rate of the signal\n"
     140"fftsize : float\n"
     141"   size of the FFT\n"
     142"\n"
     143"Returns\n"
     144"-------\n"
     145"float\n"
     146"   Frequency converted to FFT bin.\n"
     147"\n"
     148"Examples\n"
     149"--------\n"
     150"\n"
     151">>> aubio.freqtobin(440, 44100, 1024)\n"
     152"10.216779708862305\n"
     153"";
     154
     155static char Py_zero_crossing_rate_doc[] = ""
     156"zero_crossing_rate(vec)\n"
     157"\n"
     158"Compute zero-crossing rate of `vec`.\n"
     159"\n"
     160"Parameters\n"
     161"----------\n"
     162"vec : fvec\n"
     163"   input vector\n"
     164"\n"
     165"Returns\n"
     166"-------\n"
     167"float\n"
     168"   Zero-crossing rate.\n"
    41169"\n"
    42170"Example\n"
    43171"-------\n"
    44172"\n"
    45 ">>> freq = bintofreq(bin, samplerate = 44100, fftsize = 1024)";
    46 
    47 static char Py_freqtobin_doc[] = ""
    48 "freqtobin(float, samplerate = integer, fftsize = integer) -> float\n"
    49 "\n"
    50 "Convert frequency (Hz) in bin number (float), given the sampling rate and the FFT size\n"
     173">>> a = np.linspace(-1., 1., 1000, dtype=aubio.float_type)\n"
     174">>> aubio.zero_crossing_rate(a), 1/1000\n"
     175"(0.0010000000474974513, 0.001)\n"
     176"";
     177
     178static char Py_min_removal_doc[] = ""
     179"min_removal(vec)\n"
     180"\n"
     181"Remove the minimum value of a vector to each of its element.\n"
     182"\n"
     183"Modifies the input vector in-place and returns a reference to it.\n"
     184"\n"
     185"Parameters\n"
     186"----------\n"
     187"vec : fvec\n"
     188"   input vector\n"
     189"\n"
     190"Returns\n"
     191"-------\n"
     192"fvec\n"
     193"   modified input vector\n"
    51194"\n"
    52195"Example\n"
    53196"-------\n"
    54197"\n"
    55 ">>> bin = freqtobin(freq, samplerate = 44100, fftsize = 1024)";
    56 
    57 static char Py_zero_crossing_rate_doc[] = ""
    58 "zero_crossing_rate(fvec) -> float\n"
    59 "\n"
    60 "Compute Zero crossing rate of a vector\n"
    61 "\n"
    62 "Example\n"
    63 "-------\n"
    64 "\n"
    65 ">>> z = zero_crossing_rate(a)";
    66 
    67 static char Py_min_removal_doc[] = ""
    68 "min_removal(fvec) -> float\n"
    69 "\n"
    70 "Remove the minimum value of a vector, in-place modification\n"
    71 "\n"
    72 "Example\n"
    73 "-------\n"
    74 "\n"
    75 ">>> min_removal(a)";
     198">>> aubio.min_removal(aubio.fvec(np.arange(1,4)))\n"
     199"array([0., 1., 2.], dtype=" AUBIO_NPY_SMPL_STR ")\n"
     200"";
    76201
    77202extern void add_ufuncs ( PyObject *m );
     
    113238  smpl_t output;
    114239
    115   if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
     240  if (!PyArg_ParseTuple (args,
     241        "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
     242        &input, &samplerate, &fftsize)) {
    116243    return NULL;
    117244  }
     
    128255  smpl_t output;
    129256
    130   if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR , &input, &samplerate, &fftsize)) {
     257  if (!PyArg_ParseTuple (args,
     258        "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
     259        &input, &samplerate, &fftsize)) {
    131260    return NULL;
    132261  }
     
    143272  smpl_t output;
    144273
    145   if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
     274  if (!PyArg_ParseTuple (args,
     275        "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
     276        &input, &samplerate, &fftsize)) {
    146277    return NULL;
    147278  }
     
    158289  smpl_t output;
    159290
    160   if (!PyArg_ParseTuple (args, "|" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR, &input, &samplerate, &fftsize)) {
     291  if (!PyArg_ParseTuple (args,
     292        "" AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR,
     293        &input, &samplerate, &fftsize)) {
    161294    return NULL;
    162295  }
     
    238371  {"level_detection", Py_aubio_level_detection, METH_VARARGS, Py_aubio_level_detection_doc},
    239372  {"window", Py_aubio_window, METH_VARARGS, Py_aubio_window_doc},
     373  {"shift", Py_aubio_shift, METH_VARARGS, Py_aubio_shift_doc},
     374  {"ishift", Py_aubio_ishift, METH_VARARGS, Py_aubio_ishift_doc},
     375  {"hztomel", Py_aubio_hztomel, METH_VARARGS|METH_KEYWORDS, Py_aubio_hztomel_doc},
     376  {"meltohz", Py_aubio_meltohz, METH_VARARGS|METH_KEYWORDS, Py_aubio_meltohz_doc},
     377  {"hztomel_htk", Py_aubio_hztomel_htk, METH_VARARGS, Py_aubio_hztomel_htk_doc},
     378  {"meltohz_htk", Py_aubio_meltohz_htk, METH_VARARGS, Py_aubio_meltohz_htk_doc},
    240379  {NULL, NULL, 0, NULL} /* Sentinel */
    241380};
     
    324463
    325464  PyModule_AddStringConstant(m, "float_type", AUBIO_NPY_SMPL_STR);
     465  PyModule_AddStringConstant(m, "__version__", DEFINEDSTRING(AUBIO_VERSION));
    326466
    327467  // add generated objects
  • python/ext/py-cvec.c

    r5b46bc3 r633400d  
    2020} Py_cvec;
    2121
    22 static char Py_cvec_doc[] = "cvec object";
     22static char Py_cvec_doc[] = ""
     23"cvec(size)\n"
     24"\n"
     25"A container holding spectral data.\n"
     26"\n"
     27"Create one `cvec` to store the spectral information of a window\n"
     28"of `size` points. The data will be stored  in two vectors,\n"
     29":attr:`phas` and :attr:`norm`, each of shape (:attr:`length`,),\n"
     30"with `length = size // 2 + 1`.\n"
     31"\n"
     32"Parameters\n"
     33"----------\n"
     34"size: int\n"
     35"   Size of spectrum to create.\n"
     36"\n"
     37"Examples\n"
     38"--------\n"
     39">>> c = aubio.cvec(1024)\n"
     40">>> c\n"
     41"aubio cvec of 513 elements\n"
     42">>> c.length\n"
     43"513\n"
     44">>> c.norm.dtype, c.phas.dtype\n"
     45"(dtype('float32'), dtype('float32'))\n"
     46">>> c.norm.shape, c.phas.shape\n"
     47"((513,), (513,))\n"
     48"\n"
     49"See Also\n"
     50"--------\n"
     51"fvec, fft, pvoc\n"
     52"";
    2353
    2454
     
    143173  npy_intp length;
    144174  if (!PyAubio_IsValidVector(input)) {
    145     return 1;
     175    return -1;
    146176  }
    147177  length = PyArray_SIZE ((PyArrayObject *)input);
    148178  if (length != vec->length) {
    149179    PyErr_Format (PyExc_ValueError,
    150         "input array has length %ld, but cvec has length %d", length,
     180        "input array has length %" NPY_INTP_FMT ", but cvec has length %d", length,
    151181        vec->length);
    152     return 1;
     182    return -1;
    153183  }
    154184
     
    164194  npy_intp length;
    165195  if (!PyAubio_IsValidVector(input)) {
    166     return 1;
     196    return -1;
    167197  }
    168198  length = PyArray_SIZE ((PyArrayObject *)input);
    169199  if (length != vec->length) {
    170200    PyErr_Format (PyExc_ValueError,
    171         "input array has length %ld, but cvec has length %d", length,
     201        "input array has length %" NPY_INTP_FMT ", but cvec has length %d", length,
    172202        vec->length);
    173     return 1;
     203    return -1;
    174204  }
    175205
     
    183213  // TODO remove READONLY flag and define getter/setter
    184214  {"length", T_INT, offsetof (Py_cvec, length), READONLY,
    185       "length attribute"},
     215      "int: Length of `norm` and `phas` vectors."},
    186216  {NULL}                        /* Sentinel */
    187217};
     
    192222
    193223static PyGetSetDef Py_cvec_getseters[] = {
    194   {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm, 
    195       "Numpy vector of shape (length,) containing the magnitude",
     224  {"norm", (getter)Py_cvec_get_norm, (setter)Py_cvec_set_norm,
     225      "numpy.ndarray: Vector of shape `(length,)` containing the magnitude.",
    196226      NULL},
    197   {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas, 
    198       "Numpy vector of shape (length,) containing the phase",
     227  {"phas", (getter)Py_cvec_get_phas, (setter)Py_cvec_set_phas,
     228      "numpy.ndarray: Vector of shape `(length,)` containing the phase.",
    199229      NULL},
    200230  {NULL} /* sentinel */
  • python/ext/py-filterbank.c

    r5b46bc3 r633400d  
    9595  if (self->vec.length != self->win_s / 2 + 1) {
    9696    PyErr_Format(PyExc_ValueError,
    97                  "input cvec has length %d, but fft expects length %d",
     97                 "input cvec has length %d, but filterbank expects length %d",
    9898                 self->vec.length, self->win_s / 2 + 1);
    9999    return NULL;
     
    123123
    124124  PyObject *input;
    125   uint_t samplerate;
    126   if (!PyArg_ParseTuple (args, "OI", &input, &samplerate)) {
     125  smpl_t samplerate;
     126  if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR, &input, &samplerate)) {
    127127    return NULL;
    128128  }
     
    139139      &(self->freqs), samplerate);
    140140  if (err > 0) {
    141     PyErr_SetString (PyExc_ValueError,
    142         "error when setting filter to A-weighting");
     141    if (PyErr_Occurred() == NULL) {
     142      PyErr_SetString (PyExc_ValueError, "error running set_triangle_bands");
     143    } else {
     144      // change the RuntimeError into ValueError
     145      PyObject *type, *value, *traceback;
     146      PyErr_Fetch(&type, &value, &traceback);
     147      PyErr_Restore(PyExc_ValueError, value, traceback);
     148    }
    143149    return NULL;
    144150  }
     
    151157  uint_t err = 0;
    152158
    153   uint_t samplerate;
    154   if (!PyArg_ParseTuple (args, "I", &samplerate)) {
     159  smpl_t samplerate;
     160  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR, &samplerate)) {
    155161    return NULL;
    156162  }
     
    158164  err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate);
    159165  if (err > 0) {
    160     PyErr_SetString (PyExc_ValueError,
    161         "error when setting filter to A-weighting");
     166    if (PyErr_Occurred() == NULL) {
     167      PyErr_SetString (PyExc_ValueError, "error running set_mel_coeffs_slaney");
     168    } else {
     169      // change the RuntimeError into ValueError
     170      PyObject *type, *value, *traceback;
     171      PyErr_Fetch(&type, &value, &traceback);
     172      PyErr_Restore(PyExc_ValueError, value, traceback);
     173    }
     174    return NULL;
     175  }
     176  Py_RETURN_NONE;
     177}
     178
     179static PyObject *
     180Py_filterbank_set_mel_coeffs (Py_filterbank * self, PyObject *args)
     181{
     182  uint_t err = 0;
     183
     184  smpl_t samplerate;
     185  smpl_t freq_min;
     186  smpl_t freq_max;
     187  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR
     188        AUBIO_NPY_SMPL_CHR, &samplerate, &freq_min, &freq_max)) {
     189    return NULL;
     190  }
     191
     192  err = aubio_filterbank_set_mel_coeffs (self->o, samplerate,
     193      freq_min, freq_max);
     194  if (err > 0) {
     195    if (PyErr_Occurred() == NULL) {
     196      PyErr_SetString (PyExc_ValueError, "error running set_mel_coeffs");
     197    } else {
     198      // change the RuntimeError into ValueError
     199      PyObject *type, *value, *traceback;
     200      PyErr_Fetch(&type, &value, &traceback);
     201      PyErr_Restore(PyExc_ValueError, value, traceback);
     202    }
     203    return NULL;
     204  }
     205  Py_RETURN_NONE;
     206}
     207
     208static PyObject *
     209Py_filterbank_set_mel_coeffs_htk (Py_filterbank * self, PyObject *args)
     210{
     211  uint_t err = 0;
     212
     213  smpl_t samplerate;
     214  smpl_t freq_min;
     215  smpl_t freq_max;
     216  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR AUBIO_NPY_SMPL_CHR
     217        AUBIO_NPY_SMPL_CHR, &samplerate, &freq_min, &freq_max)) {
     218    return NULL;
     219  }
     220
     221  err = aubio_filterbank_set_mel_coeffs_htk (self->o, samplerate,
     222      freq_min, freq_max);
     223  if (err > 0) {
     224    if (PyErr_Occurred() == NULL) {
     225      PyErr_SetString (PyExc_ValueError, "error running set_mel_coeffs_htk");
     226    } else {
     227      // change the RuntimeError into ValueError
     228      PyObject *type, *value, *traceback;
     229      PyErr_Fetch(&type, &value, &traceback);
     230      PyErr_Restore(PyExc_ValueError, value, traceback);
     231    }
    162232    return NULL;
    163233  }
     
    194264  return (PyObject *)PyAubio_CFmatToArray(
    195265      aubio_filterbank_get_coeffs (self->o) );
     266}
     267
     268static PyObject *
     269Py_filterbank_set_power(Py_filterbank *self, PyObject *args)
     270{
     271  smpl_t power;
     272
     273  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR, &power)) {
     274    return NULL;
     275  }
     276  if(aubio_filterbank_set_power (self->o, power)) {
     277    if (PyErr_Occurred() == NULL) {
     278      PyErr_SetString (PyExc_ValueError,
     279          "error running filterbank.set_power");
     280    } else {
     281      // change the RuntimeError into ValueError
     282      PyObject *type, *value, *traceback;
     283      PyErr_Fetch(&type, &value, &traceback);
     284      PyErr_Restore(PyExc_ValueError, value, traceback);
     285    }
     286    return NULL;
     287  }
     288  Py_RETURN_NONE;
     289}
     290
     291static PyObject *
     292Py_filterbank_set_norm(Py_filterbank *self, PyObject *args)
     293{
     294  smpl_t norm;
     295
     296  if (!PyArg_ParseTuple (args, AUBIO_NPY_SMPL_CHR, &norm)) {
     297    return NULL;
     298  }
     299  if(aubio_filterbank_set_norm (self->o, norm)) {
     300    if (PyErr_Occurred() == NULL) {
     301      PyErr_SetString (PyExc_ValueError,
     302          "error running filterbank.set_power");
     303    } else {
     304      // change the RuntimeError into ValueError
     305      PyObject *type, *value, *traceback;
     306      PyErr_Fetch(&type, &value, &traceback);
     307      PyErr_Restore(PyExc_ValueError, value, traceback);
     308    }
     309    return NULL;
     310  }
     311  Py_RETURN_NONE;
    196312}
    197313
     
    201317  {"set_mel_coeffs_slaney", (PyCFunction) Py_filterbank_set_mel_coeffs_slaney,
    202318    METH_VARARGS, "set coefficients of filterbank as in Auditory Toolbox"},
     319  {"set_mel_coeffs", (PyCFunction) Py_filterbank_set_mel_coeffs,
     320    METH_VARARGS, "set coefficients of filterbank to linearly spaced mel scale"},
     321  {"set_mel_coeffs_htk", (PyCFunction) Py_filterbank_set_mel_coeffs_htk,
     322    METH_VARARGS, "set coefficients of filterbank to linearly spaced mel scale"},
    203323  {"get_coeffs", (PyCFunction) Py_filterbank_get_coeffs,
    204324    METH_NOARGS, "get coefficients of filterbank"},
    205325  {"set_coeffs", (PyCFunction) Py_filterbank_set_coeffs,
    206326    METH_VARARGS, "set coefficients of filterbank"},
     327  {"set_power", (PyCFunction) Py_filterbank_set_power,
     328    METH_VARARGS, "set power applied to filterbank input spectrum"},
     329  {"set_norm", (PyCFunction) Py_filterbank_set_norm,
     330    METH_VARARGS, "set norm applied to filterbank input spectrum"},
    207331  {NULL}
    208332};
  • python/ext/py-musicutils.c

    r5b46bc3 r633400d  
    134134  return level_detection;
    135135}
     136
     137PyObject *
     138Py_aubio_shift(PyObject *self, PyObject *args)
     139{
     140  PyObject *input;
     141  fvec_t vec;
     142
     143  if (!PyArg_ParseTuple (args, "O:shift", &input)) {
     144    return NULL;
     145  }
     146
     147  if (input == NULL) {
     148    return NULL;
     149  }
     150
     151  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     152    return NULL;
     153  }
     154
     155  fvec_shift(&vec);
     156
     157  //Py_RETURN_NONE;
     158  return (PyObject *) PyAubio_CFvecToArray(&vec);
     159}
     160
     161PyObject *
     162Py_aubio_ishift(PyObject *self, PyObject *args)
     163{
     164  PyObject *input;
     165  fvec_t vec;
     166
     167  if (!PyArg_ParseTuple (args, "O:shift", &input)) {
     168    return NULL;
     169  }
     170
     171  if (input == NULL) {
     172    return NULL;
     173  }
     174
     175  if (!PyAubio_ArrayToCFvec(input, &vec)) {
     176    return NULL;
     177  }
     178
     179  fvec_ishift(&vec);
     180
     181  //Py_RETURN_NONE;
     182  return (PyObject *) PyAubio_CFvecToArray(&vec);
     183}
     184
     185PyObject*
     186Py_aubio_hztomel(PyObject *self, PyObject *args, PyObject *kwds)
     187{
     188  smpl_t v;
     189  PyObject *htk = NULL;
     190  static char *kwlist[] = {"f", "htk", NULL};
     191  if (!PyArg_ParseTupleAndKeywords(args, kwds, AUBIO_NPY_SMPL_CHR "|O",
     192        kwlist, &v, &htk))
     193  {
     194    return NULL;
     195  }
     196  if (htk != NULL && PyObject_IsTrue(htk) == 1)
     197    return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_hztomel_htk(v));
     198  else
     199    return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_hztomel(v));
     200}
     201
     202PyObject*
     203Py_aubio_meltohz(PyObject *self, PyObject *args, PyObject *kwds)
     204{
     205  smpl_t v;
     206  PyObject *htk = NULL;
     207  static char *kwlist[] = {"m", "htk", NULL};
     208  if (!PyArg_ParseTupleAndKeywords(args, kwds, AUBIO_NPY_SMPL_CHR "|O",
     209        kwlist, &v, &htk))
     210  {
     211    return NULL;
     212  }
     213  if (htk != NULL && PyObject_IsTrue(htk) == 1)
     214    return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_meltohz_htk(v));
     215  else
     216    return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_meltohz(v));
     217}
     218
     219PyObject*
     220Py_aubio_hztomel_htk(PyObject *self, PyObject *args)
     221{
     222  smpl_t v;
     223  if (!PyArg_ParseTuple(args, AUBIO_NPY_SMPL_CHR, &v)) {
     224    return NULL;
     225  }
     226  return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_hztomel_htk(v));
     227}
     228
     229PyObject*
     230Py_aubio_meltohz_htk(PyObject *self, PyObject *args)
     231{
     232  smpl_t v;
     233  if (!PyArg_ParseTuple(args, AUBIO_NPY_SMPL_CHR, &v)) {
     234    return NULL;
     235  }
     236  return Py_BuildValue(AUBIO_NPY_SMPL_CHR, aubio_meltohz_htk(v));
     237}
  • python/ext/py-musicutils.h

    r5b46bc3 r633400d  
    33
    44static char Py_aubio_window_doc[] = ""
    5 "window(string, integer) -> fvec\n"
    6 "\n"
    7 "Create a window\n"
    8 "\n"
    9 "Example\n"
    10 "-------\n"
    11 "\n"
    12 ">>> window('hanningz', 1024)\n"
     5"window(window_type, size)\n"
     6"\n"
     7"Create a window of length `size`. `window_type` should be one\n"
     8"of the following:\n"
     9"\n"
     10"- `default` (same as `hanningz`).\n"
     11"- `ones`\n"
     12"- `rectangle`\n"
     13"- `hamming`\n"
     14"- `hanning`\n"
     15"- `hanningz` [1]_\n"
     16"- `blackman`\n"
     17"- `blackman_harris`\n"
     18"- `gaussian`\n"
     19"- `welch`\n"
     20"- `parzen`\n"
     21"\n"
     22"Parameters\n"
     23"----------\n"
     24"window_type : str\n"
     25"   Type of window.\n"
     26"size : int\n"
     27"   Length of window.\n"
     28"\n"
     29"Returns\n"
     30"-------\n"
     31"fvec\n"
     32"   Array of shape `(length,)` containing the new window.\n"
     33"\n"
     34"See Also\n"
     35"--------\n"
     36"pvoc, fft\n"
     37"\n"
     38"Examples\n"
     39"--------\n"
     40"Compute a zero-phase Hann window on `1024` points:\n"
     41"\n"
     42">>> aubio.window('hanningz', 1024)\n"
    1343"array([  0.00000000e+00,   9.41753387e-06,   3.76403332e-05, ...,\n"
    14 "         8.46982002e-05,   3.76403332e-05,   9.41753387e-06], dtype=float32)";
     44"         8.46982002e-05,   3.76403332e-05,   9.41753387e-06], dtype=float32)\n"
     45"\n"
     46"Plot different window types with `matplotlib <https://matplotlib.org/>`_:\n"
     47"\n"
     48">>> import matplotlib.pyplot as plt\n"
     49">>> modes = ['default', 'ones', 'rectangle', 'hamming', 'hanning',\n"
     50"...          'hanningz', 'blackman', 'blackman_harris', 'gaussian',\n"
     51"...          'welch', 'parzen']; n = 2048\n"
     52">>> for m in modes: plt.plot(aubio.window(m, n), label=m)\n"
     53"...\n"
     54">>> plt.legend(); plt.show()\n"
     55"\n"
     56"Note\n"
     57"----\n"
     58"The following examples contain the equivalent source code to compute\n"
     59"each type of window with `NumPy <https://numpy.org>`_:\n"
     60"\n"
     61">>> n = 1024; x = np.arange(n, dtype=aubio.float_type)\n"
     62">>> ones = np.ones(n).astype(aubio.float_type)\n"
     63">>> rectangle = 0.5 * ones\n"
     64">>> hanning = 0.5 - 0.5 * np.cos(2 * np.pi * x / n)\n"
     65">>> hanningz = 0.5 * (1 - np.cos(2 * np.pi * x / n))\n"
     66">>> hamming = 0.54 - 0.46 * np.cos(2.*np.pi * x / (n - 1))\n"
     67">>> blackman = 0.42 \\\n"
     68"...          - 0.50 * np.cos(2 * np.pi * x / (n - 1)) \\\n"
     69"...          + 0.08 * np.cos(4 * np.pi * x / (n - 1))\n"
     70">>> blackman_harris = 0.35875 \\\n"
     71"...       - 0.48829 * np.cos(2 * np.pi * x / (n - 1)) \\\n"
     72"...       + 0.14128 * np.cos(4 * np.pi * x / (n - 1)) \\\n"
     73"...       + 0.01168 * np.cos(6 * np.pi * x / (n - 1))\n"
     74">>> gaussian = np.exp( - 0.5 * ((x - 0.5 * (n - 1)) \\\n"
     75"...                            / (0.25 * (n - 1)) )**2 )\n"
     76">>> welch = 1 - ((2 * x - n) / (n + 1))**2\n"
     77">>> parzen = 1 - np.abs((2 * x - n) / (n + 1))\n"
     78">>> default = hanningz\n"
     79"References\n"
     80"----------\n"
     81#if 0
     82"`Window function <https://en.wikipedia.org/wiki/Window_function>`_ on\n"
     83"Wikipedia.\n"
     84"\n"
     85#endif
     86".. [1] Amalia de Götzen, Nicolas Bernardini, and Daniel Arfib. Traditional\n"
     87"   (?) implementations of a phase vocoder: the tricks of the trade.\n"
     88"   In *Proceedings of the International Conference on Digital Audio\n"
     89"   Effects* (DAFx-00), pages 37–44, University of Verona, Italy, 2000.\n"
     90"   (`online version <"
     91"https://www.cs.princeton.edu/courses/archive/spr09/cos325/Bernardini.pdf"
     92">`_).\n"
     93"";
    1594
    1695PyObject * Py_aubio_window(PyObject *self, PyObject *args);
    1796
    1897static char Py_aubio_level_lin_doc[] = ""
    19 "level_lin(fvec) -> fvec\n"
    20 "\n"
    21 "Compute sound level on a linear scale.\n"
    22 "\n"
    23 "This gives the average of the square amplitudes.\n"
    24 "\n"
    25 "Example\n"
    26 "-------\n"
    27 "\n"
    28 ">>> level_Lin(numpy.ones(1024))\n"
    29 "1.0";
     98"level_lin(x)\n"
     99"\n"
     100"Compute sound pressure level of `x`, on a linear scale.\n"
     101"\n"
     102"Parameters\n"
     103"----------\n"
     104"x : fvec\n"
     105"   input vector\n"
     106"\n"
     107"Returns\n"
     108"-------\n"
     109"float\n"
     110"   Linear level of `x`.\n"
     111"\n"
     112"Example\n"
     113"-------\n"
     114"\n"
     115">>> aubio.level_lin(aubio.fvec(numpy.ones(1024)))\n"
     116"1.0\n"
     117"\n"
     118"Note\n"
     119"----\n"
     120"Computed as the average of the squared amplitudes:\n"
     121"\n"
     122".. math:: L = \\frac {\\sum_{n=0}^{N-1} {x_n}^2} {N}\n"
     123"\n"
     124"See Also\n"
     125"--------\n"
     126"db_spl, silence_detection, level_detection\n"
     127"";
    30128
    31129PyObject * Py_aubio_level_lin(PyObject *self, PyObject *args);
    32130
    33131static char Py_aubio_db_spl_doc[] = ""
    34 "Compute sound pressure level (SPL) in dB\n"
    35 "\n"
    36 "This quantity is often wrongly called 'loudness'.\n"
    37 "\n"
    38 "This gives ten times the log10 of the average of the square amplitudes.\n"
    39 "\n"
    40 "Example\n"
    41 "-------\n"
    42 "\n"
    43 ">>> db_spl(numpy.ones(1024))\n"
    44 "1.0";
     132"db_spl(x)\n"
     133"\n"
     134"Compute Sound Pressure Level (SPL) of `x`, in dB.\n"
     135"\n"
     136"Parameters\n"
     137"----------\n"
     138"x : fvec\n"
     139"   input vector\n"
     140"\n"
     141"Returns\n"
     142"-------\n"
     143"float\n"
     144"   Level of `x`, in dB SPL.\n"
     145"\n"
     146"Example\n"
     147"-------\n"
     148"\n"
     149">>> aubio.db_spl(aubio.fvec(np.ones(1024)))\n"
     150"1.0\n"
     151">>> aubio.db_spl(0.7*aubio.fvec(np.ones(32)))\n"
     152"-3.098040819168091\n"
     153"\n"
     154"Note\n"
     155"----\n"
     156"Computed as `log10` of :py:func:`level_lin`:\n"
     157"\n"
     158".. math::\n"
     159"\n"
     160"   {SPL}_{dB} = log10{\\frac {\\sum_{n=0}^{N-1}{x_n}^2} {N}}\n"
     161"\n"
     162"This quantity is often incorrectly called 'loudness'.\n"
     163"\n"
     164"See Also\n"
     165"--------\n"
     166"level_lin, silence_detection, level_detection\n"
     167"";
    45168
    46169PyObject * Py_aubio_db_spl(PyObject *self, PyObject *args);
    47170
    48171static char Py_aubio_silence_detection_doc[] = ""
    49 "Check if buffer level in dB SPL is under a given threshold\n"
    50 "\n"
    51 "Return 0 if level is under the given threshold, 1 otherwise.\n"
    52 "\n"
    53 "Example\n"
    54 "-------\n"
    55 "\n"
    56 ">>> import numpy\n"""
    57 ">>> silence_detection(numpy.ones(1024, dtype=\"float32\"), -80)\n"
    58 "0";
     172"silence_detection(vec, level)\n"
     173"\n"
     174"Check if level of `vec`, in dB SPL, is under a given threshold.\n"
     175"\n"
     176"Parameters\n"
     177"----------\n"
     178"vec : fvec\n"
     179"   input vector\n"
     180"level : float\n"
     181"   level threshold, in dB SPL\n"
     182"\n"
     183"Returns\n"
     184"-------\n"
     185"int\n"
     186"   `1` if level of `vec`, in dB SPL, is under `level`,\n"
     187"   `0` otherwise.\n"
     188"\n"
     189"Examples\n"
     190"--------\n"
     191"\n"
     192">>> aubio.silence_detection(aubio.fvec(32), -100.)\n"
     193"1\n"
     194">>> aubio.silence_detection(aubio.fvec(np.ones(32)), 0.)\n"
     195"0\n"
     196"\n"
     197"See Also\n"
     198"--------\n"
     199"level_detection, db_spl, level_lin\n"
     200"";
    59201
    60202PyObject * Py_aubio_silence_detection(PyObject *self, PyObject *args);
    61203
    62204static char Py_aubio_level_detection_doc[] = ""
    63 "Get buffer level in dB SPL if over a given threshold, 1. otherwise.\n"
    64 "\n"
    65 "Example\n"
    66 "-------\n"
    67 "\n"
    68 ">>> import numpy\n"""
    69 ">>> level_detection(0.7*numpy.ones(1024, dtype=\"float32\"), -80)\n"
    70 "0";
     205"level_detection(vec, level)\n"
     206"\n"
     207"Check if `vec` is above threshold `level`, in dB SPL.\n"
     208"\n"
     209"Parameters\n"
     210"----------\n"
     211"vec : fvec\n"
     212"   input vector\n"
     213"level : float\n"
     214"   level threshold, in dB SPL\n"
     215"\n"
     216"Returns\n"
     217"-------\n"
     218"float\n"
     219"   `1.0` if level of `vec` in dB SPL is under `level`,\n"
     220"   `db_spl(vec)` otherwise.\n"
     221"\n"
     222"Example\n"
     223"-------\n"
     224"\n"
     225">>> aubio.level_detection(0.7*aubio.fvec(np.ones(1024)), -3.)\n"
     226"1.0\n"
     227">>> aubio.level_detection(0.7*aubio.fvec(np.ones(1024)), -4.)\n"
     228"-3.0980708599090576\n"
     229"\n"
     230"See Also\n"
     231"--------\n"
     232"silence_detection, db_spl, level_lin\n"
     233"";
    71234
    72235PyObject * Py_aubio_level_detection(PyObject *self, PyObject *args);
    73236
     237static char Py_aubio_shift_doc[] = ""
     238"shift(vec)\n"
     239"\n"
     240"Swap left and right partitions of a vector, in-place.\n"
     241"\n"
     242"Parameters\n"
     243"----------\n"
     244"vec : fvec\n"
     245"   input vector to shift\n"
     246"\n"
     247"Returns\n"
     248"-------\n"
     249"fvec\n"
     250"   The swapped vector.\n"
     251"\n"
     252"Notes\n"
     253"-----\n"
     254"The input vector is also modified.\n"
     255"\n"
     256"For a vector of length N, the partition is split at index N - N//2.\n"
     257"\n"
     258"Example\n"
     259"-------\n"
     260"\n"
     261">>> aubio.shift(aubio.fvec(np.arange(3)))\n"
     262"array([2., 0., 1.], dtype=" AUBIO_NPY_SMPL_STR ")\n"
     263"\n"
     264"See Also\n"
     265"--------\n"
     266"ishift\n"
     267"";
     268PyObject * Py_aubio_shift(PyObject *self, PyObject *args);
     269
     270static char Py_aubio_ishift_doc[] = ""
     271"ishift(vec)\n"
     272"\n"
     273"Swap right and left partitions of a vector, in-place.\n"
     274"\n"
     275"Parameters\n"
     276"----------\n"
     277"vec : fvec\n"
     278"   input vector to shift\n"
     279"\n"
     280"Returns\n"
     281"-------\n"
     282"fvec\n"
     283"   The swapped vector.\n"
     284"\n"
     285"Notes\n"
     286"-----\n"
     287"The input vector is also modified.\n"
     288"\n"
     289"Unlike with :py:func:`shift`, the partition is split at index N//2.\n"
     290"\n"
     291"Example\n"
     292"-------\n"
     293"\n"
     294">>> aubio.ishift(aubio.fvec(np.arange(3)))\n"
     295"array([1., 2., 0.], dtype=" AUBIO_NPY_SMPL_STR ")\n"
     296"\n"
     297"See Also\n"
     298"--------\n"
     299"shift\n"
     300"";
     301PyObject * Py_aubio_ishift(PyObject *self, PyObject *args);
     302
     303static char Py_aubio_hztomel_doc[] = ""
     304"hztomel(f, htk=False)\n"
     305"\n"
     306"Convert a scalar from frequency to mel scale.\n"
     307"\n"
     308"Parameters\n"
     309"----------\n"
     310"m : float\n"
     311"   input frequency, in Hz\n"
     312"htk : bool\n"
     313"   if `True`, use Htk mel scale instead of Slaney.\n"
     314"\n"
     315"Returns\n"
     316"-------\n"
     317"float\n"
     318"   output mel\n"
     319"\n"
     320"See Also\n"
     321"--------\n"
     322"meltohz\n"
     323"";
     324PyObject * Py_aubio_hztomel(PyObject *self, PyObject *args);
     325
     326static char Py_aubio_meltohz_doc[] = ""
     327"meltohz(m, htk=False)\n"
     328"\n"
     329"Convert a scalar from mel scale to frequency.\n"
     330"\n"
     331"Parameters\n"
     332"----------\n"
     333"m : float\n"
     334"   input mel\n"
     335"htk : bool\n"
     336"   if `True`, use Htk mel scale instead of Slaney.\n"
     337"\n"
     338"Returns\n"
     339"-------\n"
     340"float\n"
     341"   output frequency, in Hz\n"
     342"\n"
     343"See Also\n"
     344"--------\n"
     345"hztomel\n"
     346"";
     347PyObject * Py_aubio_meltohz(PyObject *self, PyObject *args);
     348
     349static char Py_aubio_hztomel_htk_doc[] = ""
     350"hztomel_htk(m)\n"
     351"\n"
     352"Same as `hztomel(m, htk=True)`\n"
     353"\n"
     354"See Also\n"
     355"--------\n"
     356"hztomel\n"
     357"";
     358PyObject * Py_aubio_hztomel_htk(PyObject *self, PyObject *args);
     359
     360static char Py_aubio_meltohz_htk_doc[] = ""
     361"meltohz_htk(m)\n"
     362"\n"
     363"Same as `meltohz(m, htk=True)`\n"
     364"\n"
     365"See Also\n"
     366"--------\n"
     367"meltohz\n"
     368"";
     369PyObject * Py_aubio_meltohz_htk(PyObject *self, PyObject *args);
     370
    74371#endif /* PY_AUBIO_MUSICUTILS_H */
  • python/ext/py-phasevoc.c

    r5b46bc3 r633400d  
    11#include "aubio-types.h"
    22
    3 static char Py_pvoc_doc[] = "pvoc object";
     3static char Py_pvoc_doc[] = ""
     4"pvoc(win_s=512, hop_s=256)\n"
     5"\n"
     6"Phase vocoder.\n"
     7"\n"
     8"`pvoc` creates callable object implements a phase vocoder [1]_,\n"
     9"using the tricks detailed in [2]_.\n"
     10"\n"
     11"The call function takes one input of type `fvec` and of size\n"
     12"`hop_s`, and returns a `cvec` of length `win_s//2+1`.\n"
     13"\n"
     14"Parameters\n"
     15"----------\n"
     16"win_s : int\n"
     17"  number of channels in the phase-vocoder.\n"
     18"hop_s : int\n"
     19"  number of samples expected between each call\n"
     20"\n"
     21"Examples\n"
     22"--------\n"
     23">>> x = aubio.fvec(256)\n"
     24">>> pv = aubio.pvoc(512, 256)\n"
     25">>> pv(x)\n"
     26"aubio cvec of 257 elements\n"
     27"\n"
     28"Default values for hop_s and win_s are provided:\n"
     29"\n"
     30">>> pv = aubio.pvoc()\n"
     31">>> pv.win_s, pv.hop_s\n"
     32"512, 256\n"
     33"\n"
     34"A `cvec` can be resynthesised using `rdo()`:\n"
     35"\n"
     36">>> pv = aubio.pvoc(512, 256)\n"
     37">>> y = aubio.cvec(512)\n"
     38">>> x_reconstructed = pv.rdo(y)\n"
     39">>> x_reconstructed.shape\n"
     40"(256,)\n"
     41"\n"
     42"References\n"
     43"----------\n"
     44".. [1] James A. Moorer. The use of the phase vocoder in computer music\n"
     45"   applications. `Journal of the Audio Engineering Society`,\n"
     46"   26(1/2):42–45, 1978.\n"
     47".. [2] Amalia de Götzen, Nicolas Bernardini, and Daniel Arfib. Traditional\n"
     48"   (?) implementations of a phase vocoder: the tricks of the trade.\n"
     49"   In `Proceedings of the International Conference on Digital Audio\n"
     50"   Effects` (DAFx-00), pages 37–44, University of Verona, Italy, 2000.\n"
     51"   (`online version <"
     52"https://www.cs.princeton.edu/courses/archive/spr09/cos325/Bernardini.pdf"
     53">`_).\n"
     54"";
     55
    456
    557typedef struct
     
    3991  self->hop_s = Py_default_vector_length/2;
    4092
    41   if (self == NULL) {
    42     return NULL;
    43   }
    44 
    4593  if (win_s > 0) {
    4694    self->win_s = win_s;
     
    122170static PyMemberDef Py_pvoc_members[] = {
    123171  {"win_s", T_INT, offsetof (Py_pvoc, win_s), READONLY,
    124     "size of the window"},
     172    "int: Size of phase vocoder analysis windows, in samples.\n"
     173    ""},
    125174  {"hop_s", T_INT, offsetof (Py_pvoc, hop_s), READONLY,
    126     "size of the hop"},
     175    "int: Interval between two analysis, in samples.\n"
     176    ""},
    127177  { NULL } // sentinel
    128178};
     
    156206}
    157207
     208static PyObject *
     209Pyaubio_pvoc_set_window (Py_pvoc *self, PyObject *args)
     210{
     211  uint_t err = 0;
     212  char_t *window = NULL;
     213
     214  if (!PyArg_ParseTuple (args, "s", &window)) {
     215    return NULL;
     216  }
     217  err = aubio_pvoc_set_window (self->o, window);
     218
     219  if (err > 0) {
     220    PyErr_SetString (PyExc_ValueError, "error running aubio_pvoc_set_window");
     221    return NULL;
     222  }
     223  Py_RETURN_NONE;
     224}
     225
    158226static PyMethodDef Py_pvoc_methods[] = {
    159227  {"rdo", (PyCFunction) Py_pvoc_rdo, METH_VARARGS,
    160     "synthesis of spectral grain"},
     228    "rdo(fftgrain)\n"
     229    "\n"
     230    "Read a new spectral grain and resynthesise the next `hop_s`\n"
     231    "output samples.\n"
     232    "\n"
     233    "Parameters\n"
     234    "----------\n"
     235    "fftgrain : cvec\n"
     236    "    new input `cvec` to synthesize from, should be of size `win_s/2+1`\n"
     237    "\n"
     238    "Returns\n"
     239    "-------\n"
     240    "fvec\n"
     241    "    re-synthesised output of shape `(hop_s,)`\n"
     242    "\n"
     243    "Example\n"
     244    "-------\n"
     245    ">>> pv = aubio.pvoc(2048, 512)\n"
     246    ">>> out = pv.rdo(aubio.cvec(2048))\n"
     247    ">>> out.shape\n"
     248    "(512,)\n"
     249    ""},
     250  {"set_window", (PyCFunction) Pyaubio_pvoc_set_window, METH_VARARGS,
     251    "set_window(window_type)\n"
     252    "\n"
     253    "Set window function\n"
     254    "\n"
     255    "Parameters\n"
     256    "----------\n"
     257    "window_type : str\n"
     258    "    the window type to use for this phase vocoder\n"
     259    "\n"
     260    "Raises\n"
     261    "------\n"
     262    "ValueError\n"
     263    "    If an unknown window type was given.\n"
     264    "\n"
     265    "See Also\n"
     266    "--------\n"
     267    "window : create a window.\n"
     268    ""},
    161269  {NULL}
    162270};
  • python/ext/py-sink.c

    r5b46bc3 r633400d  
    1313
    1414static char Py_sink_doc[] = ""
    15 "  __new__(path, samplerate = 44100, channels = 1)\n"
    16 "\n"
    17 "      Create a new sink, opening the given path for writing.\n"
    18 "\n"
    19 "      Examples\n"
    20 "      --------\n"
    21 "\n"
    22 "      Create a new sink at 44100Hz, mono:\n"
    23 "\n"
    24 "      >>> sink('/tmp/t.wav')\n"
    25 "\n"
    26 "      Create a new sink at 8000Hz, mono:\n"
    27 "\n"
    28 "      >>> sink('/tmp/t.wav', samplerate = 8000)\n"
    29 "\n"
    30 "      Create a new sink at 32000Hz, stereo:\n"
    31 "\n"
    32 "      >>> sink('/tmp/t.wav', samplerate = 32000, channels = 2)\n"
    33 "\n"
    34 "      Create a new sink at 32000Hz, 5 channels:\n"
    35 "\n"
    36 "      >>> sink('/tmp/t.wav', channels = 5, samplerate = 32000)\n"
    37 "\n"
    38 "  __call__(vec, write)\n"
    39 "      x(vec,write) <==> x.do(vec, write)\n"
    40 "\n"
    41 "      Write vector to sink.\n"
    42 "\n"
    43 "      See also\n"
    44 "      --------\n"
    45 "      aubio.sink.do\n"
     15"sink(path, samplerate=44100, channels=1)\n"
     16"\n"
     17"Write audio samples to file.\n"
     18"\n"
     19"Parameters\n"
     20"----------\n"
     21"path : str\n"
     22"   Pathname of the file to be opened for writing.\n"
     23"samplerate : int\n"
     24"   Sampling rate of the file, in Hz.\n"
     25"channels : int\n"
     26"   Number of channels to create the file with.\n"
     27"\n"
     28"Examples\n"
     29"--------\n"
     30"\n"
     31"Create a new sink at 44100Hz, mono:\n"
     32"\n"
     33">>> snk = aubio.sink('out.wav')\n"
     34"\n"
     35"Create a new sink at 32000Hz, stereo, write 100 samples into it:\n"
     36"\n"
     37">>> snk = aubio.sink('out.wav', samplerate=16000, channels=3)\n"
     38">>> snk(aubio.fvec(100), 100)\n"
     39"\n"
     40"Open a new sink at 48000Hz, stereo, write `1234` samples into it:\n"
     41"\n"
     42">>> with aubio.sink('out.wav', samplerate=48000, channels=2) as src:\n"
     43"...     snk(aubio.fvec(1024), 1024)\n"
     44"...     snk(aubio.fvec(210), 210)\n"
     45"...\n"
     46"\n"
     47"See also\n"
     48"--------\n"
     49"source: read audio samples from a file.\n"
    4650"\n";
    4751
    4852static char Py_sink_do_doc[] = ""
    49 "x.do(vec, write) <==> x(vec, write)\n"
    50 "\n"
    51 "write monophonic vector to sink";
     53"do(vec, write)\n"
     54"\n"
     55"Write a single channel vector to sink.\n"
     56"\n"
     57"Parameters\n"
     58"----------\n"
     59"vec : fvec\n"
     60"   input vector `(n,)` where `n >= 0`.\n"
     61"write : int\n"
     62"   Number of samples to write.\n"
     63"";
    5264
    5365static char Py_sink_do_multi_doc[] = ""
    54 "x.do_multi(mat, write)\n"
    55 "\n"
    56 "write polyphonic vector to sink";
     66"do_multi(mat, write)\n"
     67"\n"
     68"Write a matrix containing vectors from multiple channels to sink.\n"
     69"\n"
     70"Parameters\n"
     71"----------\n"
     72"mat : numpy.ndarray\n"
     73"   input matrix of shape `(channels, n)`, where `n >= 0`.\n"
     74"write : int\n"
     75"   Number of frames to write.\n"
     76"";
    5777
    5878static char Py_sink_close_doc[] = ""
    59 "x.close()\n"
    60 "\n"
    61 "close this sink now";
     79"close()\n"
     80"\n"
     81"Close this sink now.\n"
     82"\n"
     83"By default, the sink will be closed before being deleted.\n"
     84"Explicitely closing a sink can be useful to control the number\n"
     85"of files simultaneously opened.\n"
     86"";
    6287
    6388static PyObject *
     
    81106  }
    82107
    83   self->uri = "none";
     108  self->uri = NULL;
    84109  if (uri != NULL) {
    85     self->uri = uri;
     110    self->uri = (char_t *)malloc(sizeof(char_t) * (strnlen(uri, PATH_MAX) + 1));
     111    strncpy(self->uri, uri, strnlen(uri, PATH_MAX) + 1);
    86112  }
    87113
    88114  self->samplerate = Py_aubio_default_samplerate;
    89   if ((sint_t)samplerate > 0) {
     115  if (samplerate != 0) {
    90116    self->samplerate = samplerate;
    91   } else if ((sint_t)samplerate < 0) {
    92     PyErr_SetString (PyExc_ValueError,
    93         "can not use negative value for samplerate");
    94     return NULL;
    95117  }
    96118
    97119  self->channels = 1;
    98   if ((sint_t)channels > 0) {
     120  if (channels != 0) {
    99121    self->channels = channels;
    100   } else if ((sint_t)channels < 0) {
    101     PyErr_SetString (PyExc_ValueError,
    102         "can not use negative or null value for channels");
    103     return NULL;
    104122  }
    105123
     
    110128Py_sink_init (Py_sink * self, PyObject * args, PyObject * kwds)
    111129{
    112   if (self->channels == 1) {
    113     self->o = new_aubio_sink ( self->uri, self->samplerate );
    114   } else {
    115     self->o = new_aubio_sink ( self->uri, 0 );
    116     aubio_sink_preset_channels ( self->o, self->channels );
    117     aubio_sink_preset_samplerate ( self->o, self->samplerate );
    118   }
     130  self->o = new_aubio_sink ( self->uri, 0 );
    119131  if (self->o == NULL) {
    120     PyErr_SetString (PyExc_RuntimeError, "error creating sink with this uri");
     132    // error string was set in new_aubio_sink
    121133    return -1;
    122134  }
     135  if (aubio_sink_preset_channels(self->o, self->channels) != 0) {
     136    // error string was set in aubio_sink_preset_channels
     137    return -1;
     138  }
     139  if (aubio_sink_preset_samplerate(self->o, self->samplerate) != 0) {
     140    // error string was set in aubio_sink_preset_samplerate
     141    return -1;
     142  }
     143
    123144  self->samplerate = aubio_sink_get_samplerate ( self->o );
    124145  self->channels = aubio_sink_get_channels ( self->o );
     
    132153  del_aubio_sink(self->o);
    133154  free(self->mwrite_data.data);
     155  if (self->uri) {
     156    free(self->uri);
     157  }
    134158  Py_TYPE(self)->tp_free((PyObject *) self);
    135159}
     
    190214static PyMemberDef Py_sink_members[] = {
    191215  {"uri", T_STRING, offsetof (Py_sink, uri), READONLY,
    192     "path at which the sink was created"},
     216    "str (read-only): Path at which the sink was created."},
    193217  {"samplerate", T_INT, offsetof (Py_sink, samplerate), READONLY,
    194     "samplerate at which the sink was created"},
     218    "int (read-only): Samplerate at which the sink was created."},
    195219  {"channels", T_INT, offsetof (Py_sink, channels), READONLY,
    196     "number of channels with which the sink was created"},
     220    "int (read-only): Number of channels with which the sink was created."},
    197221  { NULL } // sentinel
    198222};
     
    203227  aubio_sink_close (self->o);
    204228  Py_RETURN_NONE;
     229}
     230
     231static char Pyaubio_sink_enter_doc[] = "";
     232static PyObject* Pyaubio_sink_enter(Py_sink *self, PyObject *unused) {
     233  Py_INCREF(self);
     234  return (PyObject*)self;
     235}
     236
     237static char Pyaubio_sink_exit_doc[] = "";
     238static PyObject* Pyaubio_sink_exit(Py_sink *self, PyObject *unused) {
     239  return Pyaubio_sink_close(self, unused);
    205240}
    206241
     
    209244  {"do_multi", (PyCFunction) Py_sink_do_multi, METH_VARARGS, Py_sink_do_multi_doc},
    210245  {"close", (PyCFunction) Pyaubio_sink_close, METH_NOARGS, Py_sink_close_doc},
     246  {"__enter__", (PyCFunction)Pyaubio_sink_enter, METH_NOARGS,
     247    Pyaubio_sink_enter_doc},
     248  {"__exit__",  (PyCFunction)Pyaubio_sink_exit, METH_VARARGS,
     249    Pyaubio_sink_exit_doc},
    211250  {NULL} /* sentinel */
    212251};
  • python/ext/py-source.c

    r5b46bc3 r633400d  
    1717
    1818static char Py_source_doc[] = ""
    19 "   __new__(path, samplerate = 0, hop_size = 512, channels = 1)\n"
    20 "\n"
    21 "       Create a new source, opening the given path for reading.\n"
    22 "\n"
    23 "       Examples\n"
    24 "       --------\n"
    25 "\n"
    26 "       Create a new source, using the original samplerate, with hop_size = 512:\n"
    27 "\n"
    28 "       >>> source('/tmp/t.wav')\n"
    29 "\n"
    30 "       Create a new source, resampling the original to 8000Hz:\n"
    31 "\n"
    32 "       >>> source('/tmp/t.wav', samplerate = 8000)\n"
    33 "\n"
    34 "       Create a new source, resampling it at 32000Hz, hop_size = 32:\n"
    35 "\n"
    36 "       >>> source('/tmp/t.wav', samplerate = 32000, hop_size = 32)\n"
    37 "\n"
    38 "       Create a new source, using its original samplerate:\n"
    39 "\n"
    40 "       >>> source('/tmp/t.wav', samplerate = 0)\n"
    41 "\n"
    42 "   __call__()\n"
    43 "       vec, read = x() <==> vec, read = x.do()\n"
    44 "\n"
    45 "       Read vector from source.\n"
    46 "\n"
    47 "       See also\n"
    48 "       --------\n"
    49 "       aubio.source.do\n"
    50 "\n";
     19"source(path, samplerate=0, hop_size=512, channels=0)\n"
     20"\n"
     21"Read audio samples from a media file.\n"
     22"\n"
     23"`source` open the file specified in `path` and creates a callable\n"
     24"returning `hop_size` new audio samples at each invocation.\n"
     25"\n"
     26"If `samplerate=0` (default), the original sampling rate of `path`\n"
     27"will be used. Otherwise, the output audio samples will be\n"
     28"resampled at the desired sampling-rate.\n"
     29"\n"
     30"If `channels=0` (default), the original number of channels\n"
     31"in `path` will be used. Otherwise, the output audio samples\n"
     32"will be down-mixed or up-mixed to the desired number of\n"
     33"channels.\n"
     34"\n"
     35"If `path` is a URL, a remote connection will be attempted to\n"
     36"open the resource and stream data from it.\n"
     37"\n"
     38"The parameter `hop_size` determines how many samples should be\n"
     39"read at each consecutive calls.\n"
     40"\n"
     41"Parameters\n"
     42"----------\n"
     43"path : str\n"
     44"   pathname (or URL) of the file to be opened for reading\n"
     45"samplerate : int, optional\n"
     46"   sampling rate of the file\n"
     47"hop_size : int, optional\n"
     48"   number of samples to be read per iteration\n"
     49"channels : int, optional\n"
     50"   number of channels of the file\n"
     51"\n"
     52"Examples\n"
     53"--------\n"
     54"By default, when only `path` is given, the file will be opened\n"
     55"with its original sampling rate and channel:\n"
     56"\n"
     57">>> src = aubio.source('stereo.wav')\n"
     58">>> src.uri, src.samplerate, src.channels, src.duration\n"
     59"('stereo.wav', 48000, 2, 86833)\n"
     60"\n"
     61"A typical loop to read all samples from a local file could\n"
     62"look like this:\n"
     63"\n"
     64">>> src = aubio.source('stereo.wav')\n"
     65">>> total_read = 0\n"
     66">>> while True:\n"
     67"...     samples, read = src()\n"
     68"...     # do something with samples\n"
     69"...     total_read += read\n"
     70"...     if read < src.hop_size:\n"
     71"...         break\n"
     72"...\n"
     73"\n"
     74"In a more Pythonic way, it can also look like this:\n"
     75"\n"
     76">>> total_read = 0\n"
     77">>> with aubio.source('stereo.wav') as src:\n"
     78"...     for frames in src:\n"
     79"...         total_read += samples.shape[-1]\n"
     80"...\n"
     81"\n"
     82".. rubric:: Basic interface\n"
     83"\n"
     84"`source` is a **callable**; its :meth:`__call__` method\n"
     85"returns a tuple containing:\n"
     86"\n"
     87"- a vector of shape `(hop_size,)`, filled with the `read` next\n"
     88"  samples available, zero-padded if `read < hop_size`\n"
     89"- `read`, an integer indicating the number of samples read\n"
     90"\n"
     91"To read the first `hop_size` samples from the source, simply call\n"
     92"the instance itself, with no argument:\n"
     93"\n"
     94">>> src = aubio.source('song.ogg')\n"
     95">>> samples, read = src()\n"
     96">>> samples.shape, read, src.hop_size\n"
     97"((512,), 512, 512)\n"
     98"\n"
     99"The first call returned the slice of samples `[0 : hop_size]`.\n"
     100"The next call will return samples `[hop_size: 2*hop_size]`.\n"
     101"\n"
     102"After several invocations of :meth:`__call__`, when reaching the end\n"
     103"of the opened stream, `read` might become less than `hop_size`:\n"
     104"\n"
     105">>> samples, read = src()\n"
     106">>> samples.shape, read\n"
     107"((512,), 354)\n"
     108"\n"
     109"The end of the vector `samples` is filled with zeros.\n"
     110"\n"
     111"After the end of the stream, `read` will be `0` since no more\n"
     112"samples are available:\n"
     113"\n"
     114">>> samples, read = src()\n"
     115">>> samples.shape, read\n"
     116"((512,), 0)\n"
     117"\n"
     118"**Note**: when the source has more than one channels, they\n"
     119"are be down-mixed to mono when invoking :meth:`__call__`.\n"
     120"To read from each individual channel, see :meth:`__next__`.\n"
     121"\n"
     122".. rubric:: ``for`` statements\n"
     123"\n"
     124"The `source` objects are **iterables**. This allows using them\n"
     125"directly in a ``for`` loop, which calls :meth:`__next__` until\n"
     126"the end of the stream is reached:\n"
     127"\n"
     128">>> src = aubio.source('stereo.wav')\n"
     129">>> for frames in src:\n"
     130">>>     print (frames.shape)\n"
     131"...\n"
     132"(2, 512)\n"
     133"(2, 512)\n"
     134"(2, 230)\n"
     135"\n"
     136"**Note**: When `next(self)` is called on a source with multiple\n"
     137"channels, an array of shape `(channels, read)` is returned,\n"
     138"unlike with :meth:`__call__` which always returns the down-mixed\n"
     139"channels.\n"
     140"\n"
     141"If the file is opened with a single channel, `next(self)` returns\n"
     142"an array of shape `(read,)`:\n"
     143"\n"
     144">>> src = aubio.source('stereo.wav', channels=1)\n"
     145">>> next(src).shape\n"
     146"(512,)\n"
     147"\n"
     148".. rubric:: ``with`` statements\n"
     149"\n"
     150"The `source` objects are **context managers**, which allows using\n"
     151"them in ``with`` statements:\n"
     152"\n"
     153">>> with aubio.source('audiotrack.wav') as source:\n"
     154"...     n_frames=0\n"
     155"...     for samples in source:\n"
     156"...         n_frames += len(samples)\n"
     157"...     print('read', n_frames, 'samples in', samples.shape[0], 'channels',\n"
     158"...         'from file \"%%s\"' %% source.uri)\n"
     159"...\n"
     160"read 239334 samples in 2 channels from file \"audiotrack.wav\"\n"
     161"\n"
     162"The file will be closed before exiting the statement.\n"
     163"\n"
     164"See also the methods implementing the context manager,\n"
     165":meth:`__enter__` and :meth:`__exit__`.\n"
     166"\n"
     167".. rubric:: Seeking and closing\n"
     168"\n"
     169"At any time, :meth:`seek` can be used to move to any position in\n"
     170"the file. For instance, to rewind to the start of the stream:\n"
     171"\n"
     172">>> src.seek(0)\n"
     173"\n"
     174"The opened file will be automatically closed when the object falls\n"
     175"out of scope and is scheduled for garbage collection.\n"
     176"\n"
     177"In some cases, it is useful to manually :meth:`close` a given source,\n"
     178"for instance to limit the number of simultaneously opened files:\n"
     179"\n"
     180">>> src.close()\n"
     181"\n"
     182".. rubric:: Input formats\n"
     183"\n"
     184"Depending on how aubio was compiled, :class:`source` may or may not\n"
     185"open certain **files format**. Below are some examples that assume\n"
     186"support for compressed files and remote urls was compiled in:\n"
     187"\n"
     188"- open a local file using its original sampling rate and channels,\n"
     189"  and with the default hop size:\n"
     190"\n"
     191">>> s = aubio.source('sample.wav')\n"
     192">>> s.uri, s.samplerate, s.channels, s.hop_size\n"
     193"('sample.wav', 44100, 2, 512)\n"
     194"\n"
     195"- open a local compressed audio file, resampling to 32000Hz if needed:\n"
     196"\n"
     197">>> s = aubio.source('song.mp3', samplerate=32000)\n"
     198">>> s.uri, s.samplerate, s.channels, s.hop_size\n"
     199"('song.mp3', 32000, 2, 512)\n"
     200"\n"
     201"- open a local video file, down-mixing and resampling it to 16kHz:\n"
     202"\n"
     203">>> s = aubio.source('movie.mp4', samplerate=16000, channels=1)\n"
     204">>> s.uri, s.samplerate, s.channels, s.hop_size\n"
     205"('movie.mp4', 16000, 1, 512)\n"
     206"\n"
     207"- open a remote resource, with hop_size = 1024:\n"
     208"\n"
     209">>> s = aubio.source('https://aubio.org/drum.ogg', hop_size=1024)\n"
     210">>> s.uri, s.samplerate, s.channels, s.hop_size\n"
     211"('https://aubio.org/drum.ogg', 48000, 2, 1024)\n"
     212"\n"
     213"See Also\n"
     214"--------\n"
     215"sink: write audio samples to a file.\n"
     216"";
    51217
    52218static char Py_source_get_samplerate_doc[] = ""
    53 "x.get_samplerate() -> source samplerate\n"
    54 "\n"
    55 "Get samplerate of source.";
     219"get_samplerate()\n"
     220"\n"
     221"Get sampling rate of source.\n"
     222"\n"
     223"Returns\n"
     224"-------\n"
     225"int\n"
     226"    Sampling rate, in Hz.\n"
     227"";
    56228
    57229static char Py_source_get_channels_doc[] = ""
    58 "x.get_channels() -> number of channels\n"
    59 "\n"
    60 "Get number of channels in source.";
     230"get_channels()\n"
     231"\n"
     232"Get number of channels in source.\n"
     233"\n"
     234"Returns\n"
     235"-------\n"
     236"int\n"
     237"    Number of channels.\n"
     238"";
    61239
    62240static char Py_source_do_doc[] = ""
    63 "vec, read = x.do() <==> vec, read = x()\n"
    64 "\n"
    65 "Read monophonic vector from source.";
     241"source.do()\n"
     242"\n"
     243"Read vector of audio samples.\n"
     244"\n"
     245"If the audio stream in the source has more than one channel,\n"
     246"the channels will be down-mixed.\n"
     247"\n"
     248"Returns\n"
     249"-------\n"
     250"samples : numpy.ndarray\n"
     251"    `fvec` of size `hop_size` containing the new samples.\n"
     252"read : int\n"
     253"    Number of samples read from the source, equals to `hop_size`\n"
     254"    before the end-of-file is reached, less when it is reached,\n"
     255"    and `0` after.\n"
     256"\n"
     257"See Also\n"
     258"--------\n"
     259"do_multi\n"
     260"\n"
     261"Examples\n"
     262"--------\n"
     263">>> src = aubio.source('sample.wav', hop_size=1024)\n"
     264">>> src.do()\n"
     265"(array([-0.00123001, -0.00036685,  0.00097106, ..., -0.2031033 ,\n"
     266"       -0.2025854 , -0.20221856], dtype=" AUBIO_NPY_SMPL_STR "), 1024)\n"
     267"";
    66268
    67269static char Py_source_do_multi_doc[] = ""
    68 "mat, read = x.do_multi()\n"
    69 "\n"
    70 "Read polyphonic vector from source.";
     270"do_multi()\n"
     271"\n"
     272"Read multiple channels of audio samples.\n"
     273"\n"
     274"If the source was opened with the same number of channels\n"
     275"found in the stream, each channel will be read individually.\n"
     276"\n"
     277"If the source was opened with less channels than the number\n"
     278"of channels in the stream, only the first channels will be read.\n"
     279"\n"
     280"If the source was opened with more channels than the number\n"
     281"of channel in the original stream, the first channels will\n"
     282"be duplicated on the additional output channel.\n"
     283"\n"
     284"Returns\n"
     285"-------\n"
     286"samples : numpy.ndarray\n"
     287"    NumPy array of shape `(hop_size, channels)` containing the new\n"
     288"    audio samples.\n"
     289"read : int\n"
     290"    Number of samples read from the source, equals to `hop_size`\n"
     291"    before the end-of-file is reached, less when it is reached,\n"
     292"    and `0` after.\n"
     293"\n"
     294"See Also\n"
     295"--------\n"
     296"do\n"
     297"\n"
     298"Examples\n"
     299"--------\n"
     300">>> src = aubio.source('sample.wav')\n"
     301">>> src.do_multi()\n"
     302"(array([[ 0.00668335,  0.0067749 ,  0.00714111, ..., -0.05737305,\n"
     303"        -0.05856323, -0.06018066],\n"
     304"       [-0.00842285, -0.0072937 , -0.00576782, ..., -0.09405518,\n"
     305"        -0.09558105, -0.09725952]], dtype=" AUBIO_NPY_SMPL_STR "), 512)\n"
     306"";
    71307
    72308static char Py_source_close_doc[] = ""
    73 "x.close()\n"
    74 "\n"
    75 "Close this source now.";
     309"close()\n"
     310"\n"
     311"Close this source now.\n"
     312"\n"
     313".. note:: Closing twice a source will **not** raise any exception.\n"
     314"";
    76315
    77316static char Py_source_seek_doc[] = ""
    78 "x.seek(position)\n"
    79 "\n"
    80 "Seek to resampled frame position.";
     317"seek(position)\n"
     318"\n"
     319"Seek to position in file.\n"
     320"\n"
     321"If the source was not opened with its original sampling-rate,\n"
     322"`position` corresponds to the position in the re-sampled file.\n"
     323"\n"
     324"Parameters\n"
     325"----------\n"
     326"position : str\n"
     327"   position to seek to, in samples\n"
     328"";
    81329
    82330static PyObject *
     
    101349  }
    102350
    103   self->uri = "none";
     351  self->uri = NULL;
    104352  if (uri != NULL) {
    105     self->uri = uri;
     353    self->uri = (char_t *)malloc(sizeof(char_t) * (strnlen(uri, PATH_MAX) + 1));
     354    strncpy(self->uri, uri, strnlen(uri, PATH_MAX) + 1);
    106355  }
    107356
     
    164413    free(self->c_mread_to.data);
    165414  }
     415  if (self->uri) {
     416    free(self->uri);
     417  }
    166418  Py_XDECREF(self->read_to);
    167419  Py_XDECREF(self->mread_to);
     
    214466static PyMemberDef Py_source_members[] = {
    215467  {"uri", T_STRING, offsetof (Py_source, uri), READONLY,
    216     "path at which the source was created"},
     468    "str (read-only): pathname or URL"},
    217469  {"samplerate", T_INT, offsetof (Py_source, samplerate), READONLY,
    218     "samplerate at which the source is viewed"},
     470    "int (read-only): sampling rate"},
    219471  {"channels", T_INT, offsetof (Py_source, channels), READONLY,
    220     "number of channels found in the source"},
     472    "int (read-only): number of channels"},
    221473  {"hop_size", T_INT, offsetof (Py_source, hop_size), READONLY,
    222     "number of consecutive frames that will be read at each do or do_multi call"},
     474    "int (read-only): number of samples read per iteration"},
    223475  {"duration", T_INT, offsetof (Py_source, duration), READONLY,
    224     "total number of frames in the source (estimated)"},
     476    "int (read-only): total number of frames in the source\n"
     477    "\n"
     478    "Can be estimated, for instance if the opened stream is\n"
     479    "a compressed media or a remote resource.\n"
     480    "\n"
     481    "Example\n"
     482    "-------\n"
     483    ">>> n = 0\n"
     484    ">>> src = aubio.source('track1.mp3')\n"
     485    ">>> for samples in src:\n"
     486    "...     n += samples.shape[-1]\n"
     487    "...\n"
     488    ">>> n, src.duration\n"
     489    "(9638784, 9616561)\n"
     490    ""},
    225491  { NULL } // sentinel
    226492};
     
    243509Pyaubio_source_close (Py_source *self, PyObject *unused)
    244510{
    245   aubio_source_close (self->o);
     511  if (aubio_source_close(self->o) != 0) return NULL;
    246512  Py_RETURN_NONE;
    247513}
     
    271537  }
    272538  Py_RETURN_NONE;
     539}
     540
     541static char Pyaubio_source_enter_doc[] = "";
     542static PyObject* Pyaubio_source_enter(Py_source *self, PyObject *unused) {
     543  Py_INCREF(self);
     544  return (PyObject*)self;
     545}
     546
     547static char Pyaubio_source_exit_doc[] = "";
     548static PyObject* Pyaubio_source_exit(Py_source *self, PyObject *unused) {
     549  return Pyaubio_source_close(self, unused);
     550}
     551
     552static PyObject* Pyaubio_source_iter(PyObject *self) {
     553  Py_INCREF(self);
     554  return (PyObject*)self;
     555}
     556
     557static PyObject* Pyaubio_source_iter_next(Py_source *self) {
     558  PyObject *done, *size;
     559  if (self->channels == 1) {
     560    done = Py_source_do(self, NULL);
     561  } else {
     562    done = Py_source_do_multi(self, NULL);
     563  }
     564  if (!PyTuple_Check(done)) {
     565    PyErr_Format(PyExc_ValueError,
     566        "error when reading source: not opened?");
     567    return NULL;
     568  }
     569  size = PyTuple_GetItem(done, 1);
     570  if (size != NULL && PyLong_Check(size)) {
     571    if (PyLong_AsLong(size) == (long)self->hop_size) {
     572      PyObject *vec = PyTuple_GetItem(done, 0);
     573      return vec;
     574    } else if (PyLong_AsLong(size) > 0) {
     575      // short read, return a shorter array
     576      PyArrayObject *shortread = (PyArrayObject*)PyTuple_GetItem(done, 0);
     577      PyArray_Dims newdims;
     578      PyObject *reshaped;
     579      newdims.len = PyArray_NDIM(shortread);
     580      newdims.ptr = PyArray_DIMS(shortread);
     581      // mono or multiple channels?
     582      if (newdims.len == 1) {
     583        newdims.ptr[0] = PyLong_AsLong(size);
     584      } else {
     585        newdims.ptr[1] = PyLong_AsLong(size);
     586      }
     587      reshaped = PyArray_Newshape(shortread, &newdims, NPY_CORDER);
     588      Py_DECREF(shortread);
     589      return reshaped;
     590    } else {
     591      PyErr_SetNone(PyExc_StopIteration);
     592      return NULL;
     593    }
     594  } else {
     595    PyErr_SetNone(PyExc_StopIteration);
     596    return NULL;
     597  }
    273598}
    274599
     
    286611  {"seek", (PyCFunction) Pyaubio_source_seek,
    287612    METH_VARARGS, Py_source_seek_doc},
     613  {"__enter__", (PyCFunction)Pyaubio_source_enter, METH_NOARGS,
     614    Pyaubio_source_enter_doc},
     615  {"__exit__",  (PyCFunction)Pyaubio_source_exit, METH_VARARGS,
     616    Pyaubio_source_exit_doc},
    288617  {NULL} /* sentinel */
    289618};
     
    315644  0,
    316645  0,
    317   0,
    318   0,
     646  Pyaubio_source_iter,
     647  (unaryfunc)Pyaubio_source_iter_next,
    319648  Py_source_methods,
    320649  Py_source_members,
  • python/ext/ufuncs.c

    r5b46bc3 r633400d  
    5959};
    6060
    61 static char Py_unwrap2pi_doc[] = "map angle to unit circle [-pi, pi[";
     61// Note: these docstrings should *not* include the function signatures
     62
     63static char Py_unwrap2pi_doc[] = ""
     64"\n"
     65"Map angle to unit circle :math:`[-\\pi, \\pi[`.\n"
     66"\n"
     67"Parameters\n"
     68"----------\n"
     69"x : numpy.ndarray\n"
     70"   input array\n"
     71"\n"
     72"Returns\n"
     73"-------\n"
     74"numpy.ndarray\n"
     75"   values clamped to the unit circle :math:`[-\\pi, \\pi[`\n"
     76"";
    6277
    6378static void* Py_unwrap2pi_data[] = {
     
    6883};
    6984
    70 static char Py_freqtomidi_doc[] = "convert frequency to midi";
     85static char Py_freqtomidi_doc[] = ""
     86"\n"
     87"Convert frequency `[0; 23000[` to midi `[0; 128[`.\n"
     88"\n"
     89"Parameters\n"
     90"----------\n"
     91"x : numpy.ndarray\n"
     92"    Array of frequencies, in Hz.\n"
     93"\n"
     94"Returns\n"
     95"-------\n"
     96"numpy.ndarray\n"
     97"    Converted frequencies, in midi note.\n"
     98"";
    7199
    72100static void* Py_freqtomidi_data[] = {
     
    75103};
    76104
    77 static char Py_miditofreq_doc[] = "convert midi to frequency";
     105static char Py_miditofreq_doc[] = ""
     106"\n"
     107"Convert midi `[0; 128[` to frequency `[0, 23000]`.\n"
     108"\n"
     109"Parameters\n"
     110"----------\n"
     111"x : numpy.ndarray\n"
     112"    Array of frequencies, in midi note.\n"
     113"\n"
     114"Returns\n"
     115"-------\n"
     116"numpy.ndarray\n"
     117"    Converted frequencies, in Hz\n"
     118"";
    78119
    79120static void* Py_miditofreq_data[] = {
  • python/lib/aubio/__init__.py

    r5b46bc3 r633400d  
    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
     26from ._aubio import __version__ as version
     27from ._aubio import float_type
    428from ._aubio import *
    5 from ._aubio import float_type
    629from .midiconv import *
    730from .slicing import *
    831
     32
    933class fvec(numpy.ndarray):
    10     """a numpy vector holding audio samples"""
     34    """fvec(input_arg=1024)
     35    A vector holding float samples.
    1136
    12     def __new__(cls, input_arg=1024, **kwargs):
     37    If `input_arg` is an `int`, a 1-dimensional vector of length `input_arg`
     38    will be created and filled with zeros. Otherwise, if `input_arg` is an
     39    `array_like` object, it will be converted to a 1-dimensional vector of
     40    type :data:`float_type`.
     41
     42    Parameters
     43    ----------
     44    input_arg : `int` or `array_like`
     45        Can be a positive integer, or any object that can be converted to
     46        a numpy array with :func:`numpy.array`.
     47
     48    Examples
     49    --------
     50    >>> aubio.fvec(10)
     51    array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)
     52    >>> aubio.fvec([0,1,2])
     53    array([0., 1., 2.], dtype=float32)
     54    >>> a = np.arange(10); type(a), type(aubio.fvec(a))
     55    (<class 'numpy.ndarray'>, <class 'numpy.ndarray'>)
     56    >>> a.dtype, aubio.fvec(a).dtype
     57    (dtype('int64'), dtype('float32'))
     58
     59    Notes
     60    -----
     61
     62    In the Python world, `fvec` is simply a subclass of
     63    :class:`numpy.ndarray`. In practice, any 1-dimensional `numpy.ndarray` of
     64    `dtype` :data:`float_type` may be passed to methods accepting
     65    `fvec` as parameter. For instance, `sink()` or `pvoc()`.
     66
     67    See Also
     68    --------
     69    cvec : a container holding spectral data
     70    numpy.ndarray : parent class of :class:`fvec`
     71    numpy.zeros : create a numpy array filled with zeros
     72    numpy.array : create a numpy array from an existing object
     73    """
     74    def __new__(cls, input_arg=1024):
    1375        if isinstance(input_arg, int):
    1476            if input_arg == 0:
    1577                raise ValueError("vector length of 1 or more expected")
    16             return numpy.zeros(input_arg, dtype=float_type, **kwargs)
     78            return numpy.zeros(input_arg, dtype=float_type, order='C')
    1779        else:
    18             return numpy.array(input_arg, dtype=float_type, **kwargs)
     80            np_input = numpy.array(input_arg, dtype=float_type, order='C')
     81            if len(np_input.shape) != 1:
     82                raise ValueError("input_arg should have shape (n,)")
     83            if np_input.shape[0] == 0:
     84                raise ValueError("vector length of 1 or more expected")
     85            return np_input
  • python/lib/aubio/midiconv.py

    r5b46bc3 r633400d  
    22""" utilities to convert midi note number to and from note names """
    33
    4 __all__ = ['note2midi', 'midi2note', 'freq2note']
     4import sys
     5from ._aubio import freqtomidi, miditofreq
    56
    6 import sys
     7__all__ = ['note2midi', 'midi2note', 'freq2note', 'note2freq']
     8
    79py3 = sys.version_info[0] == 3
    810if py3:
     
    1315    int_instances = (int, long)
    1416
     17
    1518def note2midi(note):
    16     " convert note name to midi note number, e.g. [C-1, G9] -> [0, 127] "
    17     _valid_notenames = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11}
    18     _valid_modifiers = {None: 0, u'♮': 0, '#': +1, u'♯': +1, u'\udd2a': +2,
    19                         'b': -1, u'♭': -1, u'\ufffd': -2}
     19    """Convert note name to midi note number.
     20
     21    Input string `note` should be composed of one note root
     22    and one octave, with optionally one modifier in between.
     23
     24    List of valid components:
     25
     26    - note roots: `C`, `D`, `E`, `F`, `G`, `A`, `B`,
     27    - modifiers: `b`, `#`, as well as unicode characters
     28      `𝄫`, `♭`, `♮`, `♯` and `𝄪`,
     29    - octave numbers: `-1` -> `11`.
     30
     31    Parameters
     32    ----------
     33    note : str
     34        note name
     35
     36    Returns
     37    -------
     38    int
     39        corresponding midi note number
     40
     41    Examples
     42    --------
     43    >>> aubio.note2midi('C#4')
     44    61
     45    >>> aubio.note2midi('B♭5')
     46    82
     47
     48    Raises
     49    ------
     50    TypeError
     51        If `note` was not a string.
     52    ValueError
     53        If an error was found while converting `note`.
     54
     55    See Also
     56    --------
     57    midi2note, freqtomidi, miditofreq
     58    """
     59    _valid_notenames = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7,
     60                        'A': 9, 'B': 11}
     61    _valid_modifiers = {
     62            u'𝄫': -2,                         # double flat
     63            u'♭': -1, 'b': -1, '\u266d': -1,  # simple flat
     64            u'♮': 0, '\u266e': 0, None: 0,    # natural
     65            '#': +1, u'♯': +1, '\u266f': +1,  # sharp
     66            u'𝄪': +2,                         # double sharp
     67            }
    2068    _valid_octaves = range(-1, 10)
    2169    if not isinstance(note, str_instances):
    22         raise TypeError("a string is required, got %s (%s)" % (note, str(type(note))))
     70        msg = "a string is required, got {:s} ({:s})"
     71        raise TypeError(msg.format(str(type(note)), repr(note)))
    2372    if len(note) not in range(2, 5):
    24         raise ValueError("string of 2 to 4 characters expected, got %d (%s)" \
    25                          % (len(note), note))
    26     notename, modifier, octave = [None]*3
     73        msg = "string of 2 to 4 characters expected, got {:d} ({:s})"
     74        raise ValueError(msg.format(len(note), note))
     75    notename, modifier, octave = [None] * 3
    2776
    2877    if len(note) == 4:
     
    4796        raise ValueError("%s is not a valid octave" % octave)
    4897
    49     midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier]
     98    midi = (octave + 1) * 12 + _valid_notenames[notename] \
     99                             + _valid_modifiers[modifier]
    50100    if midi > 127:
    51101        raise ValueError("%s is outside of the range C-2 to G8" % note)
    52102    return midi
    53103
     104
    54105def midi2note(midi):
    55     " convert midi note number to note name, e.g. [0, 127] -> [C-1, G9] "
     106    """Convert midi note number to note name.
     107
     108    Parameters
     109    ----------
     110    midi : int [0, 128]
     111        input midi note number
     112
     113    Returns
     114    -------
     115    str
     116        note name
     117
     118    Examples
     119    --------
     120    >>> aubio.midi2note(70)
     121    'A#4'
     122    >>> aubio.midi2note(59)
     123    'B3'
     124
     125    Raises
     126    ------
     127    TypeError
     128        If `midi` was not an integer.
     129    ValueError
     130        If `midi` is out of the range `[0, 128]`.
     131
     132    See Also
     133    --------
     134    note2midi, miditofreq, freqtomidi
     135    """
    56136    if not isinstance(midi, int_instances):
    57137        raise TypeError("an integer is required, got %s" % midi)
    58138    if midi not in range(0, 128):
    59         raise ValueError("an integer between 0 and 127 is excepted, got %d" % midi)
    60     _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
     139        msg = "an integer between 0 and 127 is excepted, got {:d}"
     140        raise ValueError(msg.format(midi))
     141    _valid_notenames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#',
     142                        'A', 'A#', 'B']
    61143    return _valid_notenames[midi % 12] + str(int(midi / 12) - 1)
    62144
     145
    63146def freq2note(freq):
    64     " convert frequency in Hz to nearest note name, e.g. [0, 22050.] -> [C-1, G9] "
    65     from aubio import freqtomidi
    66     return midi2note(int(freqtomidi(freq)))
     147    """Convert frequency in Hz to nearest note name.
     148
     149    Parameters
     150    ----------
     151    freq : float [0, 23000[
     152        input frequency, in Hz
     153
     154    Returns
     155    -------
     156    str
     157        name of the nearest note
     158
     159    Example
     160    -------
     161    >>> aubio.freq2note(440)
     162    'A4'
     163    >>> aubio.freq2note(220.1)
     164    'A3'
     165    """
     166    nearest_note = int(freqtomidi(freq) + .5)
     167    return midi2note(nearest_note)
     168
     169
     170def note2freq(note):
     171    """Convert note name to corresponding frequency, in Hz.
     172
     173    Parameters
     174    ----------
     175    note : str
     176        input note name
     177
     178    Returns
     179    -------
     180    freq : float [0, 23000[
     181        frequency, in Hz
     182
     183    Example
     184    -------
     185    >>> aubio.note2freq('A4')
     186    440
     187    >>> aubio.note2freq('A3')
     188    220.1
     189    """
     190    midi = note2midi(note)
     191    return miditofreq(midi)
  • python/lib/aubio/slicing.py

    r5b46bc3 r633400d  
    66_max_timestamp = 1e120
    77
     8
    89def 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 """
     10                           output_dir=None, samplerate=0, hopsize=256,
     11                           create_first=False):
     12    """Slice a sound file at given timestamps.
    1113
    12     if timestamps is None or len(timestamps) == 0:
     14    This function reads `source_file` and creates slices, new smaller
     15    files each starting at `t` in `timestamps`, a list of integer
     16    corresponding to time locations in `source_file`, in samples.
     17
     18    If `timestamps_end` is unspecified, the slices will end at
     19    `timestamps_end[n] = timestamps[n+1]-1`, or the end of file.
     20    Otherwise, `timestamps_end` should be a list with the same length
     21    as `timestamps` containing the locations of the end of each slice.
     22
     23    If `output_dir` is unspecified, the new slices will be written in
     24    the current directory. If `output_dir` is a string, new slices
     25    will be written in `output_dir`, after creating the directory if
     26    required.
     27
     28    The default `samplerate` is 0, meaning the original sampling rate
     29    of `source_file` will be used. When using a sampling rate
     30    different to the one of the original files, `timestamps` and
     31    `timestamps_end` should be expressed in the re-sampled signal.
     32
     33    The `hopsize` parameter simply tells :class:`source` to use this
     34    hopsize and does not change the output slices.
     35
     36    If `create_first` is True and `timestamps` does not start with `0`, the
     37    first slice from `0` to `timestamps[0] - 1` will be automatically added.
     38
     39    Parameters
     40    ----------
     41    source_file : str
     42        path of the resource to slice
     43    timestamps : :obj:`list` of :obj:`int`
     44        time stamps at which to slice, in samples
     45    timestamps_end : :obj:`list` of :obj:`int` (optional)
     46        time stamps at which to end the slices
     47    output_dir : str (optional)
     48        output directory to write the slices to
     49    samplerate : int (optional)
     50        samplerate to read the file at
     51    hopsize : int (optional)
     52        number of samples read from source per iteration
     53    create_first : bool (optional)
     54        always create the slice at the start of the file
     55
     56    Examples
     57    --------
     58    Create two slices: the first slice starts at the beginning of the
     59    input file `loop.wav` and lasts exactly one second, starting at
     60    sample `0` and ending at sample `44099`; the second slice starts
     61    at sample `44100` and lasts until the end of the input file:
     62
     63    >>> aubio.slice_source_at_stamps('loop.wav', [0, 44100])
     64
     65    Create one slice, from 1 second to 2 seconds:
     66
     67    >>> aubio.slice_source_at_stamps('loop.wav', [44100], [44100 * 2 - 1])
     68
     69    Notes
     70    -----
     71    Slices may be overlapping. If `timestamps_end` is `1` element
     72    shorter than `timestamps`, the last slice will end at the end of
     73    the file.
     74    """
     75
     76    if not timestamps:
    1377        raise ValueError("no timestamps given")
    1478
    15     if timestamps[0] != 0:
     79    if timestamps[0] != 0 and create_first:
    1680        timestamps = [0] + timestamps
    1781        if timestamps_end is not None:
     
    1983
    2084    if timestamps_end is not None:
    21         if len(timestamps_end) != len(timestamps):
     85        if len(timestamps_end) == len(timestamps) - 1:
     86            timestamps_end = timestamps_end + [_max_timestamp]
     87        elif len(timestamps_end) != len(timestamps):
    2288            raise ValueError("len(timestamps_end) != len(timestamps)")
    2389    else:
     
    2591
    2692    regions = list(zip(timestamps, timestamps_end))
    27     #print regions
    2893
    2994    source_base_name, _ = os.path.splitext(os.path.basename(source_file))
     
    3398        source_base_name = os.path.join(output_dir, source_base_name)
    3499
    35     def new_sink_name(source_base_name, timestamp, samplerate):
    36         """ create a sink based on a timestamp in samples, converted in seconds """
     100    def _new_sink_name(source_base_name, timestamp, samplerate):
     101        # create name based on a timestamp in samples, converted in seconds
    37102        timestamp_seconds = timestamp / float(samplerate)
    38103        return source_base_name + "_%011.6f" % timestamp_seconds + '.wav'
     
    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]:
    52             #print "getting", regions[0], "at", total_frames
     116        while regions and total_frames + read >= regions[0][0]:
    53117            # get next region
    54118            start_stamp, end_stamp = regions.pop(0)
    55119            # create a name for the sink
    56             new_sink_path = new_sink_name(source_base_name, start_stamp, samplerate)
     120            new_sink_path = _new_sink_name(source_base_name, start_stamp,
     121                                           samplerate)
    57122            # create its sink
    58123            _sink = sink(new_sink_path, samplerate, _source.channels)
    59124            # create a dictionary containing all this
    60             new_slice = {'start_stamp': start_stamp, 'end_stamp': end_stamp, 'sink': _sink}
     125            new_slice = {'start_stamp': start_stamp, 'end_stamp': end_stamp,
     126                         'sink': _sink}
    61127            # append the dictionary to the current list of slices
    62128            slices.append(new_slice)
     
    70136            # number of samples yet to written be until end of region
    71137            remaining = end_stamp - total_frames + 1
    72             #print current_slice, remaining, start
    73138            # not enough frames remaining, time to split
    74139            if remaining < read:
     
    76141                    # write remaining samples from current region
    77142                    _sink.do_multi(vec[:, start:remaining], remaining - start)
    78                     #print "closing region", "remaining", remaining
    79143                    # close this file
    80144                    _sink.close()
     
    83147                _sink.do_multi(vec[:, start:read], read - start)
    84148        total_frames += read
     149        # remove old slices
     150        slices = list(filter(lambda s: s['end_stamp'] > total_frames,
     151                             slices))
    85152        if read < hopsize:
    86153            break
  • python/lib/gen_code.py

    r5b46bc3 r633400d  
    33    'buf_size': 'Py_default_vector_length',
    44    'win_s': 'Py_default_vector_length',
     5    'size': 'Py_default_vector_length',
    56    # and here too
    67    'hop_size': 'Py_default_vector_length / 2',
     
    8586        'tss': 'self->buf_size',
    8687        'pitchshift': 'self->hop_size',
     88        'dct': 'self->size',
    8789        }
    8890
     
    180182        self.do_outputs = get_params_types_names(self.do_proto)[2:]
    181183        struct_output_str = ["PyObject *{0[name]}; {1} c_{0[name]}".format(i, i['type'][:-1]) for i in self.do_outputs]
     184        if len(self.prototypes['rdo']):
     185            rdo_outputs = get_params_types_names(prototypes['rdo'][0])[2:]
     186            struct_output_str += ["PyObject *{0[name]}; {1} c_{0[name]}".format(i, i['type'][:-1]) for i in rdo_outputs]
     187            self.outputs += rdo_outputs
    182188        self.struct_outputs = ";\n    ".join(struct_output_str)
    183189
     
    187193    def gen_code(self):
    188194        out = ""
    189         out += self.gen_struct()
    190         out += self.gen_doc()
    191         out += self.gen_new()
    192         out += self.gen_init()
    193         out += self.gen_del()
    194         out += self.gen_do()
    195         out += self.gen_memberdef()
    196         out += self.gen_set()
    197         out += self.gen_get()
    198         out += self.gen_methodef()
    199         out += self.gen_typeobject()
     195        try:
     196            out += self.gen_struct()
     197            out += self.gen_doc()
     198            out += self.gen_new()
     199            out += self.gen_init()
     200            out += self.gen_del()
     201            out += self.gen_do()
     202            if len(self.prototypes['rdo']):
     203                self.do_proto = self.prototypes['rdo'][0]
     204                self.do_inputs = [get_params_types_names(self.do_proto)[1]]
     205                self.do_outputs = get_params_types_names(self.do_proto)[2:]
     206                out += self.gen_do(method='rdo')
     207            out += self.gen_memberdef()
     208            out += self.gen_set()
     209            out += self.gen_get()
     210            out += self.gen_methodef()
     211            out += self.gen_typeobject()
     212        except Exception as e:
     213            print ("Failed generating code for", self.shortname)
     214            raise
    200215        return out
    201216
     
    381396        return out
    382397
    383     def gen_do(self):
     398    def gen_do(self, method = 'do'):
    384399        out = """
    385400// do {shortname}
    386401static PyObject*
    387 Py_{shortname}_do  (Py_{shortname} * self, PyObject * args)
    388 {{""".format(**self.__dict__)
     402Pyaubio_{shortname}_{method}  (Py_{shortname} * self, PyObject * args)
     403{{""".format(method = method, **self.__dict__)
    389404        input_params = self.do_inputs
    390405        output_params = self.do_outputs
     
    462477""".format(**self.__dict__)
    463478        for set_param in self.prototypes['set']:
    464             params = get_params_types_names(set_param)[1]
    465             paramtype = params['type']
     479            params = get_params_types_names(set_param)[1:]
     480            param = self.shortname.split('_set_')[-1]
     481            paramdecls = "".join(["""
     482   {0} {1};""".format(p['type'], p['name']) for p in params])
    466483            method_name = get_name(set_param)
    467484            param = method_name.split('aubio_'+self.shortname+'_set_')[-1]
    468             pyparamtype = pyargparse_chars[paramtype]
     485            refs = ", ".join(["&%s" % p['name'] for p in params])
     486            paramlist = ", ".join(["%s" % p['name'] for p in params])
     487            if len(params):
     488                paramlist = "," + paramlist
     489            pyparamtypes = ''.join([pyargparse_chars[p['type']] for p in params])
    469490            out += """
    470491static PyObject *
     
    472493{{
    473494  uint_t err = 0;
    474   {paramtype} {param};
    475 
    476   if (!PyArg_ParseTuple (args, "{pyparamtype}", &{param})) {{
     495  {paramdecls}
     496""".format(param = param, paramdecls = paramdecls, **self.__dict__)
     497
     498            if len(refs) and len(pyparamtypes):
     499                out += """
     500
     501  if (!PyArg_ParseTuple (args, "{pyparamtypes}", {refs})) {{
    477502    return NULL;
    478503  }}
    479   err = aubio_{shortname}_set_{param} (self->o, {param});
     504""".format(pyparamtypes = pyparamtypes, refs = refs)
     505
     506            out += """
     507  err = aubio_{shortname}_set_{param} (self->o {paramlist});
    480508
    481509  if (err > 0) {{
    482     PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}");
     510    if (PyErr_Occurred() == NULL) {{
     511      PyErr_SetString (PyExc_ValueError, "error running aubio_{shortname}_set_{param}");
     512    }} else {{
     513      // change the RuntimeError into ValueError
     514      PyObject *type, *value, *traceback;
     515      PyErr_Fetch(&type, &value, &traceback);
     516      PyErr_Restore(PyExc_ValueError, value, traceback);
     517    }}
    483518    return NULL;
    484519  }}
    485520  Py_RETURN_NONE;
    486521}}
    487 """.format(param = param, paramtype = paramtype, pyparamtype = pyparamtype, **self.__dict__)
     522""".format(param = param, refs = refs, paramdecls = paramdecls,
     523        pyparamtypes = pyparamtypes, paramlist = paramlist, **self.__dict__)
    488524        return out
    489525
     
    526562  {{"{shortname}", (PyCFunction) Py{name},
    527563    METH_NOARGS, ""}},""".format(name = name, shortname = shortname)
     564        for m in self.prototypes['rdo']:
     565            name = get_name(m)
     566            shortname = name.replace('aubio_%s_' % self.shortname, '')
     567            out += """
     568  {{"{shortname}", (PyCFunction) Py{name},
     569    METH_VARARGS, ""}},""".format(name = name, shortname = shortname)
    528570        out += """
    529571  {NULL} /* sentinel */
     
    551593  0,
    552594  0,
    553   (ternaryfunc)Py_{shortname}_do,
     595  (ternaryfunc)Pyaubio_{shortname}_do,
    554596  0,
    555597  0,
  • python/lib/gen_external.py

    r5b46bc3 r633400d  
    11import distutils.ccompiler
    2 import sys, os, subprocess, glob
     2import sys
     3import os
     4import subprocess
     5import glob
     6from distutils.sysconfig import customize_compiler
     7from gen_code import MappedObject
    38
    49header = os.path.join('src', 'aubio.h')
     
    914"""
    1015
    11 skip_objects = [
    12   # already in ext/
    13   'fft',
    14   'pvoc',
    15   'filter',
    16   'filterbank',
    17   #'resampler',
    18   # AUBIO_UNSTABLE
    19   'hist',
    20   'parameter',
    21   'scale',
    22   'beattracking',
    23   'resampler',
    24   'peakpicker',
    25   'pitchfcomb',
    26   'pitchmcomb',
    27   'pitchschmitt',
    28   'pitchspecacf',
    29   'pitchyin',
    30   'pitchyinfft',
    31   'sink',
    32   'sink_apple_audio',
    33   'sink_sndfile',
    34   'sink_wavwrite',
    35   #'mfcc',
    36   'source',
    37   'source_apple_audio',
    38   'source_sndfile',
    39   'source_avcodec',
    40   'source_wavread',
    41   #'sampler',
    42   'audio_unit',
    43   ]
     16default_skip_objects = [
     17    # already in ext/
     18    'fft',
     19    'pvoc',
     20    'filter',
     21    'filterbank',
     22    # AUBIO_UNSTABLE
     23    'hist',
     24    'parameter',
     25    'scale',
     26    'beattracking',
     27    'resampler',
     28    'peakpicker',
     29    'pitchfcomb',
     30    'pitchmcomb',
     31    'pitchschmitt',
     32    'pitchspecacf',
     33    'pitchyin',
     34    'pitchyinfft',
     35    'pitchyinfast',
     36    'sink',
     37    'sink_apple_audio',
     38    'sink_sndfile',
     39    'sink_wavwrite',
     40    #'mfcc',
     41    'source',
     42    'source_apple_audio',
     43    'source_sndfile',
     44    'source_avcodec',
     45    'source_wavread',
     46    #'sampler',
     47    'audio_unit',
     48    'spectral_whitening',
     49]
     50
    4451
    4552def get_preprocessor():
    4653    # findout which compiler to use
    47     from distutils.sysconfig import customize_compiler
    4854    compiler_name = distutils.ccompiler.get_default_compiler()
    4955    compiler = distutils.ccompiler.new_compiler(compiler=compiler_name)
     
    6066
    6167    cpp_cmd = None
    62     if hasattr(compiler, 'preprocessor'): # for unixccompiler
     68    if hasattr(compiler, 'preprocessor'):  # for unixccompiler
    6369        cpp_cmd = compiler.preprocessor
    64     elif hasattr(compiler, 'compiler'): # for ccompiler
     70    elif hasattr(compiler, 'compiler'):  # for ccompiler
    6571        cpp_cmd = compiler.compiler.split()
    6672        cpp_cmd += ['-E']
    67     elif hasattr(compiler, 'cc'): # for msvccompiler
     73    elif hasattr(compiler, 'cc'):  # for msvccompiler
    6874        cpp_cmd = compiler.cc.split()
    6975        cpp_cmd += ['-E']
     76
     77    # On win-amd64 (py3.x), the default compiler is cross-compiling, from x86
     78    # to amd64 with %WIN_SDK_ROOT%\x86_amd64\cl.exe, but using this binary as a
     79    # pre-processor generates no output, so we use %WIN_SDK_ROOT%\cl.exe
     80    # instead.
     81    if len(cpp_cmd) > 1 and 'cl.exe' in cpp_cmd[-2]:
     82        plat = os.path.basename(os.path.dirname(cpp_cmd[-2]))
     83        if plat == 'x86_amd64':
     84            print('workaround on win64 to avoid empty pre-processor output')
     85            cpp_cmd[-2] = cpp_cmd[-2].replace('x86_amd64', '')
     86        elif True in ['amd64' in f for f in cpp_cmd]:
     87            print('warning: not using workaround for', cpp_cmd[0], plat)
    7088
    7189    if not cpp_cmd:
     
    7391        cpp_cmd = os.environ.get('CC', 'cc').split()
    7492        cpp_cmd += ['-E']
    75 
     93    if 'emcc' in cpp_cmd:
     94        cpp_cmd += ['-x', 'c'] # emcc defaults to c++, force C language
    7695    return cpp_cmd
    7796
    78 def get_cpp_objects(header=header):
     97
     98def get_c_declarations(header=header, usedouble=False):
     99    ''' return a dense and preprocessed  string of all c declarations implied by aubio.h
     100    '''
     101    cpp_output = get_cpp_output(header=header, usedouble=usedouble)
     102    return filter_cpp_output (cpp_output)
     103
     104
     105def get_cpp_output(header=header, usedouble=False):
     106    ''' find and run a C pre-processor on aubio.h '''
    79107    cpp_cmd = get_preprocessor()
    80108
    81109    macros = [('AUBIO_UNSTABLE', 1)]
     110    if usedouble:
     111        macros += [('HAVE_AUBIO_DOUBLE', 1)]
    82112
    83113    if not os.path.isfile(header):
     
    90120    print("Running command: {:s}".format(" ".join(cpp_cmd)))
    91121    proc = subprocess.Popen(cpp_cmd,
    92             stderr=subprocess.PIPE,
    93             stdout=subprocess.PIPE)
     122                            stderr=subprocess.PIPE,
     123                            stdout=subprocess.PIPE)
    94124    assert proc, 'Proc was none'
    95125    cpp_output = proc.stdout.read()
    96126    err_output = proc.stderr.read()
     127    if err_output:
     128        print("Warning: preprocessor produced errors or warnings:\n%s" \
     129                % err_output.decode('utf8'))
    97130    if not cpp_output:
    98         raise Exception("preprocessor output is empty:\n%s" % err_output)
    99     elif err_output:
    100         print ("Warning: preprocessor produced warnings:\n%s" % err_output)
     131        raise_msg = "preprocessor output is empty! Running command " \
     132                + "\"%s\" failed" % " ".join(cpp_cmd)
     133        if err_output:
     134            raise_msg += " with stderr: \"%s\"" % err_output.decode('utf8')
     135        else:
     136            raise_msg += " with no stdout or stderr"
     137        raise Exception(raise_msg)
    101138    if not isinstance(cpp_output, list):
    102139        cpp_output = [l.strip() for l in cpp_output.decode('utf8').split('\n')]
    103140
    104     cpp_output = filter(lambda y: len(y) > 1, cpp_output)
     141    return cpp_output
     142
     143def filter_cpp_output(cpp_raw_output):
     144    ''' prepare cpp-output for parsing '''
     145    cpp_output = filter(lambda y: len(y) > 1, cpp_raw_output)
    105146    cpp_output = list(filter(lambda y: not y.startswith('#'), cpp_output))
    106147
    107148    i = 1
    108149    while 1:
    109         if i >= len(cpp_output): break
    110         if cpp_output[i-1].endswith(',') or cpp_output[i-1].endswith('{') or cpp_output[i].startswith('}'):
    111             cpp_output[i] = cpp_output[i-1] + ' ' + cpp_output[i]
    112             cpp_output.pop(i-1)
     150        if i >= len(cpp_output):
     151            break
     152        if ('{' in cpp_output[i - 1]) and ('}' not in cpp_output[i - 1]) or (';' not in cpp_output[i - 1]):
     153            cpp_output[i] = cpp_output[i - 1] + ' ' + cpp_output[i]
     154            cpp_output.pop(i - 1)
     155        elif ('}' in cpp_output[i]):
     156            cpp_output[i] = cpp_output[i - 1] + ' ' + cpp_output[i]
     157            cpp_output.pop(i - 1)
    113158        else:
    114159            i += 1
    115160
    116     typedefs = filter(lambda y: y.startswith ('typedef struct _aubio'), cpp_output)
    117 
     161    # clean pointer notations
     162    tmp = []
     163    for l in cpp_output:
     164        tmp += [l.replace(' *', ' * ')]
     165    cpp_output = tmp
     166
     167    return cpp_output
     168
     169
     170def get_cpp_objects_from_c_declarations(c_declarations, skip_objects=None):
     171    if skip_objects is None:
     172        skip_objects = default_skip_objects
     173    typedefs = filter(lambda y: y.startswith('typedef struct _aubio'), c_declarations)
    118174    cpp_objects = [a.split()[3][:-1] for a in typedefs]
    119 
    120     return cpp_output, cpp_objects
    121 
    122 
    123 def analyze_cpp_output(cpp_objects, cpp_output):
     175    cpp_objects_filtered = filter(lambda y: not y[6:-2] in skip_objects, cpp_objects)
     176    return cpp_objects_filtered
     177
     178
     179def get_all_func_names_from_lib(lib):
     180    ''' return flat string of all function used in lib
     181    '''
     182    res = []
     183    for _, v in lib.items():
     184        if isinstance(v, dict):
     185            res += get_all_func_names_from_lib(v)
     186        elif isinstance(v, list):
     187            for elem in v:
     188                e = elem.split('(')
     189                if len(e) < 2:
     190                    continue  # not a function
     191                fname_part = e[0].strip().split(' ')
     192                fname = fname_part[-1]
     193                if fname:
     194                    res += [fname]
     195                else:
     196                    raise NameError('gen_lib : weird function: ' + str(e))
     197
     198    return res
     199
     200
     201def generate_lib_from_c_declarations(cpp_objects, c_declarations):
     202    ''' returns a lib from given cpp_object names
     203
     204    a lib is a dict grouping functions by family (onset,pitch...)
     205        each eement is itself a dict of functions grouped by puposes as :
     206        struct, new, del, do, get, set and other
     207    '''
    124208    lib = {}
    125209
    126210    for o in cpp_objects:
    127         if o[:6] != 'aubio_':
    128             continue
    129         shortname = o[6:-2]
    130         if shortname in skip_objects:
    131             continue
    132         lib[shortname] = {'struct': [], 'new': [], 'del': [], 'do': [], 'get': [], 'set': [], 'other': []}
     211        shortname = o
     212        if o[:6] == 'aubio_':
     213            shortname = o[6:-2]  # without aubio_ prefix and _t suffix
     214
     215        lib[shortname] = {'struct': [], 'new': [], 'del': [], 'do': [], 'rdo': [], 'get': [], 'set': [], 'other': []}
    133216        lib[shortname]['longname'] = o
    134217        lib[shortname]['shortname'] = shortname
    135         for fn in cpp_output:
    136             if o[:-1] in fn:
    137                 #print "found", o[:-1], "in", fn
     218
     219        fullshortname = o[:-2]  # name without _t suffix
     220
     221        for fn in c_declarations:
     222            func_name = fn.split('(')[0].strip().split(' ')[-1]
     223            if func_name.startswith(fullshortname + '_') or func_name.endswith(fullshortname):
     224                # print "found", shortname, "in", fn
    138225                if 'typedef struct ' in fn:
    139226                    lib[shortname]['struct'].append(fn)
    140227                elif '_do' in fn:
    141228                    lib[shortname]['do'].append(fn)
     229                elif '_rdo' in fn:
     230                    lib[shortname]['rdo'].append(fn)
    142231                elif 'new_' in fn:
    143232                    lib[shortname]['new'].append(fn)
     
    149238                    lib[shortname]['set'].append(fn)
    150239                else:
    151                     #print "no idea what to do about", fn
     240                    # print "no idea what to do about", fn
    152241                    lib[shortname]['other'].append(fn)
    153242    return lib
    154243
    155 def print_cpp_output_results(lib, cpp_output):
    156     for fn in cpp_output:
     244
     245def print_c_declarations_results(lib, c_declarations):
     246    for fn in c_declarations:
    157247        found = 0
    158248        for o in lib:
     
    161251                    found = 1
    162252        if found == 0:
    163             print ("missing", fn)
     253            print("missing", fn)
    164254
    165255    for o in lib:
    166256        for family in lib[o]:
    167257            if type(lib[o][family]) == str:
    168                 print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ) )
     258                print("{:15s} {:10s} {:s}".format(o, family, lib[o][family]))
    169259            elif len(lib[o][family]) == 1:
    170                 print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family][0] ) )
     260                print("{:15s} {:10s} {:s}".format(o, family, lib[o][family][0]))
    171261            else:
    172                 print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ) )
     262                print("{:15s} {:10s} {:s}".format(o, family, lib[o][family]))
    173263
    174264
    175265def generate_external(header=header, output_path=output_path, usedouble=False, overwrite=True):
    176     if not os.path.isdir(output_path): os.mkdir(output_path)
    177     elif not overwrite: return glob.glob(os.path.join(output_path, '*.c'))
    178 
    179     cpp_output, cpp_objects = get_cpp_objects(header)
    180 
    181     lib = analyze_cpp_output(cpp_objects, cpp_output)
    182     # print_cpp_output_results(lib, cpp_output)
     266    if not os.path.isdir(output_path):
     267        os.mkdir(output_path)
     268    elif not overwrite:
     269        return sorted(glob.glob(os.path.join(output_path, '*.c')))
     270
     271    c_declarations = get_c_declarations(header, usedouble=usedouble)
     272    cpp_objects = get_cpp_objects_from_c_declarations(c_declarations)
     273
     274    lib = generate_lib_from_c_declarations(cpp_objects, c_declarations)
     275    # print_c_declarations_results(lib, c_declarations)
    183276
    184277    sources_list = []
    185     try:
    186         from .gen_code import MappedObject
    187     except (SystemError, ValueError):
    188         from gen_code import MappedObject
    189278    for o in lib:
    190279        out = source_header
    191         mapped = MappedObject(lib[o], usedouble = usedouble)
     280        mapped = MappedObject(lib[o], usedouble=usedouble)
    192281        out += mapped.gen_code()
    193282        output_file = os.path.join(output_path, 'gen-%s.c' % o)
    194283        with open(output_file, 'w') as f:
    195284            f.write(out)
    196             print ("wrote %s" % output_file )
     285            print("wrote %s" % output_file)
    197286            sources_list.append(output_file)
    198287
     
    206295  return ({pycheck_types});
    207296}}
    208 """.format(pycheck_types = check_types)
     297""".format(pycheck_types=check_types)
    209298
    210299    add_types = "".join(["""
    211300  Py_INCREF (&Py_{name}Type);
    212   PyModule_AddObject(m, "{name}", (PyObject *) & Py_{name}Type);""".format(name = o) for o in lib])
     301  PyModule_AddObject(m, "{name}", (PyObject *) & Py_{name}Type);""".format(name=o) for o in lib])
    213302    out += """
    214303
     
    217306{add_types}
    218307}}
    219 """.format(add_types = add_types)
     308""".format(add_types=add_types)
    220309
    221310    output_file = os.path.join(output_path, 'aubio-generated.c')
    222311    with open(output_file, 'w') as f:
    223312        f.write(out)
    224         print ("wrote %s" % output_file )
     313        print("wrote %s" % output_file)
    225314        sources_list.append(output_file)
    226315
     
    240329int generated_objects ( void );
    241330void add_generated_objects( PyObject *m );
    242 """.format(objlist = objlist)
     331""".format(objlist=objlist)
    243332
    244333    output_file = os.path.join(output_path, 'aubio-generated.h')
    245334    with open(output_file, 'w') as f:
    246335        f.write(out)
    247         print ("wrote %s" % output_file )
     336        print("wrote %s" % output_file)
    248337        # no need to add header to list of sources
    249338
    250     return sources_list
     339    return sorted(sources_list)
    251340
    252341if __name__ == '__main__':
    253     if len(sys.argv) > 1: header = sys.argv[1]
    254     if len(sys.argv) > 2: output_path = sys.argv[2]
     342    if len(sys.argv) > 1:
     343        header = sys.argv[1]
     344    if len(sys.argv) > 2:
     345        output_path = sys.argv[2]
    255346    generate_external(header, output_path)
  • python/lib/moresetuptools.py

    r5b46bc3 r633400d  
    33import sys, os, glob, subprocess
    44import distutils, distutils.command.clean, distutils.dir_util
    5 from .gen_external import generate_external, header, output_path
     5from gen_external import generate_external, header, output_path
     6
     7from this_version import get_aubio_version
    68
    79# inspired from https://gist.github.com/abergmeier/9488990
     
    2224
    2325    for package in packages:
     26        print("checking for {:s}".format(package))
    2427        cmd = ['pkg-config', '--libs', '--cflags', package]
    2528        try:
     
    5558def add_local_aubio_sources(ext):
    5659    """ build aubio inside python module instead of linking against libaubio """
    57     print("Warning: libaubio was not built with waf, adding src/")
    58     # create an empty header, macros will be passed on the command line
    59     fake_config_header = os.path.join('python', 'ext', 'config.h')
    60     distutils.file_util.write_file(fake_config_header, "")
    61     aubio_sources = glob.glob(os.path.join('src', '**.c'))
    62     aubio_sources += glob.glob(os.path.join('src', '*', '**.c'))
     60    print("Info: libaubio was not installed or built locally with waf, adding src/")
     61    aubio_sources = sorted(glob.glob(os.path.join('src', '**.c')))
     62    aubio_sources += sorted(glob.glob(os.path.join('src', '*', '**.c')))
    6363    ext.sources += aubio_sources
     64
     65def add_local_macros(ext, usedouble = False):
     66    if usedouble:
     67        ext.define_macros += [('HAVE_AUBIO_DOUBLE', 1)]
    6468    # define macros (waf puts them in build/src/config.h)
    6569    for define_macro in ['HAVE_STDLIB_H', 'HAVE_STDIO_H',
     
    7074        ext.define_macros += [(define_macro, 1)]
    7175
     76def add_external_deps(ext, usedouble = False):
    7277    # loof for additional packages
    7378    print("Info: looking for *optional* additional packages")
    74     packages = ['libavcodec', 'libavformat', 'libavutil', 'libavresample',
     79    packages = ['libavcodec', 'libavformat', 'libavutil',
     80                'libswresample', 'libavresample',
    7581                'jack',
    76                 'sndfile', 'samplerate',
     82                'sndfile',
    7783                'rubberband',
    7884                #'fftw3f',
    7985               ]
     86    # samplerate only works with float
     87    if usedouble is False:
     88        packages += ['samplerate']
     89    else:
     90        print("Info: not adding libsamplerate in double precision mode")
    8091    add_packages(packages, ext=ext)
    8192    if 'avcodec' in ext.libraries \
    8293            and 'avformat' in ext.libraries \
    83             and 'avutil' in ext.libraries \
    84             and 'avresample' in ext.libraries:
    85         ext.define_macros += [('HAVE_LIBAV', 1)]
    86     if 'jack' in ext.libraries:
    87         ext.define_macros += [('HAVE_JACK', 1)]
     94            and 'avutil' in ext.libraries:
     95        if 'swresample' in ext.libraries:
     96            ext.define_macros += [('HAVE_SWRESAMPLE', 1)]
     97        elif 'avresample' in ext.libraries:
     98            ext.define_macros += [('HAVE_AVRESAMPLE', 1)]
     99        if 'swresample' in ext.libraries or 'avresample' in ext.libraries:
     100            ext.define_macros += [('HAVE_LIBAV', 1)]
    88101    if 'sndfile' in ext.libraries:
    89102        ext.define_macros += [('HAVE_SNDFILE', 1)]
     
    108121    ext.define_macros += [('HAVE_WAVWRITE', 1)]
    109122    ext.define_macros += [('HAVE_WAVREAD', 1)]
    110     # TODO:
    111     # add cblas
     123
     124    # TODO: add cblas
    112125    if 0:
    113126        ext.libraries += ['cblas']
     
    116129def add_system_aubio(ext):
    117130    # use pkg-config to find aubio's location
    118     add_packages(['aubio'], ext)
     131    aubio_version = get_aubio_version()
     132    add_packages(['aubio = ' + aubio_version], ext)
    119133    if 'aubio' not in ext.libraries:
    120         print("Error: libaubio not found")
     134        print("Info: aubio " + aubio_version + " was not found by pkg-config")
     135    else:
     136        print("Info: using system aubio " + aubio_version + " found in " + ' '.join(ext.library_dirs))
     137
     138def add_libav_on_win(ext):
     139    """ no pkg-config on windows, simply assume these libs are available """
     140    ext.libraries += ['avformat', 'avutil', 'avcodec', 'swresample']
     141    for define_macro in ['HAVE_LIBAV', 'HAVE_SWRESAMPLE']:
     142        ext.define_macros += [(define_macro, 1)]
    121143
    122144class CleanGenerated(distutils.command.clean.clean):
    123145    def run(self):
    124         distutils.dir_util.remove_tree(output_path)
    125         distutils.command.clean.clean.run(self)
     146        if os.path.isdir(output_path):
     147            distutils.dir_util.remove_tree(output_path)
    126148
    127 class GenerateCommand(distutils.cmd.Command):
    128     description = 'generate gen/gen-*.c files from ../src/aubio.h'
    129     user_options = [
     149from distutils.command.build_ext import build_ext as _build_ext
     150class build_ext(_build_ext):
     151
     152    user_options = _build_ext.user_options + [
    130153            # The format is (long option, short option, description).
    131154            ('enable-double', None, 'use HAVE_AUBIO_DOUBLE=1 (default: 0)'),
     
    133156
    134157    def initialize_options(self):
     158        _build_ext.initialize_options(self)
    135159        self.enable_double = False
    136160
    137161    def finalize_options(self):
     162        _build_ext.finalize_options(self)
    138163        if self.enable_double:
    139164            self.announce(
     
    141166                    level=distutils.log.INFO)
    142167
    143     def run(self):
    144         self.announce( 'Generating code', level=distutils.log.INFO)
    145         generated_object_files = generate_external(header, output_path, usedouble=self.enable_double)
     168    def build_extension(self, extension):
     169        if self.enable_double or 'HAVE_AUBIO_DOUBLE' in os.environ:
     170            enable_double = True
     171        else:
     172            enable_double = False
     173        # seack for aubio headers and lib in PKG_CONFIG_PATH
     174        add_system_aubio(extension)
     175        # the lib was not installed on this system
     176        if 'aubio' not in extension.libraries:
     177            # use local src/aubio.h
     178            if os.path.isfile(os.path.join('src', 'aubio.h')):
     179                add_local_aubio_header(extension)
     180            add_local_macros(extension, usedouble=enable_double)
     181            # look for a local waf build
     182            if os.path.isfile(os.path.join('build','src', 'fvec.c.1.o')):
     183                add_local_aubio_lib(extension)
     184            else:
     185                # check for external dependencies
     186                add_external_deps(extension, usedouble=enable_double)
     187                # force adding libav on windows
     188                if os.name == 'nt' and ('WITH_LIBAV' in os.environ \
     189                        or 'CONDA_PREFIX' in os.environ):
     190                    add_libav_on_win(extension)
     191                # add libaubio sources and look for optional deps with pkg-config
     192                add_local_aubio_sources(extension)
     193        # generate files python/gen/*.c, python/gen/aubio-generated.h
     194        extension.include_dirs += [ output_path ]
     195        extension.sources += generate_external(header, output_path, overwrite = False,
     196                usedouble=enable_double)
     197        return _build_ext.build_extension(self, extension)
  • python/tests/eval_pitch

    r5b46bc3 r633400d  
    2525import os.path
    2626import numpy
    27 from utils import array_from_text_file, array_from_yaml_file
     27from .utils import array_from_text_file, array_from_yaml_file
    2828from aubio import source, pitch, freqtomidi
    2929
  • python/tests/test_aubio.py

    r5b46bc3 r633400d  
    1010        import aubio
    1111
     12    def test_version(self):
     13        """ test aubio.version """
     14        import aubio
     15        self.assertEqual('0', aubio.version[0])
     16
    1217if __name__ == '__main__':
    1318    main()
  • python/tests/test_fft.py

    r5b46bc3 r633400d  
    3434        fftgrain = f (timegrain)
    3535        assert_equal ( fftgrain.norm, 0 )
    36         assert_equal ( fftgrain.phas, 0 )
     36        try:
     37            assert_equal ( fftgrain.phas, 0 )
     38        except AssertionError:
     39            assert_equal (fftgrain.phas[fftgrain.phas > 0], +pi)
     40            assert_equal (fftgrain.phas[fftgrain.phas < 0], -pi)
     41            assert_equal (np.abs(fftgrain.phas[np.abs(fftgrain.phas) != pi]), 0)
     42            self.skipTest('fft(fvec(%d)).phas != +0, ' % win_s \
     43                    + 'This is expected when using fftw3 on powerpc.')
    3744
    3845    def test_impulse(self):
     
    136143        assert_almost_equal ( r[1:], 0)
    137144
     145class aubio_fft_odd_sizes(TestCase):
     146
     147    def test_reconstruct_with_odd_size(self):
     148        win_s = 29
     149        self.recontruct(win_s, 'odd sizes not supported')
     150
     151    def test_reconstruct_with_radix15(self):
     152        win_s = 2 ** 4 * 15
     153        self.recontruct(win_s, 'radix 15 supported')
     154
     155    def test_reconstruct_with_radix5(self):
     156        win_s = 2 ** 4 * 5
     157        self.recontruct(win_s, 'radix 5 supported')
     158
     159    def test_reconstruct_with_radix3(self):
     160        win_s = 2 ** 4 * 3
     161        self.recontruct(win_s, 'radix 3 supported')
     162
     163    def recontruct(self, win_s, skipMessage):
     164        try:
     165            f = fft(win_s)
     166        except RuntimeError:
     167            self.skipTest(skipMessage)
     168        input_signal = fvec(win_s)
     169        input_signal[win_s//2] = 1
     170        c = f(input_signal)
     171        output_signal = f.rdo(c)
     172        assert_almost_equal(input_signal, output_signal)
     173
     174class aubio_fft_wrong_params(TestCase):
     175
    138176    def test_large_input_timegrain(self):
    139177        win_s = 1024
     
    163201        with self.assertRaises(ValueError):
    164202            f.rdo(s)
    165 
    166 class aubio_fft_wrong_params(TestCase):
    167203
    168204    def test_wrong_buf_size(self):
     
    170206        with self.assertRaises(ValueError):
    171207            fft(win_s)
    172 
    173     def test_buf_size_not_power_of_two(self):
    174         # when compiled with fftw3, aubio supports non power of two fft sizes
    175         win_s = 320
    176         try:
    177             with self.assertRaises(RuntimeError):
    178                 fft(win_s)
    179         except AssertionError:
    180             self.skipTest('creating aubio.fft with size %d did not fail' % win_s)
    181208
    182209    def test_buf_size_too_small(self):
  • python/tests/test_filter.py

    r5b46bc3 r633400d  
    44from numpy.testing import TestCase, assert_equal, assert_almost_equal
    55from aubio import fvec, digital_filter
    6 from utils import array_from_text_file
     6from .utils import array_from_text_file
    77
    88class aubio_filter_test_case(TestCase):
     
    7878            f.set_biquad(0., 0., 0, 0., 0.)
    7979
     80    def test_all_available_presets(self):
     81        f = digital_filter(7)
     82        for sr in [8000, 11025, 16000, 22050, 24000, 32000,
     83                44100, 48000, 88200, 96000, 192000]:
     84            f.set_a_weighting(sr)
     85        f = digital_filter(5)
     86        for sr in [8000, 11025, 16000, 22050, 24000, 32000,
     87                44100, 48000, 88200, 96000, 192000]:
     88            f.set_c_weighting(sr)
     89
    8090class aubio_filter_wrong_params(TestCase):
    8191
  • python/tests/test_filterbank.py

    r5b46bc3 r633400d  
    11#! /usr/bin/env python
    22
    3 from unittest import main
    4 from numpy.testing import TestCase
    5 from numpy.testing import assert_equal, assert_almost_equal
    63import numpy as np
     4from numpy.testing import TestCase, assert_equal, assert_almost_equal
     5
    76from aubio import cvec, filterbank, float_type
    8 from utils import array_from_text_file
     7from .utils import array_from_text_file
    98
    109class aubio_filterbank_test_case(TestCase):
     
    6362        assert_almost_equal ( expected, f.get_coeffs() )
    6463
     64    def test_mfcc_coeffs_get_coeffs(self):
     65        f = filterbank(40, 512)
     66        coeffs = f.get_coeffs()
     67        self.assertIsInstance(coeffs, np.ndarray)
     68        assert_equal (coeffs, 0)
     69        assert_equal (np.shape(coeffs), (40, 512 / 2 + 1))
     70
    6571class aubio_filterbank_wrong_values(TestCase):
    6672
     
    8288
    8389if __name__ == '__main__':
    84     main()
     90    import nose2
     91    nose2.main()
  • python/tests/test_filterbank_mel.py

    r5b46bc3 r633400d  
    11#! /usr/bin/env python
    22
    3 from unittest import main
    4 from numpy.testing import TestCase
    5 from numpy.testing import assert_equal, assert_almost_equal
    6 from numpy import array, shape
    7 from aubio import cvec, filterbank, float_type
     3import numpy as np
     4from numpy.testing import TestCase, assert_equal, assert_almost_equal
     5
     6from aubio import fvec, cvec, filterbank, float_type
     7
     8import warnings
     9warnings.filterwarnings('ignore', category=UserWarning, append=True)
    810
    911class aubio_filterbank_mel_test_case(TestCase):
     
    1315        f.set_mel_coeffs_slaney(16000)
    1416        a = f.get_coeffs()
    15         assert_equal(shape (a), (40, 512/2 + 1) )
     17        assert_equal(np.shape (a), (40, 512/2 + 1) )
    1618
    1719    def test_other_slaney(self):
    1820        f = filterbank(40, 512*2)
    1921        f.set_mel_coeffs_slaney(44100)
    20         _ = f.get_coeffs()
     22        self.assertIsInstance(f.get_coeffs(), np.ndarray)
    2123        #print "sum is", sum(sum(a))
    2224        for win_s in [256, 512, 1024, 2048, 4096]:
    2325            f = filterbank(40, win_s)
    2426            f.set_mel_coeffs_slaney(32000)
    25             _ = f.get_coeffs()
    2627            #print "sum is", sum(sum(a))
     28            self.assertIsInstance(f.get_coeffs(), np.ndarray)
    2729
    2830    def test_triangle_freqs_zeros(self):
    2931        f = filterbank(9, 1024)
    3032        freq_list = [40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000, 24000]
    31         freqs = array(freq_list, dtype = float_type)
     33        freqs = np.array(freq_list, dtype = float_type)
    3234        f.set_triangle_bands(freqs, 48000)
    33         _ = f.get_coeffs().T
    3435        assert_equal ( f(cvec(1024)), 0)
     36        self.assertIsInstance(f.get_coeffs(), np.ndarray)
    3537
    3638    def test_triangle_freqs_ones(self):
    3739        f = filterbank(9, 1024)
    3840        freq_list = [40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000, 24000]
    39         freqs = array(freq_list, dtype = float_type)
     41        freqs = np.array(freq_list, dtype = float_type)
    4042        f.set_triangle_bands(freqs, 48000)
    41         _ = f.get_coeffs().T
     43        self.assertIsInstance(f.get_coeffs(), np.ndarray)
    4244        spec = cvec(1024)
    4345        spec.norm[:] = 1
     
    4648                    0.02133301, 0.02133301, 0.02133311, 0.02133334, 0.02133345])
    4749
     50    def test_triangle_freqs_with_zeros(self):
     51        """make sure set_triangle_bands works when list starts with 0"""
     52        freq_list = [0, 40, 80]
     53        freqs = np.array(freq_list, dtype = float_type)
     54        f = filterbank(len(freqs)-2, 1024)
     55        f.set_triangle_bands(freqs, 48000)
     56        assert_equal ( f(cvec(1024)), 0)
     57        self.assertIsInstance(f.get_coeffs(), np.ndarray)
     58
     59    def test_triangle_freqs_with_wrong_negative(self):
     60        """make sure set_triangle_bands fails when list contains a negative"""
     61        freq_list = [-10, 0, 80]
     62        f = filterbank(len(freq_list)-2, 1024)
     63        with self.assertRaises(ValueError):
     64            f.set_triangle_bands(fvec(freq_list), 48000)
     65
     66    def test_triangle_freqs_with_wrong_ordering(self):
     67        """make sure set_triangle_bands fails when list not ordered"""
     68        freq_list = [0, 80, 40]
     69        f = filterbank(len(freq_list)-2, 1024)
     70        with self.assertRaises(ValueError):
     71            f.set_triangle_bands(fvec(freq_list), 48000)
     72
     73    def test_triangle_freqs_with_large_freq(self):
     74        """make sure set_triangle_bands warns when freq > nyquist"""
     75        samplerate = 22050
     76        freq_list = [0, samplerate//4, samplerate // 2 + 1]
     77        f = filterbank(len(freq_list)-2, 1024)
     78        # TODO add assert_warns
     79        f.set_triangle_bands(fvec(freq_list), samplerate)
     80
     81    def test_triangle_freqs_with_not_enough_filters(self):
     82        """make sure set_triangle_bands warns when not enough filters"""
     83        samplerate = 22050
     84        freq_list = [0, 100, 1000, 4000, 8000, 10000]
     85        f = filterbank(len(freq_list)-3, 1024)
     86        # TODO add assert_warns
     87        f.set_triangle_bands(fvec(freq_list), samplerate)
     88
     89    def test_triangle_freqs_with_too_many_filters(self):
     90        """make sure set_triangle_bands warns when too many filters"""
     91        samplerate = 22050
     92        freq_list = [0, 100, 1000, 4000, 8000, 10000]
     93        f = filterbank(len(freq_list)-1, 1024)
     94        # TODO add assert_warns
     95        f.set_triangle_bands(fvec(freq_list), samplerate)
     96
     97    def test_triangle_freqs_with_double_value(self):
     98        """make sure set_triangle_bands works with 2 duplicate freqs"""
     99        samplerate = 22050
     100        freq_list = [0, 100, 1000, 4000, 4000, 4000, 10000]
     101        f = filterbank(len(freq_list)-2, 1024)
     102        # TODO add assert_warns
     103        f.set_triangle_bands(fvec(freq_list), samplerate)
     104
     105    def test_triangle_freqs_with_triple(self):
     106        """make sure set_triangle_bands works with 3 duplicate freqs"""
     107        samplerate = 22050
     108        freq_list = [0, 100, 1000, 4000, 4000, 4000, 10000]
     109        f = filterbank(len(freq_list)-2, 1024)
     110        # TODO add assert_warns
     111        f.set_triangle_bands(fvec(freq_list), samplerate)
     112
     113    def test_triangle_freqs_without_norm(self):
     114        """make sure set_triangle_bands works without """
     115        samplerate = 22050
     116        freq_list = fvec([0, 100, 1000, 10000])
     117        f = filterbank(len(freq_list) - 2, 1024)
     118        f.set_norm(0)
     119        f.set_triangle_bands(freq_list, samplerate)
     120        expected = f.get_coeffs()
     121        f.set_norm(1)
     122        f.set_triangle_bands(fvec(freq_list), samplerate)
     123        assert_almost_equal(f.get_coeffs().T,
     124                expected.T * 2. / (freq_list[2:] - freq_list[:-2]))
     125
     126    def test_triangle_freqs_wrong_norm(self):
     127        f = filterbank(10, 1024)
     128        with self.assertRaises(ValueError):
     129            f.set_norm(-1)
     130
     131    def test_triangle_freqs_with_power(self):
     132        f = filterbank(9, 1024)
     133        freqs = fvec([40, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 15000,
     134            24000])
     135        f.set_power(2)
     136        f.set_triangle_bands(freqs, 48000)
     137        spec = cvec(1024)
     138        spec.norm[:] = .1
     139        expected = fvec([0.02070313, 0.02138672, 0.02127604, 0.02135417,
     140            0.02133301, 0.02133301, 0.02133311, 0.02133334, 0.02133345])
     141        expected /= 100.
     142        assert_almost_equal(f(spec), expected)
     143
     144    def test_mel_coeffs(self):
     145        f = filterbank(40, 1024)
     146        f.set_mel_coeffs(44100, 0, 44100 / 2)
     147
     148    def test_zero_fmax(self):
     149        f = filterbank(40, 1024)
     150        f.set_mel_coeffs(44100, 0, 0)
     151
     152    def test_wrong_mel_coeffs(self):
     153        f = filterbank(40, 1024)
     154        with self.assertRaises(ValueError):
     155            f.set_mel_coeffs_slaney(0)
     156        with self.assertRaises(ValueError):
     157            f.set_mel_coeffs(44100, 0, -44100 / 2)
     158        with self.assertRaises(ValueError):
     159            f.set_mel_coeffs(44100, -0.1, 44100 / 2)
     160        with self.assertRaises(ValueError):
     161            f.set_mel_coeffs(-44100, 0.1, 44100 / 2)
     162        with self.assertRaises(ValueError):
     163            f.set_mel_coeffs_htk(-1, 0, 0)
     164
     165    def test_mel_coeffs_htk(self):
     166        f = filterbank(40, 1024)
     167        f.set_mel_coeffs_htk(44100, 0, 44100 / 2)
     168
     169
    48170if __name__ == '__main__':
    49     main()
     171    import nose2
     172    nose2.main()
  • python/tests/test_fvec.py

    r5b46bc3 r633400d  
    6060        self.assertRaises(IndexError, a.__getitem__, 3)
    6161        self.assertRaises(IndexError, a.__getitem__, 2)
     62
     63    def test_wrong_dimensions(self):
     64        a = np.array([[[1, 2], [3, 4]]], dtype=float_type)
     65        self.assertRaises(ValueError, fvec, a)
     66
     67    def test_wrong_size(self):
     68        a = np.ndarray([0,], dtype=float_type)
     69        self.assertRaises(ValueError, fvec, a)
    6270
    6371class aubio_wrong_fvec_input(TestCase):
  • python/tests/test_mfcc.py

    r5b46bc3 r633400d  
    111111        #print coeffs
    112112
     113
     114class aubio_mfcc_fb_params(TestCase):
     115
     116    def test_set_scale(self):
     117        buf_size, n_filters, n_coeffs, samplerate = 512, 20, 10, 16000
     118        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
     119        m.set_scale(10.5)
     120        assert m.get_scale() == 10.5
     121        m(cvec(buf_size))
     122
     123    def test_set_power(self):
     124        buf_size, n_filters, n_coeffs, samplerate = 512, 20, 10, 16000
     125        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
     126        m.set_power(2.5)
     127        assert m.get_power() == 2.5
     128        m(cvec(buf_size))
     129
     130    def test_set_mel_coeffs(self):
     131        buf_size, n_filters, n_coeffs, samplerate = 512, 20, 10, 16000
     132        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
     133        m.set_mel_coeffs(0., samplerate/2.)
     134        m(cvec(buf_size))
     135
     136    def test_set_mel_coeffs_htk(self):
     137        buf_size, n_filters, n_coeffs, samplerate = 512, 20, 10, 16000
     138        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
     139        m.set_mel_coeffs_htk(0., samplerate/2.)
     140        m(cvec(buf_size))
     141
     142    def test_set_mel_coeffs_slaney(self):
     143        buf_size, n_filters, n_coeffs, samplerate = 512, 40, 10, 16000
     144        m = mfcc(buf_size, n_filters, n_coeffs, samplerate)
     145        m.set_mel_coeffs_slaney()
     146        m(cvec(buf_size))
     147        assert m.get_power() == 1
     148        assert m.get_scale() == 1
     149
    113150if __name__ == '__main__':
    114151    main()
  • python/tests/test_midi2note.py

    r5b46bc3 r633400d  
    33
    44from aubio import midi2note
     5from nose2.tools import params
    56import unittest
    67
     
    1718class midi2note_good_values(unittest.TestCase):
    1819
    19     def test_midi2note_known_values(self):
     20    @params(*list_of_known_midis)
     21    def test_midi2note_known_values(self, midi, note):
    2022        " known values are correctly converted "
    21         for midi, note in list_of_known_midis:
    22             self.assertEqual ( midi2note(midi), note )
     23        self.assertEqual ( midi2note(midi), note )
    2324
    2425class midi2note_wrong_values(unittest.TestCase):
     
    4142
    4243if __name__ == '__main__':
    43     unittest.main()
     44    import nose2
     45    nose2.main()
  • python/tests/test_note2midi.py

    r5b46bc3 r633400d  
    44from __future__ import unicode_literals
    55
    6 from aubio import note2midi, freq2note
     6from aubio import note2midi, freq2note, note2freq, float_type
     7from nose2.tools import params
    78import unittest
    89
     
    1415        ( 'B3', 59 ),
    1516        ( 'B#3', 60 ),
     17        ( 'C♯4', 61 ),
    1618        ( 'A4', 69 ),
    1719        ( 'A#4', 70 ),
     20        ( 'A♯4', 70 ),
     21        ( 'A\u266f4', 70 ),
    1822        ( 'Bb4', 70 ),
    1923        ( 'B♭4', 70 ),
     24        ( 'B\u266d4', 70 ),
    2025        ( 'G8', 115 ),
    2126        ( 'G♯8', 116 ),
    2227        ( 'G9', 127 ),
    23         ( 'G\udd2a2', 45 ),
    24         ( 'B\ufffd2', 45 ),
    2528        ( 'A♮2', 45 ),
     29        )
     30
     31list_of_known_notes_with_unicode_issues = (
     32        ('C𝄪4', 62 ),
     33        ('E𝄫4', 62 ),
     34        )
     35
     36list_of_unknown_notes = (
     37        ( 'G\udd2a2' ),
     38        ( 'B\ufffd2' ),
     39        ( 'B\u266e\u266e2' ),
     40        ( 'B\u266f\u266d3' ),
     41        ( 'B33' ),
     42        ( 'C.3' ),
     43        ( 'A' ),
     44        ( '2' ),
    2645        )
    2746
    2847class note2midi_good_values(unittest.TestCase):
    2948
    30     def test_note2midi_known_values(self):
     49    @params(*list_of_known_notes)
     50    def test_note2midi_known_values(self, note, midi):
    3151        " known values are correctly converted "
    32         for note, midi in list_of_known_notes:
     52        self.assertEqual ( note2midi(note), midi )
     53
     54    @params(*list_of_known_notes_with_unicode_issues)
     55    def test_note2midi_known_values_with_unicode_issues(self, note, midi):
     56        " known values are correctly converted, unless decoding is expected to fail"
     57        try:
    3358            self.assertEqual ( note2midi(note), midi )
     59        except UnicodeEncodeError as e:
     60            import sys
     61            strfmt = "len(u'\\U0001D12A') != 1, excpected decoding failure | {:s} | {:s} {:s}"
     62            strres = strfmt.format(e, sys.platform, sys.version)
     63            # happens with: darwin 2.7.10, windows 2.7.12
     64            if len('\U0001D12A') != 1 and sys.version[0] == '2':
     65                self.skipTest(strres + " | upgrade to Python 3 to fix")
     66            else:
     67                raise
    3468
    3569class note2midi_wrong_values(unittest.TestCase):
     
    67101        self.assertRaises(TypeError, note2midi, 123)
    68102
     103    def test_note2midi_wrong_data_too_long(self):
     104        " fails when passed a note with a note name longer than expected"
     105        self.assertRaises(ValueError, note2midi, 'CB+-3')
     106
     107    @params(*list_of_unknown_notes)
     108    def test_note2midi_unknown_values(self, note):
     109        " unknown values throw out an error "
     110        self.assertRaises(ValueError, note2midi, note)
    69111
    70112class freq2note_simple_test(unittest.TestCase):
    71113
    72     def test_freq2note(self):
     114    def test_freq2note_above(self):
    73115        " make sure freq2note(441) == A4 "
    74116        self.assertEqual("A4", freq2note(441))
    75117
     118    def test_freq2note_under(self):
     119        " make sure freq2note(439) == A4 "
     120        self.assertEqual("A4", freq2note(439))
     121
     122class note2freq_simple_test(unittest.TestCase):
     123
     124    def test_note2freq(self):
     125        " make sure note2freq('A3') == 220"
     126        self.assertEqual(220, note2freq("A3"))
     127
     128    def test_note2freq_under(self):
     129        " make sure note2freq(A4) == 440"
     130        if float_type == 'float32':
     131            self.assertEqual(440, note2freq("A4"))
     132        else:
     133            self.assertLess(abs(note2freq("A4")-440), 1.e-12)
     134
    76135if __name__ == '__main__':
    77     unittest.main()
     136    import nose2
     137    nose2.main()
  • python/tests/test_onset.py

    r5b46bc3 r633400d  
    33from unittest import main
    44from numpy.testing import TestCase, assert_equal, assert_almost_equal
    5 from aubio import onset
     5from aubio import onset, fvec
    66
    77class aubio_onset_default(TestCase):
     
    2020
    2121    def test_get_delay(self):
    22         assert_equal (self.o.get_delay(), int(4.3 * self.o.hop_size))
     22        self.assertGreater(self.o.get_delay(), 0)
    2323
    2424    def test_get_delay_s(self):
    25         assert_almost_equal (self.o.get_delay_s(), self.o.get_delay() / float(self.samplerate))
     25        self.assertGreater(self.o.get_delay_s(), 0.)
    2626
    2727    def test_get_delay_ms(self):
    28         assert_almost_equal (self.o.get_delay_ms(), self.o.get_delay() * 1000. / self.samplerate, 5)
     28        self.assertGreater(self.o.get_delay_ms(), 0.)
    2929
    3030    def test_get_minioi(self):
    31         assert_almost_equal (self.o.get_minioi(), 0.02 * self.samplerate)
     31        self.assertGreater(self.o.get_minioi(), 0)
    3232
    3333    def test_get_minioi_s(self):
    34         assert_almost_equal (self.o.get_minioi_s(), 0.02)
     34        self.assertGreater(self.o.get_minioi_s(), 0.)
    3535
    3636    def test_get_minioi_ms(self):
    37         assert_equal (self.o.get_minioi_ms(), 20.)
     37        self.assertGreater(self.o.get_minioi_ms(), 0.)
    3838
    3939    def test_get_threshold(self):
    40         assert_almost_equal (self.o.get_threshold(), 0.3)
     40        self.assertGreater(self.o.get_threshold(), 0.)
    4141
    4242    def test_set_delay(self):
     
    8484    samplerate = 8000
    8585
     86class aubio_onset_coverate(TestCase):
     87    # extra tests to execute the C routines and improve coverage
     88
     89    def test_all_methods(self):
     90        for method in ['default', 'energy', 'hfc', 'complexdomain', 'complex',
     91                'phase', 'wphase', 'mkl', 'kl', 'specflux', 'specdiff',
     92                'old_default']:
     93            o = onset(method=method, buf_size=512, hop_size=256)
     94            o(fvec(256))
     95
     96    def test_get_methods(self):
     97        o = onset(method='default', buf_size=512, hop_size=256)
     98
     99        assert o.get_silence() == -70
     100        o.set_silence(-20)
     101        assert_almost_equal(o.get_silence(), -20)
     102
     103        assert o.get_compression() == 1
     104        o.set_compression(.99)
     105        assert_almost_equal(o.get_compression(), .99)
     106
     107        assert o.get_awhitening() == 0
     108        o.set_awhitening(1)
     109        assert o.get_awhitening() == 1
     110
     111        o.get_last()
     112        o.get_last_ms()
     113        o.get_last_s()
     114        o.get_descriptor()
     115        o.get_thresholded_descriptor()
     116
     117
    86118if __name__ == '__main__':
    87119    main()
  • python/tests/test_phasevoc.py

    r5b46bc3 r633400d  
    4747            assert_equal ( t, 0.)
    4848            assert_equal ( s.norm, 0.)
    49             assert_equal ( s.phas, 0.)
     49            try:
     50                assert_equal ( s.phas, 0 )
     51            except AssertionError:
     52                assert_equal (s.phas[s.phas > 0], +np.pi)
     53                assert_equal (s.phas[s.phas < 0], -np.pi)
     54                assert_equal (np.abs(s.phas[np.abs(s.phas) != np.pi]), 0)
     55                self.skipTest('pvoc(fvec(%d)).phas != +0, ' % win_s \
     56                        + 'This is expected when using fftw3 on powerpc.')
    5057            assert_equal ( r, 0.)
     58
     59    def test_no_overlap(self):
     60        win_s, hop_s = 1024, 1024
     61        f = pvoc (win_s, hop_s)
     62        t = fvec (hop_s)
     63        for _ in range(4):
     64            s = f(t)
     65            r = f.rdo(s)
     66            assert_equal ( t, 0.)
    5167
    5268    @params(
  • python/tests/test_pitch.py

    r5b46bc3 r633400d  
    7171        #print 'median errors: ', median(errors), 'median pitches: ', median(pitches)
    7272
    73 pitch_algorithms = [ "default", "yinfft", "yin", "schmitt", "mcomb", "fcomb" , "specacf" ]
    74 pitch_algorithms = [ "default", "yinfft", "yin", "schmitt", "mcomb", "fcomb" ]
     73pitch_algorithms = [ "default", "yinfft", "yin", "yinfast", "schmitt", "mcomb", "fcomb" , "specacf" ]
     74pitch_algorithms = [ "default", "yinfft", "yin", "yinfast", "schmitt", "mcomb", "fcomb" ]
    7575
    7676#freqs = [ 27.5, 55., 110., 220., 440., 880., 1760., 3520. ]
  • python/tests/test_sink.py

    r5b46bc3 r633400d  
    55from numpy.testing import TestCase
    66from aubio import fvec, source, sink
    7 from utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path
     7from .utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path
     8
     9import warnings
     10warnings.filterwarnings('ignore', category=UserWarning, append=True)
    811
    912list_of_sounds = list_all_sounds('sounds')
     
    2629        if not len(list_of_sounds):
    2730            self.skipTest('add some sound files in \'python/tests/sounds\'')
     31
     32    def test_wrong_filename(self):
     33        with self.assertRaises(RuntimeError):
     34            sink('')
     35
     36    def test_wrong_samplerate(self):
     37        with self.assertRaises(RuntimeError):
     38            sink(get_tmp_sink_path(), -1)
     39
     40    def test_wrong_samplerate_too_large(self):
     41        with self.assertRaises(RuntimeError):
     42            sink(get_tmp_sink_path(), 1536001, 2)
     43
     44    def test_wrong_channels(self):
     45        with self.assertRaises(RuntimeError):
     46            sink(get_tmp_sink_path(), 44100, -1)
     47
     48    def test_wrong_channels_too_large(self):
     49        with self.assertRaises(RuntimeError):
     50            sink(get_tmp_sink_path(), 44100, 202020)
    2851
    2952    def test_many_sinks(self):
     
    94117        del_tmp_sink_path(sink_path)
    95118
     119    def test_read_with(self):
     120        samplerate = 44100
     121        sink_path = get_tmp_sink_path()
     122        vec = fvec(128)
     123        with sink(sink_path, samplerate) as g:
     124            for _ in range(10):
     125                g(vec, 128)
     126
    96127if __name__ == '__main__':
    97128    main()
  • python/tests/test_slicing.py

    r5b46bc3 r633400d  
    44from numpy.testing import TestCase, assert_equal
    55from aubio import slice_source_at_stamps
    6 from utils import count_files_in_directory, get_default_test_sound
    7 from utils import count_samples_in_directory, count_samples_in_file
     6from .utils import count_files_in_directory, get_default_test_sound
     7from .utils import count_samples_in_directory, count_samples_in_file
    88
    99import tempfile
     
    2424    def test_slice_start_only_no_zero(self):
    2525        regions_start = [i*1000 for i in range(1, n_slices)]
    26         slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
     26        slice_source_at_stamps(self.source_file, regions_start,
     27                output_dir = self.output_dir, create_first=True)
    2728
    2829    def test_slice_start_beyond_end(self):
    2930        regions_start = [i*1000 for i in range(1, n_slices)]
    3031        regions_start += [count_samples_in_file(self.source_file) + 1000]
    31         slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir)
     32        slice_source_at_stamps(self.source_file, regions_start,
     33                output_dir = self.output_dir, create_first=True)
    3234
    3335    def test_slice_start_every_blocksize(self):
    3436        hopsize = 200
    35         regions_start = [i*hopsize for i in range(1, n_slices)]
     37        regions_start = [i*hopsize for i in range(0, n_slices)]
    3638        slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir,
    3739                hopsize = 200)
     40
     41    def test_slice_start_every_half_blocksize(self):
     42        hopsize = 200
     43        regions_start = [i*hopsize//2 for i in range(0, n_slices)]
     44        slice_source_at_stamps(self.source_file, regions_start,
     45                output_dir = self.output_dir, hopsize = 200)
    3846
    3947    def tearDown(self):
     
    92100            "number of samples written different from number of original samples")
    93101
     102    def test_slice_start_and_ends_with_missing_end(self):
     103        regions_start = [i*1000 for i in range(n_slices)]
     104        regions_ends = [r-1 for r in regions_start[1:]]
     105        slice_source_at_stamps(self.source_file, regions_start, regions_ends,
     106                output_dir = self.output_dir)
     107        written_samples = count_samples_in_directory(self.output_dir)
     108        original_samples = count_samples_in_file(self.source_file)
     109        total_files = count_files_in_directory(self.output_dir)
     110        assert_equal(n_slices, total_files,
     111            "number of slices created different from expected")
     112        assert_equal(written_samples, original_samples,
     113            "number of samples written different from number of original samples")
     114
    94115    def tearDown(self):
    95116        shutil.rmtree(self.output_dir)
     
    134155        regions_end = None
    135156        slice_source_at_stamps (self.source_file, regions_start, regions_end,
    136                 output_dir = self.output_dir)
     157                output_dir = self.output_dir, create_first=True)
    137158        total_files = count_files_in_directory(self.output_dir)
    138159        assert_equal(n_slices, total_files,
  • python/tests/test_source.py

    r5b46bc3 r633400d  
    33from nose2 import main
    44from nose2.tools import params
    5 from numpy.testing import TestCase
     5from numpy.testing import TestCase, assert_equal
    66from aubio import source
    7 from utils import list_all_sounds
     7from .utils import list_all_sounds
    88
    99import warnings
     
    5252        total_frames = 0
    5353        while True:
    54             _ , read = f()
     54            samples , read = f()
    5555            total_frames += read
    56             if read < f.hop_size: break
     56            if read < f.hop_size:
     57                assert_equal(samples[read:], 0)
     58                break
    5759        #result_str = "read {:.2f}s ({:d} frames in {:d} blocks at {:d}Hz) from {:s}"
    5860        #result_params = total_frames / float(f.samplerate), total_frames, total_frames//f.hop_size, f.samplerate, f.uri
     
    6769            self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e)))
    6870        assert f.samplerate != 0
    69         self.read_from_source(f)
     71        read_frames = self.read_from_source(f)
     72        if 'f_' in soundfile and samplerate == 0:
     73            import re
     74            f = re.compile('.*_\([0:9]*f\)_.*')
     75            match_f = re.findall('([0-9]*)f_', soundfile)
     76            if len(match_f) == 1:
     77                expected_frames = int(match_f[0])
     78                self.assertEqual(expected_frames, read_frames)
    7079
    7180    @params(*list_of_sounds)
     
    150159        total_frames = 0
    151160        while True:
    152             _, read = f.do_multi()
     161            samples, read = f.do_multi()
    153162            total_frames += read
    154             if read < f.hop_size: break
     163            if read < f.hop_size:
     164                assert_equal(samples[:,read:], 0)
     165                break
    155166        #result_str = "read {:.2f}s ({:d} frames in {:d} channels and {:d} blocks at {:d}Hz) from {:s}"
    156167        #result_params = total_frames / float(f.samplerate), total_frames, f.channels, int(total_frames/f.hop_size), f.samplerate, f.uri
     
    158169        return total_frames
    159170
     171class aubio_source_with(aubio_source_test_case_base):
     172
     173    #@params(*list_of_sounds)
     174    @params(*list_of_sounds)
     175    def test_read_from_mono(self, filename):
     176        total_frames = 0
     177        hop_size = 2048
     178        with source(filename, 0, hop_size) as input_source:
     179            assert_equal(input_source.hop_size, hop_size)
     180            #assert_equal(input_source.samplerate, samplerate)
     181            total_frames = 0
     182            for frames in input_source:
     183                total_frames += frames.shape[-1]
     184            # check we read as many samples as we expected
     185            assert_equal(total_frames, input_source.duration)
     186
    160187if __name__ == '__main__':
    161188    main()
Note: See TracChangeset for help on using the changeset viewer.