Está en la página 1de 77

Nsound Users Guide

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

Nsound FFT 61 7.1 Using a Window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Nsound Stretcher 67 73

Index

ii

Nsound Users Guide, Release 0.9.0

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

Nsound Users Guide, Release 0.9.0

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.

Nsound Users Guide, Release 0.9.0

1.2 Building and installing Nsound


1.2.1 Binary installers
In most cases, the best way to install Nsound on your system is by using an installable binary Python package for your operating system.
Windows

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.

1.2.2 Building from source


A general overview of building Nsound from source is given here, with detailed instructions for specic platforms given separately.
Prerequisites

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 Users Guide, Release 0.9.0

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-

1.2. Building and installing Nsound

Nsound Users Guide, Release 0.9.0

Testing that all Matplotlib dependancies are met

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

1.2.3 Compiling the C++ Library


1. Uncompress the Nsound archive:
$ tar xfz nsound-0.9.0.tar.gz

2. Execute the SCons tool:


cd nsound-0.9.0 scons

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

Nsound Users Guide, Release 0.9.0

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

release test <object_file> <program> Examples:

# 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.

1.2. Building and installing Nsound

Nsound Users Guide, Release 0.9.0

On Windows: Compiling Nsound From The Command Line

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

On Windows: Compiling Nsound C++ library Using Visual Studio

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

If you run into an error message that looks something like:

python 6140 C:\cygwin\bin\python.exe: *** fatal error - unable to remap \\?\C:\cygwin\lib\pytho

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

Nsound Users Guide, Release 0.9.0

C:\> C:\cygwin\bin\ash.exe $ cd /bin $ ./rebaseall

1.2.4 Compiling the Python Module


Note: SWIG must be installed to generate the Python interface. 1. Try compiling the C++ library rst to ensure SCons and the C++ compiler are working (see step 2 above in Compiling the C++ Library). 2. Generate the Python build script by executing:
scons setup.py

3. Build and install the Python module for a single user:


python setup.py install --user

4. Or build and install the Python module system wide:


sudo python setup.py install

5. Or build the Windows self-installer (Windows only):


python setup.py bdist_wininst

6. Test the Python module:


import Nsound as ns b = ns.Buffer() print b

You should see the text:


Nsound.Buffer holding 0 samples

1.2.5 Linking With A Python Installed In A Non-Standard Location


Sometimes a custom built Python is installed in a non-standard location, for example:
/usr/local/python2.7

You will need to install scons to this non-stanard location, then just run scons with this non-standard python:

1.2. Building and installing Nsound

Nsound Users Guide, Release 0.9.0

/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

Please report any problems you are having to Nick.


Python Errors

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

You may see a message like:

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

Nsound Users Guide, Release 0.9.0

1.3 Getting Started Using Nsound


1.3.1 Using The Nsound Python Module
After installing the Nsound Python module, you can start playing with the examples. Download the Nsound source code or check out the subversion tag:
$ svn co https://nsound.svn.sourceforge.net/svnroot/nsound/tags/nsound-0.9.0

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()

1.5 1.0 0.5 0.0 0.50

Nsound

20

40

60

80

100

120

140

1.3.2 Using The C++ Library And SCons


Nsound uses the SCons build system (http://www.scons.org). SCons is written in Python and the Makeles are Python scripts.
1.3. Getting Started Using Nsound 11

Nsound Users Guide, Release 0.9.0

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

Or if you are on Windows: scons -U example2.exe

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)

2.2 Buffer Creation


A Buer holds audio samples at discrete sample periods. The Buer object knows nothing about time, endianness or bit precision. It is a generic container of oating point data. There are 3 general ways to create an Nsound Buer: 1. Creating an empty Buer 2. Call ones(), rand() or zeros()

13

Nsound Users Guide, Release 0.9.0

3. Reading a wavele from disk

2.2.1 Creating An Empty Buffer


Call the constructor:
import Nsound as ns b = ns.Buffer()

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.

2.2.2 Call Ones, Rand or Zeros


