This document describes how to implement the PortAudio API on a new
computer platform. Implementing PortAudio on a new platform, makes it possible
to port many existing audio applications to that platform.
By Phil Burk
Copyright 2000 Phil Burk and Ross Bencina
Note that the license says: "Any person wishing to distribute modifications
to the Software is requested to send the modifications to the original
developer so that they can be incorporated into the canonical version.".
So when you have finished a new implementation, please send it back to
us at "http://www.portaudio.com"
so that we can make it available for other users. Thank you!
Download the Latest PortAudio Implementation
Always start with the latest implementation available at "http://www.portaudio.com".
Look for the nightly snapshot under the CVS section.
Select an Existing Implementation as a Basis
The fastest way to get started is to take an existing implementation and
translate it for your new platform. Choose an implementation whose architecture
is as close as possible to your target.
-
DirectSound Implementation - pa_win_ds - Uses a timer callback for the
background "thread". Polls a circular buffer and writes blocks of data
to keep it full.
-
Windows MME - pa_win_wmme - Spawns an actual Win32 thread. Writes blocks
of data to the HW device and waits for events that signal buffer completion.
-
Linux OSS - pa_linux - Spawns a real thread that writes to the "/dev/dsp"
stream using blocking I/O calls.
When you write a new implementation, you will be using some code that is
in common with all implementations. This code is in the folder "pa_common".
It provides various functions such as parameter checking, error code to
text conversion, sample format conversion, clipping and dithering, etc.
The code that you write will go into a separate folder called "pa_{os}_{api}".
For example, code specific to the DirectSound interface for Windows goes
in "pa_win_ds".
Read Docs and Code
Famialiarize yourself with the system by reading the documentation provided.
here is a suggested order:
-
User Programming Tutorial
-
Header file "pa_common/portaudio.h" which defines API.
-
Header file "pa_common/pa_host.h" for host dependant code. This definces
the routine you will need to provide.
-
Shared code in "pa_common/pa_lib.c".
-
Docs on Implementation of Start/Stop
code.
Implement Output to Default Device
Now we are ready to crank some code. For instant gratification, let's try
to play a sine wave.
-
Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c"
and the implementation specific file you are creating.
-
For now, just stub out the device query code and the audio input code.
-
Modify PaHost_OpenStream() to open your default target device and get everything
setup.
-
Modify PaHost_StartOutput() to start playing audio.
-
Modify PaHost_StopOutput() to stop audio.
-
Modify PaHost_CloseStream() to clean up. Free all memory that you allocated
in PaHost_OpenStream().
-
Keep cranking until you can play a sine wave using "patest_sine.c".
-
Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".
-
To test your Open and Close code, try "patest_many.c".
-
Now test to make sure that the three modes of stopping are properly supported
by running "patest_stop.c".
-
Test your implementation of time stamping with "patest_sync.c".
Implement Device Queries
Now that output is working, lets implement the code for querying what devices
are available to the user. Run "pa_tests/pa_devs.c". It should print all
of the devices available and their characteristics.
Implement Input
Implement audio input and test it with:
-
patest_record.c - record in half duplex, play back as recorded.
-
patest_wire.c - full duplex, copies input to output. Note that some HW
may not support full duplex.
-
patest_fuzz.c - plug in your guitar and get a feel for why latency is an
important issue in computer music.
-
paqa_devs.c - try to open every device and use it with every possible format
Debugging Tools
You generally cannot use printf() calls to debug real-time processes because
they disturb the timing. Also calling printf() from your background thread
or interrupt could crash the machine. So PA includes a tool for capturing
events and storing the information while it is running. It then prints
the events when Pa_Terminate() is called.
-
To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h"
from a (0) to a (1).
-
Link with "pa_common/pa_trace.c".
-
Add trace messages to your code by calling:
void AddTraceMessage( char *msg, int data );
for example
AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ",
past->past_NumCallbacks );
-
Run your program. You will get a dump of events at the end.
-
You can leave the trace messages in your code. They will turn to NOOPs
when you change TRACE_REALTIME_EVENTS back to (0).
Delivery
Please send your new code along with notes on the implementation back to
us at "http://www.portaudio.com".
We will review the implementation and post it with your name. If you had
to make any modifications to the code in "pa_common" or "pa_tests" please
send us those modifications and your notes. We will try to merge your changes
so that the "pa_common" code works with all implementations.
If you have suggestions for how to make future implementations easier,
please let us know.
THANKS!