Real-Time Expressive Digital Signal Processing (DSP) Package for Python!
Project description
Development |
|
---|---|
Last release |
|
PyPI status |
Laziness and object representation
There are several tools and packages that let the Python use and expressiveness look like languages such as MatLab and Octave. However, the eager evaluation done by most of these tools make it difficult, perhaps impossible, to use them for real time audio processing. To avoid such eagerness, one can make the calculations only when data is requested, not when the path to the data is given. This is the core idea in laziness that allows:
Real-time application (you don’t need to wait until all data is processed to have a result);
Endless data sequence representation;
Data-flow representation;
Task elimination when a reverse task is done: instead of doing something to then undo, nothing needs to be done, and no conscious optimization need to be done for that.
Another difficulty concerns expressive code creation for audio processing in blocks through indexes and vectors. Sometimes, that’s unavoidable, or at least such avoidance would limit the power of the system that works with sequence data.
Block sequences can be found from sample sequences being both objects, where the latter can be the result of a method or function over the former. The information needed for such is the block size and where would start the next block. Although one can think about the last block and the exact index where it would start, most of the time spent in steps like this one happens to be an implementation issue that just keep the focus away from the problem being worked on. To allow a thing like an endless data sequence, there should be no need to know when something stops.
Probably an engineer would find the use of equations and structures from electrical engineering theory much cleaner to understand than storing everything into data arrays, mainly when common operations are done to these representations. What is the product of the filter with numerator [1, 7, 2] and denominator [1, 0.5, 0.2] as its system equation with the one that has the arrays reversed like [2, 7, 1]? That might be simple, and the reversed would avoid questions like “what comes first, the zero or the [minus] two exponent?”, but maybe we could get more efficient ourselves if we had something easier: multiplication could be written once and for all and with a representation programmers are used to see. This would be even more expressive if we could get rid from the asymmetry of a method call like filt1.multiply_by(filt2), since multiplication in this case should be commutative. The use of natural operators is possible in a language that allows operator overloading, but for such we need to describe those equations and structures as objects and object relationships.
The name Hz can be a number that would allow conversion to a default DSP internal rad/samples unit, so one can write things like freq = 440 * Hz. This isn’t difficult in probably any language, but can help in expressiveness, already. If (almost) everything would need data in “samples” or “rad/sample” units, constants for converting these from “second” and “hertz” would help with the code expressiveness. A comb filter comb.tau(delay=30*s, tau=40*s) can represent a comb filter with the given delay and time constant, both in samples, but with a more clear meaning for the reader than it would have with an expression like [1] + [0] * 239999 + [alpha]. Would it be needed to store all those zeros while just using the filter to get a frequency response plot?
It’s possible to avoid some of these problems with well-chosen constants, duck typing, overloaded operators, functions as first-class citizens, object oriented together with functional style programming, etc.., resources that the Python language gives us for free.
What does it do?
Prioritizing code expressiveness, clarity and simplicity, without precluding the lazy evaluation, and aiming to be used together with Numpy, Scipy and Matplotlib as well as default Python structures like lists and generators, AudioLazy is a package written in pure Python proposing digital audio signal processing (DSP), featuring:
A Stream class for finite and endless signals representation with elementwise operators (auto-broadcast with non-iterables) in a common Python iterable container accepting heterogeneous data;
Strongly sample-based representation (Stream class) with easy conversion to block representation using the Stream.blocks(size, hop) method;
Sample-based interactive processing with ControlStream;
Streamix mixer for iterables given their starting time deltas;
Multi-thread audio I/O integration with PyAudio;
Linear filtering with Z-transform filters directly as equations (e.g. filt = 1 / (1 - .3 * z ** -1)), including linear time variant filters (i.e., the a in a * z ** k can be a Stream instance), cascade filters (behaves as a list of filters), resonators, etc.. Each LinearFilter instance is compiled just in time when called;
Zeros and poles plots and frequency response plotting integration with MatPlotLib;
Linear Predictive Coding (LPC) directly to ZFilter instances, from which you can find PARCOR coeffs and LSFs;
Both sample-based (e.g., zero-cross rate, envelope, moving average, clipping, unwrapping) and block-based (e.g., window functions, DFT, autocorrelation, lag matrix) analysis and processing tools;
A simple synthesizer (Table lookup, Karplus-Strong) with processing tools (Linear ADSR envelope, fade in/out, fixed duration line stream) and basic wave data generation (sinusoid, white noise, impulse);
Biological auditory periphery modeling (ERB and gammatone filter models);
Multiple implementation organization as StrategyDict instances: callable dictionaries that allows the same name to have several different implementations (e.g. erb, gammatone, lowpass, resonator, lpc, window);
Converters among MIDI pitch numbers, strings like “F#4” and frequencies;
Polynomials, Stream-based functions from itertools, math, cmath, and more! Go try yourself! =)
Installing
The package works both on Linux and on Windows. You can find the last stable version at PyPI and install it with the usual Python installing mechanism:
python setup.py install
If you have pip, you can go directly (use -U for update or reinstall):
pip install audiolazy
for downloading (from PyPI) and installing the package for you, or:
pip install -U .
To install from a path that has the setup.py file and the package data uncompressed previously.
For the bleeding-edge version, you can install directly from the github repository (requires git for cloning):
pip install -U git+git://github.com/danilobellini/audiolazy.git
For older versions, you can install from the PyPI link or directly from the github repository, based on the repository tags. For example, to install the version 0.04 (requires git for cloning):
pip install -U git+git://github.com/danilobellini/audiolazy.git@v0.04
The package doesn’t have any strong dependency for its core besides the Python itself (versions 2.7, 3.2 or newer) as well as its standard library, but you might need:
PyAudio: needed for playing and recording audio (AudioIO class);
NumPy: needed for doing some maths, such as finding the LSFs from a filter or roots from a polynomial;
MatPlotLib: needed for all default plotting, like in LinearFilter.plot method and several examples;
SciPy (testing and examples only): used as an oracle for LTI filter testing and for the Butterworth filter example;
Sympy (testing only): used for testing linear filters with time-varying matrices of symbolic coeffs where the Stream samples are these matrices;
tox for testing all at once, or pytest, pytest-cov and pytest-timeout for testing in a single environment (testing only): runs test suite and shows code coverage status;
wxPython (example only): used by one example with FM synthesis in an interactive GUI;
Tkinter (example only): needed for the pitch follower based on the zero-crossing rate example GUI;
Music21 (example only): there’s one example that gets the Bach chorals from that package corpora for synthesizing and playing;
Sphinx (documentation only): it can create the software documentation in several different file formats.
Beside examples and tests, only the filter plotting with plot and zplot methods needs MatPlotLib. Also, the routines that needs NumPy up to now are:
Root finding with zeros and poles properties (filter classes) or with roots property (Poly class);
Some Linear Predictive Coding (lpc) strategies: nautocor, autocor and covar;
Line Spectral Frequencies lsf and lsf_stable functions.
Getting started
Before all examples below, it’s easier to get everything from audiolazy namespace:
from audiolazy import *
All modules starts with “lazy_”, but their data is already loaded in the main namespace. These two lines of code do the same thing:
from audiolazy.lazy_stream import Stream
from audiolazy import Stream
Endless iterables with operators (be careful with loops through an endless iterator!):
>>> a = Stream(2, -2, -1) # Periodic
>>> b = Stream(3, 7, 5, 4) # Periodic
>>> c = a + b # Elementwise sum, periodic
>>> c.take(15) # First 15 elements from the Stream object
[5, 5, 4, 6, 1, 6, 7, 2, 2, 9, 3, 3, 5, 5, 4]
And also finite iterators (you can think on any Stream as a generator with elementwise operators):
>>> a = Stream([1, 2, 3, 2, 1]) # Finite, since it's a cast from an iterable
>>> b = Stream(3, 7, 5, 4) # Periodic
>>> c = a + b # Elementwise sum, finite
>>> list(c)
[4, 9, 8, 6, 4]
LTI Filtering from system equations (Z-transform). After this, try summing, composing, multiplying ZFilter objects:
>>> filt = 1 - z ** -1 # Diff between a sample and the previous one
>>> filt
1 - z^-1
>>> data = filt([.1, .2, .4, .3, .2, -.1, -.3, -.2]) # Past memory has 0.0
>>> data # This should have internally [.1, .1, .2, -.1, -.1, -.3, -.2, .1]
<audiolazy.lazy_stream.Stream object at ...>
>>> data *= 10 # Elementwise gain
>>> [int(round(x)) for x in data] # Streams are iterables
[1, 1, 2, -1, -1, -3, -2, 1]
>>> data_int = filt([1, 2, 4, 3, 2, -1, -3, -2], zero=0) # Now zero is int
>>> list(data_int)
[1, 1, 2, -1, -1, -3, -2, 1]
LTI Filter frequency response plot (needs MatPlotLib):
(1 + z ** -2).plot().show()
The matplotlib.figure.Figure.show method won’t work unless you’re using a newer version of MatPlotLib (works on MatPlotLib 1.2.0), but you still can save the above plot directly to a PDF, PNG, etc. with older versions (e.g. MatPlotLib 1.0.1):
(1 + z ** -2).plot().savefig("my_plot.pdf")
On the other hand, you can always show the figure using MatPlotLib directly:
from matplotlib import pyplot as plt # Or "import pylab as plt"
filt = 1 + z ** -2
fig1 = filt.plot(plt.figure()) # Argument not needed on the first figure
fig2 = filt.zplot(plt.figure()) # The argument ensures a new figure
plt.show()
CascadeFilter instances and ParallelFilter instances are lists of filters with the same operator behavior as a list, and also works for plotting linear filters. Constructors accepts both a filter and an iterable with filters. For example, a zeros and poles plot (needs MatPlotLib):
filt1 = CascadeFilter(0.2 - z ** -3) # 3 zeros
filt2 = CascadeFilter(1 / (1 -.8 * z ** -1 + .6 * z ** -2)) # 2 poles
# Here __add__ concatenates and __mul__ by an integer make reference copies
filt = (filt1 * 5 + filt2 * 10) # 15 zeros and 20 poles
filt.zplot().show()
Linear Predictive Coding (LPC) autocorrelation method analysis filter frequency response plot (needs MatPlotLib):
lpc([1, -2, 3, -4, -3, 2, -3, 2, 1], order=3).plot().show()
Linear Predictive Coding covariance method analysis and synthesis filter, followed by the frequency response plot together with block data DFT (MatPlotLib):
>>> data = Stream(-1., 0., 1., 0.) # Periodic
>>> blk = data.take(200)
>>> analysis_filt = lpc.covar(blk, 4)
>>> analysis_filt
1 + 0.5 * z^-2 - 0.5 * z^-4
>>> residual = list(analysis_filt(blk))
>>> residual[:10]
[-1.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
>>> synth_filt = 1 / analysis_filt
>>> synth_filt(residual).take(10)
[-1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, -1.0, 0.0]
>>> amplified_blk = list(Stream(blk) * -200) # For alignment w/ DFT
>>> synth_filt.plot(blk=amplified_blk).show()
AudioLazy doesn’t need any audio card to process audio, but needs PyAudio to play some sound:
rate = 44100 # Sampling rate, in samples/second
s, Hz = sHz(rate) # Seconds and hertz
ms = 1e-3 * s
note1 = karplus_strong(440 * Hz) # Pluck "digitar" synth
note2 = zeros(300 * ms).append(karplus_strong(880 * Hz))
notes = (note1 + note2) * .5
sound = notes.take(int(2 * s)) # 2 seconds of a Karplus-Strong note
with AudioIO(True) as player: # True means "wait for all sounds to stop"
player.play(sound, rate=rate)
See also the docstrings and the “examples” directory at the github repository for more help. Also, the huge test suite might help you understanding how the package works and how to use it.
Project files
There are several files and directories in the AudioLazy repository (as well as in the source distribution):
File/Directory |
Description |
---|---|
audiolazy/ |
AudioLazy package modules source code |
audiolazy/tests/ |
Testing subpackage |
docs/ |
Documentation generation scripts |
examples/ |
Examples for some AudioLazy use cases |
images/ |
Images referenced by some reStructuredText documentation file |
math/ |
Proof for some formula used by AudioLazy using Sympy CAS |
CHANGES.rst |
AudioLazy History, a.k.a. change log |
conftest.py |
Configuration for py.test, to work properly with doctests on StrategyDict strategies and on an environment missing Numpy |
COPYING.txt |
License file |
MANIFEST.in |
List of extra distributed files to be included in the tarball that doesn’t need to be installed together with the package |
README.rst |
Some general information about the AudioLazy project |
setup.py |
General Python setup script for installation, testing, etc. |
tox.ini |
Configuration for tox, py.test and pytest-cov |
.travis.yml |
Travis-CI configuration (not in PyPI tarball/”egg” source distribution) |
The examples and the math directories might be useful for an AudioLazy user. All Python files in these two directories are scripts intended to run on both Python 2 and 3 unless they need something not yet available for Python 3 (e.g. wxPython), most of them have some external dependency.
AudioLazy changes history
* Version 0.6 (Examples, STFT, phon2dB, tox, CI, wave file) *
examples:
Formant synthesis for voiced “ah-eh-ee-oh-oo”
Musical keyboard synth example with a QWERTY keyboard (also via jack!)
Random synthesis with saving and memoization
Aesthetics for the Tkinter GUI examples
Matplotlib animated plot with mic input data (also works via jack!)
Perceptual experiment with butterworth filters (Scipy) applied to white noise (based on the Demonstrations to Auditory Scene Analysis)
Psychoacoustics using ISO/FDIS 226:2003
Equal loudness contour curves plotting
Constant phon chirp playing
Partial recreation of the “Windows and Figures of Merit” F. Harris comparison table and window plots
Playing/synthesizing “Ode to Joy” from its “score” written as code
All recording/playback examples now prepared for using both the default API and receiving it as an argument like “jack” or “alsa”
Realtime STFT (Short Time Fourier Transform) effects:
Robotize
“Roll” the magnitude spectrum while keeping the phase
general:
Tox for testing with CPython 2.7, CPython 3.2~3.6 and PyPy
Continuous integration wih Travis CI and Coveralls
New _internals.py module to avoid exposing package internals together with the API, which also allowed the new simplified __init__.py
Renewed setup.py in both its internals (e.g. using AST instead of string manipulation to avoid importing the package before installation) and its interface (e.g. the test command now calls tox)
New conftest.py for testing doctests from strategies inside StrategyDict instances without the need of a __test__ in the module and for skipping doctests known to need Numpy when it’s not available
New math directory for adding scripts with symbolic math calculations (with Sympy) done for designing (or as a proof) for parts of the AudioLazy code. All lowpass and highpass strategies have their design explicitly explained there
lazy_analysis:
New overlap_add StrategyDict instance, allowing resynth after block processing/analysis, featuring block size auto-detection and window normalization to keep the output in the [-1; 1] range. Has 2 implementations keeping the same interface:
numpy (default): needs Numpy arrays internally
list: uses lists instead, doesn’t need Numpy and was tested on Pypy
New stft StrategyDict instance, allowing Short Time Fourier Transform block processors / phase vocoder by:
Passing a function as the first parameter
Using a stft strategies as a decorator
Creating new strategies by avoiding the only positional parameter
It was created with three Numpy-based strategies:
rfft, real or base (default): needs numpy.fft.rfft internally, as well as its inverse, to process a block in the frequency domain with values up to the Nyquist frequency, by assuming the input signal is real
cfft or complex: Alike to the default approach but uses the numpy.fft.fft for a full complex-valued block in frequency domain, which means the output is a complex signal
cfftr or complex_real: same to stft.cfft strategy, but keeps only the real part of the result
Parameters allows changing the default zero-phase behavior (before and after functions), the transform and inverse transform functions, the overlap-add strategy (as well as its parameters), and obviously the block size and hop
The window StrategyDict now returns the “periodic” window data instead of the “symmetric” window to be used with the STFT directly
New wsymm StrategyDict with the same strategies from window but returning a “symmetric” window
Default window strategy is the Hann window (the same for wsymm)
New cos strategy for window and wsymm implementing cosine to the power of alpha
lazy_auditory:
New phon2dB StrategyDict instance with the ISO/FDIS 226:2003 model for getting a SPL (Sound Pressure Level) in dBs from a phon value
lazy_core:
Add support to the new @ matrix multiplication operator
OpMethod.get() now accepts numbers "1" and "2" as strings for unary and binary query for operators, and "all" is the new default, so OpMethod.get(without="2 ~") would get all operators but the [reversed or not] binary ones and the invert operator, which means it would yield only the unary "+" (pos) and - (neg), as probably was expected; OpMethod also had a bug fix regarding the shift operators
Strategy name autocomplete works on IPython since StrategyDict now changes its instance dictionary (e.g. vars(window)) instead of depending on the __getattr__ method
StrategyDict.strategy method now allows the strategy function name to be kept by using the new keep_name keyword-only argument. It might be helpful for adding built-in functions as well as other immutable callables as multi-name strategies with the same behavior as the item assignment for adding a strategy
The default strategy in a StrategyDict instance is now removed when all its keys/names are removed. The new default is the next added strategy
Strategies can be removed both by their item name and their attribute, and removing an attribute that isn’t an strategy recovers the strategy attribute if its name belongs to a strategy
MultiKeyDict methods key2keys and value2keys to help getting a tuple with all keys that points to the same value, ordered by the insertion order
lazy_filters:
LinearFilter coefficients can now be a Stream of Numpy matrices, as well as Sympy symbols (including symbolic matrices).
New simple lowpass/highpass IIR filter strategies:
highpass.z (taken as the new highpass default)
lowpass.z
highpass.pole_exp
highpass.z_exp
lowpass.z_exp
Where the "z" name denotes the presence of a single zero (besides the single pole) and "_exp" denotes the exponential approximation from a matched Z-Transform pole value from the equivalent or mirrored analog filter equation (Laplace). The absence of such suffix denotes it was designed directly as a digital filter.
lazy_io:
New api keyword argument for AudioIO, allowing e.g. integration with JACK (for now this needs chunks.size = 1)
AudioIO.open and AudioIO.record now allows keyword arguments, to be passed directly to PyAudio, including the now default “channels” keyword (old “nchannels” keyword still works, for backward compatibility)
lazy_math:
Signal function sign now works on Python 3
lazy_misc:
New cached decorator caching the results for a function without keyword arguments
lazy_poly:
Complex numbers and Sympy symbols can now be used as Poly powers
Poly instances are now based on OrderedDict (stores the creation order internally) and Poly.terms now support both a sort and a reverse keyword arguments to choose the yielding order (sorted by powers, keep creation order or reverse any of these)
Immutable Poly behavior is now based on a cached frozenset (doesn’t depend on the terms order) and includes Poly.zero as a read-only property (after the hash is required)
The Horner-like polynomial evaluation scheme (which needs sorting) is now enabled/disabled via a keyword argument. By default, it’s enabled just for simple polynomials, but optional when powers are sortable (e.g. in a Laurent polynomial)
lazy_text:
New format_docstring decorator that use format-style templates to assign docstrings to functions, intended to avoid docstring copies on StrategyDict instances.
lazy_wav (new!):
WavStream class for opening Wave files. Can load 24-bit audio files! Tested with 8 bits files (unsigned int) and 16/24/32 bits (signed int) mono and stereo files, both casting the data to a float in [-1;1) interval (default) and keeping the original integer data as it is
multiple modules:
(lazy_math and lazy_stream) Renamed the elementwised abs to absolute, so no Python built-in name is ever replaced when importing with from audiolazy import *. Also, the built-in abs now can be used directly with Stream instances
(lazy_analysis and lazy_misc) Renamed freq2lag and lag2freq to use 2 instead of _to_, and moved them to lazy_misc
* Version 0.05 (Python 2 & 3, more examples, refactoring, polinomials) *
examples:
Pitch follower via zero-crossing rate with Tkinter GUI
Pi with Madhava-Gregory-Leibniz series and Machin formula using Stream
LPC plot with DFT, showing two formants (magnitude peaks)
A somehow disturbing example based on Shepard “going higher” tone
Linear Periodically Time Variant filter example
Now the Bach choral player can play in loop
New DFT-based pitch follower (guitar tuner like) and better ZCR-based pitch follower by using a simple limiter
Butterworth filter from SciPy as a ZFilter instance, with plots
general:
Now with 82% code coverage in tests
Mock testing for audio output
Bugfixes (envelope.abs, midi2str, StreamTeeHub.blocks, etc.)
Extended domain for some functions by using inf and nan
Removed deprecated Stream.tee() method
Constants DEFAULT_CHUNK_SIZE and LATEX_PI_SYMBOL were removed: the default values are now changeable and inside chunks and float_str, respectively (see docstrings for more details)
No more distinction between __div__ and __truediv__ (Python 2.7)
Now AudioLazy works with Python 3.2 and 3.3!
Test skipping for tests that depends upon something that is Python version-specific
Test “xfail” using XFailer classes when depending package (e.g. pyaudio) is unavailable in the testing environment
lazy_compat (new!):
Module for Python 2.x and 3.x compatibility resources (constants and functions) without AudioLazy dependencies (i.e., no Stream here)
Common place for iterable-based version of itertools/built-ins in both Python 2 and 3 starting with “x”: xmap, xfilter, xzip, xrange, xzip_longest. Versions with “i” are kept in lazy_itertools module to return Stream instances (imap, izip, izip.longest, etc.), and Python 2 list-based behaviour of range is kept as orange (a fruitful name)
New meta function for creating metaclasses always in a “Python 3 look-alike” style, keeping the semantics (including the inheritance hierarchy, which won’t have any extra “dummy” class)
lazy_core:
New OpMethod class with 33 operator method instances and querying
Changed AbstractOperatorOverloaderMeta to the new OpMethod-based interface
Now StrategyDict changes the module __test__ so that doctests from strategies are found by the doctest finder.
lazy_filters:
ZFilter instances are now better prepared for Stream coeffs and operator-based filter creation, as well as a new copy helper method
Filters are now hashable (e.g., they can be used in sets)
lazy_io:
New RecStream class for recording Stream instances with a stop method
Now chunks is a StrategyDict here, instead of two lazy_misc functions
Now the default chunk size is stored in chunks.size, and can be changed
lazy_itertools:
New accumulate itertool from Python 3, available also in Python 2 yielding a Stream. This is a new StrategyDict with one more strategy in Python 3
Strategy chain.from_iterable is now available (Stream version itertool), and chain is now a StrategyDict
Now izip is a StrategyDict, with izip.smallest (default) and izip.longest strategies
lazy_misc:
New rint for “round integer” operations as well as other higher step integer quantization
Now almost_eq is a single StrategyDict with both bits (default, comparison by significand/mantissa bits) and diff (absolute value difference) strategies
lazy_poly:
New x Poly object (to be used like the z ZFilter instance)
Waring-Lagrange polynomial interpolator StrategyDict
General resample based on Waring-Lagrange interpolators, working with time-varying sample rate
New methods Poly.is_polynomial() and Poly.is_laurent()
New property Poly.order for common polynomials
Now Poly.integrate() and Poly.diff() methods returns Poly instances, and the zero from the caller Poly is always kept in result (this includes many bugfixes)
Poly instances are now better prepared for Stream coeffs and evaluation, including a helper Poly.copy() method
Poly is now hashable and have __setitem__ (using both isn’t allowed for the same instance)
lazy_stream:
Stream.take now accepts floats, so with first sHz output as s (for second) you can now use my_stream.take(20 * s) directly, as well as a “take all” feature my_stream.take(inf)
New Stream.peek() method, allowing taking items while keeping them as the next to be yielded by the Stream or StreamTeeHub
New Stream.skip() method for neglecting the leading items without storing them
New Stream.limit() method, to enforce a maximum “length”
StreamTeeHub methods skip(), limit(), append(), map() and filter() returns the modified copy as a Stream instance (i.e., works like Stream(my_stream_tee_hub).method_name())
Control over the module name in tostream (needed for lazy_itertools)
lazy_synth:
Input “dur” in ones(), zeros(), white_noise() and impulse() now can be inf (besides None)
Impulse now have one=1. and zero=0. arguments
New gauss_noise for Normal / Gaussian-distributed noise
White-noise limits parametrization
lazy_text (new!):
Got all text/string formatting functions from lazy_misc
Namespace clean-up: new StrategyDict float_str embraces older rational/pi/auto formatters in one instance
* Version 0.04 (Documentation, LPC, Plots!) *
examples:
Random Bach Choral playing example (needs Music21 corpus)
general:
Sphinx documentation!
Self-generated package and module summary at the docstring
Integration with NumPy (tested on 1.5.0, 1.6.1 and 1.6.2) and MatPlotLib (tested on 1.0.1 and 1.2.0)
More docstrings and doctests, besides lots of corrections
Itemized package description, installation instructions and getting started examples with plots in README.rst
Now with 5400+ tests and 75% code coverage
lazy_analysis:
One-dimensional autocorrelation function with acorr and lag “covariance” (due to lpc.covar) with lag_matrix
DFT for any frequency, given a block
Three envelope filtering strategies (time domain)
Three moving average filter strategies
Signal clipping function
Signal unwrap, defaults to the 2 * pi radians range but configurable to other units and max signal difference allowed
New AMDF algorithm as a non-linear filter
lazy_core:
StrategyDict instances now are singletons of a new class, which have lazy non-memoized docstrings based on their contents
lazy_filters:
ZFilter composition/substitution, e.g., (1 + z ** -1)(1 / z) results to the ZFilter instance 1 + z
New LinearFilter.plot() directly plots the frequency response of a LTI filter to a MatPlotLib figure. Configurable:
Linear (default) or logarithmic frequency scale
Linear, squared or dB (default) magnitude scale
Plots together the DFT of a given block, if needed. Useful for LPC
Phase unwrapping (defaults to True)
Allows frequency in Hz and in rad/sample. When using radians units, the tick locator is based on pi, as well as the formatter
New LinearFilter.zplot() for plotting the zero-pole plane of a LTI filter directly into a MatPlotLib figure
New LinearFilterProperties read-only properties numpolyz and denpolyz returning polynomials based on x = z instead of the polynomials based on x = z ** -1 returned from numpoly and denpoly
New LinearFilter properties poles and zeros, based on NumPy
New class FilterList for filter grouping with a callables property, for casting from lists with constant gain values as filters. It is an instance of FilterListMeta (old CascadeFilterMeta), and CascadeFilter now inherits from this FilterList
More LinearFilter behaviour into FilterList: Plotting (plot and zplot), poles, zeros, is_lti and is_causal
New ParallelFilter class, inheriting from FilterList
Now comb is a StrategyDict too, with 3 strategies:
comb.fb (default): Feedback comb filter (IIR or time variant)
comb.tau: Same to the feedback strategy, but with a time decay tau parameter (time in samples up to 1/e amplitude, or -8.686 dB) instead of a gain alpha
comb.ff: Feed-forward comb filter (FIR or time variant)
lazy_lpc (new!):
Linear Predictive Coding (LPC) coefficients as a ZFilter from:
lpc.autocor (default): Auto-selects autocorrelation implementation (Faster)
lpc.nautocor: Autocorrelation, with linear system solved by NumPy (Safer)
lpc.kautocor: Autocorrelation, using the Levinson-Durbin algorithm
lpc.covar or lpc.ncovar: Covariance, with linear system solved by NumPy
lpc.kcovar: Covariance, slower. Mainly for those without NumPy
levinson_durbin: Same to the lpc.kautocor, but with the autocorrelation vector as the input, not the signal data
Toeplitz matrix as a list of lists
Partial correlation coefficients (PARCOR) or reflection coefficients
Line Spectral Frequencies (LSF)
Stability testers for filters with LSF and PARCOR
lazy_math:
New sign gets the sign of a given sequence.
lazy_midi:
Completed converters between frequency (in hertz), string and MIDI pitch numbers
New octaves for finding all octaves in a frequency range given one frequency
lazy_misc:
New rational_formatter: casts floats to strings, perhaps with a symbol string as multiplier
New pi_formatter: same to rational_formatter, but with the symbol fixed to pi, mainly for use in MatPlotLib labels
lazy_poly:
New Poly.roots property, based on NumPy
lazy_stream:
Streamix class for mixing Streams based on delta starting times, automatically managing the need for multiple “tracks”
lazy_synth:
Karplus-Strong algorithm now uses tau time decay constant instead of the comb filter alpha gain.
* Version 0.03 (Time variant filters, examples, etc.. Major changes!) *
examples (new!):
Gammatone frequency and impulse response plots example
FM synthesis example for benchmarking with CPython and PyPy
Simple I/O wire example, connecting the input directly to the output
Modulo Counter graphics w/ FM synthesis audio in a wxPython application
Window functions plot example (all window strategies)
general:
Namespace cleanup with __all__
Lots of optimization and refactoring, also on tests and setup.py
Better docstrings and README.rst
Doctests (with pytest) and code coverage (needs pytest-cov)
Now with 5200+ tests and 79% code coverage
lazy_analysis (new!):
New window StrategyDict instance, with:
Hamming (default)
Hann
Rectangular
Bartlett (triangular with zero endpoints)
Triangular (without zeros)
Blackman
lazy_auditory (new!):
Two ERB (Equivalent Rectangular Bandwidth) models (both by Glasberg and Moore)
Function to find gammatone bandwidth from ERB for any gammatone order
Three gammatone filter implementations: sampled impulse response, Slaney, Klapuri
lazy_core:
MultiKeyDict: an “inversible” dict (i.e., a dict whose values must be hashable) that may have several keys for each value
StrategyDict: callable dict to store multiple function implementations in. Inherits from MultiKeyDict, so the same strategy may have multiple names. It’s also an iterable on its values (functions)
lazy_filters:
LTI and LTIFreq no longer exists! They were renamed to LinearFilter and ZFilter since filters now can have Streams as coefficients (they don’t need to be “Time Invariant” anymore)
Linear filters are now iterables, allowing:
Comparison with almost_eq like assert almost_eq(filt1, filt2)
Expression like numerator_data, denominator_data = filt, where each data is a list of pairs that can be used as input for Poly, LinearFilter or ZFilter
LinearFilterProperties class, implementing numlist, denlist, numdict and dendict, besides numerator and denominator, from numpoly and denpoly
Comparison “==” and “!=” are now strict
CascadeFilter: list of filters that behave as a filter
LinearFilter.__call__ now has the “zero” optional argument (allows non-float)
LinearFilter.__call__ memory input can be a function or a Stream
LinearFilter.linearize: linear interpolated delay-line from fractional delays
Feedback comb filter
4 resonator filter models with 2-poles with exponential approximation for finding the radius from the bandwidth
Simple one pole lowpass and highpass filters
lazy_io:
AudioIO.record method, creating audio Stream instances from device data
lazy_itertools:
Now with a changed tee function that allows not-iterable inputs, helpful to let the same code work with Stream instances and constants
lazy_math (new!):
dB10, dB20 functions for converting amplitude (squared or linear, respectively) to logarithmic dB (power) values from complex-numbers (like the ones returned by LinearFilter.freq_response)
Most functions from math module, but working decorated with elementwise (sin, cos, sqrt, etc.), and the constants e and pi
Other functions: factorial, ln (the log from math), log2, cexp (the exp from cmath) and phase (from cmath)
lazy_midi:
MIDI pitch numbers and Hz frequency converters from strings like “C#4”
lazy_misc:
Elementwise decorator now based on both argument keyword and position
lazy_poly:
Horner-like scheme for Poly.__call__ evaluation
Poly now can have Streams as coefficients
Comparison “==” and “!=” are now strict
lazy_stream:
Methods and attributes from Stream elements can be used directly, elementwise, like my_stream.imag and my_stream.conjugate() in a stream with complex numbers
New thub() function and StreamTeeHub class: tee (or “T”) hub auto-copier to help working with Stream instances almost the same way as you do with numbers
lazy_synth:
Karplus-Strong synthesis algorithm
ADSR envelope
Impulse, ones, zeros/zeroes and white noise Stream generator
Faster sinusoid not based on the TableLookup class
* Version 0.02 (Interactive Stream objects & Table lookup synthesis!) *
general:
10 new tests
lazy_midi (new!):
MIDI to frequency (Hz) conversor
lazy_misc:
sHz function for explicit time (s) and frequency (Hz) units conversion
lazy_stream:
Interactive processing with ControlStream instances
Stream class now allows inheritance
lazy_synth (new!):
TableLookup class, with sinusoid and sawtooth instances
Endless counter with modulo, allowing Stream inputs, mainly created for TableLookup instances
Line, fade in, fade out, ADS attack with endless sustain
* Version 0.01 (First “pre-alpha” version!) *
general:
4786 tests (including parametrized tests), based on pytest
lazy_core:
AbstractOperatorOverloaderMeta class to help massive operator overloading as needed by Stream, Poly and LTIFreq (now ZFilter) classes
lazy_filters:
LTI filters, callable objects with operators and derivatives, returning Stream instances
Explicit filter formulas with the z object, e.g. filt = 1 / (.5 + z ** -1)
lazy_io:
Multi-thread audio playing (based on PyAudio), with context manager interface
lazy_itertools:
Stream-based version of all itertools
lazy_misc:
Block-based processing, given size and (optionally) hop
Simple zero padding generator
Elementwise decorator for functions
Bit-based and diff-based “almost equal” comparison function for floats and iterables with floats. Also works with (finite) generators
lazy_poly:
Poly: polynomials based on dictionaries, with list interface and operators
lazy_stream:
Stream: each instance is basically a generator with elementwise operators
Decorator tostream so generator functions can return Stream objects
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
File details
Details for the file audiolazy-0.6.zip
.
File metadata
- Download URL: audiolazy-0.6.zip
- Upload date:
- Size: 532.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4c1237fa1cda75ce5f809594345f3ac6c095fdebc50ea72660c628e4592995d0 |
|
MD5 | c3850eb493e793beedbec86ab88fcb1b |
|
BLAKE2b-256 | 5ace06e7f52f0a8564533fc2d7598f83d22b31835f28270d31a5d92c68fa3f8a |
File details
Details for the file audiolazy-0.6.tar.gz
.
File metadata
- Download URL: audiolazy-0.6.tar.gz
- Upload date:
- Size: 470.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | c879bab2832daf1bcbaaf52ba5829eb7cdae5f606e4c74eaea1fc826652bbc97 |
|
MD5 | dd4bdad44e0d7766952ecc1365ae9c1e |
|
BLAKE2b-256 | 6f9d670be88d77346a9ad53e961aef1c33b5e7cb4831ad58f635f8b8c5c1db4c |
File details
Details for the file audiolazy-0.6-py2.py3-none-any.whl
.
File metadata
- Download URL: audiolazy-0.6-py2.py3-none-any.whl
- Upload date:
- Size: 121.3 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 1990e9374ea5ff59c37e1d1f72ab9308f1b0adbe446460e4da57bafbc93ffa10 |
|
MD5 | 98f9af2eaa85c7006ecae5f6bdd1b037 |
|
BLAKE2b-256 | 65970b9528016ce0d4d11380d9864b6fe3b3f7d8b358a841e3489fa84fd18792 |