- Timestamp:
- Dec 5, 2018, 10:34:39 PM (6 years ago)
- 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. - Location:
- python
- Files:
-
- 18 added
- 3 deleted
- 40 edited
Legend:
- Unmodified
- Added
- Removed
-
python/README.md
r5b46bc3 r633400d 1 Python aubio module 2 ===== ==============1 aubio 2 ===== 3 3 4 This module wraps the aubio library for Python using the numpy module.4 aubio is a collection of tools for music and audio analysis. 5 5 6 Using the Python aubio module 7 ----------------------------- 6 This package integrates the aubio library with [NumPy] to provide a set of 7 efficient tools to process and analyse audio signals, including: 8 8 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 10 15 11 $ python 12 [...] 13 >>> import aubio 14 >>> help(aubio.miditofreq) 16 aubio works with both Python 2 and Python 3. 15 17 16 Finding some inspiration 17 ----- -------------------18 Links 19 ----- 18 20 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] 21 26 22 For instance, `demo_source.py` reads a media file. 27 Demos 28 ----- 23 29 24 $ ./python/demos/demo_source.py /path/to/sound/sample.wav 30 Some examples are available in the [`python/demos`][demos_dir] folder. Each 31 script is a command line program which accepts one ore more argument. 25 32 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. 27 34 28 $ ./python/demo/demo_timestretch_online.py loop.wav stretched_loop.wav 0.92` 35 ### Analysis 29 36 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. 34 44 35 Testing the Python module 36 ------------------------- 45 ### Real-time 37 46 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] 39 50 40 $ ./python/tests/run_all_tests51 ### Others 41 52 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 43 57 44 $ ./python/tests/test_note2midi.py -v 58 ### Example 45 59 46 Install in a virtualenv 47 ----------------------- 60 Use `demo_timestretch_online.py` to slow down `loop.wav`, write the results in 61 `stretched_loop.wav`: 48 62 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 51 64 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 65 Built with 90 66 ---------- 91 67 92 To install the Python module: 68 The 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 70 libraries: 93 71 94 $ ./setup.py install 72 - media file reading: 95 73 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. 98 78 99 $ export PYTHONPATH=$PYTHONPATH:$PWD/`ls -rtd build/lib.* | head -1`:$PWD/tests 79 - hardware acceleration: 100 80 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 4 4 from numpy import median, diff 5 5 6 def get_file_bpm(path, params =None):6 def get_file_bpm(path, params=None): 7 7 """ Calculate the beats per minute (bpm) of a given file. 8 8 path: path to the file … … 11 11 if params is None: 12 12 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 26 33 27 34 s = source(path, samplerate, hop_s) … … 45 52 break 46 53 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) 57 66 58 67 if __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) 62 79 print("{:6s} {:s}".format("{:2f}".format(bpm), f)) -
python/demos/demo_filter.py
r5b46bc3 r633400d 1 1 #! /usr/bin/env python 2 2 3 import sys 4 import os.path 5 import aubio 3 6 4 def apply_filter(path):5 from aubio import source, sink, digital_filter6 from os.path import basename, splitext7 7 8 def apply_filter(path, target): 8 9 # open input file, get its samplerate 9 s = source(path)10 s = aubio.source(path) 10 11 samplerate = s.samplerate 11 12 12 13 # create an A-weighting filter 13 f = digital_filter(7)14 f = aubio.digital_filter(7) 14 15 f.set_a_weighting(samplerate) 15 # alternatively, apply another filter16 16 17 17 # create output file 18 o = sink("filtered_" + splitext(basename(path))[0] + ".wav", samplerate)18 o = aubio.sink(target, samplerate) 19 19 20 20 total_frames = 0 21 21 while True: 22 # read from source 22 23 samples, read = s() 24 # filter samples 23 25 filtered_samples = f(samples) 26 # write to sink 24 27 o(filtered_samples, read) 28 # count frames read 25 29 total_frames += read 26 if read < s.hop_size: break 30 # end of file reached 31 if read < s.hop_size: 32 break 27 33 34 # print some info 28 35 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)) 32 40 33 41 if __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 1 1 #! /usr/bin/env python 2 2 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. 6 4 5 This demo uses `aubio.filterbank.set_triangle_bands` to build a set of 6 triangular filters from a list of frequencies. 7 8 The filterbank coefficients are then modified before being displayed.""" 9 10 import aubio 11 import numpy as np 12 import matplotlib.pyplot as plt 13 14 # sampling rate and size of the fft 15 samplerate = 48000 7 16 win_s = 2048 8 samplerate = 480009 17 18 # define a list of custom frequency 10 19 freq_list = [60, 80, 200, 400, 800, 1600, 3200, 6400, 12800, 24000] 20 # number of filters to create 11 21 n_filters = len(freq_list) - 2 12 22 13 f = filterbank(n_filters, win_s) 14 freqs = fvec(freq_list) 23 # create a new filterbank 24 f = aubio.filterbank(n_filters, win_s) 25 freqs = aubio.fvec(freq_list) 15 26 f.set_triangle_bands(freqs, samplerate) 16 27 28 # get the coefficients from the filterbank 17 29 coeffs = f.get_coeffs() 18 coeffs[4] *= 5. 19 30 # apply a gain to fifth band 31 coeffs[4] *= 6. 32 # load the modified coeffs into the filterbank 20 33 f.set_coeffs(coeffs) 21 34 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 36 freqs = np.vstack([np.arange(win_s // 2 + 1) * samplerate / win_s] * n_filters) 37 plt.title('filterbank built from a list of frequencies\n' 38 'The 5th band has been amplified by a factor 6.') 39 plt.loglog(freqs.T, f.get_coeffs().T, '.-') 40 plt.xlim([50, samplerate/2]) 41 plt.ylim([1.0e-6, 2.0e-2]) 42 plt.xlabel('log frequency (Hz)') 43 plt.ylabel('log amplitude') 44 plt.show() -
python/demos/demo_pitch_sinusoid.py
r5b46bc3 r633400d 38 38 pointer += partition 39 39 pointer += partition 40 freqs[ pointer : pointer + partition ] = 400 + 5 * np.random.random(sin_length/ 8)40 freqs[ pointer : pointer + partition ] = 400 + 5 * np.random.random(sin_length//8) 41 41 42 42 a = build_sinusoid(sin_length, freqs, samplerate) -
python/demos/demo_source_simple.py
r5b46bc3 r633400d 1 1 #! /usr/bin/env python 2 import sys, aubio 2 3 """A simple example using aubio.source.""" 4 5 import sys 6 import aubio 3 7 4 8 samplerate = 0 # use original source samplerate 5 hop_size = 256 # number of frames to read in one block6 s = aubio.source(sys.argv[1], samplerate, hop_size)9 hop_size = 256 # number of frames to read in one block 10 src = aubio.source(sys.argv[1], samplerate, hop_size) 7 11 total_frames = 0 8 12 9 while True: # reading loop 10 samples, read = s() 11 total_frames += read 12 if read < hop_size: break # end of file reached 13 while 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 13 18 14 19 fmt_string = "read {:d} frames at {:d}Hz from {:s}" 15 print (fmt_string.format(total_frames, s.samplerate, sys.argv[1])) 16 20 print(fmt_string.format(total_frames, src.samplerate, src.uri)) -
python/demos/demo_timestretch.py
r5b46bc3 r633400d 13 13 14 14 win_s = 1024 15 hop_s = win_s / 8 # 87.5 % overlap15 hop_s = win_s // 8 # 87.5 % overlap 16 16 17 17 warmup = win_s // hop_s - 1 -
python/demos/demo_timestretch_online.py
r5b46bc3 r633400d 12 12 import numpy as np 13 13 14 win_s = 102415 hop_s = win_s / 8 # 87.5 % overlap14 win_s = 512 15 hop_s = win_s // 8 # 87.5 % overlap 16 16 17 17 warmup = win_s // hop_s - 1 … … 93 93 old_grain.phas = np.copy(cur_grain.phas) 94 94 95 # until end of file 96 if read < hop_s: break 97 # increment block counter 95 98 block_read += 1 96 if read < hop_s: break97 99 98 100 for t in range(warmup + 2): # purge the last frames from the phase vocoder -
python/ext/aubio-types.h
r5b46bc3 r633400d 28 28 #include "aubio.h" 29 29 #else 30 #include "aubio/aubio.h"30 #include <aubio/aubio.h> 31 31 #endif 32 32 … … 45 45 #define AUBIO_NPY_SMPL_STR "float32" 46 46 #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 47 55 #endif 48 56 -
python/ext/aubiomodule.c
r5b46bc3 r633400d 3 3 #include "py-musicutils.h" 4 4 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 5 10 static char aubio_module_doc[] = "Python module for the aubio library"; 6 11 7 12 static 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" 11 28 "\n" 12 29 "Example\n" 13 30 "-------\n" 14 31 "\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 ""; 16 44 17 45 static 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" 21 64 "\n" 22 65 "Example\n" 23 66 "-------\n" 24 67 "\n" 25 ">>> midi = bintomidi(float, samplerate = 44100, fftsize = 1024)"; 68 ">>> aubio.bintomidi(10, 44100, 1024)\n" 69 "68.62871551513672\n" 70 ""; 26 71 27 72 static 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 101 static 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" 31 120 "\n" 32 121 "Example\n" 33 122 "-------\n" 34 123 "\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 128 static 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 155 static 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" 41 169 "\n" 42 170 "Example\n" 43 171 "-------\n" 44 172 "\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 178 static 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" 51 194 "\n" 52 195 "Example\n" 53 196 "-------\n" 54 197 "\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 ""; 76 201 77 202 extern void add_ufuncs ( PyObject *m ); … … 113 238 smpl_t output; 114 239 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)) { 116 243 return NULL; 117 244 } … … 128 255 smpl_t output; 129 256 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)) { 131 260 return NULL; 132 261 } … … 143 272 smpl_t output; 144 273 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)) { 146 277 return NULL; 147 278 } … … 158 289 smpl_t output; 159 290 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)) { 161 294 return NULL; 162 295 } … … 238 371 {"level_detection", Py_aubio_level_detection, METH_VARARGS, Py_aubio_level_detection_doc}, 239 372 {"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}, 240 379 {NULL, NULL, 0, NULL} /* Sentinel */ 241 380 }; … … 324 463 325 464 PyModule_AddStringConstant(m, "float_type", AUBIO_NPY_SMPL_STR); 465 PyModule_AddStringConstant(m, "__version__", DEFINEDSTRING(AUBIO_VERSION)); 326 466 327 467 // add generated objects -
python/ext/py-cvec.c
r5b46bc3 r633400d 20 20 } Py_cvec; 21 21 22 static char Py_cvec_doc[] = "cvec object"; 22 static 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 ""; 23 53 24 54 … … 143 173 npy_intp length; 144 174 if (!PyAubio_IsValidVector(input)) { 145 return 1;175 return -1; 146 176 } 147 177 length = PyArray_SIZE ((PyArrayObject *)input); 148 178 if (length != vec->length) { 149 179 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, 151 181 vec->length); 152 return 1;182 return -1; 153 183 } 154 184 … … 164 194 npy_intp length; 165 195 if (!PyAubio_IsValidVector(input)) { 166 return 1;196 return -1; 167 197 } 168 198 length = PyArray_SIZE ((PyArrayObject *)input); 169 199 if (length != vec->length) { 170 200 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, 172 202 vec->length); 173 return 1;203 return -1; 174 204 } 175 205 … … 183 213 // TODO remove READONLY flag and define getter/setter 184 214 {"length", T_INT, offsetof (Py_cvec, length), READONLY, 185 " length attribute"},215 "int: Length of `norm` and `phas` vectors."}, 186 216 {NULL} /* Sentinel */ 187 217 }; … … 192 222 193 223 static 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.", 196 226 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.", 199 229 NULL}, 200 230 {NULL} /* sentinel */ -
python/ext/py-filterbank.c
r5b46bc3 r633400d 95 95 if (self->vec.length != self->win_s / 2 + 1) { 96 96 PyErr_Format(PyExc_ValueError, 97 "input cvec has length %d, but f ftexpects length %d",97 "input cvec has length %d, but filterbank expects length %d", 98 98 self->vec.length, self->win_s / 2 + 1); 99 99 return NULL; … … 123 123 124 124 PyObject *input; 125 uint_t samplerate;126 if (!PyArg_ParseTuple (args, "O I", &input, &samplerate)) {125 smpl_t samplerate; 126 if (!PyArg_ParseTuple (args, "O" AUBIO_NPY_SMPL_CHR, &input, &samplerate)) { 127 127 return NULL; 128 128 } … … 139 139 &(self->freqs), samplerate); 140 140 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 } 143 149 return NULL; 144 150 } … … 151 157 uint_t err = 0; 152 158 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)) { 155 161 return NULL; 156 162 } … … 158 164 err = aubio_filterbank_set_mel_coeffs_slaney (self->o, samplerate); 159 165 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 179 static PyObject * 180 Py_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 208 static PyObject * 209 Py_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 } 162 232 return NULL; 163 233 } … … 194 264 return (PyObject *)PyAubio_CFmatToArray( 195 265 aubio_filterbank_get_coeffs (self->o) ); 266 } 267 268 static PyObject * 269 Py_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 291 static PyObject * 292 Py_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; 196 312 } 197 313 … … 201 317 {"set_mel_coeffs_slaney", (PyCFunction) Py_filterbank_set_mel_coeffs_slaney, 202 318 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"}, 203 323 {"get_coeffs", (PyCFunction) Py_filterbank_get_coeffs, 204 324 METH_NOARGS, "get coefficients of filterbank"}, 205 325 {"set_coeffs", (PyCFunction) Py_filterbank_set_coeffs, 206 326 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"}, 207 331 {NULL} 208 332 }; -
python/ext/py-musicutils.c
r5b46bc3 r633400d 134 134 return level_detection; 135 135 } 136 137 PyObject * 138 Py_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 161 PyObject * 162 Py_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 185 PyObject* 186 Py_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 202 PyObject* 203 Py_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 219 PyObject* 220 Py_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 229 PyObject* 230 Py_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 3 3 4 4 static 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" 13 43 "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 ""; 15 94 16 95 PyObject * Py_aubio_window(PyObject *self, PyObject *args); 17 96 18 97 static 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 ""; 30 128 31 129 PyObject * Py_aubio_level_lin(PyObject *self, PyObject *args); 32 130 33 131 static 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 ""; 45 168 46 169 PyObject * Py_aubio_db_spl(PyObject *self, PyObject *args); 47 170 48 171 static 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 ""; 59 201 60 202 PyObject * Py_aubio_silence_detection(PyObject *self, PyObject *args); 61 203 62 204 static 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 ""; 71 234 72 235 PyObject * Py_aubio_level_detection(PyObject *self, PyObject *args); 73 236 237 static 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 ""; 268 PyObject * Py_aubio_shift(PyObject *self, PyObject *args); 269 270 static 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 ""; 301 PyObject * Py_aubio_ishift(PyObject *self, PyObject *args); 302 303 static 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 ""; 324 PyObject * Py_aubio_hztomel(PyObject *self, PyObject *args); 325 326 static 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 ""; 347 PyObject * Py_aubio_meltohz(PyObject *self, PyObject *args); 348 349 static 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 ""; 358 PyObject * Py_aubio_hztomel_htk(PyObject *self, PyObject *args); 359 360 static 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 ""; 369 PyObject * Py_aubio_meltohz_htk(PyObject *self, PyObject *args); 370 74 371 #endif /* PY_AUBIO_MUSICUTILS_H */ -
python/ext/py-phasevoc.c
r5b46bc3 r633400d 1 1 #include "aubio-types.h" 2 2 3 static char Py_pvoc_doc[] = "pvoc object"; 3 static 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 4 56 5 57 typedef struct … … 39 91 self->hop_s = Py_default_vector_length/2; 40 92 41 if (self == NULL) {42 return NULL;43 }44 45 93 if (win_s > 0) { 46 94 self->win_s = win_s; … … 122 170 static PyMemberDef Py_pvoc_members[] = { 123 171 {"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 ""}, 125 174 {"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 ""}, 127 177 { NULL } // sentinel 128 178 }; … … 156 206 } 157 207 208 static PyObject * 209 Pyaubio_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 158 226 static PyMethodDef Py_pvoc_methods[] = { 159 227 {"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 ""}, 161 269 {NULL} 162 270 }; -
python/ext/py-sink.c
r5b46bc3 r633400d 13 13 14 14 static 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" 46 50 "\n"; 47 51 48 52 static 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 ""; 52 64 53 65 static 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 ""; 57 77 58 78 static 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 ""; 62 87 63 88 static PyObject * … … 81 106 } 82 107 83 self->uri = "none";108 self->uri = NULL; 84 109 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); 86 112 } 87 113 88 114 self->samplerate = Py_aubio_default_samplerate; 89 if ( (sint_t)samplerate >0) {115 if (samplerate != 0) { 90 116 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;95 117 } 96 118 97 119 self->channels = 1; 98 if ( (sint_t)channels >0) {120 if (channels != 0) { 99 121 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;104 122 } 105 123 … … 110 128 Py_sink_init (Py_sink * self, PyObject * args, PyObject * kwds) 111 129 { 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 ); 119 131 if (self->o == NULL) { 120 PyErr_SetString (PyExc_RuntimeError, "error creating sink with this uri");132 // error string was set in new_aubio_sink 121 133 return -1; 122 134 } 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 123 144 self->samplerate = aubio_sink_get_samplerate ( self->o ); 124 145 self->channels = aubio_sink_get_channels ( self->o ); … … 132 153 del_aubio_sink(self->o); 133 154 free(self->mwrite_data.data); 155 if (self->uri) { 156 free(self->uri); 157 } 134 158 Py_TYPE(self)->tp_free((PyObject *) self); 135 159 } … … 190 214 static PyMemberDef Py_sink_members[] = { 191 215 {"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."}, 193 217 {"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."}, 195 219 {"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."}, 197 221 { NULL } // sentinel 198 222 }; … … 203 227 aubio_sink_close (self->o); 204 228 Py_RETURN_NONE; 229 } 230 231 static char Pyaubio_sink_enter_doc[] = ""; 232 static PyObject* Pyaubio_sink_enter(Py_sink *self, PyObject *unused) { 233 Py_INCREF(self); 234 return (PyObject*)self; 235 } 236 237 static char Pyaubio_sink_exit_doc[] = ""; 238 static PyObject* Pyaubio_sink_exit(Py_sink *self, PyObject *unused) { 239 return Pyaubio_sink_close(self, unused); 205 240 } 206 241 … … 209 244 {"do_multi", (PyCFunction) Py_sink_do_multi, METH_VARARGS, Py_sink_do_multi_doc}, 210 245 {"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}, 211 250 {NULL} /* sentinel */ 212 251 }; -
python/ext/py-source.c
r5b46bc3 r633400d 17 17 18 18 static 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 ""; 51 217 52 218 static 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 ""; 56 228 57 229 static 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 ""; 61 239 62 240 static 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 ""; 66 268 67 269 static 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 ""; 71 307 72 308 static 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 ""; 76 315 77 316 static 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 ""; 81 329 82 330 static PyObject * … … 101 349 } 102 350 103 self->uri = "none";351 self->uri = NULL; 104 352 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); 106 355 } 107 356 … … 164 413 free(self->c_mread_to.data); 165 414 } 415 if (self->uri) { 416 free(self->uri); 417 } 166 418 Py_XDECREF(self->read_to); 167 419 Py_XDECREF(self->mread_to); … … 214 466 static PyMemberDef Py_source_members[] = { 215 467 {"uri", T_STRING, offsetof (Py_source, uri), READONLY, 216 " path at which the source was created"},468 "str (read-only): pathname or URL"}, 217 469 {"samplerate", T_INT, offsetof (Py_source, samplerate), READONLY, 218 " samplerate at which the source is viewed"},470 "int (read-only): sampling rate"}, 219 471 {"channels", T_INT, offsetof (Py_source, channels), READONLY, 220 " number of channels found in the source"},472 "int (read-only): number of channels"}, 221 473 {"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"}, 223 475 {"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 ""}, 225 491 { NULL } // sentinel 226 492 }; … … 243 509 Pyaubio_source_close (Py_source *self, PyObject *unused) 244 510 { 245 aubio_source_close (self->o);511 if (aubio_source_close(self->o) != 0) return NULL; 246 512 Py_RETURN_NONE; 247 513 } … … 271 537 } 272 538 Py_RETURN_NONE; 539 } 540 541 static char Pyaubio_source_enter_doc[] = ""; 542 static PyObject* Pyaubio_source_enter(Py_source *self, PyObject *unused) { 543 Py_INCREF(self); 544 return (PyObject*)self; 545 } 546 547 static char Pyaubio_source_exit_doc[] = ""; 548 static PyObject* Pyaubio_source_exit(Py_source *self, PyObject *unused) { 549 return Pyaubio_source_close(self, unused); 550 } 551 552 static PyObject* Pyaubio_source_iter(PyObject *self) { 553 Py_INCREF(self); 554 return (PyObject*)self; 555 } 556 557 static 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 } 273 598 } 274 599 … … 286 611 {"seek", (PyCFunction) Pyaubio_source_seek, 287 612 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}, 288 617 {NULL} /* sentinel */ 289 618 }; … … 315 644 0, 316 645 0, 317 0,318 0,646 Pyaubio_source_iter, 647 (unaryfunc)Pyaubio_source_iter_next, 319 648 Py_source_methods, 320 649 Py_source_members, -
python/ext/ufuncs.c
r5b46bc3 r633400d 59 59 }; 60 60 61 static char Py_unwrap2pi_doc[] = "map angle to unit circle [-pi, pi["; 61 // Note: these docstrings should *not* include the function signatures 62 63 static 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 ""; 62 77 63 78 static void* Py_unwrap2pi_data[] = { … … 68 83 }; 69 84 70 static char Py_freqtomidi_doc[] = "convert frequency to midi"; 85 static 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 ""; 71 99 72 100 static void* Py_freqtomidi_data[] = { … … 75 103 }; 76 104 77 static char Py_miditofreq_doc[] = "convert midi to frequency"; 105 static 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 ""; 78 119 79 120 static void* Py_miditofreq_data[] = { -
python/lib/aubio/__init__.py
r5b46bc3 r633400d 1 1 #! /usr/bin/env python 2 # -*- coding: utf8 -*- 3 4 """ 5 aubio 6 ===== 7 8 Provides a number of classes and functions for music and audio signal 9 analysis. 10 11 How to use the documentation 12 ---------------------------- 13 14 Documentation of the python module is available as docstrings provided 15 within the code, and a reference guide available online from `the 16 aubio homepage <https://aubio.org/documentation>`_. 17 18 The docstrings examples are written assuming `aubio` and `numpy` have been 19 imported with: 20 21 >>> import aubio 22 >>> import numpy as np 23 """ 2 24 3 25 import numpy 26 from ._aubio import __version__ as version 27 from ._aubio import float_type 4 28 from ._aubio import * 5 from ._aubio import float_type6 29 from .midiconv import * 7 30 from .slicing import * 8 31 32 9 33 class fvec(numpy.ndarray): 10 """a numpy vector holding audio samples""" 34 """fvec(input_arg=1024) 35 A vector holding float samples. 11 36 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): 13 75 if isinstance(input_arg, int): 14 76 if input_arg == 0: 15 77 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') 17 79 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 2 2 """ utilities to convert midi note number to and from note names """ 3 3 4 __all__ = ['note2midi', 'midi2note', 'freq2note'] 4 import sys 5 from ._aubio import freqtomidi, miditofreq 5 6 6 import sys 7 __all__ = ['note2midi', 'midi2note', 'freq2note', 'note2freq'] 8 7 9 py3 = sys.version_info[0] == 3 8 10 if py3: … … 13 15 int_instances = (int, long) 14 16 17 15 18 def 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 } 20 68 _valid_octaves = range(-1, 10) 21 69 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))) 23 72 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] *373 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 27 76 28 77 if len(note) == 4: … … 47 96 raise ValueError("%s is not a valid octave" % octave) 48 97 49 midi = 12 + octave * 12 + _valid_notenames[notename] + _valid_modifiers[modifier] 98 midi = (octave + 1) * 12 + _valid_notenames[notename] \ 99 + _valid_modifiers[modifier] 50 100 if midi > 127: 51 101 raise ValueError("%s is outside of the range C-2 to G8" % note) 52 102 return midi 53 103 104 54 105 def 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 """ 56 136 if not isinstance(midi, int_instances): 57 137 raise TypeError("an integer is required, got %s" % midi) 58 138 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'] 61 143 return _valid_notenames[midi % 12] + str(int(midi / 12) - 1) 62 144 145 63 146 def 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 170 def 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 6 6 _max_timestamp = 1e120 7 7 8 8 9 def 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. 11 13 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: 13 77 raise ValueError("no timestamps given") 14 78 15 if timestamps[0] != 0 :79 if timestamps[0] != 0 and create_first: 16 80 timestamps = [0] + timestamps 17 81 if timestamps_end is not None: … … 19 83 20 84 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): 22 88 raise ValueError("len(timestamps_end) != len(timestamps)") 23 89 else: … … 25 91 26 92 regions = list(zip(timestamps, timestamps_end)) 27 #print regions28 93 29 94 source_base_name, _ = os.path.splitext(os.path.basename(source_file)) … … 33 98 source_base_name = os.path.join(output_dir, source_base_name) 34 99 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 37 102 timestamp_seconds = timestamp / float(samplerate) 38 103 return source_base_name + "_%011.6f" % timestamp_seconds + '.wav' … … 49 114 vec, read = _source.do_multi() 50 115 # 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]: 53 117 # get next region 54 118 start_stamp, end_stamp = regions.pop(0) 55 119 # 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) 57 122 # create its sink 58 123 _sink = sink(new_sink_path, samplerate, _source.channels) 59 124 # 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} 61 127 # append the dictionary to the current list of slices 62 128 slices.append(new_slice) … … 70 136 # number of samples yet to written be until end of region 71 137 remaining = end_stamp - total_frames + 1 72 #print current_slice, remaining, start73 138 # not enough frames remaining, time to split 74 139 if remaining < read: … … 76 141 # write remaining samples from current region 77 142 _sink.do_multi(vec[:, start:remaining], remaining - start) 78 #print "closing region", "remaining", remaining79 143 # close this file 80 144 _sink.close() … … 83 147 _sink.do_multi(vec[:, start:read], read - start) 84 148 total_frames += read 149 # remove old slices 150 slices = list(filter(lambda s: s['end_stamp'] > total_frames, 151 slices)) 85 152 if read < hopsize: 86 153 break -
python/lib/gen_code.py
r5b46bc3 r633400d 3 3 'buf_size': 'Py_default_vector_length', 4 4 'win_s': 'Py_default_vector_length', 5 'size': 'Py_default_vector_length', 5 6 # and here too 6 7 'hop_size': 'Py_default_vector_length / 2', … … 85 86 'tss': 'self->buf_size', 86 87 'pitchshift': 'self->hop_size', 88 'dct': 'self->size', 87 89 } 88 90 … … 180 182 self.do_outputs = get_params_types_names(self.do_proto)[2:] 181 183 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 182 188 self.struct_outputs = ";\n ".join(struct_output_str) 183 189 … … 187 193 def gen_code(self): 188 194 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 200 215 return out 201 216 … … 381 396 return out 382 397 383 def gen_do(self ):398 def gen_do(self, method = 'do'): 384 399 out = """ 385 400 // do {shortname} 386 401 static PyObject* 387 Py _{shortname}_do(Py_{shortname} * self, PyObject * args)388 {{""".format( **self.__dict__)402 Pyaubio_{shortname}_{method} (Py_{shortname} * self, PyObject * args) 403 {{""".format(method = method, **self.__dict__) 389 404 input_params = self.do_inputs 390 405 output_params = self.do_outputs … … 462 477 """.format(**self.__dict__) 463 478 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]) 466 483 method_name = get_name(set_param) 467 484 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]) 469 490 out += """ 470 491 static PyObject * … … 472 493 {{ 473 494 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})) {{ 477 502 return NULL; 478 503 }} 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}); 480 508 481 509 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 }} 483 518 return NULL; 484 519 }} 485 520 Py_RETURN_NONE; 486 521 }} 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__) 488 524 return out 489 525 … … 526 562 {{"{shortname}", (PyCFunction) Py{name}, 527 563 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) 528 570 out += """ 529 571 {NULL} /* sentinel */ … … 551 593 0, 552 594 0, 553 (ternaryfunc)Py _{shortname}_do,595 (ternaryfunc)Pyaubio_{shortname}_do, 554 596 0, 555 597 0, -
python/lib/gen_external.py
r5b46bc3 r633400d 1 1 import distutils.ccompiler 2 import sys, os, subprocess, glob 2 import sys 3 import os 4 import subprocess 5 import glob 6 from distutils.sysconfig import customize_compiler 7 from gen_code import MappedObject 3 8 4 9 header = os.path.join('src', 'aubio.h') … … 9 14 """ 10 15 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 ] 16 default_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 44 51 45 52 def get_preprocessor(): 46 53 # findout which compiler to use 47 from distutils.sysconfig import customize_compiler48 54 compiler_name = distutils.ccompiler.get_default_compiler() 49 55 compiler = distutils.ccompiler.new_compiler(compiler=compiler_name) … … 60 66 61 67 cpp_cmd = None 62 if hasattr(compiler, 'preprocessor'): # for unixccompiler68 if hasattr(compiler, 'preprocessor'): # for unixccompiler 63 69 cpp_cmd = compiler.preprocessor 64 elif hasattr(compiler, 'compiler'): # for ccompiler70 elif hasattr(compiler, 'compiler'): # for ccompiler 65 71 cpp_cmd = compiler.compiler.split() 66 72 cpp_cmd += ['-E'] 67 elif hasattr(compiler, 'cc'): # for msvccompiler73 elif hasattr(compiler, 'cc'): # for msvccompiler 68 74 cpp_cmd = compiler.cc.split() 69 75 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) 70 88 71 89 if not cpp_cmd: … … 73 91 cpp_cmd = os.environ.get('CC', 'cc').split() 74 92 cpp_cmd += ['-E'] 75 93 if 'emcc' in cpp_cmd: 94 cpp_cmd += ['-x', 'c'] # emcc defaults to c++, force C language 76 95 return cpp_cmd 77 96 78 def get_cpp_objects(header=header): 97 98 def 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 105 def get_cpp_output(header=header, usedouble=False): 106 ''' find and run a C pre-processor on aubio.h ''' 79 107 cpp_cmd = get_preprocessor() 80 108 81 109 macros = [('AUBIO_UNSTABLE', 1)] 110 if usedouble: 111 macros += [('HAVE_AUBIO_DOUBLE', 1)] 82 112 83 113 if not os.path.isfile(header): … … 90 120 print("Running command: {:s}".format(" ".join(cpp_cmd))) 91 121 proc = subprocess.Popen(cpp_cmd, 92 stderr=subprocess.PIPE,93 stdout=subprocess.PIPE)122 stderr=subprocess.PIPE, 123 stdout=subprocess.PIPE) 94 124 assert proc, 'Proc was none' 95 125 cpp_output = proc.stdout.read() 96 126 err_output = proc.stderr.read() 127 if err_output: 128 print("Warning: preprocessor produced errors or warnings:\n%s" \ 129 % err_output.decode('utf8')) 97 130 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) 101 138 if not isinstance(cpp_output, list): 102 139 cpp_output = [l.strip() for l in cpp_output.decode('utf8').split('\n')] 103 140 104 cpp_output = filter(lambda y: len(y) > 1, cpp_output) 141 return cpp_output 142 143 def filter_cpp_output(cpp_raw_output): 144 ''' prepare cpp-output for parsing ''' 145 cpp_output = filter(lambda y: len(y) > 1, cpp_raw_output) 105 146 cpp_output = list(filter(lambda y: not y.startswith('#'), cpp_output)) 106 147 107 148 i = 1 108 149 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) 113 158 else: 114 159 i += 1 115 160 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 170 def 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) 118 174 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 179 def 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 201 def 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 ''' 124 208 lib = {} 125 209 126 210 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': []} 133 216 lib[shortname]['longname'] = o 134 217 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 138 225 if 'typedef struct ' in fn: 139 226 lib[shortname]['struct'].append(fn) 140 227 elif '_do' in fn: 141 228 lib[shortname]['do'].append(fn) 229 elif '_rdo' in fn: 230 lib[shortname]['rdo'].append(fn) 142 231 elif 'new_' in fn: 143 232 lib[shortname]['new'].append(fn) … … 149 238 lib[shortname]['set'].append(fn) 150 239 else: 151 # print "no idea what to do about", fn240 # print "no idea what to do about", fn 152 241 lib[shortname]['other'].append(fn) 153 242 return lib 154 243 155 def print_cpp_output_results(lib, cpp_output): 156 for fn in cpp_output: 244 245 def print_c_declarations_results(lib, c_declarations): 246 for fn in c_declarations: 157 247 found = 0 158 248 for o in lib: … … 161 251 found = 1 162 252 if found == 0: 163 print 253 print("missing", fn) 164 254 165 255 for o in lib: 166 256 for family in lib[o]: 167 257 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])) 169 259 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])) 171 261 else: 172 print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ))262 print("{:15s} {:10s} {:s}".format(o, family, lib[o][family])) 173 263 174 264 175 265 def 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) 183 276 184 277 sources_list = [] 185 try:186 from .gen_code import MappedObject187 except (SystemError, ValueError):188 from gen_code import MappedObject189 278 for o in lib: 190 279 out = source_header 191 mapped = MappedObject(lib[o], usedouble =usedouble)280 mapped = MappedObject(lib[o], usedouble=usedouble) 192 281 out += mapped.gen_code() 193 282 output_file = os.path.join(output_path, 'gen-%s.c' % o) 194 283 with open(output_file, 'w') as f: 195 284 f.write(out) 196 print ("wrote %s" % output_file)285 print("wrote %s" % output_file) 197 286 sources_list.append(output_file) 198 287 … … 206 295 return ({pycheck_types}); 207 296 }} 208 """.format(pycheck_types =check_types)297 """.format(pycheck_types=check_types) 209 298 210 299 add_types = "".join([""" 211 300 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]) 213 302 out += """ 214 303 … … 217 306 {add_types} 218 307 }} 219 """.format(add_types =add_types)308 """.format(add_types=add_types) 220 309 221 310 output_file = os.path.join(output_path, 'aubio-generated.c') 222 311 with open(output_file, 'w') as f: 223 312 f.write(out) 224 print ("wrote %s" % output_file)313 print("wrote %s" % output_file) 225 314 sources_list.append(output_file) 226 315 … … 240 329 int generated_objects ( void ); 241 330 void add_generated_objects( PyObject *m ); 242 """.format(objlist =objlist)331 """.format(objlist=objlist) 243 332 244 333 output_file = os.path.join(output_path, 'aubio-generated.h') 245 334 with open(output_file, 'w') as f: 246 335 f.write(out) 247 print ("wrote %s" % output_file)336 print("wrote %s" % output_file) 248 337 # no need to add header to list of sources 249 338 250 return so urces_list339 return sorted(sources_list) 251 340 252 341 if __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] 255 346 generate_external(header, output_path) -
python/lib/moresetuptools.py
r5b46bc3 r633400d 3 3 import sys, os, glob, subprocess 4 4 import distutils, distutils.command.clean, distutils.dir_util 5 from .gen_external import generate_external, header, output_path 5 from gen_external import generate_external, header, output_path 6 7 from this_version import get_aubio_version 6 8 7 9 # inspired from https://gist.github.com/abergmeier/9488990 … … 22 24 23 25 for package in packages: 26 print("checking for {:s}".format(package)) 24 27 cmd = ['pkg-config', '--libs', '--cflags', package] 25 28 try: … … 55 58 def add_local_aubio_sources(ext): 56 59 """ 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'))) 63 63 ext.sources += aubio_sources 64 65 def add_local_macros(ext, usedouble = False): 66 if usedouble: 67 ext.define_macros += [('HAVE_AUBIO_DOUBLE', 1)] 64 68 # define macros (waf puts them in build/src/config.h) 65 69 for define_macro in ['HAVE_STDLIB_H', 'HAVE_STDIO_H', … … 70 74 ext.define_macros += [(define_macro, 1)] 71 75 76 def add_external_deps(ext, usedouble = False): 72 77 # loof for additional packages 73 78 print("Info: looking for *optional* additional packages") 74 packages = ['libavcodec', 'libavformat', 'libavutil', 'libavresample', 79 packages = ['libavcodec', 'libavformat', 'libavutil', 80 'libswresample', 'libavresample', 75 81 'jack', 76 'sndfile', 'samplerate',82 'sndfile', 77 83 'rubberband', 78 84 #'fftw3f', 79 85 ] 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") 80 91 add_packages(packages, ext=ext) 81 92 if 'avcodec' in ext.libraries \ 82 93 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)] 88 101 if 'sndfile' in ext.libraries: 89 102 ext.define_macros += [('HAVE_SNDFILE', 1)] … … 108 121 ext.define_macros += [('HAVE_WAVWRITE', 1)] 109 122 ext.define_macros += [('HAVE_WAVREAD', 1)] 110 # TODO: 111 # add cblas123 124 # TODO: add cblas 112 125 if 0: 113 126 ext.libraries += ['cblas'] … … 116 129 def add_system_aubio(ext): 117 130 # 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) 119 133 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 138 def 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)] 121 143 122 144 class CleanGenerated(distutils.command.clean.clean): 123 145 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) 126 148 127 class GenerateCommand(distutils.cmd.Command): 128 description = 'generate gen/gen-*.c files from ../src/aubio.h' 129 user_options = [ 149 from distutils.command.build_ext import build_ext as _build_ext 150 class build_ext(_build_ext): 151 152 user_options = _build_ext.user_options + [ 130 153 # The format is (long option, short option, description). 131 154 ('enable-double', None, 'use HAVE_AUBIO_DOUBLE=1 (default: 0)'), … … 133 156 134 157 def initialize_options(self): 158 _build_ext.initialize_options(self) 135 159 self.enable_double = False 136 160 137 161 def finalize_options(self): 162 _build_ext.finalize_options(self) 138 163 if self.enable_double: 139 164 self.announce( … … 141 166 level=distutils.log.INFO) 142 167 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 25 25 import os.path 26 26 import numpy 27 from utils import array_from_text_file, array_from_yaml_file27 from .utils import array_from_text_file, array_from_yaml_file 28 28 from aubio import source, pitch, freqtomidi 29 29 -
python/tests/test_aubio.py
r5b46bc3 r633400d 10 10 import aubio 11 11 12 def test_version(self): 13 """ test aubio.version """ 14 import aubio 15 self.assertEqual('0', aubio.version[0]) 16 12 17 if __name__ == '__main__': 13 18 main() -
python/tests/test_fft.py
r5b46bc3 r633400d 34 34 fftgrain = f (timegrain) 35 35 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.') 37 44 38 45 def test_impulse(self): … … 136 143 assert_almost_equal ( r[1:], 0) 137 144 145 class 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 174 class aubio_fft_wrong_params(TestCase): 175 138 176 def test_large_input_timegrain(self): 139 177 win_s = 1024 … … 163 201 with self.assertRaises(ValueError): 164 202 f.rdo(s) 165 166 class aubio_fft_wrong_params(TestCase):167 203 168 204 def test_wrong_buf_size(self): … … 170 206 with self.assertRaises(ValueError): 171 207 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 sizes175 win_s = 320176 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)181 208 182 209 def test_buf_size_too_small(self): -
python/tests/test_filter.py
r5b46bc3 r633400d 4 4 from numpy.testing import TestCase, assert_equal, assert_almost_equal 5 5 from aubio import fvec, digital_filter 6 from utils import array_from_text_file6 from .utils import array_from_text_file 7 7 8 8 class aubio_filter_test_case(TestCase): … … 78 78 f.set_biquad(0., 0., 0, 0., 0.) 79 79 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 80 90 class aubio_filter_wrong_params(TestCase): 81 91 -
python/tests/test_filterbank.py
r5b46bc3 r633400d 1 1 #! /usr/bin/env python 2 2 3 from unittest import main4 from numpy.testing import TestCase5 from numpy.testing import assert_equal, assert_almost_equal6 3 import numpy as np 4 from numpy.testing import TestCase, assert_equal, assert_almost_equal 5 7 6 from aubio import cvec, filterbank, float_type 8 from utils import array_from_text_file7 from .utils import array_from_text_file 9 8 10 9 class aubio_filterbank_test_case(TestCase): … … 63 62 assert_almost_equal ( expected, f.get_coeffs() ) 64 63 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 65 71 class aubio_filterbank_wrong_values(TestCase): 66 72 … … 82 88 83 89 if __name__ == '__main__': 84 main() 90 import nose2 91 nose2.main() -
python/tests/test_filterbank_mel.py
r5b46bc3 r633400d 1 1 #! /usr/bin/env python 2 2 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 3 import numpy as np 4 from numpy.testing import TestCase, assert_equal, assert_almost_equal 5 6 from aubio import fvec, cvec, filterbank, float_type 7 8 import warnings 9 warnings.filterwarnings('ignore', category=UserWarning, append=True) 8 10 9 11 class aubio_filterbank_mel_test_case(TestCase): … … 13 15 f.set_mel_coeffs_slaney(16000) 14 16 a = f.get_coeffs() 15 assert_equal( shape (a), (40, 512/2 + 1) )17 assert_equal(np.shape (a), (40, 512/2 + 1) ) 16 18 17 19 def test_other_slaney(self): 18 20 f = filterbank(40, 512*2) 19 21 f.set_mel_coeffs_slaney(44100) 20 _ = f.get_coeffs()22 self.assertIsInstance(f.get_coeffs(), np.ndarray) 21 23 #print "sum is", sum(sum(a)) 22 24 for win_s in [256, 512, 1024, 2048, 4096]: 23 25 f = filterbank(40, win_s) 24 26 f.set_mel_coeffs_slaney(32000) 25 _ = f.get_coeffs()26 27 #print "sum is", sum(sum(a)) 28 self.assertIsInstance(f.get_coeffs(), np.ndarray) 27 29 28 30 def test_triangle_freqs_zeros(self): 29 31 f = filterbank(9, 1024) 30 32 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) 32 34 f.set_triangle_bands(freqs, 48000) 33 _ = f.get_coeffs().T34 35 assert_equal ( f(cvec(1024)), 0) 36 self.assertIsInstance(f.get_coeffs(), np.ndarray) 35 37 36 38 def test_triangle_freqs_ones(self): 37 39 f = filterbank(9, 1024) 38 40 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) 40 42 f.set_triangle_bands(freqs, 48000) 41 _ = f.get_coeffs().T43 self.assertIsInstance(f.get_coeffs(), np.ndarray) 42 44 spec = cvec(1024) 43 45 spec.norm[:] = 1 … … 46 48 0.02133301, 0.02133301, 0.02133311, 0.02133334, 0.02133345]) 47 49 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 48 170 if __name__ == '__main__': 49 main() 171 import nose2 172 nose2.main() -
python/tests/test_fvec.py
r5b46bc3 r633400d 60 60 self.assertRaises(IndexError, a.__getitem__, 3) 61 61 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) 62 70 63 71 class aubio_wrong_fvec_input(TestCase): -
python/tests/test_mfcc.py
r5b46bc3 r633400d 111 111 #print coeffs 112 112 113 114 class 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 113 150 if __name__ == '__main__': 114 151 main() -
python/tests/test_midi2note.py
r5b46bc3 r633400d 3 3 4 4 from aubio import midi2note 5 from nose2.tools import params 5 6 import unittest 6 7 … … 17 18 class midi2note_good_values(unittest.TestCase): 18 19 19 def test_midi2note_known_values(self): 20 @params(*list_of_known_midis) 21 def test_midi2note_known_values(self, midi, note): 20 22 " 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 ) 23 24 24 25 class midi2note_wrong_values(unittest.TestCase): … … 41 42 42 43 if __name__ == '__main__': 43 unittest.main() 44 import nose2 45 nose2.main() -
python/tests/test_note2midi.py
r5b46bc3 r633400d 4 4 from __future__ import unicode_literals 5 5 6 from aubio import note2midi, freq2note 6 from aubio import note2midi, freq2note, note2freq, float_type 7 from nose2.tools import params 7 8 import unittest 8 9 … … 14 15 ( 'B3', 59 ), 15 16 ( 'B#3', 60 ), 17 ( 'C♯4', 61 ), 16 18 ( 'A4', 69 ), 17 19 ( 'A#4', 70 ), 20 ( 'A♯4', 70 ), 21 ( 'A\u266f4', 70 ), 18 22 ( 'Bb4', 70 ), 19 23 ( 'B♭4', 70 ), 24 ( 'B\u266d4', 70 ), 20 25 ( 'G8', 115 ), 21 26 ( 'G♯8', 116 ), 22 27 ( 'G9', 127 ), 23 ( 'G\udd2a2', 45 ),24 ( 'B\ufffd2', 45 ),25 28 ( 'A♮2', 45 ), 29 ) 30 31 list_of_known_notes_with_unicode_issues = ( 32 ('C𝄪4', 62 ), 33 ('E𝄫4', 62 ), 34 ) 35 36 list_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' ), 26 45 ) 27 46 28 47 class note2midi_good_values(unittest.TestCase): 29 48 30 def test_note2midi_known_values(self): 49 @params(*list_of_known_notes) 50 def test_note2midi_known_values(self, note, midi): 31 51 " 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: 33 58 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 34 68 35 69 class note2midi_wrong_values(unittest.TestCase): … … 67 101 self.assertRaises(TypeError, note2midi, 123) 68 102 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) 69 111 70 112 class freq2note_simple_test(unittest.TestCase): 71 113 72 def test_freq2note (self):114 def test_freq2note_above(self): 73 115 " make sure freq2note(441) == A4 " 74 116 self.assertEqual("A4", freq2note(441)) 75 117 118 def test_freq2note_under(self): 119 " make sure freq2note(439) == A4 " 120 self.assertEqual("A4", freq2note(439)) 121 122 class 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 76 135 if __name__ == '__main__': 77 unittest.main() 136 import nose2 137 nose2.main() -
python/tests/test_onset.py
r5b46bc3 r633400d 3 3 from unittest import main 4 4 from numpy.testing import TestCase, assert_equal, assert_almost_equal 5 from aubio import onset 5 from aubio import onset, fvec 6 6 7 7 class aubio_onset_default(TestCase): … … 20 20 21 21 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) 23 23 24 24 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.) 26 26 27 27 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.) 29 29 30 30 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) 32 32 33 33 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.) 35 35 36 36 def test_get_minioi_ms(self): 37 assert_equal (self.o.get_minioi_ms(), 20.)37 self.assertGreater(self.o.get_minioi_ms(), 0.) 38 38 39 39 def test_get_threshold(self): 40 assert_almost_equal (self.o.get_threshold(), 0.3)40 self.assertGreater(self.o.get_threshold(), 0.) 41 41 42 42 def test_set_delay(self): … … 84 84 samplerate = 8000 85 85 86 class 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 86 118 if __name__ == '__main__': 87 119 main() -
python/tests/test_phasevoc.py
r5b46bc3 r633400d 47 47 assert_equal ( t, 0.) 48 48 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.') 50 57 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.) 51 67 52 68 @params( -
python/tests/test_pitch.py
r5b46bc3 r633400d 71 71 #print 'median errors: ', median(errors), 'median pitches: ', median(pitches) 72 72 73 pitch_algorithms = [ "default", "yinfft", "yin", " schmitt", "mcomb", "fcomb" , "specacf" ]74 pitch_algorithms = [ "default", "yinfft", "yin", " schmitt", "mcomb", "fcomb" ]73 pitch_algorithms = [ "default", "yinfft", "yin", "yinfast", "schmitt", "mcomb", "fcomb" , "specacf" ] 74 pitch_algorithms = [ "default", "yinfft", "yin", "yinfast", "schmitt", "mcomb", "fcomb" ] 75 75 76 76 #freqs = [ 27.5, 55., 110., 220., 440., 880., 1760., 3520. ] -
python/tests/test_sink.py
r5b46bc3 r633400d 5 5 from numpy.testing import TestCase 6 6 from aubio import fvec, source, sink 7 from utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path 7 from .utils import list_all_sounds, get_tmp_sink_path, del_tmp_sink_path 8 9 import warnings 10 warnings.filterwarnings('ignore', category=UserWarning, append=True) 8 11 9 12 list_of_sounds = list_all_sounds('sounds') … … 26 29 if not len(list_of_sounds): 27 30 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) 28 51 29 52 def test_many_sinks(self): … … 94 117 del_tmp_sink_path(sink_path) 95 118 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 96 127 if __name__ == '__main__': 97 128 main() -
python/tests/test_slicing.py
r5b46bc3 r633400d 4 4 from numpy.testing import TestCase, assert_equal 5 5 from aubio import slice_source_at_stamps 6 from utils import count_files_in_directory, get_default_test_sound7 from utils import count_samples_in_directory, count_samples_in_file6 from .utils import count_files_in_directory, get_default_test_sound 7 from .utils import count_samples_in_directory, count_samples_in_file 8 8 9 9 import tempfile … … 24 24 def test_slice_start_only_no_zero(self): 25 25 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) 27 28 28 29 def test_slice_start_beyond_end(self): 29 30 regions_start = [i*1000 for i in range(1, n_slices)] 30 31 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) 32 34 33 35 def test_slice_start_every_blocksize(self): 34 36 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)] 36 38 slice_source_at_stamps(self.source_file, regions_start, output_dir = self.output_dir, 37 39 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) 38 46 39 47 def tearDown(self): … … 92 100 "number of samples written different from number of original samples") 93 101 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 94 115 def tearDown(self): 95 116 shutil.rmtree(self.output_dir) … … 134 155 regions_end = None 135 156 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) 137 158 total_files = count_files_in_directory(self.output_dir) 138 159 assert_equal(n_slices, total_files, -
python/tests/test_source.py
r5b46bc3 r633400d 3 3 from nose2 import main 4 4 from nose2.tools import params 5 from numpy.testing import TestCase 5 from numpy.testing import TestCase, assert_equal 6 6 from aubio import source 7 from utils import list_all_sounds7 from .utils import list_all_sounds 8 8 9 9 import warnings … … 52 52 total_frames = 0 53 53 while True: 54 _, read = f()54 samples , read = f() 55 55 total_frames += read 56 if read < f.hop_size: break 56 if read < f.hop_size: 57 assert_equal(samples[read:], 0) 58 break 57 59 #result_str = "read {:.2f}s ({:d} frames in {:d} blocks at {:d}Hz) from {:s}" 58 60 #result_params = total_frames / float(f.samplerate), total_frames, total_frames//f.hop_size, f.samplerate, f.uri … … 67 69 self.skipTest('failed opening with hop_s = {:d}, samplerate = {:d} ({:s})'.format(hop_size, samplerate, str(e))) 68 70 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) 70 79 71 80 @params(*list_of_sounds) … … 150 159 total_frames = 0 151 160 while True: 152 _, read = f.do_multi()161 samples, read = f.do_multi() 153 162 total_frames += read 154 if read < f.hop_size: break 163 if read < f.hop_size: 164 assert_equal(samples[:,read:], 0) 165 break 155 166 #result_str = "read {:.2f}s ({:d} frames in {:d} channels and {:d} blocks at {:d}Hz) from {:s}" 156 167 #result_params = total_frames / float(f.samplerate), total_frames, f.channels, int(total_frames/f.hop_size), f.samplerate, f.uri … … 158 169 return total_frames 159 170 171 class 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 160 187 if __name__ == '__main__': 161 188 main()
Note: See TracChangeset
for help on using the changeset viewer.