The Buer class includes some convience functions for creating Buers that are lled with oness, random numbers or zeros: Buffer.ones(n_samples) Buffer.rand(n_samples) Buffer.zeros(n_samples) Example usage:
import Nsound as ns b1 = ns.Buffer.ones(10) b2 = ns.Buffer.rand(10) b3 = ns.Buffer.zeros(10)

In the example above, 10 samples were stored in the created Buers.

2.2.3 Reading A Wavele From Disk


A Buer can be created from a wavele:

14

Chapter 2. Nsound Basics

Nsound Users Guide, Release 0.9.0

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.).

2.3 AudioStream Creation


An AudioStream is a container that holds Buers, it also stores a sample rate, providing information about time. It is meant to easily manipulate multiple channels of audio at the same time. Most Nsound functions that operate on Buers also operate on AudioStreams. There are 3 general ways to create an AudioStream: 1. Creating an empty AudioStream 2. Call ones(), rand() or zeros() 3. Reading a wavele from disk

2.3.1 Creating An Empty AudioStream


Call the constructor:
import Nsound as ns a = ns.AudioStream()

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:

2.3. AudioStream Creation

15

Nsound Users Guide, Release 0.9.0

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.

2.3.2 Call Ones, Rand or Zeros


The Buer class includes some convience functions for creating Buers that are lled with oness, random numbers or zeros: AudioStream.ones(sample_rate, n_channels, n_samples) AudioStream.rand(sample_rate, n_channels, n_samples) AudioStream.zeros(sample_rate, n_channels, n_samples) Example usage:
import Nsound as ns a1 = ns.AudioStream.ones(44100.0, 2, 1.0) a2 = ns.AudioStream.rand(44100.0, 2, 1.0) a3 = ns.AudioStream.zeros(44100.0, 2, 1.0)

In the example above, 44100 samples (1 second) were stored in 2 channels.

2.3.3 Reading A Wavele From Disk


An AudioStream can be created from a wavele:
a = ns.AudioStream("california.wav")

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

Chapter 2. Nsound Basics

Nsound Users Guide, Release 0.9.0

2.4.1 Reading Waveles


As seen in previous sections, a wavele can be read by passing its lename to the Buer or AudioStream constructor:
import Nsound as ns b = ns.Buffer("california.wav") a = ns.AudioStream("california.wav")

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.2 Writing Waveles


Warning: Values outside the range of -1.0 and 1.0 will get clipped in the output wavele. To avoid this, call the function normalize() on the Buer or AudioStream. The Buer and AudioStream class includes a function to write waveles to disk. Buffer.writeWavefile(lename) AudioStream.writeWavefile(lename) The Wavele class is used by Buer and AudioStream to perform the actual writing. Note: the Buer class does not know the sample rate of the data contained in it. The Wavele class uses a default sample rate setting. The Wavele default sample rate and sample size can be changed by calling: Wavefile.setDefaultSampleRate(sample_rate) Wavefile.setDefaultSampleSize(sample_size) Where sample_size is 8, 16, 24, 32 or 64. When an AudioStream writes to disk, the sample rate is known by the AudioStream. Like the Buer class, the sample size is not known. Use the Wavele.setDefaultSampleSize() to set this option:
import Nsound as ns a = ns.AudioStream("california.wav") ns.Wavefile.setDefaultSampleSize(32)

2.4. Wavele IO

17

Nsound Users Guide, Release 0.9.0

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.

2.4.3 Floating Point Waveles


Warning: Few programs know how to read the IEEE oating point format. Audacity 1.3.12 is able to read mono oating point formats, but does not seem to be able to read multi channel les.

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.

2.4.4 Resampling Waveles


Sometimes a wavele wont be at the sample rate that we wish it were. For example, you downloaded a sample sound but it is not at the sample rate of your project. With Nsound its easy to resample the le to the sample rate you need:
import Nsound as ns a = ns.AudioStream("wav_at_16KHz.wav") a.resample2(48000.0)

18

Chapter 2. Nsound Basics

Nsound Users Guide, Release 0.9.0

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)

print "Resampling ..." a2 = a1.getResample(ratio) a2.setSampleRate(int(target)) print "Writing %s" % f2 a2 >> f2

2.4. Wavele IO

19

Nsound Users Guide, Release 0.9.0

