PortAudio Implementation Guide

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. 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:
  1. User Programming Tutorial
  2. Header file "pa_common/portaudio.h" which defines API.
  3. Header file "pa_common/pa_host.h" for host dependant code. This definces the routine you will need to provide.
  4. Shared code in "pa_common/pa_lib.c".
  5. 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.
  1. Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c" and the implementation specific file you are creating.
  2. For now, just stub out the device query code and the audio input code.
  3. Modify PaHost_OpenStream() to open your default target device and get everything setup.
  4. Modify PaHost_StartOutput() to start playing audio.
  5. Modify PaHost_StopOutput() to stop audio.
  6. Modify PaHost_CloseStream() to clean up. Free all memory that you allocated in PaHost_OpenStream().
  7. Keep cranking until you can play a sine wave using "patest_sine.c".
  8. Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".
  9. To test your Open and Close code, try "patest_many.c".
  10. Now test to make sure that the three modes of stopping are properly supported by running "patest_stop.c".
  11. 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:
  1. patest_record.c - record in half duplex, play back as recorded.
  2. patest_wire.c - full duplex, copies input to output. Note that some HW may not support full duplex.
  3. patest_fuzz.c - plug in your guitar and get a feel for why latency is an important issue in computer music.
  4. 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.
  1. To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h" from a (0) to a (1).
  2. Link with "pa_common/pa_trace.c".
  3. Add trace messages to your code by calling:

  4.    void AddTraceMessage( char *msg, int data );
    for example
       AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks );
  5. Run your program. You will get a dump of events at the end.
  6. 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!