Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Release 0.9.0
Nick Hilton
2013-12-24 21:11:34.080274
CONTENTS
Introduction 3 1.1 What is Nsound? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Building and installing Nsound . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.3 Getting Started Using Nsound . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Nsound Basics 2.1 Nsound Data Types . . 2.2 Buer Creation . . . . 2.3 AudioStream Creation 2.4 Wavele IO . . . . . . 2.5 Basic Manipulations . 2.6 Plotting . . . . . . . . 13 13 13 15 16 20 22
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
Nsound Audio Playback 25 3.1 Audio Backends . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.2 Limitations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.3 Know Problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Nsound Instruments 4.1 Bass Guitar . . . 4.2 Clarinet . . . . . 4.3 Kick Bass Drum 4.4 BD01 Drum . . 4.5 Hat . . . . . . . 4.6 Pipe Organ . . . 4.7 Slide Flute . . . 29 29 30 30 30 30 30 31 33 33 40 44 45
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
Nsound Generators 5.1 The Generator Draw Routines 5.2 The Sine Generator . . . . . . 5.3 The Sawtooth Generator . . . 5.4 The Square Generator . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Nsound Filters 6.1 FIR Filters . . . . . . . . . . . . . . . . . . . . 6.2 FIR Filter Frequency Response . . . . . . . . . 6.3 FIR Filter Frequency Response vs Filter Order . 6.4 IIR Filters . . . . . . . . . . . . . . . . . . . . . 6.5 IIR Filter Frequency Response . . . . . . . . . . 6.6 IIR Filter Frequency Response vs Filter Order . 6.7 IIR Filter Frequency Response vs Ripple Percent
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
47 47 48 50 52 53 55 57
Index
ii
Warning: This Users Guide is still a work in progress; some of the material is not organized, and several aspects of Nsound are not yet covered in sucient detail. This guide is intended as an introductory overview of Nsound and explains how to install and make use of the most important features of Nsound. For detailed reference documentation of the functions and classes contained in the package, see the Doxygen documentation on the nsound.sourceforge.net website. Note: Nsound is open source software, the developers continually work on improving the library and documentation and encourage others interested to contribute. For information on how to do so, please contact Nick Hilton at weegreenblobbie_yahoo_com. Thanks!
CONTENTS
CONTENTS
CHAPTER
ONE
INTRODUCTION
1.1 What is Nsound?
Nsound is a C++ library and Python module for audio synthesis featuring dynamic digital lters. Nsound lets you easily shape waveforms and write to disk or plot them. In Nsound, all audio data is represented by 64-bit oating point numbers between -1.0 and 1.0. It is easy to scale the data and adjust the volume by multiplying the audio data by a percentage, a number between 0.0 and 1.0. The audio data is is only converted to 8-bit, 16-bit, 24-bit, 32-bit or 64-bit when it is written to the disk with the Wavele class. The core of Nsound is the Buer class. Memory is dynamically allocated and frees the user from worrying about buer sizes. All the mathematical operators are overloaded to allow intuitive expressions. Generators produce oscillations of the waveform stored in them. Generators can produce a single frequency of the waveform held in them, or can dynamicly change frequency, just draw a line that represents frequency and pass it into the generator. A collection of IIR & FIR lters are also included. When creating lters, the cuto frequency is specied in Hz. The lters are also real-time, meaning they keep track of their internal state and for each audio sample passed in, an audio sample is returned. Beautiful plots can be easily created if your platform has the Python Matplotlib package installed. Most of the Nsound classes have their own plot methods. This Users Guide will specify code snippets written in Python. The C++ code is nearly identical. For specic C++ reference, view the Doxygen generated documentation available on the Nsound sourceforge website.
As of nsound-0.9.0, support for building with Vistual Studio 2010+ on 64-bits is now supported. Building on 32-bits is no longer tested as I no longer have access to a 32-bit Windows.
Linux
No binary packages are currently available. But your Linux box in most cases already has all the tools needed to build and install Nsound.
Mac OS X
No binary packages are currently available. But your OS X box in most cases already has all the tools needed to build and install Nsound.
Building Nsound requires the following software installed: 1. Python 2.7.x On Debian and derivative (Ubuntu): python On Windows: the ocial 64-bit Python installer at www.python.org is enough On Mac OSX: I highly recommend the MacPorts package manager to install the latest versions of Python, Numpy and Matplotlib www.macports.org . 2. Scons
Chapter 1. Introduction
Nsound uses this execellent build system, www.scons.org . On Windows: a 64-bit self-installer is not provied (as of 2013-12-24), youll have to download the source .Zip archive and do: python setup.py bdist_wininst and install it by running the dist/scons*.exe le. 3. A C++ compiler To build Nsound and the Python extension module, youll need a C++ compiler. On Windows: youll need to install Visual Studio 2010+ (2012 Express works). On Mac OS X: You will need to install XCode.
Optional Prerequisites
1. SWIG To build the Python module, SWIG generates the Python wrapper code. www.swig.org On Windows: youll download and unzip to C:\. 2. Matplotlib (Numpy, dateutil, pyparsing, six) For creating pretty plots, Matplotlib is used. Numpy and python-dateutil are a prerequisites for Matplotlib. Numpy: numpy.scipy.org Matplotlib: matplotlib.sourceforge.net On Windows: use the prebuilt 64-bit binaries from here: Unocial dows Binaries for Python Extension Packages 3. AO or PortAudio To enable audio playback through the soundcard, Nsound can use libao or libportaudio. AO: www.xiph.org/ao PortAudio: www.portaudio.com On Windows, these have already been statically built and provided. Win-
Usually this is only a problem for the Windows platform, since Linux and MacPorts download and install prerequisite automatically. 1. Start a Python Shell and import matplotlib:
>>> >>> >>> >>> >>> >>> import matplotlib # Try to import pylab from matplotlib import pylab # Try to plot something pylab.plot([1,2,3,4], "bo-") pylab.show()
As you run into missing packages, donload and install them. Most of them are: Numpy dateutil six pyparsing
SCons will query your computer for specic information about the build environment and generate a few les. It will then proceed to build the Nsound library and examples. To get help with scons, do:
$ scons --help scons: Reading SConscript files ... Building with 4 threads scons: done reading SConscript files. nsound-0.9.0 SCons Help usage: scons [OPTIONS] [TARGETS] ...
Chapter 1. Introduction
Local Options: --extra-warnings --disable-64 --disable-libao --disable-libportaudio --enable-cuda --disable-openmp --disable-python --help --static --prefix=PREFIX --config-debug --V, --verbose Targets: html lib install Generate the Doxyfile to create the Doxygen html files Just build libNsound Installs programs from src/bin to bindir, also instals libNsound to libdir, Nsound includedir not yet implemented (sorry). Creates a source archive named nsound-0.9.0.tar.gz Builds the unit test programs in src/test Perform actions that only result in the object_file Perform actions that only result in the program Adds extra warning flags to CXXFLAGS Disables float64 type, uses float32 instead Disables the libao AudioBackend Disables the libportaudio AudioBackend Enables Cuda accelerated functions and linking Disables OpenMp accelerated functions and linking Disables the use of matplotlib via Python, only applies to C++ lib Prints this help message Builds a static C++ lib Sets the install prefix for programs and libraries Prints lots of debug messages during scons configuration tests Shows full compiler command output
# Update the doxygen config file $ scons src/Doxyfile # Update only one program $ scons src/examples/stretcher # Create the Python builder script $ scons setup.py Use scons -H for help about command-line options.
On Windows, rather than muck around with the Systems PATH environment variables, I recommend creating a .BAT le that will insert paths into the environment. 1. Save this le to your doesktop windows_env64.bat 2. Create a shortcut to the le windows_env64.bat, edit the shortcut so the target line reads like this:
cmd /k C:\Users\USERNAME\Desktop\windows_env64.bat.bat
replacing USERNAME with your username. 3. Modify the shortcut startup directory to be located in the nsound directory, this way you wont have to cd to it all the time. 4. Double click the shortcut to open a DOS box with Visual Studio, Python, and SCons in the path, so building Nsound becomes as simple as:
C:\Users\USERNAME\Documents\nsound> scons
Before trying to compile Nsound with Vistual Studio, ensure that Python and SCons have been installed. There are Visual Studio build steps that will execute scons to generate some les. Next, examine the le msvs\properties.props to ensure the path to Python is correct, the default is C:\Python27. A Visual Studio 2010+ solution le is provide in msvs\nsound.sln. Debug builds wont link with Python because the debug library python27_d.lib is not provided, but isnt needed if youre debugging Nound C++ code.
Cygwin Notes
You will need to rebase your Cygwin installation. To do so follow these steps: 1. Close all Cygwin programs that may be using the cygwin.dll 2. Ensure the Cygwin package called rebase is installed using the setup.exe program 3. Start a Windows DOS box (not a Cygwin shell) 4. Start an ASH shell, then run the rebaseall command by executing:
Chapter 1. Introduction
You will need to install scons to this non-stanard location, then just run scons with this non-standard python:
/usr/local/python2.7/bin/scons
The SCons build environment will ask Pythons distutils module for the location of the include directory and dynamic library paths. This should get done automatically. A SCons tool was added to brute-force check the distutils build variables to locate these paths, site_scons/site_tools/ImportPythonConfig.py. To enable some extra debug messages, try using the --config-debug switch with scons:
$ scons --config-debug
Sometime everything above goes well, SCons nds the libraries, compiles and links everything ne, but at runtime you may run into other errors.
Matplotlib Backend Not Set
Traceback (most recent call last): File "/usr/local/python2.7/lib/python2.7/site-packages/matplotlib/backends/__init__.py", li fname = frame.f_back.f_code.co_filename AttributeError: NoneType object has no attribute f_code src/Nsound/Plotter.cc:171: failed to call python pylab.show()
This is due to the Matplotlib Backend not being set. So set a default backend edit the le matplotlibrc, and set the following:
backend : BACKEND
and replace BACKEND with something like GTKAgg, GTKCairo, CocoaAgg, MacOSX, QtAgg, WXAgg. The choice depends on the backends that are installed. To test if a specic backend is installed do:
>>> >>> >>> >>> >>> >>> ... import matplotlib matplotlib.use("GTKAgg") # Specify specific backend import matplotlib.pylab pylab.plot([1,2,3,4,3,2,1]) pylab.show() # Plot will appear if you selected a working GUI backend pylab.savefig("somefile.png") # Replace png with pdf or svg to # to test a file only backend
You should either see a gure window show up after the show() call or a lename written to the local directory after the saveg() call.
10 Chapter 1. Introduction
Next, modify one of the examples in src/examples, then execute the example:
$ python example1.py
and listen to the wavele written out or look at the plots created. You can also use the module in Python interactively:
>>> >>> >>> >>> >>> >>> import Nsound as ns b = ns.Buffer() b << 0 << 1 << 0.9 << 0.8 << 0.7 << 0.6 << 0.5 << 0.4 << 0.3 << 0.2 << 0.1 << 0 # Other magical lines ... b.plot("Nsound") ns.Plotter.show()
Nsound
20
40
60
80
100
120
140
SCons looks for a special le called SConstruct that serves as the master Makele that tells SCons how to build everything. Nsounds SConstruct le is located in the root of the archive. The Nsound C++ library and examples are compiled by default when you invoke scons without any arguments:
cd nsound-0.9.0 scons
Sopose you are modifying one of the examples and wish to recompile it, you could issue scons in the root and it will recompile everything that needs to be rebuilt. Now suppose you want work in the src/example directory. Running SCons in this directory results in the following error message:
scons: *** No SConstruct file found. File "/usr/lib/scons/SCons/Script/Main.py", line 858, in _main
This is because Nsound only contains one SConstruct le, and it only lives in the root of the archive. This is a common scenario and so the folks that make SCons include a command line switch to tell it to look else where for the SConstruct le. So now try this:
scons -U
This will tell scons to search up the directory structure to search for the SConstruct le. You can also tell SCons to build a specic target. Suppose you are in the examples directory and modied example2.cc. You may have changes in other example les but you only want to compile example2.cc. You can specify the target like so:
scons -U example2
12
Chapter 1. Introduction
CHAPTER
TWO
NSOUND BASICS
2.1 Nsound Data Types
When writing new features for Nsound, C++ typedefs are used to ensure the same bit width is used on all platforms. To see how these types are dened, look at the le src/Nsound/Nsound.h after running SCons. If you are using the Python module, you wont need to know anything about these data types. Type boolean int8 int16 int32 int64 oat32 oat64 uint8 uint16 uint32 uint64 Description The C++ bool type Integer (-128 to 127) Integer (-32768 to 32767) Integer (-2147483648 to 2147483647) Integer (9223372036854775808 to 9223372036854775807) Single precision oat: sign bit, 8 bits exponent, 23 bits mantissa Double precision oat: sign bit, 11 bits exponent, 52 bits mantissa Unsigned integer (0 to 255) Unsigned integer (0 to 65535) Unsigned integer (0 to 4294967295) Unsigned integer (0 to 18446744073709551615)
13
The new Buer b is empty. Calling the getLength() method will return 0. The underlying data structure that is held by the Buer class is a std::vector. One can preallocate memory when creating a buer by specify the number of samples to preallocate:
b = ns.Buffer(1024)
The new Buer b is empty, even though memory was preallocated. Calling the getLength() method will return 0. In general, you dont need to worry about preallocating memory. It is meant to be useful when implementing new features in Nsound when the size of Buers are already known.
14
b = ns.Buffer("california.wav")
The new Buer b will contain all the samples in california.wav. If the wavele has more than one channel, only the rst channel is read and stored in the new Buer. The waveles data will be converted into oat64 with a range of (-1.0, 1.0.).
The default constructor sets the sample rate to 44100.0 and a single channel. The new AudioStream a is empty. Calling the getLength() method will return 0. Calling the getDuration() method will return 0.0. To specify the sample rate:
a = ns.AudioStream(44100.0)
This will create a new AudioStream with a sample rate of 44.1 kHz and a single channel. To create a stereo AudioStream:
a = ns.AudioStream(44100.0, 2)
The is no limit to the number of channels an AudioStream can have. In practice, the number of channels and their duration will be limited to the amount of memory your computer has. The underlying data structure that is held by the AudioStream class is a std::vector of Buer objects. One can preallocate memory when creating an AudioStream by specify the number of samples to preallocate:
15
a = ns.AudioStream(44100.0, 2, 1024)
The new AudioStream a is empty, even though memory was preallocated. Calling the getLength() method will return 0, calling getDuration() will return 0.0. In general, you dont need to worry about preallocating memory. It is meant to be useful when implementing new features in Nsound when the size of AudioStreams are already known.
The new AudioStream a will contain all the samples in california.wav. If the wavele has more than one channel, all channels are read and stored in the new AudioStream. The waveles sample rate is also read and stored in the AudioStream. The waveles data will be converted into oat64 with a range of (-1.0, 1.0.).
2.4 Wavele IO
Nsound includes a simple Wavele class that can read RIFF waveles that are PCM encoded. This is a very basic wavele format. Nsound currently does not support any other audio formats, but there are plenty of other free tools on the web that can convert audio formats to PCM waveles.
16
Nsound has also overloaded the left shift operator, concatenation from waveles is easy:
import Nsound as ns b = ns.Buffer() b << "california.wav" \ << "walle.wav"
2.4. Wavele IO
17
a.writeWavefile("california-32bit.wav")
Nsound has also overloaded the right shift operator for writing waveles, the example above can be rewritten as:
import Nsound as ns a = ns.AudioStream("california.wav") ns.Wavefile.setDefaultSampleSize(32) a >> "california-32bit.wav"
Nsound will write waveles using integer data types by default. This can be changed to oating point.
Note: Since the data is stored as oating point, there is no need to normalize the data rst. Nsound can read and write waveles that store their samples in IEEE oating point format. To write les using this format, call: Wavefile.setIEEEFloat(ag) And set the ag to True. The Wavele sample size must be set to 32 or 64.
18
a >> "wav_at_48KHz.wav"
The Python script below can be used on the command line to change a waveles sample rate:
#! /usr/bin/env python import Nsound as ns from optparse import OptionParser parser = OptionParser( usage = "resample target_sample_rate input.wav output.wav") (options, argv) = parser.parse_args() argc = len(argv) if argc != 3: raise RuntimeException("Expecting 3 arguments!") target = float(argv[0]) f1 = argv[1] f2 = argv[2] print "Reading %s" % f1 a1 = ns.AudioStream(f1) source = a1.getSampleRate() print "source: %d " %(source) print "target: %d " %(target) ratio = target / source print "ratio: %f " %(ratio)
2.4. Wavele IO
19
2.5.1 Concatenation
After creating an empty Buer, one can insert samples into it with concatenation:
import Nsound as ns b = ns.Buffer() b << 1 << 2 << 3 print b.getLength() # 3 print b.toList() # [1.0, 2.0, 3.0]
20
print b.toList() # [2.0, 3.0, 6.0, 7.0, 8.0, 9.0] b *= 2.0 print b.toList() # [4.0, 6.0, 12.0, 14.0, 16.0, 18.0] b /= 3.0 print b.toList() # [1.3333, 2.0, 2.6666, 4.6666, 5.3333, 6.0]
21
# Products b3 = b1 * b2 print b3.toList() # [0.0, 1.0, 1.0] b3 = b2 * b1 print b3.toList() # [0.0, 1.0, 1.0, 1.0] # Quotients b3 = b1 / b2 print b3.toList() # [1e+20, 1.0, 1.0] b3 = b2 / b1 print b3.toList() # [0.0, 1.0, 1.0, 1.0]
2.6 Plotting
Nsound uses the wonderful Matplotlib package for making plots. To do this, a simple C++ class called Plotter wraps some of the Python C-API so that the C++ libNsound library can make calls into the Matplotlib classes to make plots.
22
Amplitude
C++ libnsound
Plotter.h
Buffer
1.0
0.5
0.0
0.5
In the Python module, the Plotter class make calls into the Python Matplotlib module. If you are using the C++ library and the Matplotlib C-API was found, plotting will be enabled. If you are using the Python module and Matplotlib is installed, plotting will be enabled. Note: Plots will not pop up by default with the C++ or non-interactive Python code. For C++, a call to Plotter::show() will render the plots to the screen. With the Python module, a call to either matplotlib.pylab.show() or Nsound.Plotter.show() will display the plots.
Note: You will not see calls to Plotter.show() in this Users Guide, the plots are generated with inline Python code and are saved to disk.
Note: On MacOSX, if you are using the MacPorts package manager to install Python, Numpy, and Matplotlib in /opt/local, you will need to set the default Matplotlib backend. To do so edit the le ~/.matplotlib/matplotlibrc and add a line that reads backend : MacOSX. Once you start manipulating your Buers and AudioStreams, it is easy to see the eect by plotting them:
import Nsound as ns b = ns.Buffer() b << 1 << 2 << 3 << 4 b.plot("Figure 1") a = ns.AudioStream(1, 2)
2.6. Plotting
23
a[0] = b a[1] = b.getReverse() a.plot("Figure 2") # Your code needs to call the show() # method to make the plots show up. # ns.Plotter.show()
4.0 3.5 3.0 2.5 2.0 1.5 1.0 0.0 4.0 3.5 3.0 2.5 2.0 1.5 1.0 0.0 4.0 3.5 3.0 2.5 2.0 1.5 1.0 0.0 0.5 1.0
Figure 1
1.5
2.0
2.5
3.0
Figure 2
Amplitude
0.5
1.0
2.5
3.0
Amplitude
0.5
1.0
2.5
3.0
24
CHAPTER
THREE
C++ libnsound
AudioPlayback.h OR
AO libao
OS
Audio playback can be as simple as:
PortAudio libportaudio
The Nsound.AudioPlayback constructor: Nsound.AudioPlayback(sample_rate, n_channels, bits_per_sample) sample_rate [oat] The number of samples per seconds n_channels [int] The number of channels, currently on 1 or 2 is supported bits_per_sample [int] The sample size to convert to before playing it on the sound card, currently only 16 and 32 are supported
25
Not all combinations of sample_rate, n_channels and bits_per_sample will work. Most platforms should work with sample_rate = 44100 n_channels = 1, n_channels = 2 bits_per_sample = 16, bits_per_sample = 32 Other combinations have not been tested.
3.2 Limitations
The Nsound.AudioPlayback class is not thread safe, so only one thread can use the class at a time. Only blocking calls are currently implemented, with memory being allocated and oating point numbers being casted to integer types on a call by call basis.
26 Chapter 3. Nsound Audio Playback
Audio will still be played to the sound card (at least on Nicks Ubuntu 10.04 box.) The error happens because Bluetooth is disabled but ALSA is still congured to use Bluetooth services, to x this, remove the bluez-alsa package:
$ sudo apt-get purge bluez-alsa
The error messsage should now go away, but be careful with this solution if you use Bluetooth devices for audio.
27
28
CHAPTER
FOUR
NSOUND INSTRUMENTS
Instruments are classes that provide a common API, their purpose is to provide a foundation of common musical elements for everyone to use. All Nsound Instruments will provide the following functions: Nsound.Instrument.play() Returns: demo [Nsound.AudioStream] Returns a demo created by the author of the instrument Nsound.Instrument.play(duration, frequency) Parameters: duration [oat] The duration in seconds of sound to generate frequency [oat] The frequency of the sound in Hz Returns: out [Nsound.AudioStream] Returns the sound of the instrument at the given frequency for duration seconds
29
4.2 Clarinet
Based on a physical model written in Csound by Hans Mikelson which was originally based on Perry Cooks physical model. Nsound.Clarinet(sample_rate) sample_rate [oat] The number of samples per seconds
4.5 Hat
Simulates a Hat hit, based on a Csound Hat instrument by Steven Cook. Nsound.Hat(sample_rate) sample_rate [oat] The number of samples per seconds
30
31
32
CHAPTER
FIVE
NSOUND GENERATORS
Note: These examples use a small sample rate (between 100 and 1000) to keep the generation of this documentation relitively quick. In practice, higher quality sample rates should be used (44100, 48000, 96000 etc.).
33
b << g.drawLine(1.0, 0.0, 1.0) b << g.drawLine(1.0, 1.0, 1.0) b << g.drawLine(1.0, 1.0, 0.0) b.plot("Basic Lines")
Basic Lines
50
100
150
200
250
300
34
Exponential Decay
20
40
60
80
100
b = ns.Buffer() b << g.drawGaussian(1.0, 0.5, 0.15) b.plot("A Gaussian Curve") b2 = ns.Buffer() b2 << g.drawFatGaussian(1.0, 0.25) b2.plot("A Fat Gaussian Curve")
35
1.0 0.8 0.6 0.4 0.2 0.00 1.0 0.8 0.6 0.4 0.2 0.00 20 20
A Gaussian Curve
40
60
80
100
40
60
80
100
Drawing parabolas, note that an AudioStream is used so the x axis has the units of seconds:
import Nsound as ns from matplotlib import pylab sr = 1000.0 g = ns.Generator(sr)
36
########################################################################### # First Parabola a = ns.AudioStream(sr, 1) a << g.drawParabola(1.0, 0.0, 0.5, 1.0, 0.0) a.plot("A Parabola") # Plot red cross hairs at the three points pylab.plot( [0.0, 0.5, 1.0], [0.0, 1.0, 0.0], "r+", markersize = 10.0) pylab.xlim(-0.05, 1.05) pylab.ylim(-0.05, 1.05) ########################################################################### # Seconds Parabola a = ns.AudioStream(sr, 1) a << g.drawParabola(1.0, 0.333, 0.666, 0.666, 0.0) a.plot("Another Parabola") # Plot red cross hairs at the three points pylab.plot( [0.000, 0.666, 1.000], [0.333, 0.666, 0.000], "r+", markersize = 10.0) pylab.xlim(-0.05, 1.05) pylab.ylim(-0.05, 1.05)
37
A Parabola
0.8
1.0
Another Parabola
0.8
1.0
Drawing sine waves. The drawSine() and drawSine2() functions use the C++ std::sin() function to generate samples. These functions do not use a wavetable, so there will not be any interpolation or aliasing problems that may occur for wavetable oscillator classes that derive from Generator. Some examples:
import Nsound as ns sr = 1000.0 g = ns.Generator(sr)
38
########################################################################### # 3 Hz a = ns.AudioStream(sr, 1) a << g.drawSine(1.0, 3.0) a.plot("3 Hz") ########################################################################### # Dynamic Frequency a = ns.AudioStream(sr, 1) a << g.drawSine(1.0, g.drawLine(1.0, 0.0, 10.0)) a.plot("Dynamic Frequency") ########################################################################### # Dynamic Phase a = ns.AudioStream(sr, 1) a << g.drawSine2(1.0, 3.0, g.drawLine(1.0, 0.0, 1.0)) a.plot("Dynamic Phase")
3 Hz
0.2
0.8
1.0
39
1.0 0.5 Amplitude 0.0 0.5 1.0 0.0 1.0 0.5 Amplitude 0.0 0.5 1.0 0.0
Dynamic Frequency
0.2
0.8
1.0
Dynamic Phase
0.2
0.8
1.0
import Nsound as ns s = ns.Sine(100.0) b = ns.Buffer() b << s.generate(1.0, 3.0) b.plot("1 second at 3 Hz")
1 second at 3 Hz
20
40
60
80
100
41
20
40
60
80
100
The Generator class also allow dynamically changing frequencies. Simply create a Buer to hold frequency values and pass the Buer to the generate function. Below the frequency will change from 1 to 10 back to 1.
import Nsound as ns s = ns.Sine(1000.0) freqs = ns.Buffer() freqs << s.drawLine(1.0,
0.0, 10.0) \
42
<< s.drawLine(1.0, 10.0, freqs.plot("Frequencies in Hz") b = ns.Buffer() b << s.generate(2.0, freqs) b.plot("Dynamic frequencies")
0.0)
Frequencies in Hz
1000
1500
2000
Dynamic frequencies
500
1000
1500
2000
43
Sawtooth, 3 harmonics
50
100
150
200
250
300
44
Sawtooth, 12 harmonics
100
150
200
250
300
45
1.5 1.0 0.5 0.0 0.5 1.0 1.50 1.5 1.0 0.5 0.0 0.5 1.0 1.50
50
100
150
200
250
300
50
100
150
200
250
300
46
CHAPTER
SIX
NSOUND FILTERS
Nsound currently provides two kinds of lters: 1. Finite Impulse Response (FIR) 2. Innite Impulse Response (IIR) Nsound provides both FIR and IIR lters for the types below: 1. Low Pass 2. High Pass 3. Band Pass 4. Band Reject (Or Notch lter)
fc The lter cut o frequency in Hz. fc_low The lower lter cut o frequency in Hz fc_high The high lter cut o frequency in Hz
Low Pass FIR Frequency Response order = 64, fc = 100.0 Hz, sr = 500.0 Hz
50
200
250
48
High Pass FIR Frequency Response order = 64, fc = 100.0 Hz, sr = 500.0 Hz
50
200
250
Band Pass FIR Frequency Response order = 64, fl = 100.0 Hz, fl = 200.0 Hz, sr = 500.0 Hz
0 Frequency Response (dB) 10 20 30 40 50 600 50 100 150 Frequency (Hz) 200 250
49
Band Reject FIR Frequency Response order = 64, fl = 100.0 Hz, fl = 200.0 Hz, sr = 500.0 Hz
0 Frequency Response (dB) 10 20 30 40 50 600 50 100 150 Frequency (Hz) 200 250
50
Low Pass FIR Frequency Response order = 16, fc = 100.0 Hz, sr = 500.0 Hz
50
200
250
Low Pass FIR Frequency Response order = 64, fc = 100.0 Hz, sr = 500.0 Hz
50
200
250
51
Low Pass FIR Frequency Response order = 256, fc = 100.0 Hz, sr = 500.0 Hz
600
50
200
250
Low Pass FIR Frequency Response order = 1024, fc = 100.0 Hz, sr = 500.0 Hz
600
50
200
250
to 0.0, then the lter is maximally at and equilavent to a Butterworth lter. Consider using 0.005 (0.5%) as the ripple percent, this acchives a sharper roll o with little ripple.
50
200
250
53
50
200
250
Band Pass IIR Frequency Response order = 8, fl = 100.0 Hz, fh = 200.0 Hz, sr = 500.0 Hz
0 Frequency Response (dB) 10 20 30 40 50 600 50 100 150 Frequency (Hz) 200 250
54
Band Reject IIR Frequency Response order = 3, fl = 100.0 Hz, fl = 200.0 Hz, sr = 500.0 Hz
0 Frequency Response (dB) 10 20 30 40 50 600 50 100 150 Frequency (Hz) 200 250
55
50
200
250
50
200
250
56
50
200
250
Low Pass IIR Frequency Response order = 15, fc = 100.0 Hz, sr = 500.0 Hz
50
200
250
57
50
200
250
50
200
250
58
50
200
250
59
60
CHAPTER
SEVEN
NSOUND FFT
Nsound currently implements its own fast Fourier transform (FFT) in C++. In the furture this will change and use the FFTW library if available. The FFT is provided by the FFTransform class. It takes an input signal Buer and transforms it into the frequency domain. The basic documentation: FFTransform(sample_rate) sample_rate The number of samples per second. The sample rate is used for creating plots with correct axes. FFTransform.fft(x, n_order) x The input Buer. n_order The size of the FFT to perform. Returns an FFTChunkVector, representing the input signal chopped up into frames, where each frame is n_order is size. FFTransform.ifft(t_chunk_vector) t_chunk_vector The input FFTChunkVector returned by t(). Returns an Buer, where each FFTChunk in the FFTChunkVector is transformed back into the time-domain. The example below creates a square wave with 5 harmonics.
import Nsound as ns sample_rate = 500.0 square = ns.Square(sample_rate, 5) b = ns.Buffer() b << square.generate(0.5, 10.0)
61
fft = ns.FFTransform(sample_rate) vec = fft.fft(b, 256) b.plot("Input signal, 4 Hz Square wave") vec[0].plot("Frequency Domain") b2 = fft.ifft(vec) b2.plot("Reconstructed")
1.5 1.0 0.5 0.0 0.5 1.0 1.50 50 0 Magnitude dB 50 100 150 2000
62
50
100
150
200
250
Frequency Domain
50
200
250
Chapter 7. Nsound FFT
Reconstructed
100
150
200
250
Notice that there are 5 peaks, these correspond to the 5 harmonics in the square wave.
63
vec2[0].plot("Frequency Domain, With Hanning Window") b1.plot("Reconstructed, No Window") b2.plot("Reconstructed, With Hanning Window")
50
200
250
50 Frequency Domain, With Hanning Window 0 Magnitude dB 50 100 150 2000 50 100 150 Frequency Hz 200 250
64
1.5 1.0 0.5 0.0 0.5 1.0 1.50 1.5 1.0 0.5 0.0 0.5 1.0 1.50
Reconstructed, No Window
50
100
150
200
250
50
100
150
200
250
As you can see, using a window can clean up the frequency domain plot, but it should not be used for reconstructing the signal.
65
66
CHAPTER
EIGHT
NSOUND STRETCHER
Nsound implements pitch and time shifting using the Stretcher class. The algorithm is based on the paper An Overlap-Add Technique Based On Wavefrom Similarity (WSOLA) For High Quality Time-Scale Modication Of Speech by Werner Verhelst and Marc Roelands. With the Stretcher class, you can change the time of the singal without modifying the frequency content. Or, you can also scale the frequency content without modifying the time. Please visit the Nsound examples webpage to listen to a 10 seconds stereo recording that was dynamically time and pitch shifted. Some of the basic documentation: Stretcher(sample_rate) Stretcher.pitchShift(x, factor) x The input Buer or AudioStream. factor A percent change factor. Stretcher.timeShift(x, factor) x The input Buer or AudioStream. factor A percent change factor. The example below creates a signal and shifts it in time, but preserves the frequency content. The results are put into the frequency domain and plotted.
import Nsound as ns sample_rate = 1000.0 stretch = ns.Stretcher(sample_rate) stretch.showProgress(True) saw = ns.Sawtooth(sample_rate, 4)
67
fft = ns.FFTransform(sample_rate) fft.setWindow(ns.HANNING) a = ns.AudioStream(sample_rate, 1) a << saw.generate(1.0, 100.0) a.plot("Original Time Domain") fft.fft(a[0], 1024)[0].plot("Original Frequency Domain") # Time shifts a2 = stretch.timeShift(a, 0.50) a2.plot("50% Time Shift") a3 = stretch.timeShift(a, 2.0) a3.plot("200% Time Shift") # Frequency Scaling a4 = stretch.pitchShift(a, 0.50) fft.fft(a4[0], 1024)[0].plot("50% Pitch shift") a5 = stretch.pitchShift(a, 2.00) fft.fft(a5[0], 1024)[0].plot("200% Pitch Shift")
0.2
0.8
1.0
68
50 0 Magnitude dB 50 100 150 2000 1.0 0.5 Amplitude 0.0 0.5 1.0 0.0
100
400
500
0.1
0.2
0.5
0.6
69
1.0 0.5 Amplitude 0.0 0.5 1.0 0.0 50 0 Magnitude dB 50 100 1500
0.5
1.5
2.0
100
400
500
70
100
400
500
71
72
INDEX
A
AudioStream.ones() (built-in function), 16 AudioStream.rand() (built-in function), 16 AudioStream.writeWavele() (built-in function), 17 AudioStream.zeros() (built-in function), 16
N
Nsound.AudioPlayback() (built-in function), 25 Nsound.Clarinet() (built-in function), 30 Nsound.DrumBD01() (built-in function), 30 Nsound.DrumKickBass() (built-in function), 30 Nsound.FluteSlide() (built-in function), 31 Nsound.GuitarBass() (built-in function), 29 Nsound.Hat() (built-in function), 30 Nsound.Instrument.play() (built-in function), 29 Nsound.OrganPipe() (built-in function), 30 Nsound.use() (built-in function), 26
B
Buer.ones() (built-in function), 14 Buer.rand() (built-in function), 14 Buer.writeWavele() (built-in function), 17 Buer.zeros() (built-in function), 14
F
FFTransform() (built-in function), 61 FFTransform.t() (built-in function), 61 FFTransform.it() (built-in function), 61 FilterBandPassFIR() (built-in function), 47 FilterBandRejectFIR() (built-in function), 47 FilterHighPassFIR() (built-in function), 47 FilterLowPassFIR() (built-in function), 47
S
Sawtooth() (built-in function), 44 Sawtooth.generator() (built-in function), 44 Sine() (built-in function), 40 Sine.generator() (built-in function), 40 Square() (built-in function), 45 Square.generator() (built-in function), 45 Stretcher() (built-in function), 67 Stretcher.pitchShift() (built-in function), 67 Stretcher.timeShift() (built-in function), 67
W Generator() (built-in function), 33 Generator.drawDecay() (built-in function), 33 Wavele.setDefaultSampleRate() (built-in funcGenerator.drawFatGaussian() (built-in function), 17 tion), 33 Wavele.setDefaultSampleSize() (built-in funcGenerator.drawGaussian() (built-in function), tion), 17 33 Wavele.setIEEEFloat() (built-in function), 18 Generator.drawLine() (built-in function), 33 Generator.drawParabola() (built-in function), 33 Generator.drawSine() (built-in function), 33 Generator.drawSine2() (built-in function), 33 Generator.drawWindow() (built-in function), 33
73