2.5 Basic Manipulations


AudioStream and Buer objects have nearly all of their mathematical operators overloaded. It is easy to manipulate the data they contain. Every operation that can be done on a Buer can be done on an AudioStream. In the following examples, only the Buer case will be demonstrated, but it can easily be done to an AudioStream as well.

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]

Buers can be concatenated together:


b2 = ns.Buffer() b2 << 6 << 7 << 8 b << b2 print b.getLength() # 6 print b.toList() # [1.0, 2.0, 3.0, 6.0, 7.0, 8.0]

2.5.2 Scalar Math


When a scaler is applied to a Buer or AudioStream, the scalar is applied element-wise for all the samples contained in the Buer:
import Nsound as ns b = ns.Buffer() b << 1 << 2 << 3 << 6 << 7 << 8 print b.toList() # [1.0, 2.0, 3.0, 6.0, 7.0, 8.0] b += 1.0 # b = b + 1.0 would also work

20

Chapter 2. Nsound Basics

Nsound Users Guide, Release 0.9.0

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]

2.5.3 Vector Math


Nsound also allows element-wise math between two Buers. Unlike other packages such as Numpy or Matlab, the Buers dont have to be the same length:
import Nsound as ns b1 = ns.Buffer() b1 << 1 << 1 << 1 b2 = ns.Buffer() b2 << 0 << 1 << 1 << 1 # Addition b3 = b1 + b2 print b3.toList() # [1.0, 2.0, 2.0] b3 = b2 + b1 print b3 # [1.0, 2.0, 2.0, 1.0] # Subtraction b3 = b1 - b2 print b3.toList() # [1.0, 0.0, 0.0] b3 = b2 - b1 print b3.toList() # [-1.0, 0.0, 0.0, 1.0]

2.5. Basic Manipulations

21

Nsound Users Guide, Release 0.9.0

# 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

Chapter 2. Nsound Basics

Nsound Users Guide, Release 0.9.0

Amplitude

C++ libnsound
Plotter.h

Buffer
1.0

0.5

0.0

0.5

C libpython Python Matplotlib

1.0 0 200 400 600 Sample 800 1000

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

Nsound Users Guide, Release 0.9.0

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

1.5 2.0 Time (sec)

2.5

3.0

Amplitude

0.5

1.0

1.5 2.0 Time (sec)

2.5

3.0

24

Chapter 2. Nsound Basics

CHAPTER

THREE

NSOUND AUDIO PLAYBACK


As of Nsound-0.8.1, playback through the soundcard is now supported on platforms that have libao or libportaudio.

C++ libnsound
AudioPlayback.h OR

AO libao
OS
Audio playback can be as simple as:

PortAudio libportaudio

import Nsound as ns a = ns.AudioStream("california.wav") a >> ns.AudioPlayback(a.getSamplerate(), a.getNChannels(), 16)

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

Nsound Users Guide, Release 0.9.0

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.1 Audio Backends


The audio backend to use can be selected. By default, the audio backend is automatically seleceted based on the backends that were available at compile time in the following order: 1. PortAudio 2. AO 3. None Following the Matplotlib convention, a call to Nsound.use() can select the audio backend to use. Nsound.use(backend) backend [str] The backend to use; currently recognized backends: 1. portaudio or libportaudio 2. ao or libao The backend must be selected before initializing the AudioPlayback class:
ns.use("portaudio") pb = ns.AudioPlayback(44100.0, 2, 16) buffer_or_audio_stream >> pb

See src/examples/example1.py and src/examples/example4.py for AudioPlayback example usage.

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

Nsound Users Guide, Release 0.9.0

3.3 Know Problems


If you are on Linux and you are using libportaudio, you may see a message like:
bt_audio_service_open: connect() failed: Connection refused (111) bt_audio_service_open: connect() failed: Connection refused (111)

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.

3.3. Know Problems

27

Nsound Users Guide, Release 0.9.0

28

Chapter 3. Nsound Audio Playback

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

4.1 Bass Guitar


Based on a physical model written in Csound by Hans Mikelson. Nsound.GuitarBass(sample_rate) sample_rate [oat] The number of samples per seconds

29

