audiolazy 0.04
Expressive Digital Signal Processing (DSP) package for Python.
Latest Version: 0.05
Lazyness 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 lazyness that allows:
 Realtime application (you don’t need to wait until all data is processed to have a result);
 Endless data sequence representation;
 Dataflow 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 wellchosen constants, duck typing, overloaded operators, functions as firstclass 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 (autobroadcast with noniterables) in a common Python iterable container accepting heterogeneous data;
 Strongly samplebased representation (Stream class) with easy conversion to block representation using the Stream.blocks(size, hop) method;
 Samplebased interactive processing with ControlStream;
 Streamix mixer for iterables given their starting time deltas;
 Multithread audio I/O integration with PyAudio;
 Linear filtering with Ztransform 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 samplebased (e.g., zerocross rate, envelope, moving average, clipping, unwrapping) and blockbased (e.g., window functions, DFT, autocorrelation, lag matrix) analysis and processing tools;
 A simple synthesizer (Table lookup, KarplusStrong) 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, Streambased 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 bleedingedge 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.03 (requires git for cloning):
pip install U git+git://github.com/danilobellini/audiolazy.git@v0.03
The package doesn’t have any strong dependency for its core besides the Python itself and 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 only): used as an oracle for LTI filter testing;
 pytest and pytestcov (testing only): runs test suite and shows code coverage status;
 wxPython (example only): used by one example with FM synthesis in an interactive 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) # 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, 9, 7, 6, 5, 9, 7, 6, 5, 9, 7, 6, 5, 9, 7]
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 (Ztransform). 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()
But 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 = 1e3 * 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 KarplusStrong 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.
AudioLazy changes history
* Version 0.04 (Documentation, LPC, Plots!) *
 examples:
 Random Bach Choral playing example (needs Music21 corpus)
 general:
 Sphinx documentation!
 Selfgenerated 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:
 Onedimensional 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 nonlinear filter
 lazy_core:
 StrategyDict instances now are singletons of a new class, which have lazy nonmemoized 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 zeropole plane of a LTI filter directly into a MatPlotLib figure
 New LinearFilterProperties readonly 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: Feedforward comb filter (FIR or time variant)
 lazy_lpc (new!):
 Linear Predictive Coding (LPC) coefficients as a ZFilter from:
 lpc.autocor (default): Autoselects autocorrelation implementation (Faster)
 lpc.nautocor: Autocorrelation, with linear system solved by NumPy (Safer)
 lpc.kautocor: Autocorrelation, using the LevinsonDurbin 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
 Linear Predictive Coding (LPC) coefficients as a ZFilter from:
 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:
 KarplusStrong 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 pytestcov)
 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
 New window StrategyDict instance, with:
 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 hasheable) 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 nonfloat)
 LinearFilter.__call__ memory input can be a function or a Stream
 LinearFilter.linearize: linear interpolated delayline from fractional delays
 Feedback comb filter
 4 resonator filter models with 2poles 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 notiterable 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 complexnumbers (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:
 Hornerlike 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 autocopier to help working with Stream instances almost the same way as you do with numbers
 lazy_synth:
 KarplusStrong 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 “prealpha” 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:
 Multithread audio playing (based on PyAudio), with context manager interface
 lazy_itertools:
 Streambased version of all itertools
 lazy_misc:
 Blockbased processing, given size and (optionally) hop
 Simple zero padding generator
 Elementwise decorator for functions
 Bitbased and diffbased “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
File  Type  Py Version  Uploaded on  Size  

audiolazy0.04.tar.gz (md5)  Source  20130218  88KB  
 Author: Danilo de Jesus da Silva Bellini
 Documentation: audiolazy package documentation
 Home Page: http://github.com/danilobellini/audiolazy
 License: GPLv3

Categories
 Development Status :: 2  PreAlpha
 Intended Audience :: Developers
 Intended Audience :: Education
 Intended Audience :: Other Audience
 Intended Audience :: Science/Research
 License :: OSI Approved :: GNU General Public License v3 (GPLv3)
 Operating System :: Microsoft :: Windows
 Operating System :: OS Independent
 Operating System :: POSIX :: Linux
 Programming Language :: Python
 Topic :: Artistic Software
 Topic :: Multimedia :: Sound/Audio
 Topic :: Multimedia :: Sound/Audio :: Analysis
 Topic :: Multimedia :: Sound/Audio :: Players
 Topic :: Multimedia :: Sound/Audio :: Sound Synthesis
 Topic :: Scientific/Engineering
 Topic :: Software Development
 Topic :: Software Development :: Libraries
 Topic :: Software Development :: Libraries :: Python Modules
 Package Index Owner: danilo.bellini
 DOAP record: audiolazy0.04.xml