Nsound Users Guide, Release 0.9.0

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.3 Kick Bass Drum


Nsound.DrumKickBass(sample_rate, high_frequency, low_frequency) sample_rate [oat] The number of samples per seconds high_frequency [oat] The starting frequency of the drum low_frequency [oat] The stopping frequency of the drum as its response decays

4.4 BD01 Drum


Simulates a bass drum. Based on a Csound drum. source: http://www.csounds.com/istvan/html/drums.html Nsound.DrumBD01(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

4.6 Pipe Organ


Based on a Csound Pipe Organ by Hons Mikelson. Nsound.OrganPipe(sample_rate)

30

Chapter 4. Nsound Instruments

Nsound Users Guide, Release 0.9.0

sample_rate [oat] The number of samples per seconds

4.7 Slide Flute


Based on a physical model written in Csound by Hans Mikelson which was originally based on Perry Cooks physical model. Nsound.FluteSlide(sample_rate) sample_rate [oat] The number of samples per seconds

4.7. Slide Flute

31

Nsound Users Guide, Release 0.9.0

32

Chapter 4. Nsound Instruments

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.).

5.1 The Generator Draw Routines


All Nsound Generators include basic drawing functions. Some basic Generator function documentation: Generator(sample_rate) Generator.drawDecay(duration, alpha=2.0*pi) Generator.drawLine(duration, y1, y2) Generator.drawGaussian(duration, mu, sigma, normalize=True) Generator.drawFatGaussian(duration, pass_band_percent=0.01) Generator.drawParabola(duration, y1, x2, y2, y3) Generator.drawSine(duration, frequency) Generator.drawSine2(duration, frequency, phase) Generator.drawWindow(duration, window_type) Drawing lines:
import Nsound as ns g = ns.Generator(100.0) b = ns.Buffer()

33

Nsound Users Guide, Release 0.9.0

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")

1.0 0.8 0.6 0.4 0.2 0.00


Drawing a decaying curve:
import Nsound as ns g = ns.Generator(100.0) b = ns.Buffer() b << g.drawDecay(1.0) b.plot("Exponential Decay")

Basic Lines

50

100

150

200

250

300

34

Chapter 5. Nsound Generators

Nsound Users Guide, Release 0.9.0

1.0 0.8 0.6 0.4 0.2 0.00


Drawing Gaussians:
import Nsound as ns g = ns.Generator(100.0)

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")

5.1. The Generator Draw Routines

35

Nsound Users Guide, Release 0.9.0

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

A Fat Gaussian Curve

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

Chapter 5. Nsound Generators

Nsound Users Guide, Release 0.9.0

########################################################################### # 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)

5.1. The Generator Draw Routines

37

Nsound Users Guide, Release 0.9.0

1.0 0.8 Amplitude 0.6 0.4 0.2 0.0 0.0 0.2

A Parabola

0.4 0.6 Time (sec)

0.8

1.0

1.0 0.8 Amplitude 0.6 0.4 0.2 0.0 0.0 0.2

Another Parabola

0.4 0.6 Time (sec)

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

Chapter 5. Nsound Generators

Nsound Users Guide, Release 0.9.0

########################################################################### # 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")

1.0 0.5 Amplitude 0.0 0.5 1.0 0.0

3 Hz

0.2

0.4 0.6 Time (sec)

0.8

1.0

5.1. The Generator Draw Routines

39

Nsound Users Guide, Release 0.9.0

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.4 0.6 Time (sec)

0.8

1.0

Dynamic Phase

0.2

0.4 0.6 Time (sec)

0.8

1.0

5.2 The Sine Generator


The Sine class is derived from Generator. Some of its documentation: Sine(sample_rate) Sine.generator(duration, frequency) It inherits all the draw functions for convience. Lets generate a 3 Hz signal.
40 Chapter 5. Nsound Generators

Nsound Users Guide, Release 0.9.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.0 0.5 0.0 0.5 1.00

1 second at 3 Hz

20

40

60

80

100

Now lets multiply the 3 Hz signal by Gaussian and decaying envelopes.


import Nsound as ns s = ns.Sine(100.0) g = ns.Buffer() g << s.drawGaussian(1.0, 0.5, 0.15) d = ns.Buffer() d << s.drawDecay(1.0) b = ns.Buffer() b << s.generate(1.0, 3.0) gauss = b * g decay = b * d gauss.plot("3 Hz With Gaussian Envelope") decay.plot("3 Hz With Decaying Envelope")

5.2. The Sine Generator

41

Nsound Users Guide, Release 0.9.0

1.0 0.5 0.0 0.5 1.00

3 Hz With Gaussian Envelope

20

40

60

80

100

3 Hz With Decaying Envelope


0.6 0.4 0.2 0.0 0.2 0 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

Chapter 5. Nsound Generators

Nsound Users Guide, Release 0.9.0

<< 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)

10 8 6 4 2 00 1.0 0.5 0.0 0.5 1.00 500

Frequencies in Hz

1000

1500

2000

Dynamic frequencies

500

1000

1500

2000

5.2. The Sine Generator

43

Nsound Users Guide, Release 0.9.0

5.3 The Sawtooth Generator


As you would expect, the Sawtooth Generator draws sawtooths, with the specied number of harmonics. Sawtooth(sample_rate, n_harmonics) Sawtooth.generator(duration, frequency)
import Nsound as ns saw = ns.Sawtooth(100, 3) b = ns.Buffer() b << saw.generate(3.0, 1.0) b.plot("Sawtooth, 3 harmonics") saw = ns.Sawtooth(100, 12) b = ns.Buffer() b << saw.generate(3.0, 1.0) b.plot("Sawtooth, 12 harmonics")

1.0 0.5 0.0 0.5 1.00

Sawtooth, 3 harmonics

50

100

150

200

250

300

44

Chapter 5. Nsound Generators

Nsound Users Guide, Release 0.9.0

1.5 1.0 0.5 0.0 0.5 1.0 1.50 50

Sawtooth, 12 harmonics

100

150

200

250

300

5.4 The Square Generator


As you would expect, the Square Generator draws square waves, with the specied number of harmonics. Square(sample_rate, n_harmonics) Square.generator(duration, frequency)
import Nsound as ns square = ns.Square(100, 3) b = ns.Buffer() b << square.generate(3.0, 1.0) b.plot("Square wave, 3 harmonics") square = ns.Square(100, 12) b = ns.Buffer() b << square.generate(3.0, 1.0) b.plot("Square wave, 12 harmonics")

5.4. The Square Generator

45

Nsound Users Guide, Release 0.9.0

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

Square wave, 3 harmonics

50

100

150

200

250

300

Square wave, 12 harmonics

50

100

150

200

250

300

46

Chapter 5. Nsound Generators

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)

6.1 FIR Filters


FIR lters are well behaved at all frequencies, they have symmetric phase distortion and are relatively computationally expensive. Currently, Nsound designs FIR lters using a windowed sinc function and a Blackman window. See DSP for Scientists and Engineer, Chapter 16, equation 16-4. Some of the basic documentation FilterLowPassFIR(sample_rate, n_order, fc) FilterHighPassFIR(sample_rate, n_order, fc) FilterBandPassFIR(sample_rate, n_order, fc_low, fc_high) FilterBandRejectFIR(sample_rate, n_order, fc_low, fc_high) sample_rate The number of samples per second. n_order The size of the lter kernel, the larger the order, the stronger the the rejection ouside of the pass band.
47

Nsound Users Guide, Release 0.9.0

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

6.2 FIR Filter Frequency Response


Frequency responses for FIR lters:
import Nsound as ns f1 f2 f3 f4 = = = = ns.FilterLowPassFIR(500.0, 64, 100.0) ns.FilterHighPassFIR(500.0, 64, 100.0) ns.FilterBandPassFIR(500.0, 64, 100.0, 200.0) ns.FilterBandRejectFIR(500.0, 64, 100.0, 200.0)

f1.plot() f2.plot() f3.plot() f4.plot()

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass FIR Frequency Response order = 64, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

48

Chapter 6. Nsound Filters

Nsound Users Guide, Release 0.9.0

0 Frequency Response (dB) 10 20 30 40 50 600

High Pass FIR Frequency Response order = 64, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

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

6.2. FIR Filter Frequency Response

49

Nsound Users Guide, Release 0.9.0

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

6.3 FIR Filter Frequency Response vs Filter Order


The plots below demonstrate the eects of lter order.
import Nsound as ns f1 f2 f3 f4 = = = = ns.FilterLowPassFIR(500.0, 16, ns.FilterLowPassFIR(500.0, 64, ns.FilterLowPassFIR(500.0, 256, ns.FilterLowPassFIR(500.0, 1024, 100.0) 100.0) 100.0) 100.0)

f1.plot() f2.plot() f3.plot() f4.plot()

50

Chapter 6. Nsound Filters

Nsound Users Guide, Release 0.9.0

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass FIR Frequency Response order = 16, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass FIR Frequency Response order = 64, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

6.3. FIR Filter Frequency Response vs Filter Order

51

Nsound Users Guide, Release 0.9.0

0 Frequency Response (dB) 10 20 30 40 50

Low Pass FIR Frequency Response order = 256, fc = 100.0 Hz, sr = 500.0 Hz

600

50

100 150 Frequency (Hz)

200

250

0 Frequency Response (dB) 10 20 30 40 50

Low Pass FIR Frequency Response order = 1024, fc = 100.0 Hz, sr = 500.0 Hz

600

50

100 150 Frequency (Hz)

200

250

6.4 IIR Filters


IIR lters are not stable for all orders and cut o frequencies, they have asymmetrical phase distortion, but they are computationally inexpensive compared to FIR designs (because they perform far fewer multiplications). Currently, Nsound designs IIR lters using Chebyshev type 1, ripples in the pass band. See DSP for Scientists and Engineers, Chapter 20, Table 20-4, 20-5. If the ripple percent parameter is set
52 Chapter 6. Nsound Filters

Nsound Users Guide, Release 0.9.0

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.

6.5 IIR Filter Frequency Response


Frequency responses for IIR lters:
import Nsound as ns ripple = 0.005 f1 f2 f3 f4 = = = = ns.FilterLowPassIIR(500.0, 4, 100.0, ripple) ns.FilterHighPassIIR(500.0, 4, 100.0, ripple) ns.FilterBandPassIIR(500.0, 4, 100.0, 200.0, ripple) ns.FilterBandRejectIIR(500.0, 4, 100.0, 200.0, ripple)

f1.plot() f2.plot() f3.plot() f4.plot()

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass IIR Frequency Response order = 3, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

6.5. IIR Filter Frequency Response

53

Nsound Users Guide, Release 0.9.0

0 Frequency Response (dB) 10 20 30 40 50 600

High Pass IIR Frequency Response order = 3, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

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

Chapter 6. Nsound Filters

Nsound Users Guide, Release 0.9.0

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

6.6 IIR Filter Frequency Response vs Filter Order


The plots below demonstrate the eects of lter order.
import Nsound as ns ripple = 0.005 f1 f2 f3 f4 = = = = ns.FilterLowPassIIR(500.0, 2, ns.FilterLowPassIIR(500.0, 4, ns.FilterLowPassIIR(500.0, 8, ns.FilterLowPassIIR(500.0, 16, 100.0, 100.0, 100.0, 100.0, ripple) ripple) ripple) ripple)

f1.plot() f2.plot() f3.plot() f4.plot()

6.6. IIR Filter Frequency Response vs Filter Order

55

Nsound Users Guide, Release 0.9.0

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass IIR Frequency Response order = 1, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass IIR Frequency Response order = 3, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

56

Chapter 6. Nsound Filters

Nsound Users Guide, Release 0.9.0

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass IIR Frequency Response order = 7, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass IIR Frequency Response order = 15, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

6.7 IIR Filter Frequency Response vs Ripple Percent


The plots below demonstrate the eects of lter order.
import Nsound as ns f1 = ns.FilterLowPassIIR(500.0, f2 = ns.FilterLowPassIIR(500.0, 4, 100.0, 0.000) 4, 100.0, 0.005)

6.7. IIR Filter Frequency Response vs Ripple Percent

57

Nsound Users Guide, Release 0.9.0

f3 = ns.FilterLowPassIIR(500.0, f4 = ns.FilterLowPassIIR(500.0, f1.plot() f2.plot() f3.plot() f4.plot()

4, 100.0, 0.010) 4, 100.0, 0.200)

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass IIR Frequency Response order = 3, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass IIR Frequency Response order = 3, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

58

Chapter 6. Nsound Filters

Nsound Users Guide, Release 0.9.0

0 Frequency Response (dB) 10 20 30 40 50 600

Low Pass IIR Frequency Response order = 3, fc = 100.0 Hz, sr = 500.0 Hz

50

100 150 Frequency (Hz)

200

250

Low Pass IIR Frequency Response order = 3, fc = 100.0 Hz, sr = 500.0 Hz


0 Frequency Response (dB) 10 20 30 40 50 600 50 100 150 Frequency (Hz) 200 250

6.7. IIR Filter Frequency Response vs Ripple Percent

59

Nsound Users Guide, Release 0.9.0

60

Chapter 6. Nsound Filters

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

Nsound Users Guide, Release 0.9.0

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

Input signal, 4 Hz Square wave

50

100

150

200

250

Frequency Domain

50

100 150 Frequency Hz

200

250
Chapter 7. Nsound FFT

Nsound Users Guide, Release 0.9.0

1.5 1.0 0.5 0.0 0.5 1.0 1.50 50

Reconstructed

100

150

200

250

Notice that there are 5 peaks, these correspond to the 5 harmonics in the square wave.

7.1 Using a Window


Setting a window on the FFT object can get rid of edge eects. This can improve the results when looking at the frequency domain, but it will aect the reconstructed signal.
import Nsound as ns sample_rate = 500.0 square = ns.Square(sample_rate, 5) b = ns.Buffer() b << square.generate(0.5, 10.0) fft = ns.FFTransform(sample_rate) vec1 = fft.fft(b, 256) b1 = fft.ifft(vec1) fft.setWindow(ns.HANNING) vec2 = fft.fft(b, 256) b2 = fft.ifft(vec2) vec1[0].plot("Frequency Domain, No Window")

7.1. Using a Window

63

Nsound Users Guide, Release 0.9.0

vec2[0].plot("Frequency Domain, With Hanning Window") b1.plot("Reconstructed, No Window") b2.plot("Reconstructed, With Hanning Window")

50 0 Magnitude dB 50 100 150 2000

Frequency Domain, No Window

50

100 150 Frequency Hz

200

250

50 Frequency Domain, With Hanning Window 0 Magnitude dB 50 100 150 2000 50 100 150 Frequency Hz 200 250

64

Chapter 7. Nsound FFT

Nsound Users Guide, Release 0.9.0

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

Reconstructed, With Hanning Window

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.

7.1. Using a Window

65

Nsound Users Guide, Release 0.9.0

66

Chapter 7. Nsound FFT

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

Nsound Users Guide, Release 0.9.0

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")

1.0 0.5 Amplitude 0.0 0.5 1.0 0.0

Original Time Domain

0.2

0.4 0.6 Time (sec)

0.8

1.0

68

Chapter 8. Nsound Stretcher

Nsound Users Guide, Release 0.9.0

50 0 Magnitude dB 50 100 150 2000 1.0 0.5 Amplitude 0.0 0.5 1.0 0.0

Original Frequency Domain

100

200 300 Frequency Hz

400

500

50% Time Shift

0.1

0.2

0.3 0.4 Time (sec)

0.5

0.6

69

Nsound Users Guide, Release 0.9.0

1.0 0.5 Amplitude 0.0 0.5 1.0 0.0 50 0 Magnitude dB 50 100 1500

200% Time Shift

0.5

1.0 Time (sec)

1.5

2.0

50% Pitch shift

100

200 300 Frequency Hz

400

500

70

Chapter 8. Nsound Stretcher

Nsound Users Guide, Release 0.9.0

50 0 Magnitude dB 50 100 1500

200% Pitch Shift

100

200 300 Frequency Hz

400

500

71

Nsound Users Guide, Release 0.9.0

72

Chapter 8. Nsound Stretcher

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

También podría gustarte