portaudio-18.1.orig/0002755000175000000620000000000010074507675015007 5ustar mikaelstaff00000000000000portaudio-18.1.orig/docs/0000755000175000000620000000000007700016420015716 5ustar mikaelstaff00000000000000portaudio-18.1.orig/docs/pa_impl_startstop.html0000644000175000017500000000716207465451052022536 0ustar mikaelmikael00000000000000 PortAudio Implementation - Start/Stop  

PortAudio Implementation

Starting and Stopping Streams

PortAudio is generally executed in two "threads". The foreground thread is the application thread. The background "thread" may be implemented as an actual thread, an interrupt handler, or a callback from a timer thread.

There are three ways that PortAudio can stop a stream. In each case we look at the sequence of events and the messages sent between the two threads. The following variables are contained in the internalPortAudioStream.

int   past_IsActive;     /* Background is still playing. */
int   past_StopSoon;     /* Stop when last buffer done. */
int   past_StopNow;      /* Stop IMMEDIATELY. */

Pa_AbortStream()

This function causes the background thread to terminate as soon as possible and audio I/O to stop abruptly.
 
Foreground Thread Background Thread
sets StopNow
sees StopNow
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O

Pa_StopStream()

This function stops the user callback function from being called and then waits for all audio data written to the output buffer to be played. In a system with very low latency, you may not hear any difference between
 
Foreground Thread Background Thread
sets StopSoon
stops calling user callback
continues until output buffer empty
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O

User callback returns one.

If the user callback returns one then the user callback function will no longer be called. Audio output will continue until all audio data written to the output buffer has been played. Then the audio I/O is stopped, the background thread terminates, and the stream becomes inactive.
 
Foreground Thread Background Thread
callback returns 1
sets StopSoon
stops calling user callback
continues until output buffer empty
clears IsActive, stops thread
waits for thread to exit
turns off audio I/O

  portaudio-18.1.orig/docs/pa_drivermodel.c.txt0000644000175000017500000002533507465451052022064 0ustar mikaelmikael00000000000000/* This file contains the host-neutral code for implementing multiple driver model support in PortAudio. It has not been compiled, but it is supplied only for example purposes at this stage. TODO: use of CHECK_DRIVER_MODEL is bogus in some instances since some of those functions don't return a PaError */ #include "pa_drivermodel.h.txt" #ifndef PA_MULTIDRIVER /* single driver support, most functions will stay in the implementation files */ PaDriverModelID Pa_CountDriverModels() { return 1; } /* Perhaps all drivers should define this with this signature const PaDriverModelInfo* Pa_GetDriverModelInfo( PaDriverModelID driverModelID ) { } */ PaDeviceID Pa_DriverModelDefaultInputDeviceID( PaDriverModelID driverModelID ) { return Pa_GetDefaultInputDeviceID(); } PaDeviceID Pa_DriverModelDefaultOutputDeviceID( PaDriverModelID driverModelID ) { return Pa_GetDefaultInputDeviceID(); } /* Perhaps all drivers should define with this signature int Pa_DriverModelMinNumBuffers( PaDriverModelID driverModelID, int framesPerBuffer, double sampleRate ) { } */ int Pa_DriverModelCountDevices( PaDriverModelID driverModelID ) { return Pa_CountDevices(); } PaDeviceID Pa_DriverModelGetDeviceID(PaDriverModelID driverModelID, int perDriverModelIndex ) { return perDriverModelIndex; } #else /* multidriver support */ typedef PaError (*PaInitializeFunPtr)( PaDriverModelImplementation** ); /* the initializers array is a static table of function pointers to all the available driverModels on the current platform. the order of pointers in the array is important. the first pointer is always considered to be the "default" driver model. */ static PaInitializeFunPtr driverModelInitializers[] = { #ifdef WINDOWS PaWin32WMME_MultiDriverInitialize, PaWin32DS_MultiDriverInitialize, PaASIO_MultiDriverInitialize #endif #ifdef MAC PaMacSM_MultiDriverInitialize, PaMacCA_MultiDriverInitialize, PaASIO_MultiDriverInitialize #endif /* other platforms here */ (PaInitializeFunPtr*)0 /* NULL terminate the list */ }; /* the driverModels array is a dynamically created table of currently available driverModels. */ static PaDriverModelImplementation* driverModels = 0; static int numDriverModels = 0; #define PA_CHECK_INITIALIZED\ if( driverModels == 0 ) return paLibraryNotInitialised #define PA_CHECK_DRIVER_MODEL_ID( id ) if( id < 0 || id >= numDriverModels ) return paBadDriverModelID; /* ConvertPublicDeviceIdToImplementationDeviceId converts deviceId from a public device id, to a device id for a particular PortAudio implementation. On return impl will either point to a valid implementation or will be NULL. */ static void ConvertPublicDeviceIDToImplementationDeviceID( PaDriverModelImplementation *impl, PaDeviceID deviceID ) { int i, count; impl = NULL; for( i=0; i < numDriverModels; ++i ){ count = driverModels[i]->countDevices(); if( deviceID < count ){ impl = driverModels[i]; return NULL; }else{ deviceID -= count; } } } static PaDeviceID ConvertImplementationDeviceIDToPublicDeviceID( PaDriverModelID driverModelID, PaDeviceID deviceID ) { int i; for( i=0; i < driverModelID; ++i ) deviceID += driverModels[i]->countDevices(); } PaError Pa_Initialize( void ) { PaError result = paNoError; int i, initializerCount; PaDriverModelImplementation *impl; if( driverModels != 0 ) return paAlreadyInitialized; /* count the number of driverModels */ initializerCount=0; while( driverModelInitializers[initializerCount] != 0 ){ ++initializerCount; } driverModels = malloc( sizeof(PaDriverModelImplementation*) * initializerCount ); if( driverModels == NULL ) return paInsufficientMemory; numDriverModels = 0; for( i=0; iterminate( driverModels[i] ); } long Pa_GetHostError( void ) { PA_CHECK_INITIALIZED; under construction. depends on error text proposal. } const char *Pa_GetErrorText( PaError errnum ) { PA_CHECK_INITIALIZED; under construction. may need to call driver model specific code depending on how the error text proposal pans out. } int Pa_CountDevices() { int i, result; PA_CHECK_INITIALIZED; result = 0; for( i=0; i < numDriverModels; ++i ) result += driverModels[i]->countDevices(); return result; } PaDeviceID Pa_GetDefaultInputDeviceID( void ) { PA_CHECK_INITIALIZED; return driverModels[0]->getDefaultInputDeviceID(); } PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { PA_CHECK_INITIALIZED; return driverModels[0]->getDefaultInputDeviceID(); } const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID deviceID ) { PaDriverModelImplementation *impl; PA_CHECK_INITIALIZED; ConvertPublicDeviceIDToImplementationDeviceID( impl, deviceID ); if( impl == NULL ) return paInvalidDeviceID; return impl->getDeviceInfo( deviceID ); } /* NEW MULTIPLE DRIVER MODEL FUNCTIONS ---------------------------------- */ PaDriverModelID Pa_CountDriverModels() { PA_CHECK_INITIALIZED; return numDriverModels; } const PaDriverModelInfo* Pa_GetDriverModelInfo( PaDriverModelID driverModelID ) { PA_CHECK_INITIALIZED; PA_CHECK_DRIVER_MODEL_ID( driverModelID ); return driverModels[ driverModelID ]->getDriverModelInfo(); } PaDeviceID Pa_DriverModelDefaultInputDeviceID( PaDriverModelID driverModelID ) { PA_CHECK_INITIALIZED; PA_CHECK_DRIVER_MODEL_ID( driverModelID ); return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, driverModels[ driverModelID ]->getDefaultInputDeviceID(); } PaDeviceID Pa_DriverModelDefaultOutputDeviceID( PaDriverModelID driverModelID ) { PA_CHECK_INITIALIZED; PA_CHECK_DRIVER_MODEL_ID( driverModelID ); return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, driverModels[ driverModelID ]->getDefaultOutputDeviceID(); } int Pa_DriverModelMinNumBuffers( PaDriverModelID driverModelID, int framesPerBuffer, double sampleRate ) { PA_CHECK_INITIALIZED; PA_CHECK_DRIVER_MODEL_ID( driverModelID ); return driverModels[ driverModelID ]->getMinNumBuffers( int framesPerBuffer, double sampleRate ); } int Pa_DriverModelCountDevices( PaDriverModelID driverModelID ) { PA_CHECK_INITIALIZED; PA_CHECK_DRIVER_MODEL_ID( driverModelID ); return driverModels[ driverModelID ]->coundDevices(); } PaDeviceID Pa_DriverModelGetDeviceID(PaDriverModelID driverModelID, int perDriverModelIndex ) { PA_CHECK_INITIALIZED; PA_CHECK_DRIVER_MODEL_ID( driverModelID ); return ConvertImplementationDeviceIDToPublicDeviceID( driverModelID, perDriverModelIndex ); } /* END NEW MULTIPLE DRIVER MODEL FUNCTIONS ------------------------------ */ PaError Pa_OpenStream( PortAudioStream** stream, PaDeviceID inputDevice, int numInputChannels, PaSampleFormat inputSampleFormat, void *inputDriverInfo, PaDeviceID outputDevice, int numOutputChannels, PaSampleFormat outputSampleFormat, void *outputDriverInfo, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PaStreamFlags streamFlags, PortAudioCallback *callback, void *userData ) { PaError result; PaDriverModelImplementation *inputImpl, *outputImpl, impl; PA_CHECK_INITIALIZED; if( inputDevice != paNoDevice ){ ConvertPublicDeviceIDToImplementationDeviceID( inputImpl, inputDevice ); if( inputImpl == NULL ) return paInvalidDeviceID; else impl = inputImpl; } if( outputDevice != paNoDevice ){ ConvertPublicDeviceIDToImplementationDeviceID( outputImpl, outputDevice ); if( outputImpl == NULL ) return paInvalidDeviceID; else impl = outputImpl; } if( inputDevice != paNoDevice && outputDevice != paNoDevice ){ if( inputImpl != outputImpl ) return paDevicesMustBelongToTheSameDriverModel; } result = impl->openStream( stream, inputDevice, numInputChannels, inputSampleFormat, inputDriverInfo, outputDevice, numOutputChannels, outputSampleFormat, outputDriverInfo, sampleRate, framesPerBuffer, numberOfBuffers, streamFlags, callback, userData ); if( result == paNoError ) ((PaStreamImplementation*)stream)->magic = PA_STREAM_MAGIC; return result; } PaError Pa_OpenDefaultStream( PortAudioStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PortAudioCallback *callback, void *userData ) { PaError result; int inputDevice = driverModels[0]->getDefaultInputDeviceID; int outputDevice = driverModels[0]->getDefaultOutputDeviceID; result = driverModels[0]->openStream( stream, inputDevice, numInputChannels, sampleFormat, 0, outputDevice, numOutputChannels, sampleFormat, 0, sampleRate, framesPerBuffer, numberOfBuffers, streamFlags, callback, userData ); if( result == paNoError ) ((PaStreamImplementation*)stream)->magic = PA_STREAM_MAGIC; return result; } PaError Pa_CloseStream( PortAudioStream* stream ) { PA_CHECK_INITIALIZED; PaError result = ((PaStreamImplementation*)stream)->close(); if( result == PaNoError ) ((PaStreamImplementation*)stream)->magic = 0; /* clear magic number */ return result; } PaError Pa_StartStream( PortAudioStream *stream ); { PA_CHECK_INITIALIZED; return ((PaStreamImplementation*)stream)->start(); } PaError Pa_StopStream( PortAudioStream *stream ); { PA_CHECK_INITIALIZED; return ((PaStreamImplementation*)stream)->stop(); } PaError Pa_AbortStream( PortAudioStream *stream ); { PA_CHECK_INITIALIZED; return ((PaStreamImplementation*)stream)->abort(); } PaError Pa_StreamActive( PortAudioStream *stream ) { PA_CHECK_INITIALIZED; return ((PaStreamImplementation*)stream)->active(); } PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { PA_CHECK_INITIALIZED; return ((PaStreamImplementation*)stream)->time(); } double Pa_StreamCPULoad( PortAudioStream* stream ) { PA_CHECK_INITIALIZED; return ((PaStreamImplementation*)stream)->cpuLoad(); } int Pa_GetMinNumBuffers( PaDeviceID deviceID, int framesPerBuffer, double sampleRate ) { PaDriverModelImplementation *impl; PA_CHECK_INITIALIZED; ConvertPublicDeviceIDToImplementationDeviceID( impl, deviceID ); if( impl == NULL ) return paInvalidDeviceID; return impl->getMinNumBuffers( framesPerBuffer, sampleRate ); } void Pa_Sleep( long msec ) { same as existing implementaion } PaError Pa_GetSampleSize( PaSampleFormat format ) { same as existing implementation } #endif /* PA_MULTIDRIVER */ portaudio-18.1.orig/docs/pa_drivermodel.h.txt0000644000175000017500000000764207465451052022072 0ustar mikaelmikael00000000000000#ifndef PA_MULTIDRIVERMODEL_H #define PA_MULTIDRIVERMODEL_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* This file contains the host-neutral code for implementing multiple driver model support in PortAudio. It has not been compiled, but it is supplied only for example purposes at this stage. */ #include "portaudio.h" #define PA_MULTIDRIVER // for multidriver support TODO: declare function pointer types for the following function pointers /* Each driver model implementation needs to implement an initialize function which is added to the driverModelInitializers array in pa_multidrivermodel.c the initializer function needs to return a pointer to a PaDriverModelImplementation structure, or NULL if initiliazation failed. TODO: need error code instead the function pointer members of this structure point to funtions which operate in exactly the same way as the corresponding functions in the PortAudio API. */ struct{ fptr terminate; /* takes the PaDriverModelImplementation* returned by initialize */ fptr getDriverModelInfo; fptr getHostError; fptr getHostErrorText; fptr countDevices; fptr getDefaultInputDeviceID; fptr getDefaultOutputDeviceID; fptr getDeviceInfo; fptr openStream; fptr getMinNumBuffers; } PaDriverModelImplementation; /* whenever an implementaion's openstream method is called it should return a PortAudioStream* whose first segment is actually the following structure. the functions pointer members of this structure point to funcitons which operate in exactly the same way as the corresponding functions in the PortAudio API. */ struct{ unsigned long magic; fptr close; fptr start; fptr stop; fptr abort; fptr active; fptr time; fptr cpuLoad; } PaStreamImplementation; /* Implementations should set magic to PA_STREAM_MAGIC when opening a stream _and_ clear it to zero when closing a stream. All functions which operate on streams should check the validity of magic. */ #define PA_STREAM_MAGIC 0x12345678 #define PA_CHECK_STREAM( stream )\ if( ((PaStreamImplementation*)stream)->magic != PA_STREAM_MAGIC )\ return paBadStreamPtr; /* PA_API allows the same implementation to be used for single driver model and multi-driver model operation. If PA_MULTIDRIVER not defined, PA_API will declare api functions as global, otherwise they will be static, and include the drivermodel code. Usage would be something like: int PA_API(CountDevices)(); The PA_MULTIDRIVER_SUPPORT macro declares the initialization and termination functions required by the multidriver support. it also allocates and deallocates the PaDriverModelImplementation structure. TODO: add macros for initializing PaStreamImplementation PortAudioStream these would be PA_INITIALIZE_STREAM and PA_TERMINATE_STREAM they would assign and clear the magic number and assign the interface functions if neceassary. */ #ifdef PA_MULTIDRIVER #define PA_API( model, name ) static Pa ## model ## _ ## name #define PA_MULTIDRIVER_SUPPORT( model )\ PaError Pa_ ## model ## _MultiDriverTerminate( PaStreamImplementation *impl )\ {\ free( impl );\ return Pa ## model ## _Terminate();\ }\ PaError Pa ## model ## _MultiDriverInitialize( PaStreamImplementation** impl )\ {\ PaError result = Pa ## model ## _Initialize();\ \ if( result == paNoError ){\ *impl = malloc( sizeof( PaDriverModelImplementation ) );\ if( impl == NULL ){\ // TODO: call terminate, return an error }else{\ (*impl)->terminate = Pa ## model ## _MultiDriverTerminate();\ (*impl)->getDriverModelInfo = Pa ## model ## _GetDriverModelInfo();\ (*impl)->getHostError = Pa ## model ## _GetHostError();\ // TODO: assign the rest of the interface functions }\ }\ return result;\ } #else /* !PA_MULTIDRIVER */ #define PA_API( model, name ) Pa_ ## name #define PA_MULTIDRIVER_SUPPORT #endif /* PA_MULTIDRIVER */ #endif /* PA_MULTIDRIVERMODEL_H */ portaudio-18.1.orig/docs/proposals.html0000644000175000017500000000207507520301362021000 0ustar mikaelmikael00000000000000 Proposed Changes to PortAudio API  

Proposed Changes to PortAudio API

PortAudio Home Page

Updated: July 27, 2002

The Proposals Have Moved

All PortAudio Enhancement Proposal documentation has moved. On the web site, it is now located at: http://www.portaudio.com/docs/proposals On the CVS server it is now located in a module named "pa_proposals".

portaudio-18.1.orig/docs/pa_tut_init.html0000644000175000017500000000321607465451052021305 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

PortAudio Tutorial

Initializing PortAudio

Before making any other calls to PortAudio, you must call Pa_Initialize(). This will trigger a scan of available devices which can be queried later. Like most PA functions, it will return a result of type paError. If the result is not paNoError, then an error has occurred.
err = Pa_Initialize();
if( err != paNoError ) goto error;
You can get a text message that explains the error message by passing it to
printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );
home | contents | previousnext portaudio-18.1.orig/docs/pa_tutorial.html0000644000175000017500000000373207465451052021314 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

PortAudio Tutorial

Copyright 2000 Phil Burk and Ross Bencina

Table of Contents

Overview of PortAudio
Compiling for Macintosh OS 7,8,9
Compiling for Macintosh OS X
Compiling for Windows (DirectSound and WMME)
Compiling for ASIO on Windows or Mac OS 8,9
Compiling for Unix OSS
Writing a Callback Function
Initializing PortAudio
Opening a Stream using Defaults
Starting and Stopping a Stream
Cleaning Up
Utilities
Querying for Devices
Blocking Read/Write Functions
Exploring the PortAudio Package
home | contents | previous |  next portaudio-18.1.orig/docs/pa_tut_open.html0000644000175000017500000000566207535106000021276 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

PortAudio Tutorial

Opening a Stream using Defaults

The next step is to open a stream which is similar to opening a file. You can specify whether you want audio input and/or output, how many channels, the data format, sample rate, etc.

First declare a variable to receive the stream pointer:

PortAudioStream   *stream;
There are two calls for opening streams, Pa_OpenStream() and Pa_OpenDefaultStream(). Pa_OpenStream() takes extra  parameters which give you more control. You can normally just use Pa_OpenDefaultStream() which just calls Pa_OpenStream() with some reasonable default values.  Let's open a stream for stereo output, using floating point data, at 44100 Hz.
err = Pa_OpenDefaultStream(
    &stream,        /* passes back stream pointer */
    0,              /* no input channels */
    2,              /* stereo output */
    paFloat32,      /* 32 bit floating point output */
    44100,          /* sample rate */
    256,            /* frames per buffer */
    0,              /* number of buffers, if zero then use default minimum */
    patestCallback, /* specify our custom callback */
    &data );        /* pass our data through to callback */
If you want to use 16 bit integer data, pass paInt16 instead of paFloat32.
home | contents | previousnext portaudio-18.1.orig/docs/pa_tut_explore.html0000644000175000017500000000310407465451052022014 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

PortAudio Tutorial

Exploring PortAudio

Now that you have a good idea of how PortAudio works, you can try out the test programs. I also encourage you to examine the source for the PortAudio libraries. If you have suggestions on ways to improve them, please let us know. if you want to implement PortAudio on a new platform, please let us know as well so we can coordinate people's efforts.
home | contents | previous |  next portaudio-18.1.orig/docs/index.html0000644000175000017500000000431007640011152020055 0ustar mikaelmikael00000000000000 PortAudio Docs  

PortAudio Documentation

Copyright 2000 Phil Burk and Ross Bencina


V18

API Reference for V18

The Application Programmer Interface is documented in "portaudio.h".

Tutorial

Describes how to write audio programs using the PortAudio API.

Implementation Guide

Describes how to write an implementation of PortAudio for a new computer platform.

Paper Presented at ICMC2001 (PDF)

Describes the PortAudio API and discusses implementation issues. Written July 2001.

V19 - improved API

Proposed V19 Changes

Describes API changes being considered by the developer community. Feedback welcome.

API Reference for V19

Reference documents for the Application Programmer Interface for V19 generated by doxygen.

Miscellaneous

Improving Latency

How to tune your computer to achieve the lowest possible audio delay.
Return to PortAudio Home Page portaudio-18.1.orig/docs/pa_tut_term.html0000644000175000017500000000341007465451052021305 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

PortAudio Tutorial

Terminating PortAudio

You can start and stop a stream as many times as you like. But when you are done using it, you should close it by calling:
err = Pa_CloseStream( stream );
if( err != paNoError ) goto error;
Then when you are done using PortAudio, you should terminate the whole system by calling:
Pa_Terminate();
That's basically it. You can now write an audio program in 'C' that will run on multiple platforms, for example PCs and Macintosh.

In the rest of the tutorial we will look at some additional utility functions, and a different way of using PortAudio that does not require the use of a callback function.

home | contents | previousnext portaudio-18.1.orig/docs/latency.html0000644000175000017500000002026307465451052020426 0ustar mikaelmikael00000000000000 PortAudio Implementation - Start/Stop  

PortAudio Latency

This page discusses the issues of audio latency for PortAudio . It offers suggestions on how to lower latency to improve the responsiveness of applications.

What is Latency?
PortAudio and Latency
Macintosh
Unix
WIndows
By Phil Burk, Copyright 2002 Phil Burk and Ross Bencina

What is Latency?

Latency is basically longest time that you have to wait before you obtain a desired result. For digital audio output it is the time between making a sound in software and finally hearing it.

Consider the example of pressing a key on the ASCII keyboard to play a note. There are several stages in this process which each contribute their own latency. First the operating system must respond to the keypress. Then the audio signal generated must work its way through the PortAudio buffers. Then it must work its way through the audio card hardware. Then it must go through the audio amplifier which is very quick and then travel through the air. Sound travels at abous one foot per millisecond through air so placing speakers across the room can add 5-20 msec of delay.

The reverse process occurs when recording or responding to audio input. If you are processing audio, for example if you implement a software guitar fuzz box, then you have both the audio input and audio output latencies added together.

The audio buffers are used to prevent glitches in the audio stream. The user software writes audio into the output buffers. That audio is read by the low level audio driver or by DMA and sent to the DAC. If the computer gets busy doing something like reading the disk or redrawing the screen, then it may not have time to fill the audio buffer. The audio hardware then runs out of audio data, which causes a glitch. By using a large enough buffer we can ensure that there is always enough audio data for the audio hardware to play. But if the buffer is too large then the latency is high and the system feels sluggish. If you play notes on the keyboard then the "instrument" will feel unresponsive. So you want the buffers to be as small as possible without glitching.

PortAudio and Latency

The only delay that PortAudio can control is the total length of its buffers. The Pa_OpenStream() call takes two parameters: numBuffers and framesPerBuffer. The latency is also affected by the sample rate which we will call framesPerSecond. A frame is a set of samples that occur simultaneously. For a stereo stream, a frame is two samples.

The latency in milliseconds due to this buffering  is:

latency_msec = 1000 * numBuffers * framesPerBuffer / framesPerSecond
This is not the total latency, as we have seen, but it is the part we can control.

If you call Pa_OpenStream() with numBuffers equal to zero, then PortAudio will select a conservative number that will prevent audio glitches. If you still get glitches, then you can pass a larger value for numBuffers until the glitching stops. if you try to pass a numBuffers value that is too small, then PortAudio will use its own idea of the minimum value.

PortAudio decides on the minimum number of buffers in a conservative way based on the frameRate, operating system and other variables. You can query the value that PortAudio will use by calling:

int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
On some systems you can override the PortAudio minimum if you know your system can handle a lower value. You do this by setting an environment variable called PA_MIN_LATENCY_MSEC which is read by PortAudio when it starts up. This is supported on the PortAudio implementations for Windows MME, Windows DirectSound, and Unix OSS.

Macintosh

The best thing you can do to improve latency on Mac OS 8 and 9 is to turn off Virtual Memory. PortAudio V18 will detect that Virtual Memory is turned off and use a very low latency.

For Mac OS X the latency is very low because Apple Core Audio is so well written. You can set the PA_MIN_LATENCY_MSEC variable using:

setenv PA_MIN_LATENCY_MSEC 4

Unix

PortAudio under Unix currently uses a backgroud thread that reads and writes to OSS. This gives you decent but not great latency. But if you raise the priority of the background thread to a very priority then you can get under 10 milliseconds latency. In order to raise your priority you must run the PortAudio program as root! You must also set PA_MIN_LATENCY_MSEC using the appropriate command for your shell.

Windows

Latency under Windows is a complex issue because of all the alternative operating system versions and device drivers. I have seen latency range from 8 milliseconds to 400 milliseconds. The worst case is when using Windows NT. Windows 98 is a little better, and Windows XP can be quite good if properly tuned.

The underlying audio API also makes a lot of difference. If the audio device has its own DirectSound driver then DirectSound can often provide better latency than WMME. But if a real DirectSound driver is not available for your device then it is emulated using WMME and the latency can be very high. That's where I saw the 400 millisecond latency. The ASIO implementation is generally very good and will give the lowest latency if available.

You can set the PA_MIN_LATENCY_MSEC variable to 50, for example, by entering in MS-DOS:

set PA_MIN_LATENCY_MSEC=50
If you enter this in a DOS window then you must run the PortAudio program from that same window for the variable to have an effect. You can add that line to your C:\AUTOEXEC.BAT file and reboot if you want it to affect any PortAudio based program.

For Windows XP, you can set environment variables as follows:

  1. Select "Control Panel" from the "Start Menu".
  2. Launch the "System" Control Panel
  3. Click on the "Advanced" tab.
  4. Click on the "Environment Variables" button.
  5. Click "New" button under  User Variables.
  6. Enter PA_MIN_LATENCY_MSEC for the name and some optimistic number for the value.
  7. Click OK, OK, OK.

Improving Latency on Windows

There are several steps you can take to improve latency under windows.
  1. Avoid reading or writng to disk when doing audio.
  2. Turn off all automated background tasks such as email clients, virus scanners, backup programs, FTP servers, web servers, etc. when doing audio.
  3. Disconnect from the network to prevent network traffic from interrupting your CPU.
Important: Windows XP users can also tune the OS to favor background tasks, such as audio, over foreground tasks, such as word processing. I lowered my latency from 40 to 10 milliseconds using this simple technique.
  1. Select "Control Panel" from the "Start Menu".
  2. Launch the "System" Control Panel
  3. Click on the "Advanced" tab.
  4. Click on the "Settings" button in the Performance area.
  5. Click on the "Advanced" tab.
  6. Select "Background services" in the Processor Scheduling area.
  7. Click OK, OK.
Please let us know if you have others sugestions for lowering latency.
 
  portaudio-18.1.orig/docs/pa_impl_guide.html0000644000175000017500000001527607465451052021575 0ustar mikaelmikael00000000000000 PortAudio Implementation - Start/Stop  

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!
  portaudio-18.1.orig/docs/pa_tut_rw.html0000644000175000017500000000761007465451052020774 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

PortAudio Tutorial

Blocking Read/Write Functions

[Note: These functions are not part of the official PortAudio API. They are simply built on top of PortAudio as an extra utility. Also note that they are under evaluation and their definition may change.]

There are two fundamentally different ways to design an audio API. One is to use callback functions the way we have already shown. The callback function operates under an interrupt or background thread This leaves the foreground application free to do other things while the audio just runs in the background. But this can sometimes be awkward.

So we have provided an alternative technique that lets a program generate audio in the foreground and then just write it to the audio stream as if it was a file. If there is not enough room in the audio buffer for more data, then the write function will just block until more room is available. This can make it very easy to write an audio example. To use this tool, you must add the files "pablio/pablio.c" and "pablio/ringbuffer.c" to your project. You must also:

#include "pablio.h"
Here is a short excerpt of a program that opens a stream for input and output. It then reads a block of samples from input, and writes them to output, in a loop.  The complete example can be found in "pablio/test_rw.c".
    #define SAMPLES_PER_FRAME     (2)
    #define FRAMES_PER_BLOCK    (1024)
    SAMPLE          samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
    PaError         err;
    PABLIO_Stream  *aStream;

/* Open simplified blocking I/O layer on top of PortAudio. */
    err = OpenAudioStream( &rwbl, SAMPLE_RATE, paFloat32,
                         (PABLIO_READ_WRITE | PABLIO_STEREO) );
    if( err != paNoError ) goto error;

/* Process samples in the foreground. */
    for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
    {
    /* Read one block of data into sample array from audio input. */
        ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK );
    /*
    ** At this point you could process the data in samples array,
    ** and write the result back to the same samples array.
    */
    /* Write that same frame of data to output. */
        WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK );
    }

    CloseAudioStream( aStream );
home | contents | previousnext portaudio-18.1.orig/docs/releases.html0000644000175000017500000001736307465454164020610 0ustar mikaelmikael00000000000000 PortAudio Release Notes  

PortAudio - Release Notes

Link to PortAudio Home Page

V18 - 5/6/02

All source code and documentation now under CVS.

Ran most of the code through AStyle to cleanup ragged indentation caused by using different editors. Used this command:
   astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c

Added "pa_common/pa_convert.c" for Mac OS X. Start of new conversion utilities.

ASIO

Mac OS X Windows MME Windows DirectSound Unix OSS

V17 - 10/15/01

Unix OSS

Macintosh Sound Manager

V16 - 9/27/01

Added Alpha implementations for ASIO, SGI, and BeOS!
 
  • CPULoad is now calculated based on the time spent to generate a known number of frames. This is more accurate than a simple percentage of real-time. Implemented in pa_unix_oss, pa_win_wmme and pa_win_ds.
  • Fix dither and shift for recording PaUInt8 format data.
  • Added "patest_maxsines.c" which tests Pa_GetCPULoad().
  • Windows WMME

    Windows DirectSound

    UNIX OSS

    Macintosh Sound Manager

    V15 - 5/29/01

    Windows WMME

    Macintosh Sound Manager

    V14 - 2/6/01

    V12 - 1/9/01

    portaudio-18.1.orig/docs/pa_tut_asio.html0000644000175000017500000000673307623460774021313 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    home | contents | previousnext

    Compiling for ASIO (Windows or Macintosh)

    ASIO is a low latency audio API from Steinberg. To compile an ASIO application, you must first download the ASIO SDK from Steinberg. You also need to obtain ASIO drivers from the manufacturer of your audio hardware.

    Note: I am using '/' as a file separator below. On Macintosh replace '/' with ':'. On Windows, replace '/' with '\'.

    You may try compiling the "pa_tests/patest_saw.c" file first because it is the simplest.

    Several files are common to all PortAudio implementations. Add the following source files to your project:

    pa_common/pa_lib.c
    pa_common/portaudio.h
    pa_common/pa_host.h
    To use ASIO with the PortAudio library add the following:
    pa_asio/pa_asio.cpp

    Macintosh Specific

    Note: there is a bug in the Macintosh ASIO code. Mac users should read the file "pa_asio:readme_asio_sdk_patch.txt" for information on how to fix the bug.

    Add these files from the ASIO SDK downloaded from Steinberg:

    host/asiodrivers.cpp
    host/mac/asioshlib.cpp
    host/mac/codefragements.cpp
    The ASIO drivers should be in a folder called "ASIO Drivers" beneath your application.

    Windows Specific

    Add these files from the ASIO SDK downloaded from Steinberg:
    host/asiodrivers.cpp
    host/asiolist.cpp
    common/asio.cpp
    Add these directories to the path for include files:
    host
    host/pc
    common
    and link with the system library "winmm.lib". For MS Visual C++:
    home | contents | previousnext portaudio-18.1.orig/docs/pa_tut_callback.html0000644000175000017500000001137207465451052022100 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    Writing a Callback Function

    To write a program using PortAudio, you must include the "portaudio.h" include file. You may wish to read "portaudio.h" because it contains a complete description of the PortAudio functions and constants.
    #include "portaudio.h"
    The next task is to write your custom callback function. It is a function that is called by the PortAudio engine whenever it has captured audio data, or when it needs more audio data for output.

    Your callback function is often called by an interrupt, or low level process so you should not do any complex system activities like allocating memory, or reading or writing files, or printf(). Just crunch numbers and generate audio signals. What is safe or not safe will vary from platform to platform. On the Macintosh, for example, you can only call "interrupt safe" routines. Also do not call any PortAudio functions in the callback except for Pa_StreamTime() and Pa_GetCPULoad().

    Your callback function must return an int and accept the exact parameters specified in this typedef:

    typedef int (PortAudioCallback)(
                   void *inputBuffer, void *outputBuffer,
                   unsigned long framesPerBuffer,
                   PaTimestamp outTime, void *userData );
    Here is an example callback function from the test file "patests/patest_saw.c". It calculates a simple left and right sawtooth signal and writes it to the output buffer. Notice that in this example, the signals are of float data type. The signals must be between -1.0 and +1.0. You can also use 16 bit integers or other formats which are specified during setup. You can pass a pointer to your data structure through PortAudio which will appear as userData.
    int patestCallback(  void *inputBuffer, void *outputBuffer,
                         unsigned long framesPerBuffer,
                         PaTimestamp outTime, void *userData )
    {
        unsigned int i;
    /* Cast data passed through stream to our structure type. */
        paTestData *data = (paTestData*)userData;
        float *out = (float*)outputBuffer;
            
        for( i=0; i<framesPerBuffer; i++ )
        {
        /* Stereo channels are interleaved. */
            *out++ = data->left_phase;              /* left */
            *out++ = data->right_phase;             /* right */
    
        /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
            data->left_phase += 0.01f;
        /* When signal reaches top, drop back down. */
            if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
    
        /* higher pitch so we can distinguish left and right. */
            data->right_phase += 0.03f; 
            if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
        }
        return 0;
    }
    home | contents | previousnext portaudio-18.1.orig/docs/pa_tut_util.html0000644000175000017500000000444307465451052021322 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    Utility Functions

    Here are several more functions that are not critical, but may be handy when using PortAudio.

    Pa_StreamActive() returns one when the stream in playing audio, zero when not playing, or a negative error number if the stream is invalid. The stream is active between calls to Pa_StartStream() and Pa_StopStream(), but may also become inactive if the callback returns a non-zero value. In the latter case, the stream is considered inactive after the last buffer has finished playing.

    PaError Pa_StreamActive( PortAudioStream *stream );
    Pa_StreamTime() returns the number of samples that have been generated. PaTimeStamp is a double precision number which is a convenient way to pass big numbers around even though we only need integers.
    PaTimestamp Pa_StreamTime( PortAudioStream *stream );
    The "CPU Load" is a fraction of total CPU time consumed by the stream's audio processing. A value of 0.5 would imply that PortAudio and the sound generating callback was consuming roughly 50% of the available CPU time. This function may be called from the callback function or the application.
    double Pa_GetCPULoad( PortAudioStream* stream );
    home | contents | previousnext portaudio-18.1.orig/docs/pa_tut_mac.html0000644000175000017500000000270007465451052021077 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    Compiling for Macintosh

    To compile a Macintosh application with the PortAudio library, add the following source files to your project:
    pa_mac:pa_mac.c
    pa_common:pa_lib.c
    pa_common:portaudio.h
    pa_common:pa_host.h
    Also add the Apple SoundLib to your project.

    You may try compiling the "pa_tests:patest_saw.c" file first because it is the simplest.

    home | contents | previousnext portaudio-18.1.orig/docs/pa_tut_oss.html0000644000175000017500000000277407465451052021156 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    Compiling for Unix OSS

    [Skip this page if you are not using Unix and OSS]

    We currently support the OSS audio drivers for Linux, Solaris, and FreeBSD. We hope to someday support the newer ALSA drivers.

    1. cd to pa_unix_oss directory
    2. Edit the Makefile and uncomment one of the tests. You may try compiling the "patest_sine.c" file first because it is very simple.
    3. gmake run
    home | contents | previousnext portaudio-18.1.orig/docs/pa_tut_devs.html0000644000175000017500000000517507465451052021311 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    Querying for Available Devices

    There are often several different audio devices available in a computer with different capabilities. They can differ in the sample rates supported, bit widths, etc. PortAudio provides a simple way to query for the available devices, and then pass the selected device to Pa_OpenStream(). For an example, see the file "pa_tests/pa_devs.c".

    To determine the number of devices:

    numDevices = Pa_CountDevices();
    You can then query each device in turn by calling Pa_GetDeviceInfo() with an index.
    for( i=0; i<numDevices; i++ ) {
         pdi = Pa_GetDeviceInfo( i );
    It will return a pointer to a PaDeviceInfo structure which is defined as:
    typedef struct{
        int structVersion; 
        const char *name;
        int maxInputChannels;
        int maxOutputChannels;
    /* Number of discrete rates, or -1 if range supported. */
        int numSampleRates;
    /* Array of supported sample rates, or {min,max} if range supported. */
        const double *sampleRates;
        PaSampleFormat nativeSampleFormat;
    }PaDeviceInfo;
    If the device supports a continuous range of sample rates, then numSampleRates will equal -1, and the sampleRates array will have two values, the minimum  and maximum rate.

    The device information is allocated by Pa_Initialize() and freed by Pa_Terminate() so you do not have to free() the structure returned by Pa_GetDeviceInfo().

    home | contents | previousnext portaudio-18.1.orig/docs/portaudio_h.txt0000644000175000017500000003453307465451052021164 0ustar mikaelmikael00000000000000#ifndef PORT_AUDIO_H #define PORT_AUDIO_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * PortAudio Portable Real-Time Audio Library * PortAudio API Header File * Latest version available at: http://www.audiomulch.com/portaudio/ * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ typedef int PaError; typedef enum { paNoError = 0, paHostError = -10000, paInvalidChannelCount, paInvalidSampleRate, paInvalidDeviceId, paInvalidFlag, paSampleFormatNotSupported, paBadIODeviceCombination, paInsufficientMemory, paBufferTooBig, paBufferTooSmall, paNullCallback, paBadStreamPtr, paTimedOut, paInternalError } PaErrorNum; /* Pa_Initialize() is the library initialisation function - call this before using the library. */ PaError Pa_Initialize( void ); /* Pa_Terminate() is the library termination function - call this after using the library. */ PaError Pa_Terminate( void ); /* Return host specific error. This can be called after receiving a paHostError. */ long Pa_GetHostError( void ); /* Translate the error number into a human readable message. */ const char *Pa_GetErrorText( PaError errnum ); /* Sample formats These are formats used to pass sound data between the callback and the stream. Each device has a "native" format which may be used when optimum efficiency or control over conversion is required. Formats marked "always available" are supported (emulated) by all devices. The floating point representation uses +1.0 and -1.0 as the respective maximum and minimum. */ typedef unsigned long PaSampleFormat; #define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/ #define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/ #define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/ #define paInt24 ((PaSampleFormat) (1<<3)) #define paPackedInt24 ((PaSampleFormat) (1<<4)) #define paInt8 ((PaSampleFormat) (1<<5)) #define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */ #define paCustomFormat ((PaSampleFormat) (1<<16)) /* Device enumeration mechanism. Device ids range from 0 to Pa_CountDevices()-1. Devices may support input, output or both. Device 0 is always the "default" device and should support at least stereo in and out if that is available on the taget platform _even_ if this involves kludging an input/output device on platforms that usually separate input from output. Other platform specific devices are specified by positive device ids. */ typedef int PaDeviceID; #define paNoDevice -1 typedef struct{ int structVersion; const char *name; int maxInputChannels; int maxOutputChannels; /* Number of discrete rates, or -1 if range supported. */ int numSampleRates; /* Array of supported sample rates, or {min,max} if range supported. */ const double *sampleRates; PaSampleFormat nativeSampleFormats; } PaDeviceInfo; int Pa_CountDevices(); /* Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() Return the default device ID or paNoDevice if there is no devices. The result can be passed to Pa_OpenStream(). On the PC, the user can specify a default device by setting an environment variable. For example, to use device #1. set PA_RECOMMENDED_OUTPUT_DEVICE=1 The user should first determine the available device ID by using the supplied application "pa_devs". */ PaDeviceID Pa_GetDefaultInputDeviceID( void ); PaDeviceID Pa_GetDefaultOutputDeviceID( void ); /* PaTimestamp is used to represent a continuous sample clock with arbitrary start time useful for syncronisation. The type is used in the outTime argument to the callback function and the result of Pa_StreamTime() */ typedef double PaTimestamp; /* Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure referring to the device specified by id. If id is out of range the function returns NULL. The returned structure is owned by the PortAudio implementation and must not be manipulated or freed. The pointer is guaranteed to be valid until between calls to Pa_Initialize() and Pa_Terminate(). */ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID ); /* PortAudioCallback is implemented by clients of the portable audio api. inputBuffer and outputBuffer are arrays of interleaved samples, the format, packing and number of channels used by the buffers are determined by parameters to Pa_OpenStream() (see below). framesPerBuffer is the number of sample frames to be processed by the callback. outTime is the time in samples when the buffer(s) processed by this callback will begin being played at the audio output. See also Pa_StreamTime() userData is the value of a user supplied pointer passed to Pa_OpenStream() intended for storing synthesis data etc. return value: The callback can return a nonzero value to stop the stream. This may be useful in applications such as soundfile players where a specific duration of output is required. However, it is not necessary to utilise this mechanism as StopStream() will also terminate the stream. A callback returning a nonzero value must fill the entire outputBuffer. NOTE: None of the other stream functions may be called from within the callback function except for Pa_GetCPULoad(). */ typedef int (PortAudioCallback)( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /* Stream flags These flags may be supplied (ored together) in the streamFlags argument to the Pa_OpenStream() function. [ suggestions? ] */ #define paNoFlag (0) #define paClipOff (1<<0) /* disable defult clipping of out of range samples */ #define paDitherOff (1<<1) /* disable default dithering */ #define paPlatformSpecificFlags (0x00010000) typedef unsigned long PaStreamFlags; /* A single PortAudioStream provides multiple channels of real-time input and output audio streaming to a client application. Pointers to PortAudioStream objects are passed between PortAudio functions. */ typedef void PortAudioStream; #define PaStream PortAudioStream /* Pa_OpenStream() opens a stream for either input, output or both. stream is the address of a PortAudioStream pointer which will receive a pointer to the newly opened stream. inputDevice is the id of the device used for input (see PaDeviceID above.) inputDevice may be paNoDevice to indicate that an input device is not required. numInputChannels is the number of channels of sound to be delivered to the callback. It can range from 1 to the value of maxInputChannels in the device input record for the device specified in the inputDevice parameter. If inputDevice is paNoDevice numInputChannels is ignored. inputSampleFormat is the format of inputBuffer provided to the callback function. inputSampleFormat may be any of the formats described by the PaSampleFormat enumeration (see above). PortAudio guarantees support for the sound devices native formats (nativeSampleFormats in the device info record) and additionally 16 and 32 bit integer and 32 bit floating point formats. Support for other formats is implementation defined. inputDriverInfo is a pointer to an optional driver specific data structure containing additional information for device setup or stream processing. inputDriverInfo is never required for correct operation. If not used inputDriverInfo should be NULL. outputDevice is the id of the device used for output (see PaDeviceID above.) outputDevice may be paNoDevice to indicate that an output device is not required. numOutputChannels is the number of channels of sound to be supplied by the callback. See the definition of numInputChannels above for more details. outputSampleFormat is the sample format of the outputBuffer filled by the callback function. See the definition of inputSampleFormat above for more details. outputDriverInfo is a pointer to an optional driver specific data structure containing additional information for device setup or stream processing. outputDriverInfo is never required for correct operation. If not used outputDriverInfo should be NULL. sampleRate is the desired sampleRate for input and output framesPerBuffer is the length in sample frames of all internal sample buffers used for communication with platform specific audio routines. Wherever possible this corresponds to the framesPerBuffer parameter passed to the callback function. numberOfBuffers is the number of buffers used for multibuffered communication with the platform specific audio routines. This parameter is provided only as a guide - and does not imply that an implementation must use multibuffered i/o when reliable double buffering is available (such as SndPlayDoubleBuffer() on the Macintosh.) streamFlags may contain a combination of flags ORed together. These flags modify the behavior of the streaming process. Some flags may only be relevant to certain buffer formats. callback is a pointer to a client supplied function that is responsible for processing and filling input and output buffers (see above for details.) userData is a client supplied pointer which is passed to the callback function. It could for example, contain a pointer to instance data necessary for processing the audio buffers. return value: Apon success Pa_OpenStream() returns PaNoError and places a pointer to a valid PortAudioStream in the stream argument. The stream is inactive (stopped). If a call to Pa_OpenStream() fails a nonzero error code is returned (see PAError above) and the value of stream is invalid. */ PaError Pa_OpenStream( PortAudioStream** stream, PaDeviceID inputDevice, int numInputChannels, PaSampleFormat inputSampleFormat, void *inputDriverInfo, PaDeviceID outputDevice, int numOutputChannels, PaSampleFormat outputSampleFormat, void *outputDriverInfo, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PaStreamFlags streamFlags, PortAudioCallback *callback, void *userData ); /* Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens the default input and/or ouput devices. Most parameters have identical meaning to their Pa_OpenStream() counterparts, with the following exceptions: If either numInputChannels or numOutputChannels is 0 the respective device is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() ) sampleFormat applies to both the input and output buffers. */ PaError Pa_OpenDefaultStream( PortAudioStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PortAudioCallback *callback, void *userData ); /* Pa_CloseStream() closes an audio stream, flushing any pending buffers. */ PaError Pa_CloseStream( PortAudioStream* ); /* Pa_StartStream() and Pa_StopStream() begin and terminate audio processing. Pa_StopStream() waits until all pending audio buffers have been played. Pa_AbortStream() stops playing immediately without waiting for pending buffers to complete. */ PaError Pa_StartStream( PortAudioStream *stream ); PaError Pa_StopStream( PortAudioStream *stream ); PaError Pa_AbortStream( PortAudioStream *stream ); /* Pa_StreamActive() returns one when the stream is playing audio, zero when not playing, or a negative error number if the stream is invalid. The stream is active between calls to Pa_StartStream() and Pa_StopStream(), but may also become inactive if the callback returns a non-zero value. In the latter case, the stream is considered inactive after the last buffer has finished playing. */ PaError Pa_StreamActive( PortAudioStream *stream ); /* Pa_StreamTime() returns the current output time for the stream in samples. This time may be used as a time reference (for example syncronising audio to MIDI). */ PaTimestamp Pa_StreamTime( PortAudioStream *stream ); /* The "CPU Load" is a fraction of total CPU time consumed by the stream's audio processing. A value of 0.5 would imply that PortAudio and the sound generating callback was consuming roughly 50% of the available CPU time. This function may be called from the callback function or the application. */ double Pa_GetCPULoad( PortAudioStream* stream ); /* Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for the current host based on minimum latency. On the PC, for the DirectSound implementation, latency can be optionally set by user by setting an environment variable. For example, to set latency to 200 msec, put: set PA_MIN_LATENCY_MSEC=200 in the AUTOEXEC.BAT file and reboot. If the environment variable is not set, then the latency will be determined based on the OS. Windows NT has higher latency than Win95. */ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ); /* Sleep for at least 'msec' milliseconds. You may sleep longer than the requested time so don't rely on this for accurate musical timing. */ void Pa_Sleep( long msec ); /* Return size in bytes of a single sample in a given PaSampleFormat or paSampleFormatNotSupported. */ PaError Pa_GetSampleSize( PaSampleFormat format ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PORT_AUDIO_H */ portaudio-18.1.orig/docs/pa_tut_over.html0000644000175000017500000000624207465451052021317 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    Overview of PortAudio

    PortAudio is a library that provides streaming audio input and output. It is a cross-platform API (Application Programming Interface) that works on Windows, Macintosh, Unix running OSS, SGI, BeOS, and perhaps other platforms by the time you read this. This means that you can write a simple 'C' program to process or generate an audio signal, and that program can run on several different types of computer just by recompiling the source code.

    Here are the steps to writing a PortAudio application:

    1. Write a callback function that will be called by PortAudio when audio processing is needed.
    2. Initialize the PA library and open a stream for audio I/O.
    3. Start the stream. Your callback function will be now be called repeatedly by PA in the background.
    4. In your callback you can read audio data from the inputBuffer and/or write data to the outputBuffer.
    5. Stop the stream by returning 1 from your callback, or by calling a stop function.
    6. Close the stream and terminate the library.
    There is also another interface provided that allows you to generate audio in the foreground. You then simply write data to the stream and the tool will not return until it is ready to accept more data. This interface is simpler to use but is usually not preferred for large applications because it requires that you launch a thread to perform the synthesis. Launching a thread may be difficult on non-multi-tasking systems such as the Macintosh prior to MacOS X.

    Let's continue by building a simple application that will play a sawtooth wave.

    Please select the page for the specific implementation you would like to use:

    or continue with the next page of the programming tutorial.
    home | contents | previous portaudio-18.1.orig/docs/portaudio_icmc2001.pdf0000644000175000017500000014343007465451052022102 0ustar mikaelmikael00000000000000%PDF-1.1 %âãÏÓ 2 0 obj << /D [1 0 R /XYZ null 67 null] >> endobj 3 0 obj << /D [1 0 R /XYZ null 626 null] >> endobj 4 0 obj << /D [1 0 R /XYZ null 612 null] >> endobj 5 0 obj << /D [1 0 R /XYZ null 398 null] >> endobj 6 0 obj << /D [1 0 R /XYZ null 385 null] >> endobj 7 0 obj << /D [1 0 R /XYZ null 264 null] >> endobj 8 0 obj << /D [1 0 R /XYZ null 202 null] >> endobj 9 0 obj << /D [1 0 R /XYZ null 391 null] >> endobj 10 0 obj << /D [1 0 R /XYZ null 378 null] >> endobj 11 0 obj << /D [1 0 R /XYZ null 353 null] >> endobj 12 0 obj << /D [1 0 R /XYZ null 292 null] >> endobj 13 0 obj << /D [1 0 R /XYZ null 219 null] >> endobj 14 0 obj << /D [1 0 R /XYZ null 138 null] >> endobj 15 0 obj << /D [1 0 R /XYZ null 125 null] >> endobj 16 0 obj << /CreationDate (D:191010723144925) /Producer (\376\377\000A\000c\000r\000o\000b\000a\000t\000 \000D\000i\000s\000t\000i\000l\000l\000e\000r\000 \0003\000.\0000\0001\000 \000f\000o\000r\000 \000W\000i\000n\000d\000o\000w\000s) /Creator (FrameMaker 5.5.3L15a) >> endobj 17 0 obj << /D [1 0 R /XYZ null null null] >> endobj 18 0 obj << /D [1 0 R /XYZ null null null] >> endobj 19 0 obj << /I << /Title (Flow98310) >> /F 20 0 R >> endobj 21 0 obj << /Length 7928 /Filter /LZWDecode >> stream €Š€ÐP¼Œ3 DC4b2 "0˜€Äl7 F¨äb.ÆÊ†Ø$JL 9à„"À€^G)ÂŒç1±ŒÃ€Òc‚ŤZ8ΔaˆÄPr0˜éeÒ¡* ÂapÐPä\8ŸIëÖàÒw>ÇáœBG%Ãç÷€Üs ;ÐEAHÜPhŒ‘HÈeI¦  .(àa8E#ñË'N2BÛñÏ.(1äò¹ü ´f(1d²˜Šn, 7d†”ã¸€ß‘Ñ ÂÜö´ÞuË °Zà£U~hu|¿{NÏ F8¡h§(Ús / (3òÚÓn\à Hx\£ )ªUQ.•³) *.ƒAR€ù§oêò(NÐdÓ´¬8ÄËa°P0¼l8ò£AÁõèÈÂ@á@Þ #pà:°¡¨P:Ü26ë¼ÓÄc \ɇ,X“ -ë̳pttÁ°­8ÎØ²jDX£LT_2l[¢þHèÚ8 ãN3BoŠ*K `¬Š…%° tzÅ»ƒÄÉ°ã¤¬Ý í´JðI tç #|玄ç*¹JC»7ãt~(¡”M3Éc»¶ãB”€b¤ Áí"Áòl1ÃÑ%Ä:M;$… Ã9Ž æËT!CÊÓÇácત¡ê¶sõ!„½ESœX0‘üôÌüNJsøÒ3H!D&££OÌñå1KÒt…¨ìÚ-¸ÚÕR’lP7ŒÑM=Cpøàà©ÓÕ>3ÓSe3O²}E7Õ›äú#á›î…×iÊvº®paE/ ÕéEÉuûˆ¡”ñÁÕ;¥»X¬v¢ãv”êÆb±3A,8ȦF¬#O~ä7¦B)xòÿ–8ÎN#&d/+¤¿OÑ6:ÆSèã+¢ÔSÖChTY^B2ŽÚ8ÆÍâÌ^˜1¨é¬bê2‘¨S9 ‰¬Ä9ÆFy+¾:L;©ßÒÜ»….Oòè»a°"†É´â‚˜§ !0U;çÍwæ°*{>5·,Úý•°Qk±ZÎÄ^LPê3ÓW=0ChÚ:ÃK½ (ÎD6°ücˆ¿¼gÒ´ô+±'±S•I~ó6³%-R休LUwrÒvb:¬PÉÆÚ0ÃŒ>;z#tã*ú>Oèí°¨ƒÀ1cpê6µ-ÍXé±wG¢7/CRò#cŽbÃ@aRçÿ³§ôäWê¤f¦œñ”çxjžIJ=ÿ²·ò›Áý?ép¤Öh#Sì­l-µ#Ca·Nj½o1%Ì´Y"Ÿ^H™h1Sñ”À }gHÁ8'èáQRÃ^´Å¾D:¾Ÿ:Lð‘CAbjHDÉ‘&­ïC¼^Êq%ÂgÛ¹:€Ø»¦ôRš4éžBúSƒ¢§S麛¥ýè p@à¿,w$CâI§}oÑè˜!²Nh]{® A²_7‡uœÂkbd£‚€ŠdÞ Á„mÕäÆâ[ù:Kéæ„Gºä›5nÞ$˜p¦oÑZ²[¬Ñè˜åŒ\™"Êdá½9^–K¿1,ÝR në!#Á“ˆÕG#½$À7ÎF½@¶þ” (]´ÐåHìÎûæ9NáÝúþgì¤85hòÌ·‰%ù¹3Õ¾ °™T¯Ûòü4ÐQøýIhü!efa´Ò§\¡è40ö挮*-"ïIoÒTñWSLbˆV»…–RøNt´4ÒSœ½¸hBd^nÊH0Á‰à8µÄìÓöýH’A‚f±)G³s‘~B`ÜÁ+&*…C¾í Ó h Å\Mñ4¬è£U,’ ñ›…àÐP‰0B Á̃¤‡zÃZ eø)™_rPu­K/Á…©_p_‡BŽb¦)V2ÓÍ|ãZ€×å²à< †¯-ÿ5רÁb×2C0f 'VÖ^„¾ÂJcA2ý®æÎb˜4F´Øùb~ áüÀäˆ|Å™ )g4‚àm,HY$Y:¸·â>S k„+”éE:ôÚ1DÁÔ©'–p¿^Aåh†BÆXHžصƒB},IÑÎ5ÂõʶúP§S¸O§bïØiÎMùØpÊœÕÌ‹“ÈwN¹èÌ hÔÀÕ…ùï½G^`Ï*½[Ç#]á{0aÐûhE?*Env,t;"›ŸXÆ®)È.Mu]KÕ›ö¬bH³TW aXÌš™ÌE$£ 3Á;ËĦ°äë ²•<¨Õ§ís&©YNne9gÃ0·fÞ¦öùoëX®îrˆtÒ˜©Âº2ߪ¸£\™Mï<ªRz}RÙ¾ü­™‡Frì¾% |ÙKö¿tÑô:†É¢bö)ÅfåâCyzävTµ1{—UOƒgm`.¿uZ½=Še¸° ë-c_ÒÁ…¦6Æ?õ.©8ùòƒè‡í÷šÿú‡0\|̬þR+õy:ÊH¿sÔQ±nyßCáÁ3ðPL-Ö™`xÄû‰Å¹èïó‹fß9¦…N¢³°zP €&†Ÿ!Úu*ñ ÅOJby=›ô¦*ùeHþÜ9¬)Þ`É«ü…v,á×ü¿[Ý‹-&:Éq£Ú>"Û¼§K²3‡ß=8bºgí¿Û§mZ‹'I}òwšS_›ÜP©KÁ Ž (˜wÜ9\ß>»y-Ý\Š£DÛ—sãÃál—RTý¯þþ|ïOâÖI^±È ˜ç"äã– Ï~zgþµoJ.‚Úä‡â˜`èŠïŒ[Å(þE¤Õ$:Gð2Ïì â¡æ|˜p4à£tÞ¨HTCTÝ):9Dàgê¨ãÞbþÔ¬R¢…>ênDè´ØDü:E$AÈ)8)Ðh0p`1nø’ÿ¬¸nÉäÓ¢Ôä‰W§z橹`NIhœJ#N¾c~%¾6Þ8‰ö‡-ÜIhý îC© 5„Údp‹¥"ß)øÝË®JI–Oœ¤¥²cD¨K&·¨¦Lð@F¥ DÍX)ÐR XäCð?ëÐ6nHªH†,±‘2IûMÄヤ÷ ÔE…’ÿP.ëìsÑ<Ýï"x î<@Öß(?¨D1Möl¢‘ íéMfá è#l]1_ n7nà KZoFÉíÀ(DFUBHål;ú˜hê@è$4Ne8‘EHG)äκèl›L¹h– (Ž®¤… š‰®ˆ¥I(OpÞ4ðâGðÄ´)ð[°Å #í®'Ån§eväLê•Fù PpHú± ŽCÄ@°‚ÿë´ØnàÂïðDÒBo^Ü΂í+ Ïñêz$B›‚ÝÊŽ)—Å xí« Ìß!>Û`rÛ¥y ² JŽlBñvQ7Ð/±ÐA>Žœ70JeÂN3ˆ9fªò ?;ð x®~çS'E#Å?qвނ²€N`Ná/÷ β/¢°sÂaFä“ïïÒ1r$ÖŸ"¤ðqT®óŒSð&Â/œþ1Å?d¨ô·1삤,ð5 ÍŠ6 #R¢Šµ#–îg…E5I(þè-HŽÆ.-¿‰TI1.2g cd¢)/WÃ$ ÂDŠ¢#eĘB£{QÑV‹k[P”Z&”7%m\H? Õ«*CV «’)|FµŽísèØ)ö_µ|Ž%£ULo)S/õIÏ$P²4åý7çD¤“vzrZþ-ŠRî«=碾‹4íz°„Ví9„ò€‰-”ªQòL1V3]žIÙ³¸þ/’r+"í)i'NÄôÀ`õ &LOKâý2HôûRoPÔ¦Õs‹;óU>Çþ–~˜1M.Ô° ™a4¤ÐÉ›4g#ROÃ$ºíŽ0Tó^ÐF²ô@ÑáÄ)ÅèÇ+î2Ñä9ª"0c¼eä¾Cꮿ\‚À#Ø;6Ì8ÄX‡ÕjrNbr š°¯XN`ƃöî|ç2 `ÞØ*ùnkzÂ#{&lf^ãï'@8ðü—D¼¶ÃsÄ.-"Fœ2¡R¶áÄ? 2¹HTD’àŸ Œ¼ÑŒÂͬÐÌ×€",ÌЖ lÌvÄ-ñžžlç!ŽHFÚ?‰¸ Ž—öƒZ úÆ.f¤j}`k´ebü4©ïf04|¢™sè*LöáHx– rÑ ŒÑlÀѾÒ$ÒBÚ+Í4W Ú$Lå2µ3ö ™ÏµJÇþè3÷24y ˆ­²`@n?½“boÔ1Q ì/Óöx8«ßãV]ôÆëoà¾MnwŠD6XáY÷ ÈÅîõ' ;äcaU6>X‰ ¸I4 µãðy¯6÷tôñK¶ô$OJ 5kEUå*f؇.Z4ïxœäç3D™3‘¿?Ò1Oç ¡6;/[no£ ÇX;™gV Š2î0Öp<Ä €}Ô¡aÕ0ª½b#¬š‰b­Š¤ˆ 냋V€“Š:ICQø^™±_<ÎÐ3¡ôµ–D,Ms_<†ü]ão.Xž¦);¶DØRÐzI‡-pQ ö0QXS)‡v²Ž“JHá4y±GE‡ùWm+мsÒ‘¢É5©t9°ã£Q,rpZ&É ·:ýu a‰§š¨–šzdX–“/ªÄט½ë%Š×6´íFõñ½SÌØµ+‘§ý]_–I, ¢QøÙÀ\˜á!8çINEyÂtI8î(XòOpô^ÐÅ(‰º¢1E¯ SÝ@QŠM®Ei­‰ýúå„ó@ EÍnR„X7àé®Þ‘“¸'ùAŽºg! \ÐK`L`јs€t™ò%E?n—;,u'5Ñ‘ˆ#å´ÿ™ÓQËGù ß#°ÖÛ @ù*Gx÷\xÈ4øþ9b@¤ä‡Ì×ùçc‹uDÕ*ر‰Q¹’² Ù7Å„µP0çþœÇ2Mu¡S˜z3X1`Ȳ5&7)ÌT–€Nhví™shR)Œw`´ö'@f8/@ÓRZš5u*öº0õT•ï6…yd÷4ò›8º´O810û¶›U4|Ð4D:n8 å/Ò6QöDŽxHꦘ͵ü5¹5½»'>nI?¸À;4%KC{rö\Xõ²e™47M™MTCò«¿dè9J›S¢ò[øR¸úQôß9vÞT“y>Ïð N‚ò)l7WVv@îHs¶Î;ã¼kCz÷¶5’®D̤0¬V;Ì"ehšQ×Ùlxdã]d@ZkÜÄrDkZ»ôØ(£s|Ðfæ ;æ&kDqˤäDÆ‚Rø¶e¼eC Ëtªú²§Z·”"ãuø-Çš3ãbE“QƒFÒÇшãŸl釣MšÀ±q>10)ú5Dî¡5n}OÔ7ä)ÝJT£Å,I54Å¢Zc1BŽ73°V‘ P”›Û8‘«‚ã«Û&$.HD:îhmJ¼"ÚÉszÔœ0"Q&PG º\ÈC®‘°ctE²Mꌠå?®D–SмM]¤Ir UºgÒZ¾¹F/Ib®\Ý_µ˜¾_òǺ1ÓRLT]}+.ï%ã†ÙÀ˜zâ“O¥ú  ê_º±¶Ýü–¿K”m¿¥Id²Ç ©f£öÓ qÞæüf¦LN£T‰¹DÙåWC=Î î3djŰÆz%=Á Ð<b)ùòCËÓ<Þ‰8zÁÆ4F«,‚`ZdË¿Îc&‰­X£Ç£êéhVÿé¨ ;æ:b‘²x~¼;Õ·o^ª\¢dXç–pL %¡l;$ôîHñÂü;KM²‚©½PB™3li—®oÄîfíE+ÆÜ‰žìúTµK‘ÙVãFÕ¾&ëƒ?ZPOþ£:´û’'£ŸPyõ\ä„7ÆrAJñsÅŸ1úé¹´SMþ#•ÖòAÀ쀲•\UTQ÷x ÷|!׆"b$Ì÷ˆ:lÆ"¥|ÌròÓqžÎ¸™å‚„ͬðW†ï¢ðËe%Z[œæäzÜMɰ˜8°` ÜÛ‹>uãAGêa[™uoiÖ>‡¤è]{Èî¤vâ {Ä|ð¹Ý¦èdç aös±õA@fL#yq`æ2ðr—¡\:†ÕW¹„… byî…¯­•ƒ„ÈâÜ+Љ®‚Å gü^±!¾—§j]Kí 1Ç2ÄËÙx©Ú«fh“z1‹L¾.€Z³$è!À8$BÈ< KÄâ³R†ÈA"& ´…±âÙõƒp=ç$3 «á߅×_ ûÐM‘ASFSá Ü©seò–B9R\%¤¬–ñîXF(Üû‘ª£eOÉ¢GB¨ðcÀ3ƒÊò>$rþÌÌaÖdnL”Ò,±Ê(YLe~¬e†ÂO+(TQSÔ}-O½0*ܪ9¬ »4&„YÌÙŸtTŽ ÞDX #H zpE/Á9{UU”PÁØ>÷,¨wiZÃè­ãd²mÑ–VCHUBܧr’‘C8~ù¦m¡±½ ÇGç3 «¿UìNiŸÒðÌÁ@O aNOè @`ÃÀ ¥R9‰K„p.F£ÊfaTº¥ÞJ¸g<å{­}5j_ÕØ–«cµYŒ‰‚‘Õç10êÕ2™QÍûÇg*æA”ÑcM5š§Dœç„€œ „M @w’k09F;N -+dR~À)þH ¤-àÄCë]S‹wÉ–Î=£ÐK¾zgÐø‹M@ÒóÝézÚÚ#f¡¯µ”…WËgilé ¨ÞÜÐ7‚âÏ¥¤ÑáÚ›]nR;HvŽ$\«_pb9ˆ¹VîèÛÔ‡vf5º÷%ä—7Çt® }Vª3ÛGê¬/SŠº”÷ÝÛ3|®m¥£7.èßsÝBË̼¿6ÚѾk?{On»ÖPÞ Å@ÑÝÌ>¯šøà¼#‚\˜*·W~λgZõ«¬D*¼GŠÎ^,ú¸Ž—ƒ߇x©-àU˜4b‹¢ 1­ˆ¶®Í˜réƒqÍîǘ[Úœx.EGp8ÃcÜp™ã»‹zÇ·&ÃÜ a29W·ºbÈŠ}A›vÈ8ùÄ^œ‹‘ó5o˜³˜L‰Gm¦4ƒ˜Ý·bŒ‰œ™^!/ps3b,I)®³ÉÒÛ%˜„ãsæz‡5Wæ ÌŽâFZyN`h< %6;Ñz9˜Lk’s6:ƒ‡Áñé*ê rZæÌZ_DA»Z°Ã¼<ñŠ`²û>õ²4­wÚ£E: ú2äaÓËXÝ\Ëõns.méåDŒO]çÆÆÏSw»›Ïƒ˜c)²çg8—²³Uƒld¹á)}–kÅz¦=îŠK›àöὺ³9»ê븥foÞ‡¢Ðc*(ä6ÍÈÚÛ­åm¼[³œËÊܘ·dð}Ó›ø^ÿºpïbùˆ‘ñ ·g¡Ép@¥ö3VJЦm2÷žì %À¦»ýŒí_fKyâ ÄJ ­ûtg/½—+PΛÓÓgQêp@õbóÖ5óÇëy•÷Võ´it8ï4´>ÉŒ¨§J¦® ¢ƒ7iòê_NS› @‹,Y HÁ’!_h±R¶xHRÑ&ÁŸØ•²@\–gË÷‹0•²€É”(†Ì­’d,@ÖgÜöå‰fwêÊà3d€­†{&z‹Ñç/¬Á9W¶ŸHº¾Id>M¦P͘¹ ØÒ–cÕ¬"Ȉ ްóA„ ›ýˆ1hƒÌ–bH½€‹>únA‘ÉM§ÀŽ’±?§Ä$rv é Ñb—¬¸0«‹­rɧA•<û»/žðÿAâx ©™“±<y²‹ˆø ˆ/q»¿‘9˜Ñ% `7ÀòÇèž ©,?p¹‘5Byš½ ) èÙˆ(Ò¦ÊG 3ö‹Ì.L/•ž’Rp€$ˆÌ#$ð€€ endstream endobj 22 0 obj << /ProcSet [/PDF /Text ] /Font << /F3 23 0 R /F5 24 0 R /F7 25 0 R /F8 26 0 R >> /ExtGState << /GS1 27 0 R >> >> endobj 30 0 obj << /D [29 0 R /XYZ null 698 null] >> endobj 31 0 obj << /D [29 0 R /XYZ null 633 null] >> endobj 32 0 obj << /D [29 0 R /XYZ null 619 null] >> endobj 33 0 obj << /D [29 0 R /XYZ null 570 null] >> endobj 34 0 obj << /D [29 0 R /XYZ null 497 null] >> endobj 35 0 obj << /D [29 0 R /XYZ null 444 null] >> endobj 36 0 obj << /D [29 0 R /XYZ null 430 null] >> endobj 37 0 obj << /D [29 0 R /XYZ null 381 null] >> endobj 38 0 obj << /D [29 0 R /XYZ null 296 null] >> endobj 39 0 obj << /D [29 0 R /XYZ null 271 null] >> endobj 40 0 obj << /D [29 0 R /XYZ null 210 null] >> endobj 41 0 obj << /D [29 0 R /XYZ null 113 null] >> endobj 42 0 obj << /D [29 0 R /XYZ null 720 null] >> endobj 43 0 obj << /D [29 0 R /XYZ null 709 null] >> endobj 44 0 obj << /D [29 0 R /XYZ null 698 null] >> endobj 45 0 obj << /D [29 0 R /XYZ null 687 null] >> endobj 46 0 obj << /D [29 0 R /XYZ null 676 null] >> endobj 47 0 obj << /D [29 0 R /XYZ null 665 null] >> endobj 48 0 obj << /D [29 0 R /XYZ null 649 null] >> endobj 49 0 obj << /D [29 0 R /XYZ null 600 null] >> endobj 50 0 obj << /D [29 0 R /XYZ null 563 null] >> endobj 51 0 obj << /D [29 0 R /XYZ null 490 null] >> endobj 52 0 obj << /D [29 0 R /XYZ null 461 null] >> endobj 53 0 obj << /D [29 0 R /XYZ null 447 null] >> endobj 54 0 obj << /D [29 0 R /XYZ null 379 null] >> endobj 55 0 obj << /D [29 0 R /XYZ null 365 null] >> endobj 56 0 obj << /D [29 0 R /XYZ null 316 null] >> endobj 57 0 obj << /D [29 0 R /XYZ null 207 null] >> endobj 58 0 obj << /D [29 0 R /XYZ null null null] >> endobj 60 0 obj << /Length 9996 /Filter /LZWDecode >> stream €Š€ÐP¼Œ7 DC4r. ˜‚ F‚á„Hn1‹†P³l)'ŒðB`@/#”áFs˜€ŠX“G0¢¡Žr2Hʇx!lPA( F‚H¸R1ŠC(¤h0ª£Y°Þ) Å ¨´p(9éõ¦À1…"ÛÒ·K9]Å« ÔPt·Š,¶s%Îà ° “v eŠ6á©f},׌3Ø,B­¨cXÁÔ±"ƒy˜A€\ lÎÎ ¤R©˜ìVRÍhت¥Ò¡*L ºH†#‘¬,‰9H!sàPÀ\1Ш€ª6Pc„;[¬7¼6ꟄӛÄ;.¾2¿³Ã!AÔÙ¨ÍÜñ÷üУWp²ÒÄyËà6ÊXê½ XÞ§8o²ž© Ìï… +ñAJüį˜Ì°,[ê6+k8X¹Âã¸Ð4¼Ž»ìñ¼­$¹@¡hRÞ7ÀP¨9 ã–äHB†¢¾“&¹¬NÒ–¹1Lô.ù1PØföª°P6 ‹ô2 ã¢,ìŠé µ+Œ¤:2“é#4Œl6³«ìT*×µ [VÅ ­‚’©JΧOb¹ª-\¸ÁMíl¶ÉJÃ*ÈNâè¬<íxÂÓËk8èþÏPõEÆmê Ç*˜ç€l…ºj0ß1M:Àö5mÑ>jJ¢¯«ðƒ-±C Òñ4cºÊ¨ŒMø±NÓØÀ®ò )Ñ¢…Á l¢Nf¨'Ž;šŽõR£„ò¹M.pÒÈí²ÏF0ï’ü¤¼Íd+¾k]×Ì ¯Ãƒë ¬CxÎ9:Ê]ÌýƒF|Õ«#*´ ÏíÙG: äí]#<1âãxÉ-¬Q•¤86µ°àZKˆã95Q Qcl¨µbÝfÍ-¤ª5d#r­pöxE õe(N²K‚§ñž–¨³OÇõÚ bõ¹škælÑäë]œ9­`Ëù_C)ú@-«ô.ÐïþAS·«£mÞÁºOáŠPTuÔxoRÜQ«¨&°ºÔÚì ÷p2Åú:¿mÛQ]37 á(¼œ;<“uׯ½9..‚ŽÛº„«Uº~Yܖų‹”šÈØÅØzgwË2Hn¸c¥{8t[6’*-œÛØbn͆³ÍÒRÜÉ£‹ó² YºÞsÀ4ÏM'Ú5žçÓŸm†1åÉæ€Í}‡]3õ§×z` Ó†774G 6ÙÉÍë| HÄ€¹ªD. "à÷Šñ’ð3~ÑÇx:±U’Í.¶Y`T©¦1M}Çaw^Ð\q…xÑaÇt¼.Àž7oÛ x¤Ú{ÓÈlå•m¶¼6÷B#§éµ>‘êa"UÃm©b¼ot¾5zº^;¸Ûl›åMÆÏ?ÃTìIáùÁ§8e;ŒëÅ+ÂÆ÷ÒV}Bp¦HÎã£dñÉŸ/òÏ<ý]–£*[+Qm‘úû‚ëûˆ –.£Ò‡NÜîÝ+dÐã>â T9îÞ**†è¸ ¾ÓL<Âí>Ã`Ì /DËŒ.߬6òŒ6ÓËŠÃEðE Š£¥ðŠTÕ¨äºnÅ#ÐæÅO, »âtÛã˜áEÆÄ€iÂäõ£ M@@¶ "@h¥¨*Ámæ €Ãp"¸°(ÞàQð2Jl. ð²@âªÔ D•ÐL*0P  ÄpVÄ­Â(˜ãR9ã”ÅéÆ"tîpä:êŠ@ÜíΊNT0èÜmHR>`@½ŒÈ: (/æÍNx9¶šéÊBež0¢ØRîŽo`ècoÄYïlkžäIÔÓnŒqÆ“šØè’4d6U¯*j‰×çŒ~ÅŒ0Ê–j€Nlcöµ%ŸÂÐnfò¹CækçXûl¨dÇøbt¼)†M¾\o(@§XÏTöÊÄØgØ€È$=ˆâ—àŒŽŽ"*kµ &» 9­v9)®‘Ë0áI"³¦”BÄ^æ°.ƒ&ƒã6 ©L Î ²j«\ãà M Â,» ÖÏÀÄuãœ{îì£ ÞWÐl%øˆ®Dle™iºmHÝ h± )Î~éº Ñˆî“)ìnD›¨NPQú*$*U¯µM`@`p$ sqß Ð ê àž¸'._Ü kƒ°¬ $¼Ä0Uؘmcâ$§ Û(â"9ðî×R0$G ¨£ú¿VÐK^Ðí  â: \™2Ñ)R˜¢må)ð¢£`Ÿ éTÔÐÍ Ð.¸#Ý+2±뎕R¸Õ2¾¥ðY!²Ç ë°G¦Z"R#r+’ÿ#œ(¥°üxœF­Æ#Š$ntÍnzp³NqLgh’åB°~f èFhDããàÑrãK4äF’ã~æ´ËaÆ&qeàj¤à¦½ŽB}D`/Ђp-/`qFM°çjû"ìhåÄH (oÑmŽÌ+0HYï¦.vžf|û”n*%Ì`#FŒÑFåòXVfÂnÔ–¦Š½…žS€í Ömí6hFæŒ4ȉæ‚o#(î mÁKmBžÎªq& lfñ"¢í`ýN¨Vc¬@ÜÕ…LôÊoˆvg ÄŒ$²o`ÖÙRãHcG&ö”販± ϼ”à€´ÈùK1<'f0xqàùÕ-HÔüF­V¦ÏNK0½‰úgÆÞµcçL†’EfèÆši(ªgˆËî”Ótb,ñ€›²tÂg•lHtnn‰Z¦©S•X”Ìh¦æhOÌYõuªøä€l&wGgZì%g[µ?&OÇLsàl-|*/”—&| ̺oc2+Ç\c6aµüs±+Q†®*Uœ+âžÀÄmNÐ m7TÆî4u)ìUuÊ”õç(Ö/\¥EBáQî™RVi2f@ŽòjÈ™R͘jŒ-]Ö385*jÓŠi1xr¥flfǃF<+VMRÎÐmHÂ÷BÄX£çdH®Ç (ÇõHN?6âç73ð «ôÝìÝRñ?à@HNÁ›0-%*!Añ*¦‚‹‹1l71°?1í;2#Þ Ú¹ì72¶Õ,+ª¦³4Å@p!ä$B%"ÂtÁ«y *ŠqÀà`ˆöÊºÏ ¢XãRwLSBü\ÇδIVvCdu^‹uËf•=Fç’¤–ˆU‡&öªŸ¯Ô¬ãGÆèîœ2lgH{Òâ4s o`ë&qnOPh¶mMB¢-U{¥dvshK.r šòyÊjÈS{Ö„ öÓ&V[M®ÛFP†Uðq &6G™v©R jfy×’jÈÜ冩OòHžxâLnžöOhVo¼WȦè¯WÀk²U›%žû+ j;iæöyÔ•¤ÑÛ3f†ÅÇjågk)ç%ŸQvD-˜ÂYöPÎãmŽÚengñ§/¢žÖ Œ©¤:Þäzè„THžxìtè+&­Ÿ8¦Ô?`Þk¢íªöf€fÃ#Ùd‹ã¢¶K)í5¶+[û(¥­TÅiNÇZ™f¬œ1Tú¥VvXŒö‚žÌ-fR;[dfæÀàl'fèq›lÆ91¤94šñ®/ÇXqÌÀØBáF,©=ˆ"B­•|H.AgÔ?úx;oajU”?[˜ÕHD,O~ƒ(. ì*G>QÍ”n]í†g´*V˜öqþh"µz úÛ¥»È>B{ä¨^sÞ„|šRÛ^øÙM7žäý­ÎÉihÙŒâc^i¯’V{pù®Œ Ï ýk1‘à UµÁÁN˜o&DzmG2*,ÿ¯kˆ¨ñgÀu 6º,L3pýlŽ´›üh®L]Üpù‹8i®Lÿ“­cF&â¯ÄŽ“ª…+9WæÉ×bxf<â<|bï@.Ô?N?9hž+·äâ-Ä0ôè?Z\õë·àjçäÚí™"Øã¦©Q{ ¬&¨+¬C î>CÙµfÔΩîèyVÿ»QiYèt0þo`Ðvæ„ 5¥æ÷Ri dP—Ššàš ˆ (±NÕ. ð6ãÄ*¢®+3èvXäÅŽ¾¯àZ·ôÍ7ùJ,Í) ¯Åû§¦†}™ôPwÌoz2g–æÛ¯ºÄg–¹gµ#kúÑd£çdæ©‘vU¡¢à á]©ì 6¡ºSôЙ5­[jr$b>¢c4W”˜.¸R§oiVh8*g:P×’+"Ä8C„—–Žr3Ã¥ð k£qpÐdâ(ç@l(SfzÍÀAô @ßt`@O#äñ˜Ã`… ÍåpÀY.Dkó3:Á½†¿EôH¸ Òo Uô£ÚóðºSö · Àäíö\7ÿ?ï¿ ÃØú©úS1ö #3ïð­¾ÅñÏÿûeñTÙUÁ.ûŸ%ð`¡ù_p?‘ ÿ•ù…·ýÛãÿwô’Ò­6¸GuÃ"(2ŠFCqAÌR0 c $Pm†ŠLÞu‰ ‘3LJ DâåÒ¡( * ¥"Ñ€¸`0ˆ †9L¼ašå%±@‚Aâ‘l„Òd £Tx1ÎNˆ”i †R0ˆ ‚‘ئM( ÈÃqÆhf”ŽEà€ap[-Â˜ÊØ5è¸d8šfóˆÊi6KÆC ARx ŸGE£ˆ ÑŒ`§8(‡‹`ÆÃdd(1Cô9ý  ×3Aƒ©»]† µ&š0ÌPo7A“ø–Tk¢ÐA"–otu9pÆ\Q;Ôâð…§®\ 9èb‘ ç•¯Óï6Ù¯ ÿ‰ ¢Øe£pÐp7ÁepÊf*Œ+±0d§¡@Ò7 ðdà5Á³”¶££6Ú„£29-&¬µ(»ªÛ! ;ÀÂaÞ3CH#€Ì²ðÂ~„2®và9ík¢-. ìM3ð«‚ÐG̲)$‘œ/… \£9)£@âÆ/Ž8ዊÖ6°dFâŽZ°$éJV–§‚Ìš°¬< ÈAC:Œÿ*sÄ<ã†n°ÆÑ†P›†Ê½È¹*…ªÍM=9ðZô7Ê;SBO#(@;Ï33B Q SPSJµ"¿'ô UÂÁLs=Å`Ã>ºÌÌ<«Buj~×QŠ+“ZÉ• \¡t\'DT!4䯡›ODîú%IcÃ-ó‹$… Ý 4¬K#Ç­@Pp¶°KŠãt n¶Ë*0€R\˜AÚ|(P(0¾)Ä/‡8éƒ^·T²B;a@¹‰…7 R²,×*Ö¶­÷Z玄 dû?•èÀ0WÌÃÀ×Úq Á6à@36ò6Ô8#t©jÜk:ҔݷRå¡.ËÀ\½^A°l+»·™v‡¤8"69"c.ªƒ ¨ê‰¢HR∂»‹¬k.~*\˦<¹mùb—†‹zõ¦iù]°ÇeÉÅŸ™'Îr¢ô7hRšÔºhE ¬¹0å£PÒ3“Ä*qÕR7q©øàõ¡MÐ<ÔãsÏ…›aSÅÁk“¡Rò ÍÊÑfÓJÁ¼ß¿™#þš@[àa•2)÷K2 óÄ@‚!QÕ) XKk*°È’‚yZÖøÔ5,äºO5Âô¥Sü6LDøŒÃxå⎼\QC5–hSø´·5ìõòܭ˹#3±*o„Ü?gà| w[ÎEñ3@ûÃÈnM U67ÆZ¶×áŽx((Ü™‚ ÖL : (˜Ë õ0ȹGL|: æry¡ä ¡$"–xš›Räh t—%Ù׃H/`Õ£™Åð¾‰ÃR_à¡€‘0¾ÚÑ» Á (0ªÁ!ä)D6PPÙØ³=mll7&>Ü£t>íÝ£ƒ2öÞÙƒ~i Â6¼"~òÜ+É=¥©†çÞuà#44ï\¢žÇJáZU|P˜ŠžÂ‹žä RòÈH \£åáÉùH˜# «·îäû;´ï™‚t1D¼ÎG4ƒ!3éh߈¨hI"Lñïg>#ól—”QßQ*€ŸCDÙñ hÒ†”rtK]ŸÀ C/5ޱ¬ Ю‚žDÌÙº()ô2Hp[3Sº$†¥Š Ê j¶£¡”Dê–C²GŒÝ øg7ÀÐä‡d^Š ª&¢Ô’ZŽM-¦èäÑ›R$zò3ráWª£@ ÓÁ?g8Ön̹· 5¸:¨‹ª$HtàÂʈŽmr¨U†šV³<0§È*“W3âæ`I¡¦jXàS:ìä }/ º‚‡ëFi™#K­œ˜_hà ï „iAº<†áÅ£ €í×\¬]$£-dëNs‚‹jb$(¤*‚ÚÿgæVAgÃ;ùìOŸXd£Ï°Ýš›ƒ61Œà¢¦OóBpÈUÓ'ôx<‰dÁŲ'™ Ûû`{Þ(l ô¡ò\+g ¨H(6gZð™þkÞ,øŸT䔲Sò~ϲ~/Îõ¨Ê„Š26‡Â0C†ÚÐaÛh Ì˜ÆD Kø9ñ6¯Ôbš¡V`a‹áŠÊ†+`­d©5¼VmC˜ÈÜY4€º6aÖ˜ clF0Ø1lPràOGÌÙ(Î:›9J³ó¨)&`Ó. U¸ë-""…’PÑó“Æ!Frfîô¥e“ÏÁŒÏ]Ô¦vÄìQ¤—G-9¡Ïrʉi‹cÈ5Þ{‚¢J bí‘äŨ7{s„t] £Ôfˆ¥² ¦ðj@±‰–±öZ Òø.^ì‰AC¸Ü¿L|ô&95:­ÀfôOFµr+ØTðâgL93²oðN¡Y'6JæÒÆ[cnd1•Ãö“õ®"‚š½9SÜœC}PQ ´ëE4'^Ñ!+' Òª¤y©ÔB%WTE,vè]F9Íky»TŽCt~ÈÒA X äxße¼5ÆÔ7Ý ËZ ™!CAæEœµOáø?@ƒ7;Ăも±+r)¤vªmB+YU-d˪ÖA±ÀJ…àŸàêÙÎÍØQs4\1¸40 ˆÇm±ó—"k€¢&Äò'ÉÈ™ãéí}Ø^=ÐÙ‰ dP¹/¥õè*>£O`i8IQ.ex•>RCÊÂ9ûu×Ë©¢ÕÁ¡6N†fŠuËþ «i «j Ùg°;#™am R —Â::-qo§R~‘9M™»—*â§ê˜3d¦¼/ ô-»D@"›–5ñë »Ùžªš@‚e¥ÔœäDEXÈøÒŒ.C“½»¸ÒQ³{6É—A)8#¢Á/ª@ÂkE¢¢¢´Š˜¹D–€£(R-Žfê’©®@+‚h&µàÊŸA aAŠP"@Á嬷â‚À®­ÎŠ×*h¨¹¹ µ–#€&ÇhC$ ¤ëÞŒ(ƾ!z™¯àŸ‚›×ÉÇ‹ÖGàïƒrù4¤”HÔ­ ³ÙÆXø¼ù@*­˜4ƒÃ1(ah‘"W½ýpн°|…ˆ4™ ø2@ºõ.Ó½ z¡²‰€"H6¥Øä”C•Ú;ñCO°#Œã< £”);' £™(Ú”ØÙŒ¨âŠi#”Ìt«9¡ó@ʬ°ž2ÿë`“®7ØãÁÔ´8 Ë$³’à0¤ ¢<ÓBa ËØËÃx£Œ¼®ü¼ «L<¹KXΔäÌRØ&X« ¼Æ¬ºL 5 ûŠKT»ŠˆË”C‹Jl¥$_'”)°ó'Y/pø¬\„¯“Ç(óM’ê¸X:³»É½Q ˆêkÈJÏ<<—I@â³±œ¡ZØÉÓ¬¬#®©ö)|(ᦤ°Œ­8ׯ=¯ÉÐø‰å‰{•ƃ=ÁËÒ½"Œ¯ÜÁáOÉlxØ´`ߤLŒ•à÷½Ê¡Å`8(+Iϳ¼=¢lŽûÇN”K3 ˆ¥Kô爀á<œ­Ä‹ úÅ©ZåIëß@K'32+”kªªÁ7ú¾L(‰›Š8k•*©L½1 $~ƒ¢­¦Áõ’½Q‚¹FD¥¨$«ÔV¸j¯ÀËQXô´ @Œfe-”y¸iN®\©#jT²tË’<Ì̾¯9$+®”™gDK˼¬ˆȈÃÜ·•BØ +E3ÀL¢ÆK¢eŽSIËrÓ4̾X«èÓ}0ه̫}Ò”¤Sx2“ìÎS5½d»ªLÄK­5Ë Ù·Å0+§x†Oò¾ Ä2rŤZö¬¸ïÁ‹®÷ªÆ ÜíÏ áB( ·ú‚»©ÎÊŒÏL‰…E;‹Ô,h8:¨+†/òÞ! †–ŠíÏÒù´åf#ð×à ³™7˜ÀPŸèÊb1GQ]޽c–‘=9aP“¹PÌQ> øâŽ9JÖñL–štPöcp¤eq×JCŽUÃC˜=a⌣ä â‡Š=,•M?–pà-~JLµË™<× ]ÊùJ•'1P™ÆVñHÝLV’ :97.hŠ3¤Ðï½#G/”Ž<€/Ï{ÒQä—VD” ë@© ÊÚù3òƒ´÷­š€­ŠÕ/E+͛ġh‹<“ÌÖ íU©´ÉðÇ„@¢9:# ­Ž‡ÀìxSQ©ÊˆPŠŽHõ‚YPê)ªžý^9•¬ÑÁjÍ]²áM4Ÿ²Pɰxð ûë#Bý´]A)½%3$ÍC‰ôgÊQ‡ XÚ”D ¸;³}¾ öÊ@Ý”¬ÆÈX­ˆ ¢±AêC£Q+—˜ó$—ÅÃŒs!2tÉÉ/E`õ”RYTCtªïÛsC–XÝeÜY-…h‹®‹h¼%< ˜D9' Ù>b³ƒ:e‰3\»Ô9Rá¡Ð”aN]ËÏ’° nܼydH ‹ÛB-§RA‘Uî7)#@2‘3Ý&¼LWÚDEzEÃEžº‰”bÕˆPÙßA<Ä‚k K˜¨ Úƒß#ë'\bá*h7{^L:ߨ"³IC3¦@ÌêbZ‘âã‘ ¡Æ«²ÙÑŒ¸5™ =5…V)–ZÞ&µ9D%ã*³2w8õƪÞ½ö(}LŒsmá½#¥Æ`Ûƒ$uQ…F¤šÉº¥P…C%-2Ò­äz/Åò©8J¡°„27€…ƒeñXP;Çè5¬» ºÀ·ÚÓ¹õÏ–!+…,³ÇA 3*º E`©–2Q7;iëcžÆƒ€:¥î$½¹Ù¨y#¶eÜ©šâT4#Ñ¥Ë'Éiä¡ä¦ä¾L­¾MãNN§Iå‘’ñ2¥éйýX„g• -žV¨¼8­™…©È’2u®’DÈ¡Ô9‘²5ñƽr[àÔƒ -”6i[aÔ(xö1 ÓI [Ó*:nIïåüšÈôg:užm”؇ÚÚßFqƒH6gÑÛ)­`0ôW®O5ŒÓjçª?e¸Mf\Am¥PZ´òÐ K1¦1Ü© åå+³Â19á¢!óSµH©§B‹£®:Iˆˆ˜'­PÝF{úg[öˆ…:°ƒ:å¿¿ÓhC»ÿ {•‰}ÙjIJF è ˜8Ì«¶%¥þWéÆXž.Uu²™ž,Ч7eÂi’‚p"Ù+ešÆ%áaû¹"ãå,½D€‰kòA¼[¤Ò¸í@CñÐÓ=©xب“w¯%KЬÿÐB-G‹ÅBÎNJÚVjÊi4×Z2ˆ´þì!ÑÐx`[¯Íf¼rÊñø÷¼Ëe™Ì¨"‚ ”ˆ endstream endobj 61 0 obj << /ProcSet [/PDF /Text ] /Font << /F3 23 0 R /F7 25 0 R /F8 26 0 R >> /ExtGState << /GS1 27 0 R >> >> endobj 63 0 obj << /D [62 0 R /XYZ null 735 null] >> endobj 64 0 obj << /D [62 0 R /XYZ null 638 null] >> endobj 65 0 obj << /D [62 0 R /XYZ null 481 null] >> endobj 66 0 obj << /D [62 0 R /XYZ null 425 null] >> endobj 67 0 obj << /D [62 0 R /XYZ null 411 null] >> endobj 68 0 obj << /D [62 0 R /XYZ null 370 null] >> endobj 69 0 obj << /D [62 0 R /XYZ null 353 null] >> endobj 70 0 obj << /D [62 0 R /XYZ null 259 null] >> endobj 71 0 obj << /D [62 0 R /XYZ null 231 null] >> endobj 72 0 obj << /D [62 0 R /XYZ null 202 null] >> endobj 73 0 obj << /D [62 0 R /XYZ null 133 null] >> endobj 74 0 obj << /D [62 0 R /XYZ null 119 null] >> endobj 75 0 obj << /D [62 0 R /XYZ null 698 null] >> endobj 76 0 obj << /D [62 0 R /XYZ null 585 null] >> endobj 77 0 obj << /D [62 0 R /XYZ null 571 null] >> endobj 78 0 obj << /D [62 0 R /XYZ null 450 null] >> endobj 79 0 obj << /D [62 0 R /XYZ null 385 null] >> endobj 80 0 obj << /D [62 0 R /XYZ null 371 null] >> endobj 81 0 obj << /D [62 0 R /XYZ null 207 null] >> endobj 82 0 obj << /D [62 0 R /XYZ null 193 null] >> endobj 83 0 obj << /D [62 0 R /XYZ null null null] >> endobj 59 0 obj << /P 29 0 R /R [45 63 567 729] /V 20 0 R /N 84 0 R >> endobj 85 0 obj << /Length 9785 /Filter /LZWDecode >> stream €Š€ÐP¼Œ8 DC4p.Bœ>" à€n1‹†ã1”,Û‰ÊD#<„X Èå8Qœæ "– ‚Ñ„l`5…˜à…±AÜÂ)Œ†âƒ±–‘JMÔúYÉTGZÁ˜ÍX2œ«ÁApR).• PH0Þ †‚‡1ìªæ8Ž¡ãHèÜ`1IJ’pTò} *PTB¡¢‘ S©#@‚Ñj¶†vød8ŒíØkü’D”O­Øš ˆi¤!˜Û# b‘ŽäéÍô¨ ëS¤îjö›\nÄ\F¢á ØguÈ0Z€TöÿÖwgÞ¾´@i6ï7'e8b9zE¹w§¾£ûÅM€Èh ãs,¤¸£¸R> 8ZâŽmàfÊ©î+†6Ël4Œïëþû…Ù¿ã`òð°P4·ïóöú… ›˜¡á¸pŸ„›÷¨£¸ï7ª R²ò±n4†1<ÜÃ8@ü©aÅ(7JB–5…, Ï6aKþ7¸ã#-ƒ@ä÷)pR–«ÅAË*7ál1¿ê3x¥ÅB²+á“dᲃ@7 ñKr4Ï­“úÜ·alÓ;¿jDEÀœI#´¸É)j›)Cl^ SZ3,Sôù.(@×Ém9*†*\ãŠaJ—0 Ócþ) °@+u@:ÈòHÓ&ËdâÔ s(4Ù,­AY·u¨P4 ÃHã.+Œ¥f•ÏV­Â –¼¬¬Ë,­)O2£D1.1ÕK¤ô‹†P|ÛE0{$Û ÖËd<ÀõtŽÜ¸rLÜÇYí¸[a?°}Xÿ½>`¾-䓟Köü¶Oä&âÀS°bÙal­Û1ÒNIŒïse1`0xÊÙV%aK—û*8f͘ӓݖSw{TÏþÄ1Nò*HŠ$Se)ûÒø2M•l¶ÐSe~I0øZÿÊmãmF¶RÅúÊí!nXÞ\[T÷²Õ „:(r ‰"-¾#!t„4.ËÂ4‘£Ã«6 J–6²J€§ÊÖÂ*°¦¹ €è²,k>ô糋Šîºð=8A~§©/ñwÃW¨£a»ÈÖ…È[xÙ1Î*œ73sÐÞwÕŠÄøà]â–²îkæ…ÁÈ`ÿF¬e4÷ÃÚ7ºžªm6Õ+Ù£3lÖÚ<¹ •ÕG6oHci¾ïýgjáóÔžºß±”W‹7†`@µC‚íJœÛ­¥œqJ:˜)H9¿ Êj|a‰%ÞôH"÷H«Ev®5`ó:ë}ŠE9t€ ÍB)uUAfh”—í+àÔÜ•÷ôºÕKs>gýÿ­¥zŸ:ŠRK¡X¶dÿ*zUЏ;©DÊ"pJ=P±ãŒ»`J*z 1¤†kXËÌ )é1%ÀÄÂl$n¯Ñ:$h¼¬â(ïð(Bõ ,K!Ô2)@ÞòT„ƒ‘9ò@µ – ¢|+ˆ©‚®µA ÀTfêw² šµ1qƵZcL{2hAÑ™¶ú“µ4Æí=Ö ­4ÍPÖ„ÒžØXâÙk´ûF‘” €á1ÄÂkB Í -±8’K£:ÀÏKü ÁÉ;2í“Àí·H§.*ÄM³fcïØÜ¢Ä8ÉðdÈ‚"IóUó:hÉ#g¶QÌå4«èžƒPrboU'Á 1VB̘âü‚袆4ŠÝÚ-YÇýž›Ô”ÛÒm#R-½˜ÀÓdÞLÁÎo“p87E[ù ̤*,Iû±0§yÇ¢ˆÜêk…a0€ÄÙŠ€eE`:•÷$ 1a+B¨&–Uã1 HÜTl Á¨1<p¢7 ÒÅW,…šé¶gK‘t¦àÕ€luè5FfðDx÷Ñø7œ2òu¹bZÀefUb«¹êVæUõIU´‹xZ‘yA¨[,¹ƒ€p¢OÍ5Ã$ IÒbíšj‚ž®h °%*OÐzjUlê(bÉ%„˜Î-{fU!K2Ü¢ë÷B FÓÒŠêIN'ý«±#d€™% m·ÓšÞÝ+~"䪛+Zþ_Áz#p𓺈Žj1Á©%f¥ÕpÞêaò*µzè+“¢¦%¶ô×’ñ^ÝRϨù=ƒ÷¨`.U¦nÆDùD¢I•©©8S@fNxõî#£Z•"=u½¾›^ÊrGÁp5§ØêùÔ'~ hSµ\!"À£J† ªá“ é6°kª.ÕèÜ qæ°Î+ “ôrøðú‚]ø•PÆ9TŠèLÿÃ똼¡\ËøUI ™rÊÒ2³FWUDäá Ø¶R#ÇÄkm¼/#És3M`q™¬œáƵgÇémtJQ&.?B!ŠLÒ@`4nP¬B",´¹™#¬Æ9§+Âsa¥Fr¥¦@\ŠBe¢¸l¦r¥I&A‰R¤ä¥&„€æ|r+bb$¶l°Þ¦-r˺ÐÎDVx)i‰gÊ)hÎÉ$0R}«B É4¦)8:Â:¬éD몈”ÄŠïCè)é"ÆC4Á£>FDjG‰È_˜ª[ ð ¨ O<Áª€ nHQ°;kì'Ä„—)ehë’>Ce ë&ª æRFøi »P`ÿ0²qøºpRCÖ&Ã ë­ ­¤ê„¹cB£‡ë^ /”¥íì>cdÀ¥ ÿ-’ˆf%æ##(ºŽ‘¤ïëÔp!ü¯ãjøz€`·nä BÊxfñÁC BŒ4¬ªÌ0 ЭQ”àÅô(<ªàí'Ê® 0–MqPW`¸1¤óââ¢&uGîñ":ŠÐ0&¦qŠˆõ‡Z+„ b0Ì $àf‰ðº ¯™ ‹¸ú#ô ¯ÈÞï…‡™.2"a\ø¤r¥„í¯—.¯ŠeÏy.* 7$>÷à÷ŠáͳÒôøLü:`h¬û2’H¦v‚~¢[!†¼ìîŒ)æÚC®ýÑ ï,Cds÷ nvïg:\O4娱6o1 ®MБ8RÁ¯pJr§©còd_¢7&Ï'—'eû' Ó¡)îU*NUì’åR®?Ò²Ê/BâÌx¨ÇS¢vÊGòÄ¡‘fXhy Nè’?¸è¤ñ3ë¢J žè…pèƒdW f6LÍ-ÆËº %jpî!SDÅÉnõ‰hÃ‡Ç ­¸8’Fx+n jTnÚ8¯sl=Ã} °DäZкú'ФÊT ˜4"°‚ ’²DçÉDlžÁq¦•î1&ÂUIn4#Nœ U²n˲kc¦•#ô’ìn„” @P äd.àÒùF@Âdχ.Œ â“Ó+ªô¾Kà4G¨¨Q–Ë¥kqœcãù¤T › ,‹ÔxÚsI/”˜jÔgC!GÂ> †?à’]mcOäº~†.‹^)Æ€EJ¬)nCçs‚2#Q æQ«'Q%BuRKäd5JT4_V¢§QðšI2õOÒ9 ÃãUÕa"¤ª6Ín'qŠ“Ô.¡O¸|nõãZ ˆ¦³%´ (8þ@@ …)jVx0 €ê5´=ð<²O› ufÏEÆ ÀÞÝ0EK›*S6¤ô êRˆR~ÚV`ÜTEÆš–• üI/†«Ø’iT»æÀ»ÅØ>sdmæº2²šnk¤»4Â@H – ÔüíPGò* uI\¦„{I´ž#b;.c§:’Ì0ó¯K#à0¬è ¤ µð6´Léé$e:xˆXngFœ4àÁïD°4¡eæV§3«>‹'`lòt”"3b'C JÑÚ|`’ý¨ÓùKÕü]¥@ƒI.‰fðK…ª FD-(mÆÕàÞZ¥ªRŠžÄY¤¨‘ˆ8‘´ïÛZ¶þM¨WpÔ½X㺓å0:©l;Év|lJ£ð|nÅUƒm1K¢Zv>m††l‹ž+—]ÀäkrNU®ìþ¤! r*>!ËcDŽ’%—aæÌ¤<ºÀÉdë–¥Hû"†6íMXÀ°®¢&¬å0ûQ°Ë´8—¦feñDE©Œe©–dNdAèáæAærdìI&ZÑ¥\dCL J,‰ ¢×©Ftæ1Biv?`@ íž¹"žd2Jgf@ÒéFÆZaÈgÏž¥Æ;$WË&›kñÜœ (€„OM3'iCEÑRŽSDTJ‹±nwVˆ€Ì ˆ"S$¸Lä–; Ò¯‚öEm\EHƒ‰ †cþKpà4”`“\˜\_ cEÍd]¯Ê¥TsU– É&?àðX ¬ÔöÈÝ%µZ¤ô^³é @E–fý ÄVoÊ*èæµ©"Z¦2…ª³h¤1ñ@ælÌTw—(Ñ“k÷Œ;ZÆLV5a+»b äO°x6VþQ'„ç ÞŒ$»Ü`³D»{”}xb£vã+“=aòô2£ò6Ù1GÅr6À’ ø_ˆm§Ž*cŽiAy·&;09g®ËãZsN[GƒàW5R®g”êTyd6…â®J6vK‡ æwðî£úÞîD•˜ £]8:K„? ë&8d¢Ü¨^*sü]y–]ªK‚Äæm¬…ñ†âV¦„l·r­yÖ¤H–©jÑÃkUk@sk™^/òr;Ëg42« BRˆ†Ø¯mEbÑ¥…ˆ°ª‹…)Œõp(8Dy´™Z·‰eµ-c­ìEEƃEÎü©1ÙȈí Åרår Õª— #ȋȗpvÖˆ BKfê³ú8ÕøH³H—]ÙÅZ§ùnˆÕˆ` ˜Œ/àŒ5eH½[Öø]¸¨)uЕ”‘*ñyÚFÒÄ¡÷'ž" žv®®Ñ©ŸõŽÙøË¬±O•Ö„µ-d‚– :QW„ÀƒˆÛoé"Ä£oh—lš°ÐŠäÀ¼Ùcǘä¤\jKd8Í/ÈKˆàˆý¥Ï°HZêÛ•—#¦EñYd=ñfe¸æ“îZ«s –b÷ª[·ÇZÆÇ‹ÊB‰(Ö¤5s4VÔØºpý`ÏMJC¶›oøæ¦wœã3«Âã¬óÊѬ©r×úÑžºÕk9Ùºö»Y™úÃCC®C!]šë"£D¨½nXš]úEZ<[Eg‰¸ìØ‚w@yš$\d¢ªTƒ›öàZÝ(%ƒ›‰Çƒ%µ†ð1¥êÎzÑÔù÷=ØòµY1b¤ÙHp†»¦Ä†‚–í=.…ˆˆ0OtÄ“uUΥݔ:Ca£+й%‘Æì»}Åã—6ÄtV6}„aäGsžktF _лqÙX·Ù_Þ1f[¥ªýµ¼Žµ½¾+RµecŒ\¶ΈI(þPDõã(J˜¦Þ*Ìø|Ù¼V5ÿÅÎf™~à—â?å4Zwz)gøPœà–öÃ5$¨Dhgc§†ºCÙ«¥m%>V(l¥5«¾ èº6…¨¸Rä“î‘Áƒs²$Oq;0µý:VÝÆÈŒçè^µž¡í OÔ¯eqgÁM¤E×p|)xoݬB èÎgªÞüIÈ¢…bn¬Š¹¾©´€#R7"Å)hà0­šó…ZÙC±<˜…޳âº.˜««+¹B)δlîÎÎRØŠ±LrÙ­Rê#¬RdÚ”ãFÖ ¯ÚÍ¥Àf‚³,PÇGÁK,L5F…Ö•PP1 AšGPÎÌ;„¶2L” )25a¤á@ž¸)š^ŒÖ:R×o]¦W©ciHËô’ÜÖì¬4Œtû'<†T…_P1êºôJz»q¼(–Ⱥ½QDÑ%¬­§#pë"‘¢rÈÞ3ŽR½7= ¨A€L8=‚Ž£$攢H¢=:½NÐØ?˜àÜ3À–~ ZP…7uB«B¥B† •² LýVü%òkqh­{w’7ÈÛ÷ DÃTÅ MxÜ4Ž#«Š¿iš+^×ImŠ?'®ˆXÓ KÀP)Ù¡@ò7>ꆶ¹<ëf'jK“XMÌ|à×ÎL>¡_Iã Ò¾2ÓŒ½ä«†!s{Q¬þæ³®l£X¹ ;ýá8ûhŒ6ŒvçŠ kª*¢î@ÄÃôhXÅtÁ@ÐöýchÌõ<숂â,V&8 ã“”Ï! `Äй dœò1G'ÞZ¤2Å6kªYÄÞ Eäд[¸²XmÍŒÅ|V[X‘,²óLƒ/Öƒ ÎR Ï®_ž ÔÄèlèÈ)³ ©­P¸ŒÁŠìhv£5ØÿS$dªÿAአ¤µ’lÙH ¯Ü4Á”FO, IaM´HTÚÈyr6ê„`f‰S Å Ça!±Öe “¬ A©W(Ô6ˆnÍÎÃg€ ›pZnAœTî<0Âc> a­Ý‚BoË’X(­yY'å°›R tñ…²2’F–1E#@½¢,Èd—¬M‡ (‚àp !ô=r7 ©Ú Ì”âÁÞÔ5‰ÅšÅÀ ÜxvfI¬+ÖùÁIraŒ8ü!’ qÌB° fæJÓ«‹«ZMˆI‘’†º °l@F¾Y¸ƒ)y³%È⥂ú^ÛÓüŽ:W­rúà“.4$¡Ÿ†€“ÉùA(e4¤¢˜QŠyQ*eUí(¶pV" ‘,˜:†ä¶[Xâ'Šð+òØz¦}Ķz—ôŠ,ÃH'öÁYQ p(­–ͺ!=Iz¼‚kIu ‰è¾Pí% !„@6 •)|M‡•’ÔL“sÙ*åÆx:²uE™;)=Ç¡‚’ Q’¢û/!È4¤*ÉÉ…D%¡ÊÆ =P«·-4 •Ñ ¢oÏCz<Œ€–¤8½TõYá¬O*:zz24ÀHÉ1'HšH#hŽCõ-X‰äì`»Ù@- c$¿?ŠBãlM ˆ³¿ô:Ÿ óÏYèN¦Ö’'™­EfLNÔ4÷Ѽ spÉœ³Ücæ¸d`ÐüEBúÒ é’™ Ue-“^ZÒS06._<)bŽÃòBf¢i“Ê™h¦‰ykºeÊvÀ°m³g>áPùa*.»d¨JR²ãY1!yf6f&ÎÒãg”jGE™`¡’ZJà”)PÏ›“"Ñ©).ææö´Ž‡Ob n$˜¹O2xæh!reu½K#”Fˆö§8*¹kì”ÈÕõBJ„‚À–Œ È)÷«óà‚mˆîà-kÆäŠÞ)ØWS†Š+â°S¢Z‚m•QªåººQ@Rudåí>;@¸ Êp#U ÞQ¶(ñî?bæ½f4bòÚO X €¦Ú ÈÏ­ŽºI‘)9 R€C¡ª5ªFc :Èß³²"˜$ÚXe¦`±pTÉJ%ÇR{ 2ár¯&{׉WÖr²%î¥ëÎó†…âJHÜÞ'TKMÔ)е¥ÚÓÑduÔºåNØ U˜œ ì#Y;  k=SŠfJÌžÍLdež–(Ú=bØñ‚·Ã «“¥[Yô¦’—”O‹•@@ÁÕ–“g0zÏSVc–”òPê(B¨µ•#Ö]™j•ÞÎW¬Q-ÔçI–Êhïé´=š]h¼œÈÓ¡¥ZQ1š=´ÈvDì“ ×Ì I§ÅÔ'éÔ¬u´~œ3æ[‹¥4^¼ÒŽÜ” ¼pb¡Ž©(ÓŒ¥”Ø‚ âlê{¥`ì¸Â° $â7“ñk¤ðÊŠ]Ë‚æk¬¢–ÈÐÉäu†(ÇôSØ5Qtž~廾]yÊŽ5špך£^g˯EêýEÕ®Ã?ÔÜ®‰Iüü˜óڢыí—=;¥b$»;!ˆ5ëI+^ßÛÌquÔI=Št3SÓ臭E'‘Îb ÎçS5Å«ÎHÓ6¨Õ±Ùä½ d‰<%<³øTB¤4‡‚€’Ÿ'ÊPK4Œ<* ¯e9yÄð·æSrwÖ~hlèú‹DéR¥ O™ÙàëâØ”±Õ¼VlêVÔoéA¡yÇ\ á+.j".©Jáú\qM?Ñ0ó2iÊï•wa3Z ˆbZ§²è½¬×—ærŸ†wé-! ÖßÈÅ¢$Þ·U´A†\ Óß΃rŠÂ¤ÉB»—”i:ªà‰¨9Q>=H…½s5 …=‚6©…(Ú¸ €Ž)¶âš« ²ó`S„ë…¶«–ª¡3j™j½‰¬’ÁA”³‘Þ‹z”0SÒ@8)ႵȶÂkÍ‚I' Žsr¢w"k6­Ó©4A·.q¶P9RU(–™yµºc.²ú».¾“ü(€26¤“  A›¢*¤5­B(Iƒ¼ ’ ÑÇD{ô’£þ·ÿÈK©œ6J{‘Ch KiIIÌ’ ¬Š¯ô˜:£ÈÈ32‚ˆ)¹LÇ[)Ëo(ñ*5”š‰uªá,¼Œ¦›Ê ²G$'’ËÏŠ˜³»R€±â·˜i‡–™/HÊa§¬òQ§Bôµ7@Ò Ë1pš¡’ð̈Ñ)5—òzô„' š¾DƤè1³ jŒúF1¼Õ¿ ¹‘ìÓ)£ c{‡ƒÜ»ˆ3 tÕ#C£3¡+MhÑã DÕÑÊM3Q&M4Ý7MÀ¹ ÑÖ5<* ­=j»”ß*ôè’4îžQkš2[­ÔØÀì¶€RŠ\+P$ ¥ÃìøÀ¥Âä/"˜ž”\1ŠÁ—²NP/–da%ðƒÐ@7M£_F ”ÊÆX2(˜2Ìõ!œ<¢@Ãü>Ãø¢K–ÏÈ"˜Ä1íD@êR™py,$¦m#ª¯ÆU&S œé 9öªî y ‘‹©¾/lNÜTÈô\QÜQ °”"êád`ˆPÌÅAj‹«Et<ø%'(§<*tœRñ¾ó #7)(ºÎJ8hü‰ß‰°84¹ÝÓc¦Sz~¸Š+%Æ`ÿ8’胫?]8cê.¤qÔ³Ù#R DR Ý¢À…ˆpÅ4Øõ´,J·£H¡ÙtÎMÍ®Qg½ªÇ[Y§ôǵ´È’¤É’élNÄÃÂE´*]H@k´ÈþÉèú½àÅ£Ke‘`‰ »CÕBÄ(rúÏ25œ«u¹×4‚89ºÙÔƒe8¦7›ã|¹å ´¹6,c£'ÁySc@}e6Uó)Pôd+:åš¶&’?³ó:‰€64ŸjäÁÞÑŽJ…ûé/CÒÈÚÆ«³f’ß™!“ã¼$”F 3×A’‰Wa#W¤Ä +,‰(ZX9Y™×SkŠc7Ù×;Ƚ•‚×ÑÙUeAÔ¹j3ìoÓõ\]h\yÞBNŸQiãágËõT*9É|¤6u%ø·J‰µ®a Ö™bµ´áD³Í3܉†G½Û=uÙ¦Jä¾L‘_æRZŒÚ̧z(ˈˆÎBÈ Ý&vÖVE¿ä Æ„=f6VO½“Ú {¦'먼uÈ꽋Ñ$+½H(ÜÝ*“Z“k´Xì"<ÙÖ;eTä&<ÖˆYýˆØåð¢üYe&\ˆ(* €€ endstream endobj 86 0 obj << /ProcSet [/PDF /Text ] /Font << /F3 23 0 R /F7 25 0 R /F8 26 0 R /F9 87 0 R >> /ExtGState << /GS1 27 0 R >> >> endobj 89 0 obj << /D [88 0 R /XYZ null 747 null] >> endobj 90 0 obj << /D [88 0 R /XYZ null 710 null] >> endobj 91 0 obj << /D [88 0 R /XYZ null 666 null] >> endobj 92 0 obj << /D [88 0 R /XYZ null 651 null] >> endobj 93 0 obj << /D [88 0 R /XYZ null 615 null] >> endobj 94 0 obj << /D [88 0 R /XYZ null 745 null] >> endobj 95 0 obj << /D [88 0 R /XYZ null 730 null] >> endobj 96 0 obj << /D [88 0 R /XYZ null 706 null] >> endobj 97 0 obj << /D [88 0 R /XYZ null 669 null] >> endobj 98 0 obj << /D [88 0 R /XYZ null 645 null] >> endobj 99 0 obj << /D [88 0 R /XYZ null 621 null] >> endobj 100 0 obj << /D [88 0 R /XYZ null 597 null] >> endobj 101 0 obj << /D [88 0 R /XYZ null 547 null] >> endobj 102 0 obj << /D [88 0 R /XYZ null 536 null] >> endobj 103 0 obj << /D [88 0 R /XYZ null 524 null] >> endobj 104 0 obj << /D [88 0 R /XYZ null 513 null] >> endobj 105 0 obj << /D [88 0 R /XYZ null 502 null] >> endobj 106 0 obj << /D [88 0 R /XYZ null 490 null] >> endobj 107 0 obj << /D [88 0 R /XYZ null 479 null] >> endobj 108 0 obj << /D [88 0 R /XYZ null 468 null] >> endobj 109 0 obj << /D [88 0 R /XYZ null 457 null] >> endobj 110 0 obj << /D [88 0 R /XYZ null 447 null] >> endobj 111 0 obj << /D [88 0 R /XYZ null 436 null] >> endobj 112 0 obj << /D [88 0 R /XYZ null 424 null] >> endobj 113 0 obj << /D [88 0 R /XYZ null 413 null] >> endobj 114 0 obj << /D [88 0 R /XYZ null 402 null] >> endobj 115 0 obj << /D [88 0 R /XYZ null 391 null] >> endobj 116 0 obj << /D [88 0 R /XYZ null 381 null] >> endobj 117 0 obj << /D [88 0 R /XYZ null 370 null] >> endobj 118 0 obj << /D [88 0 R /XYZ null 358 null] >> endobj 119 0 obj << /D [88 0 R /XYZ null 347 null] >> endobj 120 0 obj << /D [88 0 R /XYZ null 336 null] >> endobj 121 0 obj << /D [88 0 R /XYZ null 325 null] >> endobj 122 0 obj << /D [88 0 R /XYZ null 315 null] >> endobj 123 0 obj << /D [88 0 R /XYZ null 304 null] >> endobj 124 0 obj << /D [88 0 R /XYZ null 292 null] >> endobj 125 0 obj << /D [88 0 R /XYZ null 281 null] >> endobj 126 0 obj << /D [88 0 R /XYZ null 270 null] >> endobj 127 0 obj << /D [88 0 R /XYZ null 259 null] >> endobj 128 0 obj << /D [88 0 R /XYZ null 249 null] >> endobj 129 0 obj << /D [88 0 R /XYZ null 238 null] >> endobj 130 0 obj << /D [88 0 R /XYZ null 226 null] >> endobj 131 0 obj << /D [88 0 R /XYZ null 215 null] >> endobj 132 0 obj << /D [88 0 R /XYZ null 204 null] >> endobj 133 0 obj << /D [88 0 R /XYZ null 193 null] >> endobj 134 0 obj << /D [88 0 R /XYZ null 183 null] >> endobj 135 0 obj << /D [88 0 R /XYZ null 172 null] >> endobj 136 0 obj << /D [88 0 R /XYZ null 160 null] >> endobj 137 0 obj << /D [88 0 R /XYZ null 149 null] >> endobj 138 0 obj << /D [88 0 R /XYZ null 138 null] >> endobj 139 0 obj << /D [88 0 R /XYZ null 127 null] >> endobj 140 0 obj << /D [88 0 R /XYZ null 117 null] >> endobj 141 0 obj << /D [88 0 R /XYZ null null null] >> endobj 142 0 obj << /D [88 0 R /XYZ null null null] >> endobj 84 0 obj << /P 62 0 R /R [45 63 567 729] /V 59 0 R /N 143 0 R >> endobj 159 0 obj << /Length 4151 /Filter /LZWDecode >> stream €Š€ÐP¼Œ7 DC4r. ˜‚ ‡á¤Hn1‹†P³l)'ŒðB`@/#”áFs˜€ŠX“ †PÇ9 г¼¶(+ŠF# Ê)Å B¤r)Ôª‚ 2Š*£‘² 3éCA¼R0©™…#!À Óg®ã*m¨cl4[îÆã8€êpªUªdÚ­DPc®TëöÎán¸©øáêd½ÓMõám‚ís¦›j ÂÍ|­ãµT½HÝs­,u!h¤ºT%A£àØgáȆ#‘¬,‰9²B ”PUé¨Ó‹móp²•uÄã¶ã*Ñ“ÃW¬Öì•=vîózìaÃ]ØÍÔ¾»[Î ®Ø1ª“þ¦®îÒÚñ«KS†­2Üò@;7 "9 #xê¿-îØ£;Bþ·î*J–…§àPZ'Kˆ£R…‚”­ +ZÒïªpR¤:…!šØ1°*è¿<´n mZà*Fë@\ß8#ˆ8ÎC‰##îtTʼnËÈÆnª¥ C6*kê¬,*xbð1³ƒ^´/Í”©²¼>®Ã$í9…+Òñ¬,,ò ‹šÂÐ0”’¦6-Áªà;…£bž)°£M7…Ü‚¥)¬8à7«”p:A°z¬D®·.„Hdå¹¢£žF Ú{Ø*Ò£ŒM{E@ªC]‰!xžÒ4ÐÚÁZ‹ 8UP­YX@!@àÁ\p€Ø4Ù³kC0Dªc¸ÐüÂ/L쮲aE¬À®£Ïn4ÃG|ÄpPc ÷¥ÜÞÖ±Œ¤m$…Ç0PFÍ\Â,!2$2šÔJ?nä!¥7·àŸH‘ƒc˜DeŽ1½b1†äÓR6NÁ”ÐÊW¡ó¨/åˆ1¢0ܵƒxs00ùÜ—4pÍ™]¦E°Æ·}Qdªbê$¸æîßèªZÀÙȇàÄ¢²¿û#FW޹p:îÍq)Yy‚­5‘HÀúȃ)f¬½qÖGÌ÷@.1°ú–W…=^s>‡Á¾-ր‘+b°u¦‰ÏF÷*¬kT Þ)¸ÊºãßÊÇÑEMõZV©Ì. ÒK“²V¬ùN r•9^g剣•èè´™{1I…ÂØí ¼vñþ= dªSú¦Öö㕲á#˜É6[âë1Ñ3ì²/Â(¶~ã)%¤ïîjš ÜñK {œ¤“Ë6êo}3¡pÊs¼ ^zXžA¨7¢M2êÄS«`ÂË”z¾€õx\e³•*Ò\+\>5PÖ¼@ÜÙ0•Šneb¹ «\« tà ̷V@Û„K(i Uà9W²¯ë%Œ‰¤Š_ä]vÅVKjíÉ]òtãb½[Wvh*/0@j‹ªD†™– í¦48R¡qdpR]jB#®VtØ'“QúÕ*†§c;ùcª•TÇ8Õ“„±p*ï‡ËñkÖJ eì‚°O4¸W*Ž«>xŒ§)Èq@(Ñ*²Ë Uñ]sÆ 6؆Œ~†ÐUÖ´_¢ 3F7ªwoÙHáeœvBHÐ'Çð¦ÕÈ Õ¥J”é|èC¬¾<ÖÍ"ËlË~ïìõÇê6`á€ìºÁ¤4 £‚Ñ Pœ*@ëD‚û‡Y¸wЕҼVM ±,>×8WBN ñ‰ôñoGQf­‰dñê*¼1Rñ£@ «%=c,5 n,©˜2{Ïx2œ7†£ñÀWÖcÿOæ}Ù°æ[íÀYƒ`~X°Uf¯<h›†¦ëÆÚÏe§rèõ¹¡.šHz$?rd7^F‰Ux³h+^=d xÊý´œlEÈ‘(è Q«%A‘l/¬4iCÂÛ:åj$# …\Ò@‘=V@’ Ž ®}¦jÚS0½WYé„Å…"BsVT‘Bèá–° `of†)Ú•¨¶Ž;ú4kŒ©/~ÐT‹54Xqð6⦩·oHVD†õ"ãýrc!Ó¸˜#n’¯Ÿ• |!šCÇ‘ôžN§ê.J(¹#ÆÀfOZîÈqÄSf€G¦ ~ÒМÍÓÀE‡*.Û†2ñ`EºH¥Ü™ªü£ûúñðtoÃR®‚-¤[på`Å̘|Êóó¾„k<žÞ)”p^ «Á ¯ÓL¢àô¸iÏÅ•è/¸P ðì(nÑ£ÿêÚ‡§hm&6ÎF Âg¾g´oöòÿ°e,¥êðÞîh¯<­0`jí)¡¨| ­àÆ-ÒEhnj .j]âø`Ý" /íBʦkbÙPx™Îm †ü`Ù Äü`Æ¢ZÝ|qŒ…o¨¹PÀÞÓ̯Tø¾ƒ ðO´ ÌA0ád&¯Ï ű Í ŠÈ´€„¯ë /®êÈáŒné&¶#OÔ "{ ç¡/ãjÉQKÎæ ‡ÀÝÇ S¯b»‰,äɦ¬€ ÿàå-€ÍKî§Žè¨à¨ÓÚÿðe.L1Ý䨬ƒèÛ©¶¯¸æ•ôßͺ0PÖÂàüjÂ]Jx¾^aïxE P`R €Ô Ž“ļ$Q âf"Î Í ß Pç*ȧ¡ 19 Éã¨}ïªðí±HÜQM@w¤iðÝPÀø@zЯÔ¯ÏÍÑ¥Pµ iˆ} Êñ » qúa¯¢8‡Ýâ€Ùg÷ çJþ¬‹F—q) nj›d0¯ÎâÀé%Cm%’6‰²;OØÔë4ÜjÈç(|w»ò$_G  2nDÐ`M@Ó³(ðMìC"ÒQü§€z¯³jÈ Àª¯˜ ã‘f,Bû@åÂ&¯’8Q®öñ²ýr@MOÞþ ¥qŽÂ°ãÝ%âÒ-Ä0QM¬X0QR+¯¾f®GízÉÇqÛп%ô¯Ç tLC/Ñ00.­È|@]nyΔ<‘ 'l|)Žœ³˜bqþtnÎgp°½oî 2²‡Àaªx xt`Í6ÀÂ5PRx¢¥'GgGs„•CЇÑû7 Vt`Vkêa²—ëþ¥£qªBC6/ÔmÒæ÷H®ÙSdMP*º±92h?£íEaÂú󪬀W±§’ ¯ÞœoþVŠ‘E=¯Æ® *¦[#c=±…?¯0¬ðÄŰQs8§‡G3Íû4/0ŠÈ+ágG!Î:ý%umN³,ƒ=K5%ò‚§d–òk9§G A>Âö6Óª‡Ó÷@Ù'"øÈrx÷±É9£þ*@WGâ»7oJ,³  Fth>€GV@TUK´dêÔhá(|G¢à*@e0â§N7,Ñ4ë Qb®Õùˆ}(²¤¬2“3òY4Ö¨™ô.Œ¯Ã!l¬or’ ¯:¯–¯awWaâŽ×m0Ïâzav—-?÷1WÀPªãŒ[ÖCÒðí yCÌ•JÕ<63GxQ$÷E¤m¯”º®jº°ÖÂc³8¬€Üû@Û$‡lYz6'HV4ž´Œ/–S$3^(àÚ‡h}çG 4:’ãtpœÌÕ† £ b ·÷6  Ó$‡Ò½,ŶÄ*U¶¢)p§<®%lö¯nÄüuꬖo ÏoQ`ñ“_ƒ_×”¾•·HÕÎÞØJ¯Ïþ ¯¿)ç*¬•4.³7ƒˆ¢»ƒtÛyW‘ ” w¼ð¯¾A°Ýãˆ8r"ÒÿéÁ2—¢ÚìçP—]4SBÌê‡Ã!Œ‚Ó(mJóuµwÄs‡lBüÀá„× ÿó‹!5iõix•[v+ŽvÒ2­üÀæÿøVÛ¶ò½x_¸¬®ØfÜøkV7SŠÈ ño MÎø8]9-Ž$ii%õZï㉗fy[øGYH¯Y•œ@Š ` endstream endobj 160 0 obj << /ProcSet [/PDF /Text ] /Font << /F3 23 0 R /F7 25 0 R /F8 26 0 R /F11 161 0 R >> /ExtGState << /GS1 27 0 R >> >> endobj 162 0 obj << /Type /Halftone /HalftoneType 1 /HalftoneName (Default) /Frequency 60 /Angle 45 /SpotFunction /Round >> endobj 27 0 obj << /Type /ExtGState /SA false /OP false /HT /Default >> endobj 23 0 obj << /Type /Font /Subtype /Type1 /Name /F3 /Encoding 163 0 R /BaseFont /Times-Bold >> endobj 24 0 obj << /Type /Font /Subtype /Type1 /Name /F5 /Encoding 163 0 R /BaseFont /Times-Italic >> endobj 25 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /Encoding 163 0 R /BaseFont /Times-Roman >> endobj 26 0 obj << /Type /Font /Subtype /Type1 /Name /F8 /Encoding 163 0 R /BaseFont /Courier >> endobj 87 0 obj << /Type /Font /Subtype /Type1 /Name /F9 /BaseFont /Symbol >> endobj 161 0 obj << /Type /Font /Subtype /Type1 /Name /F11 /Encoding 163 0 R /BaseFont /Courier-Bold >> endobj 163 0 obj << /Type /Encoding /Differences [ 0/grave/acute/circumflex/tilde/macron/breve/dotaccent/dieresis /ring/cedilla/hungarumlaut/ogonek/caron/dotlessi/bullet/bullet /bullet/bullet/bullet/bullet/bullet/bullet/bullet/bullet /bullet/bullet/bullet/bullet/bullet/bullet/bullet/bullet 39/quotesingle 96/grave 130/quotesinglbase/florin/quotedblbase/ellipsis/dagger/daggerdbl /circumflex/perthousand/Scaron/guilsinglleft/OE 145/quoteleft/quoteright/quotedblleft /quotedblright/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright /oe 159/Ydieresis/space 164/currency 166/brokenbar 168/dieresis/copyright/ordfeminine 172/logicalnot/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior /acute/mu 183/periodcentered/cedilla/onesuperior/ordmasculine 188/onequarter/onehalf /threequarters 192/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE /Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex /Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis /multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn /germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae /ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex /idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis /divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn /ydieresis ] >> endobj 1 0 obj << /Type /Page /Parent 28 0 R /Resources 22 0 R /Contents 21 0 R /CropBox [0 0 612 791] /B [20 0 R] >> endobj 29 0 obj << /Type /Page /Parent 28 0 R /Resources 61 0 R /Contents 60 0 R /CropBox [0 0 612 791] /B [59 0 R] >> endobj 62 0 obj << /Type /Page /Parent 28 0 R /Resources 86 0 R /Contents 85 0 R /CropBox [0 0 612 791] /B [84 0 R] >> endobj 88 0 obj << /Type /Page /Parent 28 0 R /Resources 160 0 R /Contents 159 0 R /CropBox [0 0 612 791] /B [143 0 R] >> endobj 28 0 obj << /Type /Pages /Kids [1 0 R 29 0 R 62 0 R 88 0 R] /Count 4 /MediaBox [0 0 612 792] >> endobj 164 0 obj << /Count 15 /First 144 0 R /Last 155 0 R >> endobj 144 0 obj << /Title (1. Introduction) /Dest [1 0 R /XYZ null 407 null] /Parent 164 0 R /Next 145 0 R >> endobj 145 0 obj << /Title (2. The PortAudio Architecture) /Dest [1 0 R /XYZ null 400 null] /Parent 164 0 R /Prev 144 0 R /Next 146 0 R >> endobj 146 0 obj << /Title (3. API Overview) /Dest [1 0 R /XYZ null 147 null] /Parent 164 0 R /Prev 145 0 R /Next 147 0 R >> endobj 147 0 obj << /Title (3.1. Initialisation and Device Enumeration) /Dest [29 0 R /XYZ null 641 null] /Parent 164 0 R /Prev 146 0 R /Next 148 0 R >> endobj 148 0 obj << /Title (3.2. Stream Management) /Dest [29 0 R /XYZ null 452 null] /Parent 164 0 R /Prev 147 0 R /Next 149 0 R >> endobj 149 0 obj << /Title (3.3. Error Handling) /Dest [29 0 R /XYZ null 469 null] /Parent 164 0 R /Prev 148 0 R /Next 152 0 R /First 150 0 R /Last 151 0 R /Count 2 >> endobj 150 0 obj << /Title (4. Existing Implementations) /Dest [29 0 R /XYZ null 388 null] /Parent 149 0 R /Next 151 0 R >> endobj 151 0 obj << /Title (5. Design Considerations) /Dest [62 0 R /XYZ null 434 null] /Parent 149 0 R /Prev 150 0 R >> endobj 152 0 obj << /Title (5.1. Requirements) /Dest [62 0 R /XYZ null 378 null] /Parent 164 0 R /Prev 149 0 R /Next 153 0 R >> endobj 153 0 obj << /Title (5.2. Concurrency) /Dest [62 0 R /XYZ null 141 null] /Parent 164 0 R /Prev 152 0 R /Next 154 0 R >> endobj 154 0 obj << /Title (5.3. Callbacks versus Blocking I/O) /Dest [62 0 R /XYZ null 593 null] /Parent 164 0 R /Prev 153 0 R /Next 155 0 R >> endobj 155 0 obj << /Title (5.4. Latency) /Dest [62 0 R /XYZ null 393 null] /Parent 164 0 R /Prev 154 0 R /First 156 0 R /Last 158 0 R /Count 3 >> endobj 156 0 obj << /Title (6. Future Work) /Dest [62 0 R /XYZ null 216 null] /Parent 155 0 R /Next 157 0 R >> endobj 157 0 obj << /Title (7. References) /Dest [88 0 R /XYZ null 675 null] /Parent 155 0 R /Prev 156 0 R /Next 158 0 R >> endobj 158 0 obj << /Title (8. Links) /Dest [88 0 R /XYZ null 754 null] /Parent 155 0 R /Prev 157 0 R >> endobj 143 0 obj << /P 88 0 R /R [45 526 567 729] /V 84 0 R /N 20 0 R >> endobj 20 0 obj << /T 19 0 R /P 1 0 R /R [45 63 567 729] /V 143 0 R /N 59 0 R >> endobj 165 0 obj [ 19 0 R ] endobj 166 0 obj << /F 18 0 R /G100 13 0 R /G1000 10 0 R /G102 14 0 R /G104 15 0 R /G1057 68 0 R /G106 31 0 R /G1061 73 0 R /G1065 76 0 R /G1071 79 0 R /G1075 89 0 R /G108 32 0 R /G110 33 0 R /G1113 57 0 R /G1133 70 0 R /G1147 82 0 R /G1161 98 0 R /G1162 99 0 R /G138 34 0 R /G140 35 0 R /G142 36 0 R /G144 37 0 R /G146 38 0 R /G148 39 0 R /G150 40 0 R /G152 41 0 R /G1520 101 0 R /G1527 105 0 R /G1528 106 0 R /G1530 107 0 R /G1531 108 0 R /G1532 109 0 R /G1533 110 0 R /G1534 111 0 R /G1536 112 0 R /G1537 113 0 R /G1538 114 0 R /G1539 115 0 R /G1540 116 0 R /G1541 117 0 R /G1542 118 0 R /G1543 119 0 R /G1544 120 0 R /G1545 121 0 R /G1546 122 0 R /G1548 124 0 R /G1549 125 0 R /G1550 126 0 R /G1551 127 0 R /G1552 128 0 R /G1553 129 0 R /G1554 130 0 R /G1556 131 0 R /G1557 132 0 R /G1558 133 0 R /G1559 134 0 R /G156 42 0 R /G1560 135 0 R /G1561 136 0 R /G1562 137 0 R /G1563 138 0 R /G1564 139 0 R /G1565 140 0 R /G158 43 0 R /G160 44 0 R /G162 45 0 R /G164 46 0 R /G166 47 0 R /G170 48 0 R /G172 49 0 R /G1737 100 0 R /G1738 103 0 R /G174 50 0 R /G1751 102 0 R /G176 51 0 R /G178 52 0 R /G180 53 0 R /G182 54 0 R /G184 55 0 R /G186 56 0 R /G190 63 0 R /G192 64 0 R /G194 65 0 R /G196 66 0 R /G198 67 0 R /G200 69 0 R /G2005 30 0 R /G204 71 0 R /G206 72 0 R /G208 74 0 R /G210 75 0 R /G214 77 0 R /G218 81 0 R /G2181 92 0 R /G2192 94 0 R /G2200 93 0 R /G222 90 0 R /G228 91 0 R /G230 95 0 R /G2426 104 0 R /G2427 123 0 R /G2446 78 0 R /G2525 96 0 R /G2534 97 0 R /G64 2 0 R /G76 3 0 R /G78 4 0 R /G84 5 0 R /G855 80 0 R /G88 6 0 R /G90 8 0 R /G92 9 0 R /G96 11 0 R /G98 12 0 R /G989 7 0 R /L 142 0 R /P.1 17 0 R /P.2 58 0 R /P.3 83 0 R /P.4 141 0 R >> endobj 167 0 obj << /Type /Catalog /Pages 28 0 R /Outlines 164 0 R /Threads 165 0 R /Dests 166 0 R /OpenAction [1 0 R /XYZ null null null] /PageMode /UseOutlines >> endobj xref 0 168 0000000000 65535 f 0000042483 00000 n 0000000017 00000 n 0000000072 00000 n 0000000128 00000 n 0000000184 00000 n 0000000240 00000 n 0000000296 00000 n 0000000352 00000 n 0000000408 00000 n 0000000464 00000 n 0000000521 00000 n 0000000578 00000 n 0000000635 00000 n 0000000692 00000 n 0000000749 00000 n 0000000806 00000 n 0000001092 00000 n 0000001150 00000 n 0000001208 00000 n 0000045358 00000 n 0000001276 00000 n 0000009283 00000 n 0000040472 00000 n 0000040581 00000 n 0000040692 00000 n 0000040802 00000 n 0000040392 00000 n 0000043001 00000 n 0000042611 00000 n 0000009427 00000 n 0000009485 00000 n 0000009543 00000 n 0000009601 00000 n 0000009659 00000 n 0000009717 00000 n 0000009775 00000 n 0000009833 00000 n 0000009891 00000 n 0000009949 00000 n 0000010007 00000 n 0000010065 00000 n 0000010123 00000 n 0000010181 00000 n 0000010239 00000 n 0000010297 00000 n 0000010355 00000 n 0000010413 00000 n 0000010471 00000 n 0000010529 00000 n 0000010587 00000 n 0000010645 00000 n 0000010703 00000 n 0000010761 00000 n 0000010819 00000 n 0000010877 00000 n 0000010935 00000 n 0000010993 00000 n 0000011051 00000 n 0000022536 00000 n 0000011110 00000 n 0000021185 00000 n 0000042740 00000 n 0000021317 00000 n 0000021375 00000 n 0000021433 00000 n 0000021491 00000 n 0000021549 00000 n 0000021607 00000 n 0000021665 00000 n 0000021723 00000 n 0000021781 00000 n 0000021839 00000 n 0000021897 00000 n 0000021955 00000 n 0000022013 00000 n 0000022071 00000 n 0000022129 00000 n 0000022187 00000 n 0000022245 00000 n 0000022303 00000 n 0000022361 00000 n 0000022419 00000 n 0000022477 00000 n 0000035800 00000 n 0000022615 00000 n 0000032479 00000 n 0000040908 00000 n 0000042869 00000 n 0000032623 00000 n 0000032681 00000 n 0000032739 00000 n 0000032797 00000 n 0000032855 00000 n 0000032913 00000 n 0000032971 00000 n 0000033029 00000 n 0000033087 00000 n 0000033145 00000 n 0000033203 00000 n 0000033261 00000 n 0000033320 00000 n 0000033379 00000 n 0000033438 00000 n 0000033497 00000 n 0000033556 00000 n 0000033615 00000 n 0000033674 00000 n 0000033733 00000 n 0000033792 00000 n 0000033851 00000 n 0000033910 00000 n 0000033969 00000 n 0000034028 00000 n 0000034087 00000 n 0000034146 00000 n 0000034205 00000 n 0000034264 00000 n 0000034323 00000 n 0000034382 00000 n 0000034441 00000 n 0000034500 00000 n 0000034559 00000 n 0000034618 00000 n 0000034677 00000 n 0000034736 00000 n 0000034795 00000 n 0000034854 00000 n 0000034913 00000 n 0000034972 00000 n 0000035031 00000 n 0000035090 00000 n 0000035149 00000 n 0000035208 00000 n 0000035267 00000 n 0000035326 00000 n 0000035385 00000 n 0000035444 00000 n 0000035503 00000 n 0000035562 00000 n 0000035621 00000 n 0000035680 00000 n 0000035740 00000 n 0000045277 00000 n 0000043181 00000 n 0000043300 00000 n 0000043448 00000 n 0000043582 00000 n 0000043744 00000 n 0000043886 00000 n 0000044066 00000 n 0000044198 00000 n 0000044327 00000 n 0000044464 00000 n 0000044600 00000 n 0000044754 00000 n 0000044912 00000 n 0000045031 00000 n 0000045164 00000 n 0000035880 00000 n 0000040111 00000 n 0000040994 00000 n 0000040258 00000 n 0000041107 00000 n 0000043112 00000 n 0000045448 00000 n 0000045479 00000 n 0000047261 00000 n trailer << /Size 168 /Root 167 0 R /Info 16 0 R /ID [<4be34e0059e36b8c4193c56f6241a211><4be34e0059e36b8c4193c56f6241a211>] >> startxref 47437 %%EOF portaudio-18.1.orig/docs/pa_tut_run.html0000644000175000017500000000456107465451052021152 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    Starting and Stopping a Stream

    The stream will not start running until you call Pa_StartStream(). Then it will start calling your callback function to perform the audio processing.
    err = Pa_StartStream( stream );
    if( err != paNoError ) goto error;
    At this point, audio is being generated. You can communicate to your callback routine through the data structure you passed in on the open call, or through global variables, or using other interprocess communication techniques. Please be aware that your callback function may be called at interrupt time when your foreground process is least expecting it. So avoid sharing complex data structures that are easily corrupted like double linked lists.

    In many of the tests we simply sleep for a few seconds so we can hear the sound. This is easy to do with Pa_Sleep() which will sleep for some number of milliseconds. Do not rely on this function for accurate scheduling. it is mostly for writing examples.

    /* Sleep for several seconds. */
    Pa_Sleep(NUM_SECONDS*1000);
    When you are through, you can stop the stream from the foreground.
    err = Pa_StopStream( stream );
    if( err != paNoError ) goto error;
    You can also stop the stream by returning 1 from your custom callback function.
    home | contents | previousnext portaudio-18.1.orig/docs/pa_tut_pc.html0000644000175000017500000000746007550766354020762 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    Compiling for Windows (WMME or DirectSound)

    To compile PortAudio for Windows, you can choose between three options: Some advantages of using DirectSound are that DirectSound may have lower latency than WMME, and supports effects processing plugins. But one disadvantage is that DirectSound is not installed on all PCs, and is not well supported under Windows NT. So WMME is the best choice for most projects.

    Note: If you are compiling one of the PortAudio test programs with Visual C++, then create a new Project of type "Win32 Console Application".

    All

    For any Windows implementation, add the following source files to your project:
    pa_common\pa_lib.c
    pa_common\portaudio.h
    pa_common\pa_host.h
    Link with the system library "winmm.lib". For Visual C++:
    1. select "Settings..." from the "Project" menu,
    2. select the project name in the tree on the left,
    3. choose "All Configurations" in the popup menu above the tree,
    4. select the "Link" tab,
    5. enter "winmm.lib", without quotes, as the first item in the "Object/library modules:" field.

    WMME

    To use the WMME implementation, add the following source files to your project:
    pa_win_wmme/pa_win_wmme.c

    DirectSound

    If you want to use the DirectSound implementation of PortAudio then you must have a recent copy of the free DirectX SDK for Developers from Microsoft installed on your computer. To compile an application add the following source files to your project:
    pa_win_ds\dsound_wrapper.c
    pa_win_ds\pa_dsound.c
    Link with both system libraries "dsound.lib" and "winmm.lib" using the procedure described above for "winmm.lib".
     
    Borland users cannot link with the "dsound.lib" from Microsoft directly. Emmanuel offered this advice:

    One can use implib from Borland to generate a new .lib file which is compatible with Borland C++.

    Use: "implib dsound.dll dsound.lib" and include dsound.lib into your project.

    I still had a problem executing the patest_record example. The thread ended with an error like 'Floating point overflow at...'. This problem was caused due to a fault in the compiler. Now I'm using Borland 5.02 (instead of 5.01). Everything seems to be working fine at the moment.

    You might try compiling the "pa_tests\patest_saw.c" file first because it is the simplest.
    home | contents | previousnext portaudio-18.1.orig/docs/pa_tut_mac_osx.html0000644000175000017500000000643207655744730022007 0ustar mikaelmikael00000000000000 PortAudio Tutorial  

    PortAudio Tutorial

    home | contents | previousnext

    Compiling for Macintosh OS X

    To compile a Macintosh OS X CoreAudio application with the PortAudio library you will use the following source files:
    pa_mac_core/pa_mac_core.c
    pa_common/pa_lib.c
    pa_common/portaudio.h
    pa_common/pa_host.h
    pa_common/pa_convert.c
    pablio/ringbuffer.c
    pablio/ringbuffer.h

    Using Apple Project Builder

    Create a new ProjectBuilder project. You can use a "Tool" project to run the PortAudio examples.

    Add the source files from above to your Project.

    Add both the Apple CoreAudio.framework and the AudioToolbox.framework to your project by selecting "Add FrameWorks..." from the Project menu.

    Compile and run the "pa_tests:patest_saw.c" file first because it is the simplest.

    Or Using Metrowerks CodeWarrior 8

    by James Vanlommel
    Create a new CodeWarrior project using Mac OS C++ Stationery.
    Then choose Mac OS X Mach-O > Standard Console > C++ Console Mach-O.

    In the project window, Clear the HelloWorld.cpp file and add the source files from above to your Project.

    Add a test file of your choosing, like
       patests    /patest_sine8.c
     
    Add the frameworks to the Frameworks tab using Project > Add Files...
       CoreAudio
       AudioToolbox

    (The System framework should already be a part of the project.)

    Open the current target's settings, and in Language Settings > C/C++ Language, uncheck (disable) the "ANSI Strict" setting. (Do this for both Debug and Release projects, if necessary.)

    Edit pa_mac_core.c:
       On line 1546, cast the PaHost_AllocateFastMemory() result to a (char *) or you will get a compile error.
     
    Compile and run. (may need to run from a terminal window)

    I've successfully built patest_sine8.c this way using the CVS .tar version of portaudio (date: 2003-04-27). I get 17 warnings during compilation, all of which deal with unused variables or arguments.

    home | contents | previousnext portaudio-18.1.orig/pa_dll_switch/0000755000175000000620000000000007700016420017602 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_dll_switch/pa_lib.c0000644000175000017500000006767707423043500021370 0ustar mikaelmikael00000000000000/* * Portable Audio I/O Library * Host Independant Layer * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* Modification History: PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC */ #include #include #include #include /* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ #ifdef _WIN32 #ifndef __MWERKS__ #include #endif /* __MWERKS__ */ #else /* !_WIN32 */ #include #endif /* _WIN32 */ #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" /* The reason we might NOT want to validate the rate before opening the stream * is because many DirectSound drivers lie about the rates they actually support. */ #define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */ /* O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion */ #ifndef FALSE #define FALSE (0) #define TRUE (!FALSE) #endif #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */ static PaError Pa_KillStream( PortAudioStream *stream, int abort ); /***********************************************************************/ int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate ) { double err, minErr = allowableError; int i, bestFit = -1; for( i=0; inumSampleRates == -1 ) { /* Is it out of range? */ if( (requestedFrameRate < pdi->sampleRates[0]) || (requestedFrameRate > pdi->sampleRates[1]) ) { return paInvalidSampleRate; } *closestFrameRatePtr = requestedFrameRate; } else { bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate ); if( bestRateIndex < 0 ) return paInvalidSampleRate; *closestFrameRatePtr = pdi->sampleRates[bestRateIndex]; } return paNoError; } /*************************************************************************/ DLL_API PaError Pa_OpenStream( PortAudioStream** streamPtrPtr, PaDeviceID inputDeviceID, int numInputChannels, PaSampleFormat inputSampleFormat, void *inputDriverInfo, PaDeviceID outputDeviceID, int numOutputChannels, PaSampleFormat outputSampleFormat, void *outputDriverInfo, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, unsigned long streamFlags, PortAudioCallback *callback, void *userData ) { internalPortAudioStream *past = NULL; PaError result = paNoError; int bitsPerInputSample; int bitsPerOutputSample; /* Print passed parameters. */ DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n", streamPtrPtr, inputDeviceID, numInputChannels, inputSampleFormat, inputDriverInfo )); DBUG((" %d, %d, %d, %p, /* output */\n", outputDeviceID, numOutputChannels, outputSampleFormat, outputDriverInfo )); DBUG((" %g, %d, %d, 0x%x, , %p )\n", sampleRate, framesPerBuffer, numberOfBuffers, streamFlags, userData )); /* Check for parameter errors. */ if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag; if( streamPtrPtr == NULL ) return paBadStreamPtr; if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */ if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */ if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId; if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) ) return paInvalidDeviceId; if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount; #if SUPPORT_AUDIO_CAPTURE if( inputDeviceID >= 0 ) { PaError size = Pa_GetSampleSize( inputSampleFormat ); if( size < 0 ) return size; bitsPerInputSample = 8 * size; if( (numInputChannels <= 0) ) return paInvalidChannelCount; } #else if( inputDeviceID >= 0 ) { return paInvalidChannelCount; } #endif /* SUPPORT_AUDIO_CAPTURE */ else { if( numInputChannels > 0 ) return paInvalidChannelCount; bitsPerInputSample = 0; } if( outputDeviceID >= 0 ) { PaError size = Pa_GetSampleSize( outputSampleFormat ); if( size < 0 ) return size; bitsPerOutputSample = 8 * size; if( (numOutputChannels <= 0) ) return paInvalidChannelCount; } else { if( numOutputChannels > 0 ) return paInvalidChannelCount; bitsPerOutputSample = 0; } if( callback == NULL ) return paNullCallback; /* Allocate and clear stream structure. */ past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) ); if( past == NULL ) return paInsufficientMemory; memset( past, 0, sizeof(internalPortAudioStream) ); AddTraceMessage("Pa_OpenStream: past", (long) past ); past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */ past->past_FramesPerUserBuffer = framesPerBuffer; past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */ past->past_Callback = callback; past->past_UserData = userData; past->past_OutputSampleFormat = outputSampleFormat; past->past_InputSampleFormat = inputSampleFormat; past->past_OutputDeviceID = outputDeviceID; past->past_InputDeviceID = inputDeviceID; past->past_NumInputChannels = numInputChannels; past->past_NumOutputChannels = numOutputChannels; past->past_Flags = streamFlags; /* Check for absurd sample rates. */ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) ) { result = paInvalidSampleRate; goto cleanup; } /* Allocate buffers that may be used for format conversion from user to native buffers. */ if( numInputChannels > 0 ) { #if PA_VALIDATE_RATE result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate ); if( result < 0 ) { goto cleanup; } #else past->past_SampleRate = sampleRate; #endif /* Allocate single Input buffer. */ past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8); past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize); if( past->past_InputBuffer == NULL ) { result = paInsufficientMemory; goto cleanup; } } else { past->past_InputBuffer = NULL; } /* Allocate single Output buffer. */ if( numOutputChannels > 0 ) { #if PA_VALIDATE_RATE result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate ); if( result < 0 ) { goto cleanup; } #else past->past_SampleRate = sampleRate; #endif past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8); past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize); if( past->past_OutputBuffer == NULL ) { result = paInsufficientMemory; goto cleanup; } } else { past->past_OutputBuffer = NULL; } result = PaHost_OpenStream( past ); if( result < 0 ) goto cleanup; *streamPtrPtr = (void *) past; return result; cleanup: if( past != NULL ) Pa_CloseStream( past ); *streamPtrPtr = NULL; return result; } /*************************************************************************/ DLL_API PaError Pa_OpenDefaultStream( PortAudioStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PortAudioCallback *callback, void *userData ) { return Pa_OpenStream( stream, ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice), numInputChannels, sampleFormat, NULL, ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice), numOutputChannels, sampleFormat, NULL, sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData ); } /*************************************************************************/ DLL_API PaError Pa_CloseStream( PortAudioStream* stream) { PaError result; internalPortAudioStream *past; DBUG(("Pa_CloseStream()\n")); if( stream == NULL ) return paBadStreamPtr; past = (internalPortAudioStream *) stream; Pa_AbortStream( past ); result = PaHost_CloseStream( past ); if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize ); if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize ); PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) ); return result; } /*************************************************************************/ DLL_API PaError Pa_StartStream( PortAudioStream *stream ) { PaError result = paHostError; internalPortAudioStream *past; if( stream == NULL ) return paBadStreamPtr; past = (internalPortAudioStream *) stream; past->past_FrameCount = 0.0; if( past->past_NumInputChannels > 0 ) { result = PaHost_StartInput( past ); DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result)); if( result < 0 ) goto error; } if( past->past_NumOutputChannels > 0 ) { result = PaHost_StartOutput( past ); DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result)); if( result < 0 ) goto error; } result = PaHost_StartEngine( past ); DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result)); if( result < 0 ) goto error; return paNoError; error: return result; } /*************************************************************************/ DLL_API PaError Pa_StopStream( PortAudioStream *stream ) { return Pa_KillStream( stream, 0 ); } /*************************************************************************/ DLL_API PaError Pa_AbortStream( PortAudioStream *stream ) { return Pa_KillStream( stream, 1 ); } /*************************************************************************/ static PaError Pa_KillStream( PortAudioStream *stream, int abort ) { PaError result = paNoError; internalPortAudioStream *past; DBUG(("Pa_StopStream().\n")); if( stream == NULL ) return paBadStreamPtr; past = (internalPortAudioStream *) stream; if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) ) { result = PaHost_StopEngine( past, abort ); DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result)); if( result < 0 ) goto error; } if( past->past_NumInputChannels > 0 ) { result = PaHost_StopInput( past, abort ); DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result)); if( result != paNoError ) goto error; } if( past->past_NumOutputChannels > 0 ) { result = PaHost_StopOutput( past, abort ); DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result)); if( result != paNoError ) goto error; } error: past->past_Usage = 0; past->past_IfLastExitValid = 0; return result; } /*************************************************************************/ DLL_API PaError Pa_StreamActive( PortAudioStream *stream ) { internalPortAudioStream *past; if( stream == NULL ) return paBadStreamPtr; past = (internalPortAudioStream *) stream; return PaHost_StreamActive( past ); } /*************************************************************************/ DLL_API const char *Pa_GetErrorText( PaError errnum ) { const char *msg; switch(errnum) { case paNoError: msg = "Success"; break; case paHostError: msg = "Host error."; break; case paInvalidChannelCount: msg = "Invalid number of channels."; break; case paInvalidSampleRate: msg = "Invalid sample rate."; break; case paInvalidDeviceId: msg = "Invalid device ID."; break; case paInvalidFlag: msg = "Invalid flag."; break; case paSampleFormatNotSupported: msg = "Sample format not supported"; break; case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break; case paInsufficientMemory: msg = "Insufficient memory."; break; case paBufferTooBig: msg = "Buffer too big."; break; case paBufferTooSmall: msg = "Buffer too small."; break; case paNullCallback: msg = "No callback routine specified."; break; case paBadStreamPtr: msg = "Invalid stream pointer."; break; case paTimedOut : msg = "Wait Timed Out."; break; case paInternalError: msg = "Internal PortAudio Error."; break; default: msg = "Illegal error number."; break; } return msg; } /* Get CPU Load as a fraction of total CPU time. A value of 0.5 would imply that PortAudio and the sound generating callback was consuming roughly 50% of the available CPU time. The amount may vary depending on CPU load. This function may be called from the callback function. */ DLL_API double Pa_GetCPULoad( PortAudioStream* stream) { internalPortAudioStream *past; if( stream == NULL ) return (double) paBadStreamPtr; past = (internalPortAudioStream *) stream; return past->past_Usage; } /************************************************************* ** Calculate 2 LSB dither signal with a triangular distribution. ** Ranged properly for adding to a 32 bit integer prior to >>15. */ #define DITHER_BITS (15) #define DITHER_SCALE (1.0f / ((1<>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS)); /* High pass filter to reduce audibility. */ highPass = current - previous; previous = current; return highPass; } /************************************************************************* ** Called by host code. ** Convert input from Int16, call user code, then convert output ** to Int16 format for native use. ** Assumes host native format is paInt16. ** Returns result from user callback. */ long Pa_CallConvertInt16( internalPortAudioStream *past, short *nativeInputBuffer, short *nativeOutputBuffer ) { long temp; long bytesEmpty = 0; long bytesFilled = 0; int userResult; unsigned int i; void *inputBuffer = NULL; void *outputBuffer = NULL; #if SUPPORT_AUDIO_CAPTURE /* Get native data from DirectSound. */ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) ) { /* Convert from native format to PA format. */ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels; switch(past->past_InputSampleFormat) { case paFloat32: { float *inBufPtr = (float *) past->past_InputBuffer; inputBuffer = past->past_InputBuffer; for( i=0; ipast_InputBuffer; inputBuffer = past->past_InputBuffer; for( i=0; ipast_InputBuffer; inputBuffer = past->past_InputBuffer; if( past->past_Flags & paDitherOff ) { for( i=0; i> 8); } } else { for( i=0; i> 7; temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); inBufPtr[i] = (char)(temp >> 8); } } break; } case paUInt8: { /* Convert 16 bit data to 8 bit unsigned chars */ unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer; inputBuffer = past->past_InputBuffer; if( past->past_Flags & paDitherOff ) { for( i=0; i> 8)) + 0x80; } } else { /* If you dither then you have to clip because dithering could push the signal out of range! */ for( i=0; i> 7; temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); inBufPtr[i] = (unsigned char)(temp + 0x80); } } break; } default: break; } } #endif /* SUPPORT_AUDIO_CAPTURE */ /* Are we doing output time? */ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) ) { /* May already be in native format so just write directly to native buffer. */ outputBuffer = (past->past_OutputSampleFormat == paInt16) ? nativeOutputBuffer : past->past_OutputBuffer; } /* AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer ); AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer ); */ /* Call user callback routine. */ userResult = past->past_Callback( inputBuffer, outputBuffer, past->past_FramesPerUserBuffer, past->past_FrameCount, past->past_UserData ); past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer; /* Convert to native format if necessary. */ if( outputBuffer != NULL ) { unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels; switch(past->past_OutputSampleFormat) { case paFloat32: { float *outBufPtr = (float *) past->past_OutputBuffer; if( past->past_Flags & paDitherOff ) { if( past->past_Flags & paClipOff ) /* NOTHING */ { for( i=0; i 0x7FFF) ? 0x7FFF : temp)); } } } else { /* If you dither then you have to clip because dithering could push the signal out of range! */ for( i=0; i 0x7FFF) ? 0x7FFF : temp)); } } break; } case paInt32: { int *outBufPtr = (int *) past->past_OutputBuffer; if( past->past_Flags & paDitherOff ) { for( i=0; i> 16 ); } } else { for( i=0; i> 1) + Pa_TriangularDither(); temp = temp >> 15; *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); } } break; } case paInt8: { char *outBufPtr = (char *) past->past_OutputBuffer; for( i=0; ipast_OutputBuffer; for( i=0; ipast_NumInputChannels > 0) && (nativeInputBuffer != NULL) ) { inputBuffer = nativeInputBuffer; // FIXME } /* Are we doing output time? */ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) ) { /* May already be in native format so just write directly to native buffer. */ outputBuffer = (past->past_OutputSampleFormat == paFloat32) ? nativeOutputBuffer : past->past_OutputBuffer; } /* AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer ); AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer ); */ /* Call user callback routine. */ userResult = past->past_Callback( inputBuffer, outputBuffer, past->past_FramesPerUserBuffer, past->past_FrameCount, past->past_UserData ); past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer; /* Convert to native format if necessary. */ // FIXME return userResult; } /*************************************************************************/ DLL_API PaError Pa_Initialize( void ) { if( gInitCount++ > 0 ) return paNoError; ResetTraceMessages(); return PaHost_Init(); } DLL_API PaError Pa_Terminate( void ) { PaError result = paNoError; if( gInitCount == 0 ) return paNoError; else if( --gInitCount == 0 ) { result = PaHost_Term(); DumpTraceMessages(); } return result; } /*************************************************************************/ DLL_API PaError Pa_GetSampleSize( PaSampleFormat format ) { int size; switch(format ) { case paUInt8: case paInt8: size = 1; break; case paInt16: size = 2; break; case paPackedInt24: size = 3; break; case paFloat32: case paInt32: case paInt24: size = 4; break; default: size = paSampleFormatNotSupported; break; } return (PaError) size; } portaudio-18.1.orig/pa_dll_switch/loadPA_DLL.cpp0000644000175000017500000001432107423043500022307 0ustar mikaelmikael00000000000000////////////////////////////////////////////////////////////////////////// HINSTANCE pPaDll; /* the function pointers to the PortAudio DLLs */ PaError (__cdecl* Pa_Initialize)( void ); PaError (__cdecl* Pa_Terminate)( void ); long (__cdecl* Pa_GetHostError)( void ); const char* (__cdecl* Pa_GetErrorText)( PaError ); int (__cdecl* Pa_CountDevices)(void); PaDeviceID (__cdecl* Pa_GetDefaultInputDeviceID)( void ); PaDeviceID (__cdecl* Pa_GetDefaultOutputDeviceID)( void ); const PaDeviceInfo* (__cdecl* Pa_GetDeviceInfo)( PaDeviceID); PaError (__cdecl* Pa_OpenStream)( PortAudioStream ** , PaDeviceID , int , PaSampleFormat , void *, PaDeviceID , int , PaSampleFormat , void *, double , unsigned long , unsigned long , unsigned long , PortAudioCallback *, void * ); PaError (__cdecl* Pa_OpenDefaultStream)( PortAudioStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PortAudioCallback *callback, void *userData ); PaError (__cdecl* Pa_CloseStream)( PortAudioStream* ); PaError (__cdecl* Pa_StartStream)( PortAudioStream *stream ); PaError (__cdecl* Pa_StopStream)( PortAudioStream *stream ); PaError (__cdecl* Pa_AbortStream)( PortAudioStream *stream ); PaError (__cdecl* Pa_StreamActive)( PortAudioStream *stream ); PaTimestamp (__cdecl* Pa_StreamTime)( PortAudioStream *stream ); double (__cdecl* Pa_GetCPULoad)( PortAudioStream* stream ); int (__cdecl* Pa_GetMinNumBuffers)( int framesPerBuffer, double sampleRate ); void (__cdecl* Pa_Sleep)( long msec ); PaError (__cdecl* Pa_GetSampleSize)( PaSampleFormat format ); ////////////////////////////////////////////////////////////////////////// ... ZERROR AudioEngine::DirectXSupport(ZBOOL bSupDX) { if (bSupDX) if (CheckForDirectXSupport()) bSupportDirectX = _TRUE; else return _NO_SOUND; else bSupportDirectX = _FALSE; return _NO_ERROR; } ZBOOL AudioEngine::CheckForDirectXSupport() { HMODULE pTestDXLib; FARPROC pFunctionality; pTestDXLib=LoadLibrary("DSOUND"); if (pTestDXLib!=NULL) // check if there is a DirectSound { pFunctionality = GetProcAddress(pTestDXLib, (char*) 7); if (pFunctionality!=NULL) { FreeLibrary(pTestDXLib); return _TRUE; } else { FreeLibrary(pTestDXLib); return _FALSE; } } else return _FALSE; } ZERROR AudioEngine::LoadPALib() { #ifdef _DEBUG if (bSupportDirectX) pPaDll = LoadLibrary("PA_DXD"); else pPaDll = LoadLibrary("PA_MMED"); #else if (bSupportDirectX) pPaDll = LoadLibrary("PA_DX"); else pPaDll = LoadLibrary("PA_MME"); #endif if (pPaDll!=NULL) { Pa_Initialize = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_Initialize"); Pa_Terminate = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_Terminate"); Pa_GetHostError = (long (__cdecl* )( void )) GetProcAddress(pPaDll,"Pa_GetHostError"); Pa_GetErrorText = (const char* (__cdecl* )( PaError )) GetProcAddress(pPaDll,"Pa_GetErrorText"); Pa_CountDevices = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_CountDevices"); Pa_GetDefaultInputDeviceID = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_GetDefaultInputDeviceID"); Pa_GetDefaultOutputDeviceID = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_GetDefaultOutputDeviceID"); Pa_GetDeviceInfo = (const PaDeviceInfo* (__cdecl* )( PaDeviceID)) GetProcAddress(pPaDll,"Pa_GetDeviceInfo"); Pa_OpenStream = ( PaError (__cdecl* )( PortAudioStream ** , PaDeviceID , int , PaSampleFormat , void *, PaDeviceID , int , PaSampleFormat , void *, double , unsigned long , unsigned long , unsigned long , PortAudioCallback *, void * )) GetProcAddress(pPaDll,"Pa_OpenStream"); Pa_OpenDefaultStream = (PaError (__cdecl* )( PortAudioStream** , int , int , PaSampleFormat , double , unsigned long , unsigned long , PortAudioCallback *, void * )) GetProcAddress(pPaDll,"Pa_OpenDefaultStream"); Pa_CloseStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_CloseStream"); Pa_StartStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_StartStream"); Pa_StopStream = (PaError (__cdecl* )( PortAudioStream* ))GetProcAddress(pPaDll,"Pa_StopStream"); Pa_AbortStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_AbortStream"); Pa_StreamActive = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_StreamActive"); Pa_StreamTime = (PaTimestamp (__cdecl* )( PortAudioStream *))GetProcAddress(pPaDll,"Pa_StreamTime"); Pa_GetCPULoad = (double (__cdecl* )( PortAudioStream* ))GetProcAddress(pPaDll,"Pa_GetCPULoad"); Pa_GetMinNumBuffers = (int (__cdecl* )( int , double )) GetProcAddress(pPaDll,"Pa_GetMinNumBuffers"); Pa_Sleep = (void (__cdecl* )( long )) GetProcAddress(pPaDll,"Pa_Sleep"); Pa_GetSampleSize = (PaError (__cdecl* )( PaSampleFormat )) GetProcAddress(pPaDll,"Pa_GetSampleSize"); return _NO_ERROR; } else return _DLL_NOT_FOUND; } ZERROR AudioEngine::UnLoadPALib() { if (pPaDll!=NULL) FreeLibrary(pPaDll); return _NO_ERROR; } ... portaudio-18.1.orig/pa_dll_switch/letter_from_tim_010817.txt0000644000175000017500000000223007423043474024532 0ustar mikaelmikael00000000000000From: "Tim Flohrer" To: "Phil Burk" Subject: Re: suggestion - multiple backends Date: Friday, August 17, 2001 7:48 AM Hi Phil, here is what I did: 1. I changed the pa_lib.c and portaudio.h in order to provide a dll api if wanted 2. in my application I had a couple of function pointers defined (see excerpt loadPA_DLL.cpp) that get their value when the dll is loaded 3. all other files that use the PortAudio-functions had the PaDllEntry.h included I extracted the loadPA_DLL.cpp out of my source so I hope it's understandable somehow. If not feel free to ask. There are also functions for checking if DirectX is available. I am not really sure if this is 100% correct, but I noticed that on NT systems it is missing the function no. 7 in the dsound.dll so I just check if it's there ;O) On the other hand this doesn't tell you if Dsound is emulated or not (Dsound gets really bad when emulated, but i suppose you know that). Hope I didn't forget anything cheers tim -- tim flohrer flohrer@zplane.de zplane.development holsteinische str. 39-42 12161 berlin fon: +49.30.854 09 15.0 fax: +49.30.854 09 15.5 portaudio-18.1.orig/pa_dll_switch/PaDllEntry.h0000644000175000017500000001251107423043476022152 0ustar mikaelmikael00000000000000 /* * PortAudio Portable Real-Time Audio Library * PortAudio DLL Header File * Latest version available at: http://www.audiomulch.com/portaudio/ * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ // changed by zplane.developement in order to generate a DLL #ifndef __PADLLENTRY_HEADER_INCLUDED__ #define __PADLLENTRY_HEADER_INCLUDED__ typedef int PaError; typedef enum { paNoError = 0, paHostError = -10000, paInvalidChannelCount, paInvalidSampleRate, paInvalidDeviceId, paInvalidFlag, paSampleFormatNotSupported, paBadIODeviceCombination, paInsufficientMemory, paBufferTooBig, paBufferTooSmall, paNullCallback, paBadStreamPtr, paTimedOut, paInternalError } PaErrorNum; typedef unsigned long PaSampleFormat; #define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/ #define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/ #define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/ #define paInt24 ((PaSampleFormat) (1<<3)) #define paPackedInt24 ((PaSampleFormat) (1<<4)) #define paInt8 ((PaSampleFormat) (1<<5)) #define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */ #define paCustomFormat ((PaSampleFormat) (1<<16)) typedef int PaDeviceID; #define paNoDevice -1 typedef struct { int structVersion; const char *name; int maxInputChannels; int maxOutputChannels; /* Number of discrete rates, or -1 if range supported. */ int numSampleRates; /* Array of supported sample rates, or {min,max} if range supported. */ const double *sampleRates; PaSampleFormat nativeSampleFormats; } PaDeviceInfo; typedef double PaTimestamp; typedef int (PortAudioCallback)( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); #define paNoFlag (0) #define paClipOff (1<<0) /* disable default clipping of out of range samples */ #define paDitherOff (1<<1) /* disable default dithering */ #define paPlatformSpecificFlags (0x00010000) typedef unsigned long PaStreamFlags; typedef void PortAudioStream; #define PaStream PortAudioStream extern PaError (__cdecl* Pa_Initialize)( void ); extern PaError (__cdecl* Pa_Terminate)( void ); extern long (__cdecl* Pa_GetHostError)( void ); extern const char* (__cdecl* Pa_GetErrorText)( PaError ); extern int (__cdecl* Pa_CountDevices)(void); extern PaDeviceID (__cdecl* Pa_GetDefaultInputDeviceID)( void ); extern PaDeviceID (__cdecl* Pa_GetDefaultOutputDeviceID)( void ); extern const PaDeviceInfo* (__cdecl* Pa_GetDeviceInfo)( PaDeviceID); extern PaError (__cdecl* Pa_OpenStream)( PortAudioStream ** , PaDeviceID , int , PaSampleFormat , void *, PaDeviceID , int , PaSampleFormat , void *, double , unsigned long , unsigned long , unsigned long , PortAudioCallback *, void * ); extern PaError (__cdecl* Pa_OpenDefaultStream)( PortAudioStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PortAudioCallback *callback, void *userData ); extern PaError (__cdecl* Pa_CloseStream)( PortAudioStream* ); extern PaError (__cdecl* Pa_StartStream)( PortAudioStream *stream ); extern PaError (__cdecl* Pa_StopStream)( PortAudioStream *stream ); extern PaError (__cdecl* Pa_AbortStream)( PortAudioStream *stream ); extern PaError (__cdecl* Pa_StreamActive)( PortAudioStream *stream ); extern PaTimestamp (__cdecl* Pa_StreamTime)( PortAudioStream *stream ); extern double (__cdecl* Pa_GetCPULoad)( PortAudioStream* stream ); extern int (__cdecl* Pa_GetMinNumBuffers)( int framesPerBuffer, double sampleRate ); extern void (__cdecl* Pa_Sleep)( long msec ); extern PaError (__cdecl* Pa_GetSampleSize)( PaSampleFormat format ); #endif // __PADLLENTRY_HEADER_INCLUDED__ portaudio-18.1.orig/pa_dll_switch/portaudio.h0000644000175000017500000003703007423043476022145 0ustar mikaelmikael00000000000000#ifndef PORT_AUDIO_H #define PORT_AUDIO_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * PortAudio Portable Real-Time Audio Library * PortAudio API Header File * Latest version available at: http://www.audiomulch.com/portaudio/ * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ // added by zplane.developement in order to generate a DLL #if defined(PA_MME_EXPORTS) || defined(PA_DX_EXPORTS) #define DLL_API __declspec( dllexport ) #elif defined(_LIB) || defined(_STATIC_LINK) || defined(_STATIC_APP) #define DLL_API #else #define DLL_API __declspec(dllexport) #endif typedef int PaError; typedef enum { paNoError = 0, paHostError = -10000, paInvalidChannelCount, paInvalidSampleRate, paInvalidDeviceId, paInvalidFlag, paSampleFormatNotSupported, paBadIODeviceCombination, paInsufficientMemory, paBufferTooBig, paBufferTooSmall, paNullCallback, paBadStreamPtr, paTimedOut, paInternalError } PaErrorNum; /* Pa_Initialize() is the library initialisation function - call this before using the library. */ DLL_API PaError Pa_Initialize( void ); /* Pa_Terminate() is the library termination function - call this after using the library. */ DLL_API PaError Pa_Terminate( void ); /* Return host specific error. This can be called after receiving a paHostError. */ DLL_API long Pa_GetHostError( void ); /* Translate the error number into a human readable message. */ DLL_API const char *Pa_GetErrorText( PaError errnum ); /* Sample formats These are formats used to pass sound data between the callback and the stream. Each device has a "native" format which may be used when optimum efficiency or control over conversion is required. Formats marked "always available" are supported (emulated) by all devices. The floating point representation uses +1.0 and -1.0 as the respective maximum and minimum. */ typedef unsigned long PaSampleFormat; #define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/ #define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/ #define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/ #define paInt24 ((PaSampleFormat) (1<<3)) #define paPackedInt24 ((PaSampleFormat) (1<<4)) #define paInt8 ((PaSampleFormat) (1<<5)) #define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */ #define paCustomFormat ((PaSampleFormat) (1<<16)) /* Device enumeration mechanism. Device ids range from 0 to Pa_CountDevices()-1. Devices may support input, output or both. Device 0 is always the "default" device and should support at least stereo in and out if that is available on the taget platform _even_ if this involves kludging an input/output device on platforms that usually separate input from output. Other platform specific devices are specified by positive device ids. */ typedef int PaDeviceID; #define paNoDevice -1 typedef struct { int structVersion; const char *name; int maxInputChannels; int maxOutputChannels; /* Number of discrete rates, or -1 if range supported. */ int numSampleRates; /* Array of supported sample rates, or {min,max} if range supported. */ const double *sampleRates; PaSampleFormat nativeSampleFormats; } PaDeviceInfo; DLL_API int Pa_CountDevices(); /* Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() Return the default device ID or paNoDevice if there is no devices. The result can be passed to Pa_OpenStream(). On the PC, the user can specify a default device by setting an environment variable. For example, to use device #1. set PA_RECOMMENDED_OUTPUT_DEVICE=1 The user should first determine the available device ID by using the supplied application "pa_devs". */ DLL_API PaDeviceID Pa_GetDefaultInputDeviceID( void ); DLL_API PaDeviceID Pa_GetDefaultOutputDeviceID( void ); /* PaTimestamp is used to represent a continuous sample clock with arbitrary start time useful for syncronisation. The type is used in the outTime argument to the callback function and the result of Pa_StreamTime() */ typedef double PaTimestamp; /* Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure referring to the device specified by id. If id is out of range the function returns NULL. The returned structure is owned by the PortAudio implementation and must not be manipulated or freed. The pointer is guaranteed to be valid until between calls to Pa_Initialize() and Pa_Terminate(). */ DLL_API const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ); /* PortAudioCallback is implemented by clients of the portable audio api. inputBuffer and outputBuffer are arrays of interleaved samples, the format, packing and number of channels used by the buffers are determined by parameters to Pa_OpenStream() (see below). framesPerBuffer is the number of sample frames to be processed by the callback. outTime is the time in samples when the buffer(s) processed by this callback will begin being played at the audio output. See also Pa_StreamTime() userData is the value of a user supplied pointer passed to Pa_OpenStream() intended for storing synthesis data etc. return value: The callback can return a nonzero value to stop the stream. This may be useful in applications such as soundfile players where a specific duration of output is required. However, it is not necessary to utilise this mechanism as StopStream() will also terminate the stream. A callback returning a nonzero value must fill the entire outputBuffer. NOTE: None of the other stream functions may be called from within the callback function except for Pa_GetCPULoad(). */ typedef int (PortAudioCallback)( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /* Stream flags These flags may be supplied (ored together) in the streamFlags argument to the Pa_OpenStream() function. [ suggestions? ] */ #define paNoFlag (0) #define paClipOff (1<<0) /* disable defult clipping of out of range samples */ #define paDitherOff (1<<1) /* disable default dithering */ #define paPlatformSpecificFlags (0x00010000) typedef unsigned long PaStreamFlags; /* A single PortAudioStream provides multiple channels of real-time input and output audio streaming to a client application. Pointers to PortAudioStream objects are passed between PortAudio functions. */ typedef void PortAudioStream; #define PaStream PortAudioStream /* Pa_OpenStream() opens a stream for either input, output or both. stream is the address of a PortAudioStream pointer which will receive a pointer to the newly opened stream. inputDevice is the id of the device used for input (see PaDeviceID above.) inputDevice may be paNoDevice to indicate that an input device is not required. numInputChannels is the number of channels of sound to be delivered to the callback. It can range from 1 to the value of maxInputChannels in the device input record for the device specified in the inputDevice parameter. If inputDevice is paNoDevice numInputChannels is ignored. inputSampleFormat is the format of inputBuffer provided to the callback function. inputSampleFormat may be any of the formats described by the PaSampleFormat enumeration (see above). PortAudio guarantees support for the sound devices native formats (nativeSampleFormats in the device info record) and additionally 16 and 32 bit integer and 32 bit floating point formats. Support for other formats is implementation defined. inputDriverInfo is a pointer to an optional driver specific data structure containing additional information for device setup or stream processing. inputDriverInfo is never required for correct operation. If not used inputDriverInfo should be NULL. outputDevice is the id of the device used for output (see PaDeviceID above.) outputDevice may be paNoDevice to indicate that an output device is not required. numOutputChannels is the number of channels of sound to be supplied by the callback. See the definition of numInputChannels above for more details. outputSampleFormat is the sample format of the outputBuffer filled by the callback function. See the definition of inputSampleFormat above for more details. outputDriverInfo is a pointer to an optional driver specific data structure containing additional information for device setup or stream processing. outputDriverInfo is never required for correct operation. If not used outputDriverInfo should be NULL. sampleRate is the desired sampleRate for input and output framesPerBuffer is the length in sample frames of all internal sample buffers used for communication with platform specific audio routines. Wherever possible this corresponds to the framesPerBuffer parameter passed to the callback function. numberOfBuffers is the number of buffers used for multibuffered communication with the platform specific audio routines. This parameter is provided only as a guide - and does not imply that an implementation must use multibuffered i/o when reliable double buffering is available (such as SndPlayDoubleBuffer() on the Macintosh.) streamFlags may contain a combination of flags ORed together. These flags modify the behavior of the streaming process. Some flags may only be relevant to certain buffer formats. callback is a pointer to a client supplied function that is responsible for processing and filling input and output buffers (see above for details.) userData is a client supplied pointer which is passed to the callback function. It could for example, contain a pointer to instance data necessary for processing the audio buffers. return value: Apon success Pa_OpenStream() returns PaNoError and places a pointer to a valid PortAudioStream in the stream argument. The stream is inactive (stopped). If a call to Pa_OpenStream() fails a nonzero error code is returned (see PAError above) and the value of stream is invalid. */ DLL_API PaError Pa_OpenStream( PortAudioStream** stream, PaDeviceID inputDevice, int numInputChannels, PaSampleFormat inputSampleFormat, void *inputDriverInfo, PaDeviceID outputDevice, int numOutputChannels, PaSampleFormat outputSampleFormat, void *outputDriverInfo, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PaStreamFlags streamFlags, PortAudioCallback *callback, void *userData ); /* Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens the default input and/or ouput devices. Most parameters have identical meaning to their Pa_OpenStream() counterparts, with the following exceptions: If either numInputChannels or numOutputChannels is 0 the respective device is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() ) sampleFormat applies to both the input and output buffers. */ DLL_API PaError Pa_OpenDefaultStream( PortAudioStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PortAudioCallback *callback, void *userData ); /* Pa_CloseStream() closes an audio stream, flushing any pending buffers. */ DLL_API PaError Pa_CloseStream( PortAudioStream* ); /* Pa_StartStream() and Pa_StopStream() begin and terminate audio processing. When Pa_StopStream() returns, all pending audio buffers have been played. Pa_AbortStream() stops playing immediately without waiting for pending buffers to complete. */ DLL_API PaError Pa_StartStream( PortAudioStream *stream ); DLL_API PaError Pa_StopStream( PortAudioStream *stream ); DLL_API PaError Pa_AbortStream( PortAudioStream *stream ); /* Pa_StreamActive() returns one when the stream is playing audio, zero when not playing, or a negative error number if the stream is invalid. The stream is active between calls to Pa_StartStream() and Pa_StopStream(), but may also become inactive if the callback returns a non-zero value. In the latter case, the stream is considered inactive after the last buffer has finished playing. */ DLL_API PaError Pa_StreamActive( PortAudioStream *stream ); /* Pa_StreamTime() returns the current output time for the stream in samples. This time may be used as a time reference (for example syncronising audio to MIDI). */ DLL_API PaTimestamp Pa_StreamTime( PortAudioStream *stream ); /* The "CPU Load" is a fraction of total CPU time consumed by the stream's audio processing. A value of 0.5 would imply that PortAudio and the sound generating callback was consuming roughly 50% of the available CPU time. This function may be called from the callback function or the application. */ DLL_API double Pa_GetCPULoad( PortAudioStream* stream ); /* Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for the current host based on minimum latency. On the PC, for the DirectSound implementation, latency can be optionally set by user by setting an environment variable. For example, to set latency to 200 msec, put: set PA_MIN_LATENCY_MSEC=200 in the AUTOEXEC.BAT file and reboot. If the environment variable is not set, then the latency will be determined based on the OS. Windows NT has higher latency than Win95. */ DLL_API int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ); /* Sleep for at least 'msec' milliseconds. You may sleep longer than the requested time so don't rely on this for accurate musical timing. */ DLL_API void Pa_Sleep( long msec ); /* Return size in bytes of a single sample in a given PaSampleFormat or paSampleFormatNotSupported. */ DLL_API PaError Pa_GetSampleSize( PaSampleFormat format ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* PORT_AUDIO_H */ portaudio-18.1.orig/pa_tests/0000755000175000000620000000000007700016420016610 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_tests/debug_record.c0000644000175000017500000002423407631472620021564 0ustar mikaelmikael00000000000000/* * $Id: debug_record.c,v 1.3.4.3 2003/03/06 06:09:20 philburk Exp $ * patest_record.c * Record input into an array. * Save array to a file. * Playback recorded data. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define SAMPLE_RATE (44100) #define NUM_SECONDS (6) #define NUM_CHANNELS (2) #define FRAMES_PER_BUFFER (64) /* #define DITHER_FLAG (paDitherOff) */ #define DITHER_FLAG (0) /* Select sample format. */ #if 1 #define PA_SAMPLE_TYPE paFloat32 typedef float SAMPLE; #define SAMPLE_SILENCE (0.0f) #elif 0 #define PA_SAMPLE_TYPE paInt32 typedef long SAMPLE; #define SAMPLE_SILENCE (0) #elif 0 #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; #define SAMPLE_SILENCE (0) #elif 0 #define PA_SAMPLE_TYPE paInt8 typedef char SAMPLE; #define SAMPLE_SILENCE (0) #else #define PA_SAMPLE_TYPE paUInt8 typedef unsigned char SAMPLE; #define SAMPLE_SILENCE (128) #endif typedef struct { int frameIndex; /* Index into sample array. */ int maxFrameIndex; SAMPLE *recordedSamples; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int recordCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; SAMPLE *rptr = (SAMPLE*)inputBuffer; SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; long framesToCalc; long i; int finished; unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; (void) outputBuffer; /* Prevent unused variable warnings. */ (void) outTime; if( framesLeft < framesPerBuffer ) { framesToCalc = framesLeft; finished = 1; } else { framesToCalc = framesPerBuffer; finished = 0; } if( inputBuffer == NULL ) { for( i=0; iframeIndex += framesToCalc; return finished; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int playCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; SAMPLE *wptr = (SAMPLE*)outputBuffer; unsigned int i; int finished; unsigned int framesLeft = data->maxFrameIndex - data->frameIndex; (void) inputBuffer; /* Prevent unused variable warnings. */ (void) outTime; if( framesLeft < framesPerBuffer ) { /* final buffer... */ for( i=0; iframeIndex += framesLeft; finished = 1; } else { for( i=0; iframeIndex += framesPerBuffer; finished = 0; } return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; int totalFrames; int numSamples; int numBytes; SAMPLE max, average, val; printf("debug_record.c, sampleRate = %d, numChannels = %d\n", SAMPLE_RATE, NUM_CHANNELS ); fflush(stdout); data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */ data.frameIndex = 0; numSamples = totalFrames * NUM_CHANNELS; numBytes = numSamples * sizeof(SAMPLE); data.recordedSamples = (SAMPLE *) malloc( numBytes ); if( data.recordedSamples == NULL ) { printf("Could not allocate record array.\n"); exit(1); } for( i=0; i max ) { max = val; } average += val; } average = average / numSamples; if( PA_SAMPLE_TYPE == paFloat32 ) { printf("sample max amplitude = %f\n", (double) max ); printf("sample average = %f\n", (double) average ); } else { printf("sample max amplitude = %d\n", (int) max ); printf("sample average = %d\n", (int) average ); } /* Write recorded data to a file. */ #if 0 { FILE *fid; fid = fopen("recorded.raw", "wb"); if( fid == NULL ) { printf("Could not open file."); } else { fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid ); fclose( fid ); printf("Wrote data to 'recorded.raw'\n"); } } #endif /* Playback recorded data. -------------------------------------------- */ data.frameIndex = 0; printf("Begin playback.\n"); fflush(stdout); err = Pa_OpenStream( &stream, paNoDevice, 0, /* NO input */ PA_SAMPLE_TYPE, NULL, Pa_GetDefaultOutputDeviceID(), NUM_CHANNELS, /* stereo output */ PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ playCallback, &data ); if( err != paNoError ) goto error; if( stream ) { err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Start playback!!\n"); fflush(stdout); while( Pa_StreamActive( stream ) ) { Pa_Sleep(1000); printf("index = %d\n", data.frameIndex ); fflush(stdout); } printf("Stop playback!!\n"); fflush(stdout); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; printf("Done.\n"); fflush(stdout); } free( data.recordedSamples ); Pa_Terminate(); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; } portaudio-18.1.orig/pa_tests/debug_dual.c0000644000175000017500000001524607423043514021231 0ustar mikaelmikael00000000000000/* * $Id: debug_dual.c,v 1.1.1.1 2002/01/22 00:52:27 phil Exp $ * debug_dual.c * Try to open TWO streams on separate cards. * Play a sine sweep using the Portable Audio api for several seconds. * Hacked test for debugging PA. * * Author: Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define DEV_ID_1 (13) #define DEV_ID_2 (15) #define NUM_SECONDS (8) #define SLEEP_DUR (800) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #if 0 #define MIN_LATENCY_MSEC (200) #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #else #define NUM_BUFFERS (0) #endif #define MIN_FREQ (100.0f) #define MAX_FREQ (4000.0f) #define FREQ_SCALAR (1.00002f) #define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (400) typedef struct { float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation float phase_increment; float left_phase; float right_phase; } paTestData; /* Convert phase between and 1.0 to sine value * using linear interpolation. */ float LookupSine( paTestData *data, float phase ); float LookupSine( paTestData *data, float phase ) { float fIndex = phase*TABLE_SIZE; int index = (int) fIndex; float fract = fIndex - index; float lo = data->sine[index]; float hi = data->sine[index+1]; float val = lo + fract*(hi-lo); return val; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned long i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; ileft_phase); /* left */ *out++ = LookupSine(data, data->right_phase); /* right */ data->left_phase += data->phase_increment; if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f; data->right_phase += (data->phase_increment * 1.5f); /* fifth above */ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f; /* sweep frequency then start over. */ data->phase_increment *= FREQ_SCALAR; if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ); } return 0; } PaError TestStart( PortAudioStream **streamPtr, PaDeviceID devID, paTestData *data ); /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream1, *stream2; PaError err; paTestData DATA1, DATA2; printf("PortAudio Test: DUAL sine sweep. ask for %d buffers\n", NUM_BUFFERS ); err = Pa_Initialize(); if( err != paNoError ) goto error; err = TestStart( &stream1, DEV_ID_1, &DATA1 ); if( err != paNoError ) goto error; err = TestStart( &stream2, DEV_ID_2, &DATA2 ); if( err != paNoError ) goto error; printf("Hit ENTER\n"); getchar(); err = Pa_StopStream( stream1 ); if( err != paNoError ) goto error; err = Pa_StopStream( stream2 ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } PaError TestStart( PortAudioStream **streamPtr, PaDeviceID devID, paTestData *data ) { PortAudioStream *stream; PaError err; int i; /* initialise sinusoidal wavetable */ for( i=0; isine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); } data->sine[TABLE_SIZE] = data->sine[0]; // set guard point data->left_phase = data->right_phase = 0.0; data->phase_increment = CalcPhaseIncrement(MIN_FREQ); printf("PortAudio Test: output device = %d\n", devID ); err = Pa_OpenStream( &stream, paNoDevice, 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, devID, 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, /* number of buffers, if zero then use default minimum */ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; *streamPtr = stream; return 0; error: return err; } portaudio-18.1.orig/pa_tests/pa_devs.c0000644000175000017500000000757007622176614020571 0ustar mikaelmikael00000000000000/* * $Id: pa_devs.c,v 1.1.1.1.4.1 2003/02/11 21:41:32 philburk Exp $ * pa_devs.c * List available devices. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" /*******************************************************************/ int main(void); int main(void) { int i,j; int numDevices; const PaDeviceInfo *pdi; PaError err; Pa_Initialize(); numDevices = Pa_CountDevices(); if( numDevices < 0 ) { printf("ERROR: Pa_CountDevices returned 0x%x\n", numDevices ); err = numDevices; goto error; } printf("Number of devices = %d\n", numDevices ); for( i=0; iname ); printf("Max Inputs = %d", pdi->maxInputChannels ); printf(", Max Outputs = %d\n", pdi->maxOutputChannels ); if( pdi->numSampleRates == -1 ) { printf("Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] ); } else { printf("Sample Rates ="); for( j=0; jnumSampleRates; j++ ) { printf(" %8.2f,", pdi->sampleRates[j] ); } printf("\n"); } printf("Native Sample Formats = "); if( pdi->nativeSampleFormats & paInt8 ) printf("paInt8, "); if( pdi->nativeSampleFormats & paUInt8 ) printf("paUInt8, "); if( pdi->nativeSampleFormats & paInt16 ) printf("paInt16, "); if( pdi->nativeSampleFormats & paInt32 ) printf("paInt32, "); if( pdi->nativeSampleFormats & paFloat32 ) printf("paFloat32, "); if( pdi->nativeSampleFormats & paInt24 ) printf("paInt24, "); if( pdi->nativeSampleFormats & paPackedInt24 ) printf("paPackedInt24, "); printf("\n"); } Pa_Terminate(); printf("----------------------------------------------\n"); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/pa_fuzz.c0000644000175000017500000001216507622176614020622 0ustar mikaelmikael00000000000000/* * $Id: pa_fuzz.c,v 1.1.1.1.4.1 2003/02/11 21:41:32 philburk Exp $ * pa_fuzz.c * Distort input like a fuzz boz. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" /* ** Note that many of the older ISA sound cards on PCs do NOT support ** full duplex audio (simultaneous record and playback). ** And some only support full duplex at lower sample rates. */ #define SAMPLE_RATE (44100) #define PA_SAMPLE_TYPE paFloat32 #define FRAMES_PER_BUFFER (64) typedef float SAMPLE; float CubicAmplifier( float input ); static int fuzzCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /* Non-linear amplifier with soft distortion curve. */ float CubicAmplifier( float input ) { float output, temp; if( input < 0.0 ) { temp = input + 1.0f; output = (temp * temp * temp) - 1.0f; } else { temp = input - 1.0f; output = (temp * temp * temp) + 1.0f; } return output; } #define FUZZ(x) CubicAmplifier(CubicAmplifier(CubicAmplifier(CubicAmplifier(x)))) static int gNumNoInputs = 0; /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int fuzzCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { SAMPLE *out = (SAMPLE*)outputBuffer; SAMPLE *in = (SAMPLE*)inputBuffer; unsigned int i; (void) outTime; /* Prevent unused variable warnings. */ (void) userData; if( inputBuffer == NULL ) { for( i=0; i * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define SAMPLE_RATE (48000) #define AMPLITUDE (0.3) #define FRAMES_PER_BUFFER (64) #define OUTPUT_DEVICE Pa_GetDefaultOutputDeviceID() //#define OUTPUT_DEVICE (2) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int left_phase; int right_phase; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned long i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; isine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d, devID = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, OUTPUT_DEVICE); /* initialise sinusoidal wavetable */ for( i=0; i #include #include "portaudio.h" #define NUM_SECONDS (4) #define SAMPLE_RATE (44100) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct paTestData { float sine[TABLE_SIZE]; float amplitude; int left_phase; int right_phase; } paTestData; PaError PlaySine( paTestData *data, PaStreamFlags flags, float amplitude ); static int sineCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int sineCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; float amplitude = data->amplitude; unsigned int i; (void) outTime; (void) inputBuffer; for( i=0; isine[data->left_phase]; /* left */ *out++ = amplitude * data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } return 0; } /*******************************************************************/ int main(void); int main(void) { PaError err; paTestData DATA; int i; float amplitude = 32.0 / (1<<15); printf("PortAudio Test: output EXTREMELY QUIET sine wave with and without dithering.\n"); /* initialise sinusoidal wavetable */ for( i=0; ileft_phase = data->right_phase = 0; data->amplitude = amplitude; err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, paNoDevice,/* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, 1024, 0, /* number of buffers, if zero then use default minimum */ flags, /* we won't output out of range samples so don't bother clipping them */ sineCallback, (void *)data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; Pa_Sleep( NUM_SECONDS * 1000 ); printf("CPULoad = %8.6f\n", Pa_GetCPULoad( stream ) ); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); return paNoError; error: return err; } portaudio-18.1.orig/pa_tests/patest1.c0000644000175000017500000000665007423043522020515 0ustar mikaelmikael00000000000000/* $Id: patest1.c,v 1.1.1.1 2002/01/22 00:52:33 phil Exp $ patest1.c Ring modulate the audio input with a sine wave for 20 seconds using the Portable Audio api Author: Ross Bencina Modifications: April 5th, 2001 - PLB - Check for NULL inputBuffer. */ #include #include #include "portaudio.h" #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { float sine[100]; int phase; int sampsToGo; } patest1data; static int patest1Callback( void *inputBuffer, void *outputBuffer, unsigned long bufferFrames, PaTimestamp outTime, void *userData ) { patest1data *data = (patest1data*)userData; float *in = (float*)inputBuffer; float *out = (float*)outputBuffer; int framesToCalc = bufferFrames; unsigned long i; int finished = 0; /* Check to see if any input data is available. */ if(inputBuffer == NULL) return 0; if( data->sampsToGo < bufferFrames ) { framesToCalc = data->sampsToGo; finished = 1; } for( i=0; isine[data->phase]; /* left */ *out++ = *in++ * data->sine[data->phase++]; /* right */ if( data->phase >= 100 ) data->phase = 0; } data->sampsToGo -= framesToCalc; /* zero remainder of final buffer if not already done */ for( ; i #include #include "portaudio.h" #define NUM_SECONDS (5) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (512) #define LEFT_FREQ ((2 * SAMPLE_RATE)/FRAMES_PER_BUFFER) /* So we hit 1.0 */ #define RIGHT_FREQ (500.0) #define AMPLITUDE (0.9) /* Select ONE format for testing. */ #define TEST_UINT8 (0) #define TEST_INT8 (0) #define TEST_INT16 (0) #define TEST_INT32 (1) #define TEST_FLOAT32 (0) #if TEST_UINT8 #define TEST_FORMAT paUInt8 typedef unsigned char SAMPLE_t; #define SAMPLE_ZERO (0x80) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) #define FORMAT_NAME "Unsigned 8 Bit" #elif TEST_INT8 #define TEST_FORMAT paInt8 typedef char SAMPLE_t; #define SAMPLE_ZERO (0) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) #define FORMAT_NAME "Signed 8 Bit" #elif TEST_INT16 #define TEST_FORMAT paInt16 typedef short SAMPLE_t; #define SAMPLE_ZERO (0) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x))) #define FORMAT_NAME "Signed 16 Bit" #elif TEST_INT32 #define TEST_FORMAT paInt32 typedef long SAMPLE_t; #define SAMPLE_ZERO (0) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(0x7FFFFFFF * (x))) #define FORMAT_NAME "Signed 32 Bit" #elif TEST_FLOAT32 #define TEST_FORMAT paFloat32 typedef float SAMPLE_t; #define SAMPLE_ZERO (0.0) #define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x)) #define FORMAT_NAME "Float 32 Bit" #endif #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { double left_phase; double right_phase; unsigned int framesToGo; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; SAMPLE_t *out = (SAMPLE_t *)outputBuffer; int i; int framesToCalc; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; if( data->framesToGo < framesPerBuffer ) { framesToCalc = data->framesToGo; data->framesToGo = 0; finished = 1; } else { framesToCalc = framesPerBuffer; data->framesToGo -= framesPerBuffer; } for( i=0; ileft_phase += (LEFT_FREQ / SAMPLE_RATE); if( data->left_phase > 1.0) data->left_phase -= 1.0; *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); data->right_phase += (RIGHT_FREQ / SAMPLE_RATE); if( data->right_phase > 1.0) data->right_phase -= 1.0; *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); } /* zero remainder of final buffer */ for( ; i<(int)framesPerBuffer; i++ ) { *out++ = SAMPLE_ZERO; /* left */ *out++ = SAMPLE_ZERO; /* right */ } return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int totalSamps; printf("PortAudio Test: output " FORMAT_NAME "\n"); data.left_phase = data.right_phase = 0.0; data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */ err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, paNoDevice,/* default input device */ 0, /* no input */ TEST_FORMAT, NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ 2, /* stereo output */ TEST_FORMAT, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS ); fflush(stdout); while( Pa_StreamActive( stream ) ) Pa_Sleep(10); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("PortAudio Test Finished: " FORMAT_NAME "\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/debug_test1.c0000644000175000017500000000660307423043516021343 0ustar mikaelmikael00000000000000/* * $Id: debug_test1.c,v 1.1.1.1 2002/01/22 00:52:30 phil Exp $ patest1.c Ring modulate the audio input with a 441hz sine wave for 20 seconds using the Portable Audio api Author: Ross Bencina Modifications: April 5th, 2001 - PLB - Check for NULL inputBuffer. */ #include #include #include "portaudio.h" #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { float sine[100]; int phase; int sampsToGo; } patest1data; static int patest1Callback( void *inputBuffer, void *outputBuffer, unsigned long bufferFrames, PaTimestamp outTime, void *userData ) { patest1data *data = (patest1data*)userData; float *in = (float*)inputBuffer; float *out = (float*)outputBuffer; int framesToCalc = bufferFrames; unsigned long i; int finished = 0; if(inputBuffer == NULL) return 0; if( data->sampsToGo < bufferFrames ) { finished = 1; } for( i=0; iphase >= 100 ) data->phase = 0; } data->sampsToGo -= bufferFrames; /* zero remainder of final buffer if not already done */ for( ; i #include #include #include "portaudio.h" #define EWS88MT_12_REC (1) #define EWS88MT_12_PLAY (10) #define SBLIVE_REC (2) #define SBLIVE_PLAY (11) #if 0 #define INPUT_DEVICE_ID Pa_GetDefaultInputDeviceID() #define OUTPUT_DEVICE_ID Pa_GetDefaultOutputDeviceID() #else #define INPUT_DEVICE_ID (EWS88MT_12_REC) #define OUTPUT_DEVICE_ID (SBLIVE_PLAY) #endif #define INPUT_SAMPLE_RATE (22050.0) #define OUTPUT_SAMPLE_RATE (22050.0) #define NUM_SECONDS (4) #define SLEEP_DUR_MSEC (1000) #define FRAMES_PER_BUFFER (64) #define NUM_REC_BUFS (0) #define SAMPLES_PER_FRAME (2) #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; typedef struct { long frameIndex; /* Index into sample array. */ } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int recordCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData *) userData; (void) outputBuffer; /* Prevent unused variable warnings. */ (void) outTime; if( inputBuffer != NULL ) { data->frameIndex += framesPerBuffer; } return 0; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int playCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData *) userData; (void) inputBuffer; /* Prevent unused variable warnings. */ (void) outTime; if( outputBuffer != NULL ) { data->frameIndex += framesPerBuffer; } return 0; } /****************************************************************/ PaError MeasureStreamRate( PortAudioStream *stream, paTestData *dataPtr, double *ratePtr ) { PaError err; int i; int totalFrames = 0; int totalMSec = 0; dataPtr->frameIndex = 0; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) { int delta, endIndex; int startIndex = dataPtr->frameIndex; Pa_Sleep(SLEEP_DUR_MSEC); endIndex = dataPtr->frameIndex; delta = endIndex - startIndex; totalFrames += delta; totalMSec += SLEEP_DUR_MSEC; printf("index = %d, delta = %d\n", endIndex, delta ); fflush(stdout); } err = Pa_StopStream( stream ); if( err != paNoError ) goto error; *ratePtr = (totalFrames * 1000.0) / totalMSec; error: return err; } void ReportRate( double measuredRate, double expectedRate ) { double error; error = (measuredRate - expectedRate) / expectedRate; error = (error < 0 ) ? -error : error; printf("Measured rate = %6.1f, expected rate = %6.1f\n", measuredRate, expectedRate ); if( error > 0.1 ) { printf("ERROR: unexpected rate! --------------------- ERROR!\n"); } else { printf("SUCCESS: rate within tolerance!\n"); } } /*******************************************************************/ int main(void); int main(void) { PaError err; paTestData data = { 0 }; long i; double rate; const PaDeviceInfo *pdi; PortAudioStream *outputStream; PortAudioStream *inputStream; err = Pa_Initialize(); if( err != paNoError ) goto error; pdi = Pa_GetDeviceInfo( INPUT_DEVICE_ID ); printf("Input device = %s\n", pdi->name ); pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE_ID ); printf("Output device = %s\n", pdi->name ); /* Open input stream. */ err = Pa_OpenStream( &inputStream, INPUT_DEVICE_ID, SAMPLES_PER_FRAME, /* stereo input */ PA_SAMPLE_TYPE, NULL, paNoDevice, 0, PA_SAMPLE_TYPE, NULL, INPUT_SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ recordCallback, &data ); if( err != paNoError ) goto error; err = Pa_OpenStream( &outputStream, paNoDevice, 0, /* NO input */ PA_SAMPLE_TYPE, NULL, OUTPUT_DEVICE_ID, SAMPLES_PER_FRAME, /* stereo output */ PA_SAMPLE_TYPE, NULL, OUTPUT_SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ playCallback, &data ); if( err != paNoError ) goto error; /* Record and playback multiple times. */ for( i=0; i<2; i++ ) { printf("Measuring INPUT ------------------------- \n"); err = MeasureStreamRate( inputStream, &data, &rate ); if( err != paNoError ) goto error; ReportRate( rate, INPUT_SAMPLE_RATE ); printf("Measuring OUTPUT ------------------------- \n"); err = MeasureStreamRate( outputStream, &data, &rate ); if( err != paNoError ) goto error; ReportRate( rate, OUTPUT_SAMPLE_RATE ); } /* Clean up. */ err = Pa_CloseStream( inputStream ); if( err != paNoError ) goto error; err = Pa_CloseStream( outputStream ); if( err != paNoError ) goto error; if( err != paNoError ) goto error; Pa_Terminate(); printf("Test complete.\n"); fflush(stdout); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); if( err == paHostError ) { fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() ); } return -1; } portaudio-18.1.orig/pa_tests/debug_multi_in.c0000644000175000017500000001456307647243634022142 0ustar mikaelmikael00000000000000/* * $Id: debug_multi_in.c,v 1.1.1.1.4.3 2003/04/16 19:07:56 philburk Exp $ * debug_multi_in.c * Pass output from each of multiple channels * to a stereo output using the Portable Audio api. * Hacked test for debugging PA. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "portaudio.h" //#define INPUT_DEVICE_NAME ("EWS88 MT Interleaved Rec") #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) //#define OUTPUT_DEVICE (18) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define MIN_LATENCY_MSEC (400) #define MAX_INPUT_CHANNELS (9999) #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { int liveChannel; int numChannels; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; float *in = (float*)inputBuffer; int i; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; if( in == NULL ) return 0; for( i=0; i<(int)framesPerBuffer; i++ ) { /* Copy one channel of input to stereo output. */ *out++ = in[data->liveChannel]; *out++ = in[data->liveChannel]; in += data->numChannels; } return 0; } /*******************************************************************/ int PaFindDeviceByName( const char *name ) { int i; int numDevices; const PaDeviceInfo *pdi; int len = strlen( name ); PaDeviceID result = paNoDevice; numDevices = Pa_CountDevices(); for( i=0; iname, len ) == 0 ) { result = i; break; } } return result; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; PaDeviceID inputDevice; const PaDeviceInfo *pdi; printf("PortAudio Test: input signal from each channel. %d buffers\n", NUM_BUFFERS ); data.liveChannel = 0; err = Pa_Initialize(); if( err != paNoError ) goto error; #ifdef INPUT_DEVICE_NAME printf("Try to use device: %s\n", INPUT_DEVICE_NAME ); inputDevice = PaFindDeviceByName(INPUT_DEVICE_NAME); if( inputDevice == paNoDevice ) { printf("Could not find %s. Using default instead.\n", INPUT_DEVICE_NAME ); inputDevice = Pa_GetDefaultInputDeviceID(); } #else printf("Using default input device.\n"); inputDevice = Pa_GetDefaultInputDeviceID(); #endif pdi = Pa_GetDeviceInfo( inputDevice ); if( pdi == NULL ) { printf("Could not get device info!\n"); goto error; } printf("Input Device name is %s\n", pdi->name ); printf("Input Device has %d channels.\n", pdi->maxInputChannels); if( pdi->maxInputChannels <= MAX_INPUT_CHANNELS ) { data.numChannels = pdi->maxInputChannels; } else { data.numChannels = MAX_INPUT_CHANNELS; printf("Only use %d channels.\n", MAX_INPUT_CHANNELS ); } err = Pa_OpenStream( &stream, inputDevice, data.numChannels, paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, 2, paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; data.liveChannel = 0; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; for( i=0; i #include #include #include "portaudio.h" #ifndef M_PI #define M_PI (3.14159265) #endif #define TWOPI (M_PI * 2.0) #define DEFAULT_BUFFER_SIZE (64) typedef struct { double left_phase; double right_phase; } paTestData; /* Very simple synthesis routine to generate two sine waves. */ static int paminlatCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned int i; double left_phaseInc = 0.02; double right_phaseInc = 0.06; double left_phase = data->left_phase; double right_phase = data->right_phase; for( i=0; i TWOPI ) left_phase -= TWOPI; *out++ = (float) sin( left_phase ); right_phase += right_phaseInc; if( right_phase > TWOPI ) right_phase -= TWOPI; *out++ = (float) sin( right_phase ); } data->left_phase = left_phase; data->right_phase = right_phase; return 0; } void main( int argc, char **argv ); void main( int argc, char **argv ) { PortAudioStream *stream; PaError err; paTestData data; int go; int numBuffers = 0; int minBuffers = 0; int framesPerBuffer; double sampleRate = 44100.0; char str[256]; printf("paminlat - Determine minimum latency for your computer.\n"); printf(" usage: paminlat {framesPerBuffer}\n"); printf(" for example: paminlat 256\n"); printf("Adjust your stereo until you hear a smooth tone in each speaker.\n"); printf("Then try to find the smallest number of buffers that still sounds smooth.\n"); printf("Note that the sound will stop momentarily when you change the number of buffers.\n"); /* Get bufferSize from command line. */ framesPerBuffer = ( argc > 1 ) ? atol( argv[1] ) : DEFAULT_BUFFER_SIZE; printf("Frames per buffer = %d\n", framesPerBuffer ); data.left_phase = data.right_phase = 0.0; err = Pa_Initialize(); if( err != paNoError ) goto error; /* Ask PortAudio for the recommended minimum number of buffers. */ numBuffers = minBuffers = Pa_GetMinNumBuffers( framesPerBuffer, sampleRate ); printf("NumBuffers set to %d based on a call to Pa_GetMinNumBuffers()\n", numBuffers ); /* Try different numBuffers in a loop. */ go = 1; while( go ) { printf("Latency = framesPerBuffer * numBuffers = %d * %d = %d frames = %d msecs.\n", framesPerBuffer, numBuffers, framesPerBuffer*numBuffers, (int)((1000 * framesPerBuffer * numBuffers) / sampleRate) ); err = Pa_OpenStream( &stream, paNoDevice, 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ NULL, sampleRate, framesPerBuffer, numBuffers, /* number of buffers */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ paminlatCallback, &data ); if( err != paNoError ) goto error; if( stream == NULL ) goto error; /* Start audio. */ err = Pa_StartStream( stream ); if( err != paNoError ) goto error; /* Ask user for a new number of buffers. */ printf("\nMove windows around to see if the sound glitches.\n"); printf("NumBuffers currently %d, enter new number, or 'q' to quit: ", numBuffers ); gets( str ); if( str[0] == 'q' ) go = 0; else { numBuffers = atol( str ); if( numBuffers < minBuffers ) { printf( "numBuffers below minimum of %d! Set to minimum!!!\n", minBuffers ); numBuffers = minBuffers; } } /* Stop sound until ENTER hit. */ err = Pa_StopStream( stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; } printf("A good setting for latency would be somewhat higher than\n"); printf("the minimum latency that worked.\n"); printf("PortAudio: Test finished.\n"); Pa_Terminate(); return; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); } portaudio-18.1.orig/pa_tests/patest_clip.c0000644000175000017500000001417107423043522021440 0ustar mikaelmikael00000000000000/* * $Id: patest_clip.c,v 1.1.1.1 2002/01/22 00:52:34 phil Exp $ * patest_clip.c * Play a sine wave using the Portable Audio api for several seconds * at an amplitude that would require clipping. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (4) #define SAMPLE_RATE (44100) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct paTestData { float sine[TABLE_SIZE]; float amplitude; int left_phase; int right_phase; } paTestData; PaError PlaySine( paTestData *data, unsigned long flags, float amplitude ); /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int sineCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; float amplitude = data->amplitude; unsigned int i; (void) inputBuffer; /* Prevent "unused variable" warnings. */ (void) outTime; for( i=0; isine[data->left_phase]; /* left */ *out++ = amplitude * data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } return 0; } /*******************************************************************/ int main(void); int main(void) { PaError err; paTestData DATA; int i; printf("PortAudio Test: output sine wave with and without clipping.\n"); /* initialise sinusoidal wavetable */ for( i=0; ileft_phase = data->right_phase = 0; data->amplitude = amplitude; err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, paNoDevice,/* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, 1024, 0, /* number of buffers, if zero then use default minimum */ flags, /* we won't output out of range samples so don't bother clipping them */ sineCallback, data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; Pa_Sleep( NUM_SECONDS * 1000 ); printf("CPULoad = %8.6f\n", Pa_GetCPULoad( stream ) ); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); return paNoError; error: return err; } portaudio-18.1.orig/pa_tests/debug_sine.c0000644000175000017500000001624307631472620021245 0ustar mikaelmikael00000000000000/* * $Id: debug_sine.c,v 1.2.4.2 2003/03/06 06:09:20 philburk Exp $ * debug_sine.c * Play a sine sweep using the Portable Audio api for several seconds. * Hacked test for debugging PA. * * Author: Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) //#define OUTPUT_DEVICE (11) #define NUM_SECONDS (8) #define SLEEP_DUR (800) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define MSEC_PER_BUFFER (1000 * FRAMES_PER_BUFFER / SAMPLE_RATE) #if 0 #define MIN_LATENCY_MSEC (200) #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #else #define NUM_BUFFERS (0) #endif #define MIN_FREQ (100.0f) #define MAX_FREQ (4000.0f) #define FREQ_SCALAR (1.00002f) #define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (400) typedef struct { float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation float phase_increment; float left_phase; float right_phase; unsigned int framesToGo; } paTestData; /* Convert phase between and 1.0 to sine value * using linear interpolation. */ float LookupSine( paTestData *data, float phase ); float LookupSine( paTestData *data, float phase ) { float fIndex = phase*TABLE_SIZE; int index = (int) fIndex; float fract = fIndex - index; float lo = data->sine[index]; float hi = data->sine[index+1]; float val = lo + fract*(hi-lo); return val; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; int framesToCalc; int i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; if( data->framesToGo < framesPerBuffer ) { framesToCalc = data->framesToGo; data->framesToGo = 0; finished = 1; } else { framesToCalc = framesPerBuffer; data->framesToGo -= framesPerBuffer; } for( i=0; ileft_phase); /* left */ *out++ = LookupSine(data, data->right_phase); /* right */ data->left_phase += data->phase_increment; if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f; data->right_phase += (data->phase_increment * 1.5f); /* fifth above */ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f; /* sweep frequency then start over. */ data->phase_increment *= FREQ_SCALAR; if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ); } /* zero remainder of final buffer */ for( ; i<(int)framesPerBuffer; i++ ) { *out++ = 0; /* left */ *out++ = 0; /* right */ } // Pa_Sleep( 3 * MSEC_PER_BUFFER / 4 ); // Pa_Sleep( MSEC_PER_BUFFER / 3 ); return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; int totalSamps; printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS ); printf("MSEC_PER_BUFFER = %d\n", MSEC_PER_BUFFER ); /* initialise sinusoidal wavetable */ for( i=0; i * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (1024) #ifndef M_PI #define M_PI (3.14159265) #endif #define TWOPI (M_PI * 2.0) typedef struct paTestData { int sleepFor; double phase; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned long i; int finished = 0; double phaseInc = 0.02; double phase = data->phase; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; i TWOPI ) phase -= TWOPI; /* This is not a very efficient way to calc sines. */ *out++ = (float) sin( phase ); /* mono */ } if( data->sleepFor > 0 ) { Pa_Sleep( data->sleepFor ); } data->phase = phase; return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; int i; paTestData data = {0}; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER ); err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, paNoDevice,/* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ 1, /* mono output */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; /* Gradually increase sleep time. */ for( i=0; i<10000; i+= 1000 ) { printf("Sleep for %d milliseconds in audio callback.\n", i ); data.sleepFor = i; fflush(stdout); Pa_Sleep( ((i<1000) ? 1000 : i) ); } printf("Suffer for 10 seconds.\n"); fflush(stdout); Pa_Sleep( 10000 ); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_ringmix.c0000644000175000017500000000264707423043526022177 0ustar mikaelmikael00000000000000/* $Id: patest_ringmix.c,v 1.1.1.1 2002/01/22 00:52:37 phil Exp $ */ #include "stdio.h" #include "portaudio.h" /* This will be called asynchronously by the PortAudio engine. */ static int myCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { float *out = (float *) outputBuffer; float *in = (float *) inputBuffer; float leftInput, rightInput; unsigned int i; if( inputBuffer == NULL ) return 0; /* Read input buffer, process data, and fill output buffer. */ for( i=0; i * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (20) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (2048) #define MSEC_PER_BUFFER ( (FRAMES_PER_BUFFER * 1000) / SAMPLE_RATE ) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int left_phase; int right_phase; int sleepTime; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned long i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; isine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } /* Cause underflow to occur. */ if( data->sleepTime > 0 ) Pa_Sleep( data->sleepTime ); data->sleepTime += 1; return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); /* initialise sinusoidal wavetable */ for( i=0; i * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (8) #define SAMPLE_RATE (44100) #define TEST_UNSIGNED (1) #if TEST_UNSIGNED #define TEST_FORMAT paUInt8 #else #define TEST_FORMAT paInt8 #endif #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { #if TEST_UNSIGNED unsigned char sine[TABLE_SIZE]; #else char sine[TABLE_SIZE]; #endif int left_phase; int right_phase; unsigned int framesToGo; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; char *out = (char*)outputBuffer; int i; int framesToCalc; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; if( data->framesToGo < framesPerBuffer ) { framesToCalc = data->framesToGo; data->framesToGo = 0; finished = 1; } else { framesToCalc = framesPerBuffer; data->framesToGo -= framesPerBuffer; } for( i=0; isine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } /* zero remainder of final buffer */ for( ; i<(int)framesPerBuffer; i++ ) { #if TEST_UNSIGNED *out++ = (unsigned char) 0x80; /* left */ *out++ = (unsigned char) 0x80; /* right */ #else *out++ = 0; /* left */ *out++ = 0; /* right */ #endif } return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; int totalSamps; #if TEST_UNSIGNED printf("PortAudio Test: output UNsigned 8 bit sine wave.\n"); #else printf("PortAudio Test: output signed 8 bit sine wave.\n"); #endif /* initialise sinusoidal wavetable */ for( i=0; i #include #include #include "portaudio.h" #define NUM_SECONDS (1) #define SAMPLE_RATE (44100) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { short sine[TABLE_SIZE]; int left_phase; int right_phase; unsigned int sampsToGo; } paTestData; PaError TestOnce( void ); static int patest1Callback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patest1Callback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; short *out = (short*)outputBuffer; unsigned int i; int finished = 0; (void) inputBuffer; /* Prevent "unused variable" warnings. */ (void) outTime; if( data->sampsToGo < framesPerBuffer ) { /* final buffer... */ for( i=0; isampsToGo; i++ ) { *out++ = data->sine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } /* zero remainder of final buffer */ for( ; isine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } data->sampsToGo -= framesPerBuffer; } return finished; } /*******************************************************************/ #ifdef MACINTOSH int main(void); int main(void) { int i; PaError err; int numLoops = 10; printf("Loop %d times.\n", numLoops ); for( i=0; i 1 ) { numLoops = atoi(argv[1]); } for( i=0; i * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (10) #define SAMPLE_RATE (44100) #define AMPLITUDE (0.8) #define FRAMES_PER_BUFFER (64) #define OUTPUT_DEVICE Pa_GetDefaultOutputDeviceID() #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int phase; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned long i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; isine[data->phase]; /* left */ data->phase += 1; if( data->phase >= TABLE_SIZE ) data->phase -= TABLE_SIZE; } return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; printf("PortAudio Test: output MONO sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); /* initialise sinusoidal wavetable */ for( i=0; i #include #include "portaudio.h" #define NUM_SECONDS (10) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define LEFT_FREQ (SAMPLE_RATE/512.0) /* So we hit 1.0 */ #define RIGHT_FREQ (500.0) #define AMPLITUDE (1.0) /* Select ONE format for testing. */ #define TEST_UINT8 (1) #define TEST_INT8 (0) #define TEST_INT16 (0) #define TEST_FLOAT32 (0) #if TEST_UINT8 #define TEST_FORMAT paUInt8 typedef unsigned char SAMPLE_t; #define SAMPLE_ZERO (0x80) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) #define FORMAT_NAME "Unsigned 8 Bit" #elif TEST_INT8 #define TEST_FORMAT paInt8 typedef char SAMPLE_t; #define SAMPLE_ZERO (0) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x))) #define FORMAT_NAME "Signed 8 Bit" #elif TEST_INT16 #define TEST_FORMAT paInt16 typedef short SAMPLE_t; #define SAMPLE_ZERO (0) #define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x))) #define FORMAT_NAME "Signed 16 Bit" #elif TEST_FLOAT32 #define TEST_FORMAT paFloat32 typedef float SAMPLE_t; #define SAMPLE_ZERO (0.0) #define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x)) #define FORMAT_NAME "Float 32 Bit" #endif #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { double left_phase; double right_phase; unsigned int framesToGo; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; SAMPLE_t *out = (SAMPLE_t *)outputBuffer; SAMPLE_t sample; int i; int framesToCalc; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; if( data->framesToGo < framesPerBuffer ) { framesToCalc = data->framesToGo; data->framesToGo = 0; finished = 1; } else { framesToCalc = framesPerBuffer; data->framesToGo -= framesPerBuffer; } for( i=0; ileft_phase += (LEFT_FREQ / SAMPLE_RATE); if( data->left_phase > 1.0) data->left_phase -= 1.0; sample = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); /**/ *out++ = sample; /* *out++ = sample; /**/ /* *out++ = 0; /**/ data->right_phase += (RIGHT_FREQ / SAMPLE_RATE); if( data->right_phase > 1.0) data->right_phase -= 1.0; *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); /**/ /* *out++ = 0; /* */ } /* zero remainder of final buffer */ for( ; i<(int)framesPerBuffer; i++ ) { *out++ = SAMPLE_ZERO; /* left */ *out++ = SAMPLE_ZERO; /* right */ } return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int totalSamps; printf("PortAudio Test: output " FORMAT_NAME "\n"); data.left_phase = data.right_phase = 0.0; data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */ err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, paNoDevice,/* default input device */ 0, /* no input */ TEST_FORMAT, NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ 2, /* stereo output */ TEST_FORMAT, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS ); while( Pa_StreamActive( stream ) ) Pa_Sleep(10); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("PortAudio Test Finished: " FORMAT_NAME "\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_pink.c0000644000175000017500000002122107423043524021446 0ustar mikaelmikael00000000000000/* * $Id: patest_pink.c,v 1.1.1.1 2002/01/22 00:52:36 phil Exp $ patest_pink.c Generate Pink Noise using Gardner method. Optimization suggested by James McCartney uses a tree to select which random value to replace. x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x Tree is generated by counting trailing zeros in an increasing index. When the index is zero, no random number is selected. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define PINK_MAX_RANDOM_ROWS (30) #define PINK_RANDOM_BITS (24) #define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS) typedef struct { long pink_Rows[PINK_MAX_RANDOM_ROWS]; long pink_RunningSum; /* Used to optimize summing of generators. */ int pink_Index; /* Incremented each sample. */ int pink_IndexMask; /* Index wrapped by ANDing with this mask. */ float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */ } PinkNoise; /* Prototypes */ static unsigned long GenerateRandomNumber( void ); void InitializePinkNoise( PinkNoise *pink, int numRows ); float GeneratePinkNoise( PinkNoise *pink ); /************************************************************/ /* Calculate pseudo-random 32 bit number based on linear congruential method. */ static unsigned long GenerateRandomNumber( void ) { /* Change this seed for different random sequences. */ static unsigned long randSeed = 22222; randSeed = (randSeed * 196314165) + 907633515; return randSeed; } /************************************************************/ /* Setup PinkNoise structure for N rows of generators. */ void InitializePinkNoise( PinkNoise *pink, int numRows ) { int i; long pmax; pink->pink_Index = 0; pink->pink_IndexMask = (1<pink_Scalar = 1.0f / pmax; /* Initialize rows. */ for( i=0; ipink_Rows[i] = 0; pink->pink_RunningSum = 0; } #define PINK_MEASURE #ifdef PINK_MEASURE float pinkMax = -999.0; float pinkMin = 999.0; #endif /* Generate Pink noise values between -1.0 and +1.0 */ float GeneratePinkNoise( PinkNoise *pink ) { long newRandom; long sum; float output; /* Increment and mask index. */ pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask; /* If index is zero, don't update any random values. */ if( pink->pink_Index != 0 ) { /* Determine how many trailing zeros in PinkIndex. */ /* This algorithm will hang if n==0 so test first. */ int numZeros = 0; int n = pink->pink_Index; while( (n & 1) == 0 ) { n = n >> 1; numZeros++; } /* Replace the indexed ROWS random value. * Subtract and add back to RunningSum instead of adding all the random * values together. Only one changes each time. */ pink->pink_RunningSum -= pink->pink_Rows[numZeros]; newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; pink->pink_RunningSum += newRandom; pink->pink_Rows[numZeros] = newRandom; } /* Add extra white noise value. */ newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; sum = pink->pink_RunningSum + newRandom; /* Scale to range of -1.0 to 0.9999. */ output = pink->pink_Scalar * sum; #ifdef PINK_MEASURE /* Check Min/Max */ if( output > pinkMax ) pinkMax = output; else if( output < pinkMin ) pinkMin = output; #endif return output; } /*******************************************************************/ #define PINK_TEST #ifdef PINK_TEST /* Context for callback routine. */ typedef struct { PinkNoise leftPink; PinkNoise rightPink; unsigned int sampsToGo; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { int finished; int i; int numFrames; paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; (void) inputBuffer; /* Prevent "unused variable" warnings. */ (void) outTime; /* Are we almost at end. */ if( data->sampsToGo < framesPerBuffer ) { numFrames = data->sampsToGo; finished = 1; } else { numFrames = framesPerBuffer; finished = 0; } for( i=0; ileftPink ); *out++ = GeneratePinkNoise( &data->rightPink ); } data->sampsToGo -= numFrames; return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int totalSamps; /* Initialize two pink noise signals with different numbers of rows. */ InitializePinkNoise( &data.leftPink, 12 ); InitializePinkNoise( &data.rightPink, 16 ); /* Look at a few values. */ { int i; float pink; for( i=0; i<20; i++ ) { pink = GeneratePinkNoise( &data.leftPink ); printf("Pink = %f\n", pink ); } } data.sampsToGo = totalSamps = 8*44100; /* Play for a few seconds. */ err = Pa_Initialize(); if( err != paNoError ) goto error; /* Open a stereo PortAudio stream so we can hear the result. */ err = Pa_OpenStream( &stream, paNoDevice, 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ NULL, 44100., 2048, /* 46 msec buffers */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Waiting for sound to finish.\n"); while( Pa_StreamActive( stream ) ) { Pa_Sleep(100); /* SPIN! */ } err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; #ifdef PINK_MEASURE printf("Pink min = %f, max = %f\n", pinkMin, pinkMax ); #endif Pa_Terminate(); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return 0; } #endif /* PINK_TEST */ portaudio-18.1.orig/pa_tests/patest_two_rates.c0000644000175000017500000001322507622176700022525 0ustar mikaelmikael00000000000000/* * $Id: patest_two_rates.c,v 1.1.2.1 2003/02/11 21:42:24 philburk Exp $ * patest_two_rates.c * Play two streams at different rates to make sure they don't interfere. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SAMPLE_RATE_1 (44100) #define SAMPLE_RATE_2 (44100) #define FRAMES_PER_BUFFER (256) #define FREQ_INCR (0.1) #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { double phase; double numFrames; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; int frameIndex, channelIndex; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) { /* Generate sine wave. */ float value = (float) 0.3 * sin(data->phase); /* Stereo - two channels. */ *out++ = value; *out++ = value; data->phase += FREQ_INCR; if( data->phase >= (2.0 * M_PI) ) data->phase -= (2.0 * M_PI); } return 0; } /*******************************************************************/ int main(void); int main(void) { PaError err; PortAudioStream *stream1; PortAudioStream *stream2; paTestData data1 = {0}; paTestData data2 = {0}; printf("PortAudio Test: two rates.\n" ); err = Pa_Initialize(); if( err != paNoError ) goto error; /* Start first stream. **********************/ err = Pa_OpenStream( &stream1, paNoDevice, /* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, 2, /* Stereo */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE_1, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data1 ); if( err != paNoError ) goto error; err = Pa_StartStream( stream1 ); if( err != paNoError ) goto error; Pa_Sleep( 3 * 1000 ); /* Start second stream. **********************/ err = Pa_OpenStream( &stream2, paNoDevice, /* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, 2, /* Stereo */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE_2, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data2 ); if( err != paNoError ) goto error; err = Pa_StartStream( stream2 ); if( err != paNoError ) goto error; Pa_Sleep( 3 * 1000 ); err = Pa_StopStream( stream2 ); if( err != paNoError ) goto error; Pa_Sleep( 3 * 1000 ); err = Pa_StopStream( stream1 ); if( err != paNoError ) goto error; Pa_CloseStream( stream2 ); Pa_CloseStream( stream1 ); Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_sine.c0000644000175000017500000001216607622176614021463 0ustar mikaelmikael00000000000000/* * $Id: patest_sine.c,v 1.2.4.1 2003/02/11 21:41:32 philburk Exp $ * patest_sine.c * Play a sine wave using the Portable Audio api for several seconds. * * Authors: * Ross Bencina * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (10) #define SAMPLE_RATE (44100) #define AMPLITUDE (0.9) #define FRAMES_PER_BUFFER (64) #define OUTPUT_DEVICE Pa_GetDefaultOutputDeviceID() //#define OUTPUT_DEVICE (2) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int left_phase; int right_phase; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned long i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; isine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d, devID = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER, OUTPUT_DEVICE); /* initialise sinusoidal wavetable */ for( i=0; i * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SLEEP_DUR (200) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define LATENCY_MSEC (3000) #define NUM_BUFFERS ((LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #define FRAMES_PER_NOTE (SAMPLE_RATE/2) #define MAX_REPEATS (2) #define FUNDAMENTAL (400.0f / SAMPLE_RATE) #define NOTE_0 (FUNDAMENTAL * 1.0f / 1.0f) #define NOTE_1 (FUNDAMENTAL * 5.0f / 4.0f) #define NOTE_2 (FUNDAMENTAL * 4.0f / 3.0f) #define NOTE_3 (FUNDAMENTAL * 3.0f / 2.0f) #define NOTE_4 (FUNDAMENTAL * 2.0f / 1.0f) #define MODE_FINISH (0) #define MODE_STOP (1) #define MODE_ABORT (2) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (400) typedef struct { float waveform[TABLE_SIZE + 1]; // add one for guard point for interpolation float phase_increment; float phase; float *tune; int notesPerTune; int frameCounter; int noteCounter; int repeatCounter; PaTimestamp outTime; int stopMode; int done; } paTestData; /************* Prototypes *****************************/ int TestStopMode( paTestData *data ); float LookupWaveform( paTestData *data, float phase ); /****************************************************** * Convert phase between 0.0 and 1.0 to waveform value * using linear interpolation. */ float LookupWaveform( paTestData *data, float phase ) { float fIndex = phase*TABLE_SIZE; int index = (int) fIndex; float fract = fIndex - index; float lo = data->waveform[index]; float hi = data->waveform[index+1]; float val = lo + fract*(hi-lo); return val; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; float value; unsigned int i = 0; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; data->outTime = outTime; if( !data->done ) { for( i=0; iframeCounter >= FRAMES_PER_NOTE ) { data->noteCounter += 1; data->frameCounter = 0; /* Are we done with this tune? */ if( data->noteCounter >= data->notesPerTune ) { data->noteCounter = 0; data->repeatCounter += 1; /* Are we totally done? */ if( data->repeatCounter >= MAX_REPEATS ) { data->done = 1; if( data->stopMode == MODE_FINISH ) { finished = 1; break; } } } data->phase_increment = data->tune[data->noteCounter]; } value = LookupWaveform(data, data->phase); *out++ = value; /* left */ *out++ = value; /* right */ data->phase += data->phase_increment; if( data->phase >= 1.0f ) data->phase -= 1.0f; data->frameCounter += 1; } } /* zero remainder of final buffer */ for( ; idone = 0; data->phase = 0.0; data->frameCounter = 0; data->noteCounter = 0; data->repeatCounter = 0; data->phase_increment = data->tune[data->noteCounter]; err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, paNoDevice,/* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; if( data->stopMode == MODE_FINISH ) { while( Pa_StreamActive( stream ) ) { /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime, data->noteCounter, data->repeatCounter ); fflush(stdout); /**/ Pa_Sleep( SLEEP_DUR ); } } else { while( data->repeatCounter < MAX_REPEATS ) { /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime, data->noteCounter, data->repeatCounter ); fflush(stdout); /**/ Pa_Sleep( SLEEP_DUR ); } } if( data->stopMode == MODE_ABORT ) { printf("Call Pa_AbortStream()\n"); err = Pa_AbortStream( stream ); } else { printf("Call Pa_StopStream()\n"); err = Pa_StopStream( stream ); } if( err != paNoError ) goto error; printf("Call Pa_CloseStream()\n"); fflush(stdout); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_sync.c0000644000175000017500000002106607423043530021465 0ustar mikaelmikael00000000000000/* * $Id: patest_sync.c,v 1.1.1.1 2002/01/22 00:52:40 phil Exp $ * patest_sync.c * Test time stamping and synchronization of audio and video. * A high latency is used so we can hear the difference in time. * Random durations are used so we know we are hearing the right beep * and not the one before or after. * * Sequence of events: * Foreground requests a beep. * Background randomly schedules a beep. * Foreground waits for the beep to be heard based on Pa_StreamTime(). * Foreground outputs video (printf) in sync with audio. * Repeat. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_BEEPS (6) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define BEEP_DURATION (1000) #define LATENCY_MSEC (2000) #define SLEEP_MSEC (10) #define TIMEOUT_MSEC ((3 * LATENCY_MSEC) / (2 * SLEEP_MSEC)) #define NUM_BUFFERS ((LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #define STATE_BKG_IDLE (0) #define STATE_BKG_PENDING (1) #define STATE_BKG_BEEPING (2) typedef struct { float left_phase; float right_phase; int state; int requestBeep; /* Set by foreground, cleared by background. */ PaTimestamp beepTime; int beepCount; } paTestData; static unsigned long GenerateRandomNumber( void ); /************************************************************/ /* Calculate pseudo-random 32 bit number based on linear congruential method. */ static unsigned long GenerateRandomNumber( void ) { static unsigned long randSeed = 22222; /* Change this for different random sequences. */ randSeed = (randSeed * 196314165) + 907633515; return randSeed; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { /* Cast data passed through stream to our structure. */ paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned int i; (void) inputBuffer; for( i=0; istate ) { case STATE_BKG_IDLE: /* Schedule beep at some random time in the future. */ if( data->requestBeep ) { int random = GenerateRandomNumber() >> 14; data->beepTime = outTime + (i + random + (SAMPLE_RATE/4)); data->state = STATE_BKG_PENDING; data->requestBeep = 0; data->left_phase = data->right_phase = 0.0; } *out++ = 0.0; /* left */ *out++ = 0.0; /* right */ break; case STATE_BKG_PENDING: if( (outTime + i) >= data->beepTime ) { data->state = STATE_BKG_BEEPING; data->beepCount = BEEP_DURATION; } *out++ = 0.0; /* left */ *out++ = 0.0; /* right */ break; case STATE_BKG_BEEPING: if( data->beepCount <= 0 ) { data->state = STATE_BKG_IDLE; *out++ = 0.0; /* left */ *out++ = 0.0; /* right */ } else { /* Play sawtooth wave. */ *out++ = data->left_phase; /* left */ *out++ = data->right_phase; /* right */ /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */ data->left_phase += 0.01f; /* When signal reaches top, drop back down. */ if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f; /* higher pitch so we can distinguish left and right. */ data->right_phase += 0.03f; if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f; } data->beepCount -= 1; break; default: data->state = STATE_BKG_IDLE; break; } } return 0; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData DATA; int i, timeout; PaTimestamp previousTime; printf("PortAudio Test: you should see BEEP at the same time you hear it.\n"); printf("Wait for a few seconds random delay between BEEPs.\n"); printf("BEEP %d times.\n", NUM_BEEPS ); /* Initialize our DATA for use by callback. */ DATA.left_phase = DATA.right_phase = 0.0; DATA.state = STATE_BKG_IDLE; DATA.requestBeep = 0; /* Initialize library before making any other calls. */ err = Pa_Initialize(); if( err != paNoError ) goto error; /* Open an audio I/O stream. */ err = Pa_OpenDefaultStream( &stream, 0, /* no input channels */ 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, patestCallback, &DATA ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; previousTime = Pa_StreamTime( stream ); for( i=0; i 0 ) ) Pa_Sleep(SLEEP_MSEC); if( timeout <= 0 ) { fprintf( stderr, "Timed out waiting for background to acknowledge request.\n" ); goto error; } /* Wait for scheduled beep time. */ timeout = TIMEOUT_MSEC + (10000/SLEEP_MSEC); while( (Pa_StreamTime( stream ) < DATA.beepTime) && (timeout-- > 0 ) ) { Pa_Sleep(SLEEP_MSEC); } if( timeout <= 0 ) { fprintf( stderr, "Timed out waiting for time. Now = %g, Beep for %g.\n", Pa_StreamTime( stream ), DATA.beepTime ); goto error; } /* Beep should be sounding now so print synchronized BEEP. */ printf("BEEP"); fflush(stdout); printf(" at %d, delta = %d\n", (long) DATA.beepTime, (long) (DATA.beepTime - previousTime) ); fflush(stdout); previousTime = DATA.beepTime; } err = Pa_StopStream( stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_wire.c0000644000175000017500000001374407645313504021472 0ustar mikaelmikael00000000000000/* * $Id: patest_wire.c,v 1.2.4.3 2003/04/10 23:09:40 philburk Exp $ * patest_wire.c * * Pass input directly to output. * Note that some HW devices, for example many ISA audio cards * on PCs, do NOT support full duplex! For a PC, you normally need * a PCI based audio card such as the SBLive. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define INPUT_DEVICE Pa_GetDefaultInputDeviceID() #define OUTPUT_DEVICE Pa_GetDefaultOutputDeviceID() /* ** Note that many of the older ISA sound cards on PCs do NOT support ** full duplex audio (simultaneous record and playback). ** And some only support full duplex at lower sample rates. */ #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (64) #if 1 #define PA_SAMPLE_TYPE paFloat32 typedef float SAMPLE; #else #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; #endif static int wireCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int wireCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { SAMPLE *out = (SAMPLE*)outputBuffer; SAMPLE *in = (SAMPLE*)inputBuffer; unsigned int i; (void) outTime; int samplesPerFrame; int numSamples; samplesPerFrame = (int) userData; numSamples = framesPerBuffer * samplesPerFrame; /* This may get called with NULL inputBuffer during initial setup. */ if( inputBuffer == NULL ) { for( i=0; imaxInputChannels < outputInfo->maxOutputChannels) ? inputInfo->maxInputChannels : outputInfo->maxOutputChannels; printf("maxInputChannels channels = %d\n", inputInfo->maxInputChannels ); printf("maxOutputChannels channels = %d\n", outputInfo->maxOutputChannels ); if( numChannels > 0 ) { printf("Using %d channels.\n", numChannels ); err = Pa_OpenStream( &stream, INPUT_DEVICE, numChannels, PA_SAMPLE_TYPE, NULL, OUTPUT_DEVICE, numChannels, PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ wireCallback, (void *) numChannels ); /* pass numChannels to callback */ if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Full duplex sound test in progress.\n"); printf("Hit ENTER to exit test.\n"); fflush(stdout); getchar(); printf("Closing stream.\n"); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; } else { printf("Sorry, not enough channels.\n"); } Pa_Terminate(); printf("Full duplex sound test complete.\n"); fflush(stdout); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; } portaudio-18.1.orig/pa_tests/patest_buffer.c0000644000175000017500000001445707622176614022003 0ustar mikaelmikael00000000000000/* * $Id: patest_buffer.c,v 1.1.1.1.4.1 2003/02/11 21:41:32 philburk Exp $ * patest_buffer.c * Test opening streams with different buffer sizes. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "portaudio.h" #define NUM_SECONDS (1) #define SAMPLE_RATE (44100) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) #define BUFFER_TABLE 9 long buffer_table[] = {200,256,500,512,600, 723, 1000, 1024, 2345}; typedef struct { short sine[TABLE_SIZE]; int left_phase; int right_phase; unsigned int sampsToGo; } paTestData; PaError TestOnce( int buffersize ); static int paSineCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int paSineCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; short *out = (short*)outputBuffer; unsigned int i; int finished = 0; (void) inputBuffer; /* Prevent "unused variable" warnings. */ (void) outTime; if( data->sampsToGo < framesPerBuffer ) { for( i=0; isampsToGo; i++ ) { *out++ = data->sine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } /* zero remainder of final buffer */ for( ; isine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } data->sampsToGo -= framesPerBuffer; } return finished; } /*******************************************************************/ int main(void); int main(void) { int i; PaError err; printf("Test opening streams with different buffer sizes\n\n"); for (i = 0 ; i < BUFFER_TABLE; i++) { printf("Buffer size %d\n", buffer_table[i]); err = TestOnce(buffer_table[i]); if( err < 0 ) return 0; } } PaError TestOnce( int buffersize ) { PortAudioStream *stream; PaError err; paTestData data; int i; int totalSamps; /* initialise sinusoidal wavetable */ for( i=0; i #include #include "portaudio.h" #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define FREQ_INCR (300.0 / SAMPLE_RATE) #define MAX_CHANNELS (64) #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { int numChannels; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; int frameIndex, channelIndex; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) { for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) { /* Output sine wave on every channel. */ *out++ = (float) ((channelIndex + 1) * 0.1); } } return 0; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; const PaDeviceInfo *pdi; paTestData data = {0}; printf("PortAudio Test: output channel number on each channel.\n" ); err = Pa_Initialize(); if( err != paNoError ) goto error; pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE ); data.numChannels = pdi->maxOutputChannels; if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; printf("Number of Channels = %d\n", data.numChannels ); err = Pa_OpenStream( &stream, paNoDevice, /* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, data.numChannels, paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Hit ENTER to stop sound.\n"); fflush(stdout); getchar(); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; Pa_CloseStream( stream ); Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_saw.c0000644000175000017500000001100607423043526021301 0ustar mikaelmikael00000000000000/* * $Id: patest_saw.c,v 1.1.1.1 2002/01/22 00:52:38 phil Exp $ * patest_saw.c * Play a simple sawtooth wave. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (4) #define SAMPLE_RATE (44100) typedef struct { float left_phase; float right_phase; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { /* Cast data passed through stream to our structure. */ paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned int i; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; ileft_phase; /* left */ *out++ = data->right_phase; /* right */ /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */ data->left_phase += 0.01f; /* When signal reaches top, drop back down. */ if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f; /* higher pitch so we can distinguish left and right. */ data->right_phase += 0.03f; if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f; } return 0; } /*******************************************************************/ static paTestData data; int main(void); int main(void) { PortAudioStream *stream; PaError err; printf("PortAudio Test: output sawtooth wave.\n"); /* Initialize our data for use by callback. */ data.left_phase = data.right_phase = 0.0; /* Initialize library before making any other calls. */ err = Pa_Initialize(); if( err != paNoError ) goto error; /* Open an audio I/O stream. */ err = Pa_OpenDefaultStream( &stream, 0, /* no input channels */ 2, /* stereo output */ paFloat32, /* 32 bit floating point output */ SAMPLE_RATE, 256, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; /* Sleep for several seconds. */ Pa_Sleep(NUM_SECONDS*1000); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_sine_time.c0000644000175000017500000001613307446137706022502 0ustar mikaelmikael00000000000000/* * $Id: patest_sine_time.c,v 1.2 2002/03/21 00:58:45 philburk Exp $ * patest_sine_time.c * Play a sine wave using the Portable Audio api for several seconds. * Pausing in the middle. * use the Pa_StreamTime() and Pa_StreamActive() calls. * * Authors: * Ross Bencina * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (8) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (64) #define NUM_BUFFERS (0) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int left_phase; int right_phase; int framesToGo; volatile PaTimestamp outTime; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; int i; int framesToCalc; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; data->outTime = outTime; if( data->framesToGo < framesPerBuffer ) { framesToCalc = data->framesToGo; data->framesToGo = 0; finished = 1; } else { framesToCalc = framesPerBuffer; data->framesToGo -= framesPerBuffer; } for( i=0; isine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } /* zero remainder of final buffer */ for( ; i<(int)framesPerBuffer; i++ ) { *out++ = 0; /* left */ *out++ = 0; /* right */ } return finished; } /*******************************************************************/ static void ReportStreamTime( PortAudioStream *stream, paTestData *data ); static void ReportStreamTime( PortAudioStream *stream, paTestData *data ) { PaTimestamp streamTime, latency, outTime; streamTime = Pa_StreamTime( stream ); outTime = data->outTime; if( outTime < 0.0 ) { printf("Stream time = %8.1f\n", streamTime ); } else { latency = outTime - streamTime; printf("Stream time = %8.1f, outTime = %8.1f, latency = %8.1f\n", streamTime, outTime, latency ); } fflush(stdout); } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData DATA; int i; int totalSamps; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); /* initialise sinusoidal wavetable */ for( i=0; i #include #include "portaudio.h" #include "pa_host.h" /*******************************************************************/ int main(void); int main(void) { long max,min; int i; for( i=0; i<10000; i++ ) { long dither = PaConvert_TriangularDither(); // printf("dither = 0x%08X\n", dither ); if( dither < min ) min = dither; else if( dither > max ) max = dither; } printf("min = 0x%08X = %d, max = 0x%08X = %d\n", min, min, max, max ); } portaudio-18.1.orig/pa_tests/debug_sine_amp.c0000644000175000017500000001273007446136164022103 0ustar mikaelmikael00000000000000/* * $Id: debug_sine_amp.c,v 1.1 2002/03/21 00:44:35 philburk Exp $ * Play a different sine wave on each channels, * using the Portable Audio api. * Allos amplitude to be set interactively. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define FREQ_INCR (300.0 / SAMPLE_RATE) #define MAX_CHANNELS (64) #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { int numChannels; double phases[MAX_CHANNELS]; float amplitude; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; int frameIndex, channelIndex; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) { for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) { /* Output sine wave on every channel. */ *out++ = (float) ( data->amplitude * sin(data->phases[channelIndex]) ); /* Play each channel at a higher frequency. */ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); } } return 0; } /*******************************************************************/ int main(void); int main(void) { char pad[256]; PortAudioStream *stream; PaError err; const PaDeviceInfo *pdi; paTestData data = {0}; printf("PortAudio Test: output sine wave on each channel.\n" ); err = Pa_Initialize(); if( err != paNoError ) goto error; pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE ); data.numChannels = pdi->maxOutputChannels; if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; printf("Number of Channels = %d\n", data.numChannels ); data.amplitude = 1.0; err = Pa_OpenStream( &stream, paNoDevice, /* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, data.numChannels, paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; do { printf("Current amplitude = %f\n", data.amplitude ); printf("Enter new amplitude or 'q' to quit.\n"); fflush(stdout); gets( pad ); if( pad[0] != 'q' ) { // I tried to use atof but it seems to be broken on Mac OS X 10.1 float amp; sscanf( pad, "%f", & ); data.amplitude = amp; } } while( pad[0] != 'q' ); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; Pa_CloseStream( stream ); Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_toomanysines.c0000644000175000017500000001342007622176614023247 0ustar mikaelmikael00000000000000/* * $Id: patest_toomanysines.c,v 1.2.4.1 2003/02/11 21:41:32 philburk Exp $ * Play more sine waves than we can handle in real time as a stress test, * * Authors: * Ross Bencina * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define MAX_SINES (500) #define MAX_LOAD (1.2) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (512) #ifndef M_PI #define M_PI (3.14159265) #endif #define TWOPI (M_PI * 2.0) typedef struct paTestData { int numSines; double phases[MAX_SINES]; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned long i; int j; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; inumSines; j++ ) { /* Advance phase of next oscillator. */ phase = data->phases[j]; phase += phaseInc; if( phase > TWOPI ) phase -= TWOPI; phaseInc *= 1.02; if( phaseInc > 0.5 ) phaseInc *= 0.5; /* This is not a very efficient way to calc sines. */ output += (float) sin( phase ); data->phases[j] = phase; } *out++ = (float) (output / data->numSines); } return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; int numStress; paTestData data = {0}; double load; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d. MAX_LOAD = %f\n", SAMPLE_RATE, FRAMES_PER_BUFFER, MAX_LOAD ); err = Pa_Initialize(); if( err != paNoError ) goto error; err = Pa_OpenStream( &stream, paNoDevice,/* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, Pa_GetDefaultOutputDeviceID(), /* default output device */ 1, /* mono output */ paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; /* Determine number of sines required to get to 50% */ do { data.numSines++; Pa_Sleep( 100 ); load = Pa_GetCPULoad( stream ); printf("numSines = %d, CPU load = %f\n", data.numSines, load ); fflush(stdout); } while( load < 0.5 ); /* Calculate target stress value then ramp up to that level*/ numStress = (int) (2.0 * data.numSines * MAX_LOAD ); for( ; data.numSines < numStress; data.numSines++ ) { Pa_Sleep( 200 ); load = Pa_GetCPULoad( stream ); printf("STRESSING: numSines = %d, CPU load = %f\n", data.numSines, load ); fflush(stdout); } printf("Suffer for 5 seconds.\n"); Pa_Sleep( 5000 ); printf("Stop stream.\n"); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/debug_record_reuse.c0000644000175000017500000002544207464236056022776 0ustar mikaelmikael00000000000000/* * $Id: debug_record_reuse.c,v 1.1 2002/05/02 20:16:29 philburk Exp $ * debug_record_reuse.c * Record input into an array. * Save array to a file. * Based on patest_record.c but with various ugly debug hacks thrown in. * Loop twice and reuse same streams. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "portaudio.h" #define SAMPLE_RATE (22050) #define NUM_SECONDS (4) #define SLEEP_DUR_MSEC (200) #define FRAMES_PER_BUFFER (256) #define NUM_REC_BUFS (0) #if 1 #define PA_SAMPLE_TYPE paFloat32 typedef float SAMPLE; #else #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; #endif typedef struct { long frameIndex; /* Index into sample array. */ long maxFrameIndex; long samplesPerFrame; long numSamples; PortAudioStream *outputStream; PortAudioStream *inputStream; SAMPLE *recordedSamples; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int recordCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; SAMPLE *rptr = (SAMPLE*)inputBuffer; SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; long framesToCalc; unsigned long i; int finished; unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; (void) outputBuffer; /* Prevent unused variable warnings. */ (void) outTime; if( framesLeft < framesPerBuffer ) { framesToCalc = framesLeft; finished = 1; } else { framesToCalc = framesPerBuffer; finished = 0; } if( inputBuffer == NULL ) { for( i=0; iframeIndex += framesToCalc; return finished; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int playCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame]; SAMPLE *wptr = (SAMPLE*)outputBuffer; unsigned long i; int finished; unsigned int framesLeft = data->maxFrameIndex - data->frameIndex; if( outputBuffer == NULL ) return 0; (void) inputBuffer; /* Prevent unused variable warnings. */ (void) outTime; if( framesLeft < framesPerBuffer ) { /* final buffer... */ for( i=0; iframeIndex += framesLeft; finished = 1; } else { for( i=0; iframeIndex += framesPerBuffer; finished = 0; } return finished; } /****************************************************************/ PaError TestRecording( paTestData *dataPtr ) { PaError err; int i; int lastIndex = 0; /* Open input stream if not already open. */ if( dataPtr->inputStream == NULL ) { /* Record some audio. */ err = Pa_OpenStream( &dataPtr->inputStream, Pa_GetDefaultInputDeviceID(), dataPtr->samplesPerFrame, /* stereo input */ PA_SAMPLE_TYPE, NULL, paNoDevice, 0, PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ recordCallback, dataPtr ); if( err != paNoError ) goto error; } dataPtr->frameIndex = 0; err = Pa_StartStream( dataPtr->inputStream ); if( err != paNoError ) goto error; printf("Now recording!\n"); fflush(stdout); for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) { int frameIndex, delta; Pa_Sleep(SLEEP_DUR_MSEC); frameIndex = dataPtr->frameIndex; if( Pa_StreamActive( dataPtr->inputStream ) <= 0) { printf("Stream inactive!\n"); break; } if( dataPtr->maxFrameIndex <= frameIndex ) { printf("Buffer recording complete.\n"); break; } delta = frameIndex - lastIndex; lastIndex = frameIndex; printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout); } err = Pa_StopStream( dataPtr->inputStream ); if( err != paNoError ) goto error; printf("Done.\n"); fflush(stdout); error: return err; } /****************************************************************/ PaError TestPlayback( paTestData *dataPtr ) { PaError err; int i; int lastIndex = 0; /* Playback recorded data. */ dataPtr->frameIndex = 0; printf("Begin playback.\n"); fflush(stdout); /* Open output stream if not already open. */ if( dataPtr->outputStream == NULL ) { err = Pa_OpenStream( &dataPtr->outputStream, paNoDevice, 0, /* NO input */ PA_SAMPLE_TYPE, NULL, Pa_GetDefaultOutputDeviceID(), dataPtr->samplesPerFrame, /* stereo output */ PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ playCallback, dataPtr ); if( err != paNoError ) goto error; } err = Pa_StartStream( dataPtr->outputStream ); if( err != paNoError ) goto error; printf("Waiting for playback to finish.\n"); fflush(stdout); for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ ) { int frameIndex, delta; Pa_Sleep(SLEEP_DUR_MSEC); frameIndex = dataPtr->frameIndex; delta = frameIndex - lastIndex; lastIndex = frameIndex; printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout); } err = Pa_StopStream( dataPtr->outputStream ); if( err != paNoError ) goto error; error: return err; } /*******************************************************************/ int main(void); int main(void) { PaError err; paTestData data = { 0 }; long totalFrames; long numBytes; long i; printf("patest_record.c\n"); fflush(stdout); /* Set up test data structure and sample array. */ data.frameIndex = 0; data.samplesPerFrame = 2; data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE; printf("totalFrames = %d\n", totalFrames ); fflush(stdout); data.numSamples = totalFrames * data.samplesPerFrame; numBytes = data.numSamples * sizeof(SAMPLE); data.recordedSamples = (SAMPLE *) malloc( numBytes ); if( data.recordedSamples == NULL ) { printf("Could not allocate record array.\n"); exit(1); } for( i=0; i * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define MAX_SINES (500) #define MAX_USAGE (0.8) #define SAMPLE_RATE (44100) #define FREQ_TO_PHASE_INC(freq) (freq/(float)SAMPLE_RATE) #define MIN_PHASE_INC FREQ_TO_PHASE_INC(200.0f) #define MAX_PHASE_INC (MIN_PHASE_INC * (1 << 5)) #define FRAMES_PER_BUFFER (512) #ifndef M_PI #define M_PI (3.14159265) #endif #define TWOPI (M_PI * 2.0) #define TABLE_SIZE (512) typedef struct paTestData { int numSines; float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */ float phases[MAX_SINES]; } paTestData; /* Convert phase between and 1.0 to sine value * using linear interpolation. */ float LookupSine( paTestData *data, float phase ); float LookupSine( paTestData *data, float phase ) { float fIndex = phase*TABLE_SIZE; int index = (int) fIndex; float fract = fIndex - index; float lo = data->sine[index]; float hi = data->sine[index+1]; float val = lo + fract*(hi-lo); return val; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; float outSample; float scaler; int numForScale; unsigned long i; int j; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; /* Detemine amplitude scaling factor */ numForScale = data->numSines; if( numForScale < 8 ) numForScale = 8; /* prevent pops at beginning */ scaler = 1.0f / numForScale; for( i=0; inumSines; j++ ) { /* Advance phase of next oscillator. */ phase = data->phases[j]; phase += phaseInc; if( phase >= 1.0 ) phase -= 1.0; output += LookupSine(data, phase); data->phases[j] = phase; phaseInc *= 1.02f; if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC; } outSample = (float) (output * scaler); *out++ = outSample; /* Left */ *out++ = outSample; /* Right */ } return finished; } /*******************************************************************/ int main(void); int main(void) { int i; PortAudioStream *stream; PaError err; paTestData data = {0}; double load; printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); /* initialise sinusoidal wavetable */ for( i=0; i #include #include "portaudio.h" #define SAMPLE_RATE (44100) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int left_phase; int right_phase; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned int i; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; isine[data->left_phase]; /* left */ *out++ = data->sine[data->right_phase]; /* right */ data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } return 0; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; printf("PortAudio Test: output sine wave.\n"); /* initialise sinusoidal wavetable */ for( i=0; i * Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define NUM_SECONDS (8) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (512) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (200) typedef struct { float sine[TABLE_SIZE]; int left_phase; int right_phase; int toggle; int countDown; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; unsigned long i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; itoggle ) { *out++ = data->sine[data->left_phase]; /* left */ *out++ = 0; /* right */ } else { *out++ = 0; /* left */ *out++ = data->sine[data->right_phase]; /* right */ } data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; } if( data->countDown < 0 ) { data->countDown = SAMPLE_RATE; data->toggle = !data->toggle; } data->countDown -= framesPerBuffer; return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; int timeout; printf("Play different tone sine waves that alternate between left and right channel.\n"); printf("The low tone should be on the left channel.\n"); /* initialise sinusoidal wavetable */ for( i=0; i 0 ) { Pa_Sleep( 300 ); timeout -= 1; } err = Pa_StopStream( stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_multi_sine.c0000644000175000017500000001203307622666752022675 0ustar mikaelmikael00000000000000/* * $Id: patest_multi_sine.c,v 1.1.4.2 2003/02/13 18:05:30 philburk Exp $ * patest_multi_out.c * Play a different sine wave on each channels, * using the Portable Audio api. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define FREQ_INCR (300.0 / SAMPLE_RATE) #define MAX_CHANNELS (64) #ifndef M_PI #define M_PI (3.14159265) #endif typedef struct { int numChannels; double phases[MAX_CHANNELS]; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; int frameIndex, channelIndex; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ ) { for( channelIndex=0; channelIndexnumChannels; channelIndex++ ) { /* Output sine wave on every channel. */ *out++ = (float) (0.7 * sin(data->phases[channelIndex])); /* Play each channel at a higher frequency. */ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex); if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI); } } return 0; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; const PaDeviceInfo *pdi; paTestData data = {0}; printf("PortAudio Test: output sine wave on each channel.\n" ); err = Pa_Initialize(); if( err != paNoError ) goto error; pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE ); data.numChannels = pdi->maxOutputChannels; if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS; printf("Number of Channels = %d\n", data.numChannels ); err = Pa_OpenStream( &stream, paNoDevice, /* default input device */ 0, /* no input */ paFloat32, /* 32 bit floating point input */ NULL, OUTPUT_DEVICE, data.numChannels, paFloat32, /* 32 bit floating point output */ NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ patestCallback, &data ); if( err != paNoError ) goto error; err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Hit ENTER to stop sound.\n"); fflush(stdout); getchar(); err = Pa_StopStream( stream ); if( err != paNoError ) goto error; Pa_CloseStream( stream ); Pa_Terminate(); printf("Test finished.\n"); return err; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return err; } portaudio-18.1.orig/pa_tests/patest_record.c0000644000175000017500000002342307647243634022005 0ustar mikaelmikael00000000000000/* * $Id: patest_record.c,v 1.2.4.4 2003/04/16 19:07:56 philburk Exp $ * patest_record.c * Record input into an array. * Optionally save array to a file. * Playback recorded data. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" /* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ #define SAMPLE_RATE (44100) #define NUM_SECONDS (5) #define NUM_CHANNELS (2) /* #define DITHER_FLAG (paDitherOff) */ #define DITHER_FLAG (0) /**/ #define FRAMES_PER_BUFFER (1024) /* Select sample format. */ #if 1 #define PA_SAMPLE_TYPE paFloat32 typedef float SAMPLE; #define SAMPLE_SILENCE (0.0f) #elif 0 #define PA_SAMPLE_TYPE paInt16 typedef short SAMPLE; #define SAMPLE_SILENCE (0) #elif 0 #define PA_SAMPLE_TYPE paInt8 typedef char SAMPLE; #define SAMPLE_SILENCE (0) #else #define PA_SAMPLE_TYPE paUInt8 typedef unsigned char SAMPLE; #define SAMPLE_SILENCE (128) #endif typedef struct { int frameIndex; /* Index into sample array. */ int maxFrameIndex; SAMPLE *recordedSamples; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int recordCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; SAMPLE *rptr = (SAMPLE*)inputBuffer; SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; long framesToRecord; long i; int finished; unsigned long framesLeft = data->maxFrameIndex - data->frameIndex; int samplesToRecord; (void) outputBuffer; /* Prevent unused variable warnings. */ (void) outTime; if( framesLeft < framesPerBuffer ) { framesToRecord = framesLeft; finished = 1; } else { framesToRecord = framesPerBuffer; finished = 0; } samplesToRecord = framesToRecord * NUM_CHANNELS; if( inputBuffer == NULL ) { for( i=0; iframeIndex += framesToRecord; return finished; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int playCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS]; SAMPLE *wptr = (SAMPLE*)outputBuffer; unsigned int i; int finished; unsigned int framesLeft = data->maxFrameIndex - data->frameIndex; (void) inputBuffer; /* Prevent unused variable warnings. */ (void) outTime; int framesToPlay, samplesToPlay, samplesPerBuffer; if( framesLeft < framesPerBuffer ) { framesToPlay = framesLeft; finished = 1; } else { framesToPlay = framesPerBuffer; finished = 0; } samplesToPlay = framesToPlay * NUM_CHANNELS; samplesPerBuffer = framesPerBuffer * NUM_CHANNELS; for( i=0; iframeIndex += framesToPlay; return finished; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; int totalFrames; int numSamples; int numBytes; SAMPLE max, average, val; printf("patest_record.c\n"); fflush(stdout); data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */ data.frameIndex = 0; numSamples = totalFrames * NUM_CHANNELS; numBytes = numSamples * sizeof(SAMPLE); data.recordedSamples = (SAMPLE *) malloc( numBytes ); if( data.recordedSamples == NULL ) { printf("Could not allocate record array.\n"); exit(1); } for( i=0; i max ) { max = val; } average += val; } average = average / numSamples; if( PA_SAMPLE_TYPE == paFloat32 ) /* This should be done at compile-time with "#if" ?? */ { /* MIPS-compiler warns at the int-version below. */ printf("sample max amplitude = %f\n", max ); printf("sample average = %f\n", average ); } else { printf("sample max amplitude = %d\n", max ); /* <-- This IS compiled anyhow. */ printf("sample average = %d\n", average ); } /* Write recorded data to a file. */ #if 0 { FILE *fid; fid = fopen("recorded.raw", "wb"); if( fid == NULL ) { printf("Could not open file."); } else { fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid ); fclose( fid ); printf("Wrote data to 'recorded.raw'\n"); } } #endif /* Playback recorded data. -------------------------------------------- */ data.frameIndex = 0; printf("Begin playback.\n"); fflush(stdout); err = Pa_OpenStream( &stream, paNoDevice, 0, /* NO input */ PA_SAMPLE_TYPE, NULL, Pa_GetDefaultOutputDeviceID(), NUM_CHANNELS, PA_SAMPLE_TYPE, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ playCallback, &data ); if( err != paNoError ) goto error; if( stream ) { err = Pa_StartStream( stream ); if( err != paNoError ) goto error; printf("Waiting for playback to finish.\n"); fflush(stdout); while( Pa_StreamActive( stream ) ) Pa_Sleep(100); err = Pa_CloseStream( stream ); if( err != paNoError ) goto error; printf("Done.\n"); fflush(stdout); } free( data.recordedSamples ); Pa_Terminate(); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; } portaudio-18.1.orig/pa_tests/paqa_devs.c0000644000175000017500000002717607622176614021117 0ustar mikaelmikael00000000000000/* * $Id: paqa_devs.c,v 1.1.1.1.4.1 2003/02/11 21:41:32 philburk Exp $ * paqa_devs.c * Self Testing Quality Assurance app for PortAudio * Try to open each device and run through all the * possible configurations. * * Author: Phil Burk http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #include "pa_trace.h" /****************************************** Definitions ***********/ #define MODE_INPUT (0) #define MODE_OUTPUT (1) typedef struct PaQaData { unsigned long framesLeft; int numChannels; int bytesPerSample; int mode; short sawPhase; PaSampleFormat format; } PaQaData; /****************************************** Prototypes ***********/ static void TestDevices( int mode ); static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate, int numChannels ); static int TestAdvance( int mode, PaDeviceID deviceID, double sampleRate, int numChannels, PaSampleFormat format ); static int QaCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /****************************************** Globals ***********/ static int gNumPassed = 0; static int gNumFailed = 0; /****************************************** Macros ***********/ /* Print ERROR if it fails. Tally success or failure. */ /* Odd do-while wrapper seems to be needed for some compilers. */ #define EXPECT(_exp) \ do \ { \ if ((_exp)) {\ /* printf("SUCCESS for %s\n", #_exp ); */ \ gNumPassed++; \ } \ else { \ printf("ERROR - 0x%x - %s for %s\n", result, \ ((result == 0) ? "-" : Pa_GetErrorText(result)), \ #_exp ); \ gNumFailed++; \ goto error; \ } \ } while(0) /*******************************************************************/ /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int QaCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { unsigned long i; short phase; PaQaData *data = (PaQaData *) userData; (void) inputBuffer; (void) outTime; /* Play simple sawtooth wave. */ if( data->mode == MODE_OUTPUT ) { phase = data->sawPhase; switch( data->format ) { case paFloat32: { float *out = (float *) outputBuffer; for( i=0; inumChannels == 2 ) { *out++ = (float) (phase * (1.0 / 32768.0)); } } } break; case paInt32: { int *out = (int *) outputBuffer; for( i=0; inumChannels == 2 ) { *out++ = ((int) phase ) << 16; } } } break; case paInt16: { short *out = (short *) outputBuffer; for( i=0; inumChannels == 2 ) { *out++ = phase; } } } break; default: { unsigned char *out = (unsigned char *) outputBuffer; unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; for( i=0; isawPhase = phase; } /* Are we through yet? */ if( data->framesLeft > framesPerBuffer ) { AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft ); data->framesLeft -= framesPerBuffer; return 0; } else { AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft ); data->framesLeft = 0; return 1; } } /*******************************************************************/ int main(void); int main(void) { PaError result; EXPECT( ((result=Pa_Initialize()) == 0) ); printf("Test OUTPUT ---------------\n"); TestDevices( MODE_OUTPUT ); printf("Test INPUT ---------------\n"); TestDevices( MODE_INPUT ); error: Pa_Terminate(); printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed ); } /******************************************************************* * Try each output device, through its full range of capabilities. */ static void TestDevices( int mode ) { int id,jc,kr; int maxChannels; const PaDeviceInfo *pdi; int numDevices = Pa_CountDevices(); /* Iterate through all devices. */ for( id=0; idmaxInputChannels : pdi->maxOutputChannels; for( jc=1; jc<=maxChannels; jc++ ) { printf("Name = %s\n", pdi->name ); /* Try each legal sample rate. */ if( pdi->numSampleRates == -1 ) { double low, high; low = pdi->sampleRates[0]; high = pdi->sampleRates[1]; if( low < 8000.0 ) low = 8000.0; TestFormats( mode, id, low, jc ); #define TESTSR(sr) {if(((sr)>=low) && ((sr)<=high)) TestFormats( mode, id, (sr), jc ); } TESTSR(11025.0); TESTSR(22050.0); TESTSR(34567.0); TESTSR(44100.0); TestFormats( mode, id, high, jc ); } else { for( kr=0; krnumSampleRates; kr++ ) { TestFormats( mode, id, pdi->sampleRates[kr], jc ); } } } } } /*******************************************************************/ static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate, int numChannels ) { TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); /* */ TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); /* */ TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); /* */ } /*******************************************************************/ static int TestAdvance( int mode, PaDeviceID deviceID, double sampleRate, int numChannels, PaSampleFormat format ) { PortAudioStream *stream = NULL; PaError result; PaQaData myData; #define FRAMES_PER_BUFFER (64) printf("------ TestAdvance: %s, device = %d, rate = %g, numChannels = %d, format = %d -------\n", ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT", deviceID, sampleRate, numChannels, format); fflush(stdout); /* Setup data for synthesis thread. */ myData.framesLeft = (unsigned long) (sampleRate * 100); /* 100 seconds */ myData.numChannels = numChannels; myData.mode = mode; myData.format = format; switch( format ) { case paFloat32: case paInt32: case paInt24: myData.bytesPerSample = 4; break; case paPackedInt24: myData.bytesPerSample = 3; break; default: myData.bytesPerSample = 2; break; } EXPECT( ((result = Pa_OpenStream( &stream, ( mode == MODE_INPUT ) ? deviceID : paNoDevice, ( mode == MODE_INPUT ) ? numChannels : 0, format, NULL, ( mode == MODE_OUTPUT ) ? deviceID : paNoDevice, ( mode == MODE_OUTPUT ) ? numChannels : 0, format, NULL, sampleRate, FRAMES_PER_BUFFER, /* frames per buffer */ 0, /* number of buffers, if zero then use default minimum */ paClipOff, /* we won't output out of range samples so don't bother clipping them */ QaCallback, &myData ) ) == 0) ); if( stream ) { PaTimestamp oldStamp, newStamp; unsigned long oldFrames; int minDelay = ( mode == MODE_INPUT ) ? 1000 : 400; int minNumBuffers = Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); int msec = (int) ((minNumBuffers * 3 * 1000.0 * FRAMES_PER_BUFFER) / sampleRate); if( msec < minDelay ) msec = minDelay; printf("msec = %d\n", msec); /**/ EXPECT( ((result=Pa_StartStream( stream )) == 0) ); /* Check to make sure PortAudio is advancing timeStamp. */ result = paNoError; oldStamp = Pa_StreamTime(stream); fflush(stdout); Pa_Sleep(msec); newStamp = Pa_StreamTime(stream); printf("oldStamp = %g,newStamp = %g\n", oldStamp, newStamp ); /**/ EXPECT( (oldStamp < newStamp) ); /* Check to make sure callback is decrementing framesLeft. */ oldFrames = myData.framesLeft; Pa_Sleep(msec); printf("oldFrames = %d, myData.framesLeft = %d\n", oldFrames, myData.framesLeft ); /**/ EXPECT( (oldFrames > myData.framesLeft) ); EXPECT( ((result=Pa_CloseStream( stream )) == 0) ); stream = NULL; } error: if( stream != NULL ) Pa_CloseStream( stream ); fflush(stdout); return result; } portaudio-18.1.orig/pa_tests/patest_latency.c0000644000175000017500000001431707446137706022167 0ustar mikaelmikael00000000000000/* * $Id: patest_latency.c,v 1.4 2002/03/21 00:58:45 philburk Exp $ * Hear the latency caused by big buffers. * Play a sine wave and change frequency based on letter input. * * Author: Phil Burk , and Darren Gibbs * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (64) #if 0 #define MIN_LATENCY_MSEC (2000) #define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000)) #else #define NUM_BUFFERS (0) #endif #define MIN_FREQ (100.0f) #define CalcPhaseIncrement(freq) ((freq)/SAMPLE_RATE) #ifndef M_PI #define M_PI (3.14159265) #endif #define TABLE_SIZE (400) typedef struct { float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation float phase_increment; float left_phase; float right_phase; } paTestData; float LookupSine( paTestData *data, float phase ); /* Convert phase between and 1.0 to sine value * using linear interpolation. */ float LookupSine( paTestData *data, float phase ) { float fIndex = phase*TABLE_SIZE; int index = (int) fIndex; float fract = fIndex - index; float lo = data->sine[index]; float hi = data->sine[index+1]; float val = lo + fract*(hi-lo); return val; } /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; float *out = (float*)outputBuffer; int i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; for( i=0; ileft_phase); /* left */ *out++ = LookupSine(data, data->right_phase); /* right */ data->left_phase += data->phase_increment; if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f; data->right_phase += (data->phase_increment * 1.5f); /* fifth above */ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f; } return 0; } /*******************************************************************/ int main(void); int main(void) { PortAudioStream *stream; PaError err; paTestData data; int i; int done = 0; printf("PortAudio Test: enter letter then hit ENTER. numBuffers = %d\n", NUM_BUFFERS ); /* initialise sinusoidal wavetable */ for( i=0; i #include #include "portaudio.h" /****************************************** Definitions ***********/ #define MODE_INPUT (0) #define MODE_OUTPUT (1) #define FRAMES_PER_BUFFER (64) #define SAMPLE_RATE (44100.0) #define NUM_BUFFERS (0) typedef struct PaQaData { unsigned long framesLeft; int numChannels; int bytesPerSample; int mode; } PaQaData; /****************************************** Prototypes ***********/ static void TestDevices( int mode ); static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate, int numChannels ); static int TestBadOpens( void ); static int TestBadActions( void ); static int QaCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); /****************************************** Globals ***********/ static int gNumPassed = 0; static int gNumFailed = 0; /****************************************** Macros ***********/ /* Print ERROR if it fails. Tally success or failure. */ /* Odd do-while wrapper seems to be needed for some compilers. */ #define EXPECT( msg, _exp) \ do \ { \ if ((_exp)) {\ gNumPassed++; \ } \ else { \ printf("\nERROR %s\n - 0x%x - %s for %s\n", (msg), result, Pa_GetErrorText(result), #_exp ); \ gNumFailed++; \ goto error; \ } \ } while(0) #define HOPEFOR( msg, _exp) \ do \ { \ if ((_exp)) {\ gNumPassed++; \ } \ else { \ printf("\nERROR %s\n - 0x%x - %s for %s\n", (msg), result, Pa_GetErrorText(result), #_exp ); \ gNumFailed++; \ } \ } while(0) /*******************************************************************/ /* This routine will be called by the PortAudio engine when audio is needed. ** It may be called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int QaCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { unsigned long i; unsigned char *out = (unsigned char *) outputBuffer; PaQaData *data = (PaQaData *) userData; (void) inputBuffer; /* Prevent "unused variable" warnings. */ (void) outTime; /* Zero out buffer so we don't hear terrible noise. */ if( data->mode == MODE_OUTPUT ) { unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample; for( i=0; iframesLeft > framesPerBuffer ) { data->framesLeft -= framesPerBuffer; return 0; } else { data->framesLeft = 0; return 1; } } /*******************************************************************/ int main(void); int main(void) { PaError result; EXPECT( "init", ((result=Pa_Initialize()) == 0) ); TestBadActions(); TestBadOpens(); error: Pa_Terminate(); printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed ); return 0; } /*******************************************************************/ static int TestBadOpens( void ) { PortAudioStream *stream = NULL; PaError result; PaQaData myData; /* Setup data for synthesis thread. */ myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */ myData.numChannels = 1; myData.mode = MODE_OUTPUT; HOPEFOR( "No devices specified.",( (result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, paNoDevice, 0, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidDeviceId) ); HOPEFOR( "Out of range input device specified.",( (result = Pa_OpenStream( &stream, Pa_CountDevices(), 0, paFloat32, NULL, paNoDevice, 0, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidDeviceId) ); HOPEFOR( "Out of range output device specified.",( (result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, Pa_CountDevices(), 0, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidDeviceId) ); HOPEFOR( "Zero input channels.",( (result = Pa_OpenStream( &stream, Pa_GetDefaultInputDeviceID(), 0, paFloat32, NULL, paNoDevice, 0, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidChannelCount) ); HOPEFOR( "Zero output channels.",( (result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), 0, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidChannelCount) ); HOPEFOR( "Nonzero input channels but no device.",( (result = Pa_OpenStream( &stream, Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL, paNoDevice, 2, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidChannelCount) ); HOPEFOR( "Nonzero output channels but no device.",( (result = Pa_OpenStream( &stream, paNoDevice, 2, paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidChannelCount) ); HOPEFOR( "NULL stream pointer.",( (result = Pa_OpenStream( NULL, paNoDevice, 0, paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paBadStreamPtr) ); HOPEFOR( "Low sample rate.",( (result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, 1.0, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidSampleRate) ); HOPEFOR( "High sample rate.",( (result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, 10000000.0, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidSampleRate) ); HOPEFOR( "NULL callback.",( (result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, NULL, &myData ) ) == paNullCallback) ); HOPEFOR( "Bad flag.",( (result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, (1<<3), QaCallback, &myData ) ) == paInvalidFlag) ); #if 1 /* FIXME - this is legal for some implementations. */ HOPEFOR( "Use input device as output device.",( (result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidDeviceId) ); HOPEFOR( "Use output device as input device.",( (result = Pa_OpenStream( &stream, Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, paNoDevice, 0, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == paInvalidDeviceId) ); #endif if( stream != NULL ) Pa_CloseStream( stream ); return result; } /*******************************************************************/ static int TestBadActions( void ) { PortAudioStream *stream = NULL; PaError result; PaQaData myData; /* Setup data for synthesis thread. */ myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */ myData.numChannels = 1; myData.mode = MODE_OUTPUT; /* Default output. */ EXPECT( "TestBadActions", ((result = Pa_OpenStream( &stream, paNoDevice, 0, paFloat32, NULL, Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL, SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS, paClipOff, QaCallback, &myData ) ) == 0) ); HOPEFOR( "start", ((result = Pa_StartStream( NULL )) == paBadStreamPtr) ); HOPEFOR( "stop", ((result = Pa_StopStream( NULL )) == paBadStreamPtr) ); HOPEFOR( "active?", ((result = Pa_StreamActive( NULL )) == paBadStreamPtr) ); HOPEFOR( "close", ((result = Pa_CloseStream( NULL )) == paBadStreamPtr) ); HOPEFOR( "time?", ((result = (PaError)Pa_StreamTime( NULL )) != 0) ); HOPEFOR( "CPULoad?", ((result = (PaError)Pa_GetCPULoad( NULL )) != 0) ); error: if( stream != NULL ) Pa_CloseStream( stream ); return result; } portaudio-18.1.orig/pa_tests/debug_convert.c0000644000175000017500000001132207446136164021764 0ustar mikaelmikael00000000000000/* * $Id: debug_convert.c,v 1.1 2002/03/21 00:44:35 philburk Exp $ * Convert tagged values. * * Author: Phil Burk * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "portaudio.h" #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID()) //#define OUTPUT_DEVICE (11) #define NUM_SECONDS (8) #define SLEEP_DUR (800) #define SAMPLE_RATE (44100) #define FRAMES_PER_BUFFER (256) #define NUM_BUFFERS (0) typedef struct { unsigned int framesToGo; } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int patestCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { paTestData *data = (paTestData*)userData; short *out = (short*)outputBuffer; int i; int finished = 0; (void) outTime; /* Prevent unused variable warnings. */ (void) inputBuffer; if( data->framesToGo < framesPerBuffer ) finished = 1; for( i=0; i #include #include #include /* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ #ifdef _WIN32 #ifndef __MWERKS__ #include #endif /* __MWERKS__ */ #else /* !_WIN32 */ #include #endif /* _WIN32 */ #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" /* The reason we might NOT want to validate the rate before opening the stream * is because many DirectSound drivers lie about the rates they actually support. */ #define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */ /* O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion */ #ifndef FALSE #define FALSE (0) #define TRUE (!FALSE) #endif #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */ static PaError Pa_KillStream( PortAudioStream *stream, int abort ); /***********************************************************************/ int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate ) { double err, minErr = allowableError; int i, bestFit = -1; for( i=0; inumSampleRates == -1 ) { /* Is it out of range? */ if( (requestedFrameRate < pdi->sampleRates[0]) || (requestedFrameRate > pdi->sampleRates[1]) ) { return paInvalidSampleRate; } *closestFrameRatePtr = requestedFrameRate; } else { bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate ); if( bestRateIndex < 0 ) return paInvalidSampleRate; *closestFrameRatePtr = pdi->sampleRates[bestRateIndex]; } return paNoError; } /*************************************************************************/ PaError Pa_OpenStream( PortAudioStream** streamPtrPtr, PaDeviceID inputDeviceID, int numInputChannels, PaSampleFormat inputSampleFormat, void *inputDriverInfo, PaDeviceID outputDeviceID, int numOutputChannels, PaSampleFormat outputSampleFormat, void *outputDriverInfo, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, unsigned long streamFlags, PortAudioCallback *callback, void *userData ) { internalPortAudioStream *past = NULL; PaError result = paNoError; int bitsPerInputSample; int bitsPerOutputSample; /* Print passed parameters. */ DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n", streamPtrPtr, inputDeviceID, numInputChannels, inputSampleFormat, inputDriverInfo )); DBUG((" %d, %d, %d, %p, /* output */\n", outputDeviceID, numOutputChannels, outputSampleFormat, outputDriverInfo )); DBUG((" %g, %d, %d, 0x%x, , %p )\n", sampleRate, framesPerBuffer, numberOfBuffers, streamFlags, userData )); /* Check for parameter errors. */ if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag; if( streamPtrPtr == NULL ) return paBadStreamPtr; if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */ if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */ if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId; if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) ) { return paInvalidDeviceId; } if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount; #if SUPPORT_AUDIO_CAPTURE if( inputDeviceID >= 0 ) { PaError size = Pa_GetSampleSize( inputSampleFormat ); if( size < 0 ) return size; bitsPerInputSample = 8 * size; if( (numInputChannels <= 0) ) return paInvalidChannelCount; } #else if( inputDeviceID >= 0 ) { return paInvalidChannelCount; } #endif /* SUPPORT_AUDIO_CAPTURE */ else { if( numInputChannels > 0 ) return paInvalidChannelCount; bitsPerInputSample = 0; } if( outputDeviceID >= 0 ) { PaError size = Pa_GetSampleSize( outputSampleFormat ); if( size < 0 ) return size; bitsPerOutputSample = 8 * size; if( (numOutputChannels <= 0) ) return paInvalidChannelCount; } else { if( numOutputChannels > 0 ) return paInvalidChannelCount; bitsPerOutputSample = 0; } if( callback == NULL ) return paNullCallback; /* Allocate and clear stream structure. */ past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) ); if( past == NULL ) return paInsufficientMemory; memset( past, 0, sizeof(internalPortAudioStream) ); AddTraceMessage("Pa_OpenStream: past", (long) past ); past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */ past->past_FramesPerUserBuffer = framesPerBuffer; past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() MUST CHECK FOR ZERO! */ past->past_Callback = callback; past->past_UserData = userData; past->past_OutputSampleFormat = outputSampleFormat; past->past_InputSampleFormat = inputSampleFormat; past->past_OutputDeviceID = outputDeviceID; past->past_InputDeviceID = inputDeviceID; past->past_NumInputChannels = numInputChannels; past->past_NumOutputChannels = numOutputChannels; past->past_Flags = streamFlags; /* Check for absurd sample rates. */ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) ) { result = paInvalidSampleRate; goto cleanup; } /* Allocate buffers that may be used for format conversion from user to native buffers. */ if( numInputChannels > 0 ) { #if PA_VALIDATE_RATE result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate ); if( result < 0 ) { goto cleanup; } #else past->past_SampleRate = sampleRate; #endif /* Allocate single Input buffer for passing formatted samples to user callback. */ past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8); past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize); if( past->past_InputBuffer == NULL ) { result = paInsufficientMemory; goto cleanup; } } else { past->past_InputBuffer = NULL; } /* Allocate single Output buffer. */ if( numOutputChannels > 0 ) { #if PA_VALIDATE_RATE result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate ); if( result < 0 ) { goto cleanup; } #else past->past_SampleRate = sampleRate; #endif past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8); past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize); if( past->past_OutputBuffer == NULL ) { result = paInsufficientMemory; goto cleanup; } } else { past->past_OutputBuffer = NULL; } result = PaHost_OpenStream( past ); if( result < 0 ) goto cleanup; *streamPtrPtr = (void *) past; return result; cleanup: if( past != NULL ) Pa_CloseStream( past ); *streamPtrPtr = NULL; return result; } /*************************************************************************/ PaError Pa_OpenDefaultStream( PortAudioStream** stream, int numInputChannels, int numOutputChannels, PaSampleFormat sampleFormat, double sampleRate, unsigned long framesPerBuffer, unsigned long numberOfBuffers, PortAudioCallback *callback, void *userData ) { return Pa_OpenStream( stream, ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice), numInputChannels, sampleFormat, NULL, ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice), numOutputChannels, sampleFormat, NULL, sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData ); } /*************************************************************************/ PaError Pa_CloseStream( PortAudioStream* stream) { PaError result; internalPortAudioStream *past; DBUG(("Pa_CloseStream()\n")); if( stream == NULL ) return paBadStreamPtr; past = (internalPortAudioStream *) stream; Pa_AbortStream( past ); result = PaHost_CloseStream( past ); if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize ); if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize ); PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) ); return result; } /*************************************************************************/ PaError Pa_StartStream( PortAudioStream *stream ) { PaError result = paHostError; internalPortAudioStream *past; if( stream == NULL ) return paBadStreamPtr; past = (internalPortAudioStream *) stream; past->past_FrameCount = 0.0; if( past->past_NumInputChannels > 0 ) { result = PaHost_StartInput( past ); DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result)); if( result < 0 ) goto error; } if( past->past_NumOutputChannels > 0 ) { result = PaHost_StartOutput( past ); DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result)); if( result < 0 ) goto error; } result = PaHost_StartEngine( past ); DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result)); if( result < 0 ) goto error; return paNoError; error: return result; } /*************************************************************************/ PaError Pa_StopStream( PortAudioStream *stream ) { return Pa_KillStream( stream, 0 ); } /*************************************************************************/ PaError Pa_AbortStream( PortAudioStream *stream ) { return Pa_KillStream( stream, 1 ); } /*************************************************************************/ static PaError Pa_KillStream( PortAudioStream *stream, int abort ) { PaError result = paNoError; internalPortAudioStream *past; DBUG(("Pa_StopStream().\n")); if( stream == NULL ) return paBadStreamPtr; past = (internalPortAudioStream *) stream; if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) ) { result = PaHost_StopEngine( past, abort ); DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result)); if( result < 0 ) goto error; } if( past->past_NumInputChannels > 0 ) { result = PaHost_StopInput( past, abort ); DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result)); if( result != paNoError ) goto error; } if( past->past_NumOutputChannels > 0 ) { result = PaHost_StopOutput( past, abort ); DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result)); if( result != paNoError ) goto error; } error: past->past_Usage = 0; past->past_IfLastExitValid = 0; return result; } /*************************************************************************/ PaError Pa_StreamActive( PortAudioStream *stream ) { internalPortAudioStream *past; if( stream == NULL ) return paBadStreamPtr; past = (internalPortAudioStream *) stream; return PaHost_StreamActive( past ); } /*************************************************************************/ const char *Pa_GetErrorText( PaError errnum ) { const char *msg; switch(errnum) { case paNoError: msg = "Success"; break; case paHostError: msg = "Host error."; break; case paInvalidChannelCount: msg = "Invalid number of channels."; break; case paInvalidSampleRate: msg = "Invalid sample rate."; break; case paInvalidDeviceId: msg = "Invalid device ID."; break; case paInvalidFlag: msg = "Invalid flag."; break; case paSampleFormatNotSupported: msg = "Sample format not supported"; break; case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break; case paInsufficientMemory: msg = "Insufficient memory."; break; case paBufferTooBig: msg = "Buffer too big."; break; case paBufferTooSmall: msg = "Buffer too small."; break; case paNullCallback: msg = "No callback routine specified."; break; case paBadStreamPtr: msg = "Invalid stream pointer."; break; case paTimedOut : msg = "Wait Timed Out."; break; case paInternalError: msg = "Internal PortAudio Error."; break; case paDeviceUnavailable: msg = "Device Unavailable."; break; default: msg = "Illegal error number."; break; } return msg; } /* Get CPU Load as a fraction of total CPU time. A value of 0.5 would imply that PortAudio and the sound generating callback was consuming roughly 50% of the available CPU time. The amount may vary depending on CPU load. This function may be called from the callback function. */ double Pa_GetCPULoad( PortAudioStream* stream) { internalPortAudioStream *past; if( stream == NULL ) return (double) paBadStreamPtr; past = (internalPortAudioStream *) stream; return past->past_Usage; } /*************************************************************************/ internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream ) { internalPortAudioStream* result = (internalPortAudioStream*) stream; if( result == NULL || result->past_Magic != PA_MAGIC ) return NULL; else return result; } /************************************************************* ** Calculate 2 LSB dither signal with a triangular distribution. ** Ranged properly for adding to a 32 bit integer prior to >>15. ** Range of output is +/- 32767 */ #define PA_DITHER_BITS (15) #define PA_DITHER_SCALE (1.0f / ((1<>DITHER_SHIFT) + (((long)randSeed2)>>DITHER_SHIFT); /* High pass filter to reduce audibility. */ highPass = current - previous; previous = current; return highPass; } /************************************************************************* ** Called by host code. ** Convert input from Int16, call user code, then convert output ** to Int16 format for native use. ** Assumes host native format is paInt16. ** Returns result from user callback. */ long Pa_CallConvertInt16( internalPortAudioStream *past, short *nativeInputBuffer, short *nativeOutputBuffer ) { long temp; int userResult; unsigned int i; void *inputBuffer = NULL; void *outputBuffer = NULL; #if SUPPORT_AUDIO_CAPTURE /* Get native data from DirectSound. */ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) ) { /* Convert from native format to PA format. */ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels; switch(past->past_InputSampleFormat) { case paFloat32: { float *inBufPtr = (float *) past->past_InputBuffer; inputBuffer = past->past_InputBuffer; for( i=0; ipast_InputBuffer; inputBuffer = past->past_InputBuffer; for( i=0; ipast_InputBuffer; inputBuffer = past->past_InputBuffer; if( past->past_Flags & paDitherOff ) { for( i=0; i> 8); } } else { for( i=0; i> 8; /* PLB20010820 */ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); inBufPtr[i] = (char)(temp >> 8); } } break; } case paUInt8: { /* Convert 16 bit data to 8 bit unsigned chars */ unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer; inputBuffer = past->past_InputBuffer; if( past->past_Flags & paDitherOff ) { for( i=0; i> 8) + 0x80); } } else { /* If you dither then you have to clip because dithering could push the signal out of range! */ for( i=0; i> 8; /* PLB20010820 */ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */ } } break; } default: break; } } #endif /* SUPPORT_AUDIO_CAPTURE */ /* Are we doing output time? */ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) ) { /* May already be in native format so just write directly to native buffer. */ outputBuffer = (past->past_OutputSampleFormat == paInt16) ? (void*)nativeOutputBuffer : past->past_OutputBuffer; } /* AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer ); AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer ); */ /* Call user callback routine. */ userResult = past->past_Callback( inputBuffer, outputBuffer, past->past_FramesPerUserBuffer, past->past_FrameCount, past->past_UserData ); past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer; /* Convert to native format if necessary. */ if( outputBuffer != NULL ) { unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels; switch(past->past_OutputSampleFormat) { case paFloat32: { float *outBufPtr = (float *) past->past_OutputBuffer; if( past->past_Flags & paDitherOff ) { if( past->past_Flags & paClipOff ) /* NOTHING */ { for( i=0; i 0x7FFF) ? 0x7FFF : temp)); } } } else { /* If you dither then you have to clip because dithering could push the signal out of range! */ for( i=0; i 0x7FFF) ? 0x7FFF : temp)); } } break; } case paInt32: { int *outBufPtr = (int *) past->past_OutputBuffer; if( past->past_Flags & paDitherOff ) { for( i=0; i> 16 ); } } else { for( i=0; i> 1) + PaConvert_TriangularDither(); temp = temp >> 15; *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp)); } } break; } case paInt8: { char *outBufPtr = (char *) past->past_OutputBuffer; for( i=0; ipast_OutputBuffer; for( i=0; i 0 ) return paNoError; ResetTraceMessages(); return PaHost_Init(); } PaError Pa_Terminate( void ) { PaError result = paNoError; if( gInitCount == 0 ) return paNoError; else if( --gInitCount == 0 ) { result = PaHost_Term(); DumpTraceMessages(); } return result; } int PaHost_IsInitialized() { return gInitCount; } /*************************************************************************/ PaError Pa_GetSampleSize( PaSampleFormat format ) { int size; switch(format ) { case paUInt8: case paInt8: size = 1; break; case paInt16: size = 2; break; case paPackedInt24: size = 3; break; case paFloat32: case paInt32: case paInt24: size = 4; break; default: size = paSampleFormatNotSupported; break; } return (PaError) size; } portaudio-18.1.orig/pa_common/pa_host.h0000644000175000017500000001734607622175706020743 0ustar mikaelmikael00000000000000#ifndef PA_HOST_H #define PA_HOST_H /* * $Id: pa_host.h,v 1.3.4.1 2003/02/11 21:33:58 philburk Exp $ * Host dependant internal API for PortAudio * * Author: Phil Burk * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.softsynth.com/portaudio/ * DirectSound and Macintosh Implementation * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "portaudio.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef SUPPORT_AUDIO_CAPTURE #define SUPPORT_AUDIO_CAPTURE (1) #endif #ifndef int32 typedef long int32; #endif #ifndef uint32 typedef unsigned long uint32; #endif #ifndef int16 typedef short int16; #endif #ifndef uint16 typedef unsigned short uint16; #endif /* Used to convert between various sample formats. */ typedef void (PortAudioConverter)( void *inputBuffer, int inputStride, void *outputBuffer, int outputStride, int numSamples ); #define PA_MAGIC (0x18273645) /************************************************************************************/ /****************** Structures ******************************************************/ /************************************************************************************/ typedef struct internalPortAudioStream { uint32 past_Magic; /* ID for struct to catch bugs. */ /* Begin user specified information. */ uint32 past_FramesPerUserBuffer; uint32 past_NumUserBuffers; double past_SampleRate; /* Closest supported sample rate. */ int past_NumInputChannels; int past_NumOutputChannels; PaDeviceID past_InputDeviceID; PaDeviceID past_OutputDeviceID; PaSampleFormat past_InputSampleFormat; PaSampleFormat past_OutputSampleFormat; PortAudioCallback *past_Callback; void *past_UserData; uint32 past_Flags; /* End user specified information. */ void *past_DeviceData; PaSampleFormat past_NativeOutputSampleFormat; PaSampleFormat past_NativeInputSampleFormat; /* Flags for communicating between foreground and background. */ volatile int past_IsActive; /* Background is still playing. */ volatile int past_StopSoon; /* Background should keep playing when buffers empty. */ volatile int past_StopNow; /* Background should stop playing now. */ /* These buffers are used when the native format does not match the user format. */ void *past_InputBuffer; uint32 past_InputBufferSize; /* Size in bytes of the input buffer. */ void *past_OutputBuffer; uint32 past_OutputBufferSize; /* Measurements */ uint32 past_NumCallbacks; PaTimestamp past_FrameCount; /* Frames output to buffer. */ /* For measuring CPU utilization. */ double past_AverageInsideCount; double past_AverageTotalCount; double past_Usage; int past_IfLastExitValid; /* Format Conversion */ /* These are setup by PaConversion_Setup() */ PortAudioConverter *past_InputConversionProc; int past_InputConversionSourceStride; int past_InputConversionTargetStride; PortAudioConverter *past_OutputConversionProc; int past_OutputConversionSourceStride; int past_OutputConversionTargetStride; } internalPortAudioStream; /************************************************************************************/ /******** These functions must be provided by a platform implementation. ************/ /************************************************************************************/ PaError PaHost_Init( void ); PaError PaHost_Term( void ); PaError PaHost_OpenStream( internalPortAudioStream *past ); PaError PaHost_CloseStream( internalPortAudioStream *past ); PaError PaHost_StartOutput( internalPortAudioStream *past ); PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ); PaError PaHost_StartInput( internalPortAudioStream *past ); PaError PaHost_StopInput( internalPortAudioStream *past, int abort ); PaError PaHost_StartEngine( internalPortAudioStream *past ); PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ); PaError PaHost_StreamActive( internalPortAudioStream *past ); void *PaHost_AllocateFastMemory( long numBytes ); void PaHost_FreeFastMemory( void *addr, long numBytes ); /* This only called if PA_VALIDATE_RATE IS CALLED. */ PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate, double *closestFrameRatePtr ); /**********************************************************************/ /************ Common Utility Routines provided by PA ******************/ /**********************************************************************/ /* PaHost_IsInitialized() returns non-zero if PA is initialized, 0 otherwise */ int PaHost_IsInitialized( void ); internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream ); int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate ); long Pa_CallConvertInt16( internalPortAudioStream *past, short *nativeInputBuffer, short *nativeOutputBuffer ); /* Calculate 2 LSB dither signal with a triangular distribution. ** Ranged properly for adding to a 32 bit 1.31 fixed point value prior to >>15. ** Range of output is +/- 65535 ** Multiply by PA_DITHER_SCALE to get a float between -2.0 and 2.0. */ #define PA_DITHER_BITS (15) #define PA_DITHER_SCALE (1.0f / ((1< #include #include #include "pa_trace.h" #if TRACE_REALTIME_EVENTS static char *traceTextArray[MAX_TRACE_RECORDS]; static int traceIntArray[MAX_TRACE_RECORDS]; static int traceIndex = 0; static int traceBlock = 0; /*********************************************************************/ void ResetTraceMessages() { traceIndex = 0; } /*********************************************************************/ void DumpTraceMessages() { int i; int numDump = (traceIndex < MAX_TRACE_RECORDS) ? traceIndex : MAX_TRACE_RECORDS; printf("DumpTraceMessages: traceIndex = %d\n", traceIndex ); for( i=0; i #include "portaudio.h" #include "pa_host.h" #define CLIP( val, min, max ) { val = ((val) < (min)) ? min : (((val) < (max)) ? (max) : (val)); } /*************************************************************************/ static void PaConvert_Float32_Int16( float *sourceBuffer, int sourceStride, short *targetBuffer, int targetStride, int numSamples ) { int i; for( i=0; ipast_NativeInputSampleFormat = nativeInputSampleFormat; past->past_InputConversionSourceStride = 1; past->past_InputConversionTargetStride = 1; if( nativeInputSampleFormat != past->past_InputSampleFormat ) { int ifDither = (past->past_Flags & paDitherOff) == 0; past->past_InputConversionProc = PaConvert_SelectProc( nativeInputSampleFormat, past->past_InputSampleFormat, 0, ifDither ); if( past->past_InputConversionProc == NULL ) return paSampleFormatNotSupported; } else { past->past_InputConversionProc = NULL; /* no conversion necessary */ } return paNoError; } /*************************************************************************/ PaError PaConvert_SetupOutput( internalPortAudioStream *past, PaSampleFormat nativeOutputSampleFormat ) { past->past_NativeOutputSampleFormat = nativeOutputSampleFormat; past->past_OutputConversionSourceStride = 1; past->past_OutputConversionTargetStride = 1; if( nativeOutputSampleFormat != past->past_OutputSampleFormat ) { int ifDither = (past->past_Flags & paDitherOff) == 0; int ifClip = (past->past_Flags & paClipOff) == 0; past->past_OutputConversionProc = PaConvert_SelectProc( past->past_OutputSampleFormat, nativeOutputSampleFormat, ifClip, ifDither ); if( past->past_OutputConversionProc == NULL ) return paSampleFormatNotSupported; } else { past->past_OutputConversionProc = NULL; /* no conversion necessary */ } return paNoError; } /************************************************************************* ** Called by host code. ** Convert input from native format to user format, ** call user code, ** then convert output to native format. ** Returns result from user callback. */ long PaConvert_Process( internalPortAudioStream *past, void *nativeInputBuffer, void *nativeOutputBuffer ) { int userResult; void *inputBuffer = NULL; void *outputBuffer = NULL; /* Get native input data. */ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) ) { if( past->past_InputSampleFormat == past->past_NativeInputSampleFormat ) { /* Already in native format so just read directly from native buffer. */ inputBuffer = nativeInputBuffer; } else { inputBuffer = past->past_InputBuffer; /* Convert input data to user format. */ (*past->past_InputConversionProc)(nativeInputBuffer, past->past_InputConversionSourceStride, inputBuffer, past->past_InputConversionTargetStride, past->past_FramesPerUserBuffer * past->past_NumInputChannels ); } } /* Are we doing output? */ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) ) { outputBuffer = (past->past_OutputConversionProc == NULL) ? nativeOutputBuffer : past->past_OutputBuffer; } /* AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer ); AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer ); */ /* Call user callback routine. */ userResult = past->past_Callback( inputBuffer, outputBuffer, past->past_FramesPerUserBuffer, past->past_FrameCount, past->past_UserData ); /* Advance frame counter for timestamp. */ past->past_FrameCount += past->past_FramesPerUserBuffer; // FIXME - should this be in here? /* Convert to native format if necessary. */ if( (past->past_OutputConversionProc != NULL ) && (outputBuffer != NULL) ) { (*past->past_OutputConversionProc)( outputBuffer, past->past_OutputConversionSourceStride, nativeOutputBuffer, past->past_OutputConversionTargetStride, past->past_FramesPerUserBuffer * past->past_NumOutputChannels ); } return userResult; } portaudio-18.1.orig/fixfile.bat0000644000175000000620000000032207434437540017117 0ustar mikaelstaff00000000000000rem Use Astyle to fix style in a file fixlines -p %1% astyle --style=ansi -c -o --convert-tabs --indent-preprocessor %1% del %1%.orig @rem convert line terminators to Unix style LFs fixlines -u %1% del %1%.bak portaudio-18.1.orig/configure0000755000175000000620000023740507622303110016706 0ustar mikaelstaff00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by Autoconf 2.52. # # Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Sed expression to map a string onto a valid variable name. as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi # Name of the executable. as_me=`echo "$0" |sed 's,.*[\\/],,'` if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file as_executable_p="test -f" # Support unset when possible. if (FOO=FOO; unset FOO) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # NLS nuisances. $as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; } $as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; } $as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; } $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; } $as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; } $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; } $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; } $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; } # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; } # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} ac_unique_file="pa_common/portaudio.h" # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. build=$build_alias host=$host_alias target=$target_alias # FIXME: should be removed in autoconf 3.0. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo "$ac_prog" | sed 's%[\\/][^\\/][^\\/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat < if you have libraries in a nonstandard directory CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. EOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_subdir in : $ac_subdirs_all; do test "x$ac_subdir" = x: && continue cd $ac_subdir # A "../" for each directory in /$ac_subdir. ac_dots=`echo $ac_subdir | sed 's,^\./,,;s,[^/]$,&/,;s,[^/]*/,../,g'` case $srcdir in .) # No --srcdir option. We are building in place. ac_sub_srcdir=$srcdir ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_sub_srcdir=$srcdir/$ac_subdir ;; *) # Relative path. ac_sub_srcdir=$ac_dots$srcdir/$ac_subdir ;; esac # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_sub_srcdir/configure.gnu; then echo $SHELL $ac_sub_srcdir/configure.gnu --help=recursive elif test -f $ac_sub_srcdir/configure; then echo $SHELL $ac_sub_srcdir/configure --help=recursive elif test -f $ac_sub_srcdir/configure.ac || test -f $ac_sub_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_subdir" >&2 fi cd $ac_popdir done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\EOF Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. EOF exit 0 fi exec 5>config.log cat >&5 </dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` PATH = $PATH _ASUNAME } >&5 cat >&5 <\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" ac_sep=" " ;; *) ac_configure_args="$ac_configure_args$ac_sep$ac_arg" ac_sep=" " ;; esac # Get rid of the leading space. done # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. trap 'exit_status=$? # Save into config.log some information that might help in debugging. echo >&5 echo "## ----------------- ##" >&5 echo "## Cache variables. ##" >&5 echo "## ----------------- ##" >&5 echo >&5 # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } >&5 sed "/^$/d" confdefs.h >conftest.log if test -s conftest.log; then echo >&5 echo "## ------------ ##" >&5 echo "## confdefs.h. ##" >&5 echo "## ------------ ##" >&5 echo >&5 cat conftest.log >&5 fi (echo; echo) >&5 test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" >&5 echo "$as_me: exit $exit_status" >&5 rm -rf conftest* confdefs* core core.* *.core conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:818: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} cat "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:829: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:837: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:853: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:857: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:863: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:865: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:867: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. It doesn't matter if # we pass some twice (in addition to the command line arguments). if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_var=$ac_new_val" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:886: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:888: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac echo "#! $SHELL" >conftest.sh echo "exit 0" >>conftest.sh chmod +x conftest.sh if { (echo "$as_me:908: PATH=\".;.\"; conftest.sh") >&5 (PATH=".;."; conftest.sh) 2>&5 ac_status=$? echo "$as_me:911: \$? = $ac_status" >&5 (exit $ac_status); }; then ac_path_separator=';' else ac_path_separator=: fi PATH_SEPARATOR="$ac_path_separator" rm -f conftest.sh ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo "$as_me:928: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:943: found $ac_dir/$ac_word" >&5 break done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:951: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:954: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo "$as_me:963: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:978: found $ac_dir/$ac_word" >&5 break done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:986: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:989: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 echo "$as_me:1002: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:1017: found $ac_dir/$ac_word" >&5 break done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:1025: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:1028: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:1037: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_CC="cc" echo "$as_me:1052: found $ac_dir/$ac_word" >&5 break done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:1060: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:1063: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:1076: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:1096: found $ac_dir/$ac_word" >&5 break done if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift set dummy "$ac_dir/$ac_word" ${1+"$@"} shift ac_cv_prog_CC="$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:1118: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:1121: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:1132: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:1147: found $ac_dir/$ac_word" >&5 break done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:1155: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:1158: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:1171: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:1186: found $ac_dir/$ac_word" >&5 break done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:1194: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:1197: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:1209: error: no acceptable cc found in \$PATH" >&5 echo "$as_me: error: no acceptable cc found in \$PATH" >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:1214:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:1217: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:1220: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:1222: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:1225: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:1227: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:1230: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF #line 1234 "configure" #include "confdefs.h" int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. echo "$as_me:1250: checking for C compiler default output" >&5 echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:1253: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:1256: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. for ac_file in `ls a.exe conftest.exe 2>/dev/null; ls a.out conftest 2>/dev/null; ls a.* conftest.* 2>/dev/null`; do case $ac_file in *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; a.out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 { { echo "$as_me:1279: error: C compiler cannot create executables" >&5 echo "$as_me: error: C compiler cannot create executables" >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:1285: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:1290: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:1296: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:1299: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:1306: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:1314: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:1321: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:1323: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:1326: checking for executable suffix" >&5 echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6 if { (eval echo "$as_me:1328: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:1331: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:1347: error: cannot compute EXEEXT: cannot compile and link" >&5 echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:1353: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:1359: checking for object suffix" >&5 echo $ECHO_N "checking for object suffix... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line 1365 "configure" #include "confdefs.h" int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:1377: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:1380: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 { { echo "$as_me:1392: error: cannot compute OBJEXT: cannot compile" >&5 echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:1399: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:1403: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line 1409 "configure" #include "confdefs.h" int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:1424: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:1427: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:1430: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:1433: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:1445: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:1451: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF #line 1457 "configure" #include "confdefs.h" int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:1469: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:1472: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:1475: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:1478: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:1488: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:1515: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:1518: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:1521: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:1524: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ ''\ '#include ' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF #line 1536 "configure" #include "confdefs.h" #include $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:1549: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:1552: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:1555: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:1558: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 continue fi rm -f conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF #line 1568 "configure" #include "confdefs.h" $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:1580: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:1583: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:1586: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:1589: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -f conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo "$as_me:1619: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" echo "$as_me:1634: found $ac_dir/$ac_word" >&5 break done fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then echo "$as_me:1642: result: $RANLIB" >&5 echo "${ECHO_T}$RANLIB" >&6 else echo "$as_me:1645: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo "$as_me:1654: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. $as_executable_p "$ac_dir/$ac_word" || continue ac_cv_prog_ac_ct_RANLIB="ranlib" echo "$as_me:1669: found $ac_dir/$ac_word" >&5 break done test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":" fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then echo "$as_me:1678: result: $ac_ct_RANLIB" >&5 echo "${ECHO_T}$ac_ct_RANLIB" >&6 else echo "$as_me:1681: result: no" >&5 echo "${ECHO_T}no" >&6 fi RANLIB=$ac_ct_RANLIB else RANLIB="$ac_cv_prog_RANLIB" fi ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f $ac_dir/shtool; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:1707: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:1727: checking for a BSD compatible install" >&5 echo $ECHO_N "checking for a BSD compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_save_IFS=$IFS; IFS=$ac_path_separator for ac_dir in $PATH; do IFS=$ac_save_IFS # Account for people who put trailing slashes in PATH elements. case $ac_dir/ in / | ./ | .// | /cC/* \ | /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* \ | /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do if $as_executable_p "$ac_dir/$ac_prog"; then if test $ac_prog = install && grep dspmsg "$ac_dir/$ac_prog" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$ac_dir/$ac_prog" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$ac_dir/$ac_prog -c" break 2 fi fi done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:1776: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 echo "$as_me:1789: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_path_AR+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else case $AR in [\\/]* | ?:[\\/]*) ac_cv_path_AR="$AR" # Let the user override the test with a path. ;; *) ac_save_IFS=$IFS; IFS=$ac_path_separator ac_dummy="$PATH" for ac_dir in $ac_dummy; do IFS=$ac_save_IFS test -z "$ac_dir" && ac_dir=. if $as_executable_p "$ac_dir/$ac_word"; then ac_cv_path_AR="$ac_dir/$ac_word" echo "$as_me:1806: found $ac_dir/$ac_word" >&5 break fi done test -z "$ac_cv_path_AR" && ac_cv_path_AR="no" ;; esac fi AR=$ac_cv_path_AR if test -n "$AR"; then echo "$as_me:1818: result: $AR" >&5 echo "${ECHO_T}$AR" >&6 else echo "$as_me:1821: result: no" >&5 echo "${ECHO_T}no" >&6 fi if [ $AR = "no" ] ; then { { echo "$as_me:1826: error: \"Could not find ar - needed to create a library\"" >&5 echo "$as_me: error: \"Could not find ar - needed to create a library\"" >&2;} { (exit 1); exit 1; }; }; fi # Make sure we can run config.sub. $ac_config_sub sun4 >/dev/null 2>&1 || { { echo "$as_me:1833: error: cannot run $ac_config_sub" >&5 echo "$as_me: error: cannot run $ac_config_sub" >&2;} { (exit 1); exit 1; }; } echo "$as_me:1837: checking build system type" >&5 echo $ECHO_N "checking build system type... $ECHO_C" >&6 if test "${ac_cv_build+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_build_alias=$build_alias test -z "$ac_cv_build_alias" && ac_cv_build_alias=`$ac_config_guess` test -z "$ac_cv_build_alias" && { { echo "$as_me:1846: error: cannot guess build type; you must specify one" >&5 echo "$as_me: error: cannot guess build type; you must specify one" >&2;} { (exit 1); exit 1; }; } ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || { { echo "$as_me:1850: error: $ac_config_sub $ac_cv_build_alias failed." >&5 echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed." >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:1855: result: $ac_cv_build" >&5 echo "${ECHO_T}$ac_cv_build" >&6 build=$ac_cv_build build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$as_me:1862: checking host system type" >&5 echo $ECHO_N "checking host system type... $ECHO_C" >&6 if test "${ac_cv_host+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_host_alias=$host_alias test -z "$ac_cv_host_alias" && ac_cv_host_alias=$ac_cv_build_alias ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || { { echo "$as_me:1871: error: $ac_config_sub $ac_cv_host_alias failed" >&5 echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} { (exit 1); exit 1; }; } fi echo "$as_me:1876: result: $ac_cv_host" >&5 echo "${ECHO_T}$ac_cv_host" >&6 host=$ac_cv_host host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` case "${host_os}" in darwin* ) OTHER_OBJS="pa_mac_core/pa_mac_core.o"; LIBS="-framework CoreAudio -lm"; PADLL="libportaudio.dylib"; SHARED_FLAGS="-framework CoreAudio -dynamiclib"; ;; mingw* ) OTHER_OBJS="pa_win_wmme/pa_win_wmme.o"; LIBS="-lwinmm -lm"; PADLL="portaudio.dll"; SHARED_FLAGS="-shared -mthreads"; DLL_LIBS="-lwinmm"; ;; cygwin* ) OTHER_OBJS="pa_win_wmme/pa_win_wmme.o"; LIBS="-lwinmm -lm"; PADLL="portaudio.dll"; SHARED_FLAGS="-shared -mthreads"; DLL_LIBS="-lwinmm"; ;; *) echo "$as_me:1912: checking for pthread_create in -lpthread" >&5 echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6 if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat >conftest.$ac_ext <<_ACEOF #line 1920 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char pthread_create (); int main () { pthread_create (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:1939: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:1942: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:1945: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:1948: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_lib_pthread_pthread_create=yes else echo "$as_me: failed program was:" >&5 cat conftest.$ac_ext >&5 ac_cv_lib_pthread_pthread_create=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi echo "$as_me:1959: result: $ac_cv_lib_pthread_pthread_create" >&5 echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6 if test $ac_cv_lib_pthread_pthread_create = yes; then cat >>confdefs.h <&5 echo "$as_me: error: libpthread not found!" >&2;} { (exit 1); exit 1; }; } fi OTHER_OBJS="pa_unix_oss/pa_unix_oss.o pa_unix_oss/pa_unix.o"; LIBS="-lm -lpthread"; PADLL="libportaudio.so"; SHARED_FLAGS="-shared"; esac ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overriden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if cmp -s $cache_file confcache; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then we branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. cat >confdef2opt.sed <<\EOF t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g t quote s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g t quote d : quote s,[ `~#$^&*(){}\\|;'"<>?],\\&,g s,\[,\\&,g s,\],\\&,g s,\$,$$,g p EOF # We use echo to avoid assuming a particular line-breaking character. # The extra dot is to prevent the shell from consuming trailing # line-breaks from the sub-command output. A line-break within # single-quotes doesn't work because, if this script is created in a # platform that uses two characters for line-breaks (e.g., DOS), tr # would break. ac_LF_and_DOT=`echo; echo .` DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'` rm -f confdef2opt.sed : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:2090: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated automatically by configure. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false SHELL=\${CONFIG_SHELL-$SHELL} ac_cs_invocation="\$0 \$@" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi # Name of the executable. as_me=`echo "$0" |sed 's,.*[\\/],,'` if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file as_executable_p="test -f" # Support unset when possible. if (FOO=FOO; unset FOO) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # NLS nuisances. $as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; } $as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; } $as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; } $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; } $as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; } $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; } $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; } $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; } # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; } exec 6>&1 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\EOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to ." EOF cat >>$CONFIG_STATUS <>$CONFIG_STATUS <<\EOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` shift set dummy "$ac_option" "$ac_optarg" ${1+"$@"} shift ;; -*);; *) # This is not an option, so the user has probably given explicit # arguments. ac_need_defaults=false;; esac case $1 in # Handling of the options. EOF cat >>$CONFIG_STATUS <>$CONFIG_STATUS <<\EOF --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:2258: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) shift CONFIG_FILES="$CONFIG_FILES $1" ac_need_defaults=false;; --header | --heade | --head | --hea ) shift CONFIG_HEADERS="$CONFIG_HEADERS $1" ac_need_defaults=false;; # This is an error. -*) { { echo "$as_me:2277: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done exec 5>>config.log cat >&5 << _ACEOF ## ----------------------- ## ## Running config.status. ## ## ----------------------- ## This file was extended by $as_me 2.52, executed with CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS > $ac_cs_invocation on `(hostname || uname -n) 2>/dev/null | sed 1q` _ACEOF EOF cat >>$CONFIG_STATUS <<\EOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) { { echo "$as_me:2313: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. : ${TMPDIR=/tmp} { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=$TMPDIR/cs$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 { (exit 1); exit 1; } } EOF cat >>$CONFIG_STATUS <\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@DEFS@,$DEFS,;t t s,@LIBS@,$LIBS,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@RANLIB@,$RANLIB,;t t s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@AR@,$AR,;t t s,@OTHER_OBJS@,$OTHER_OBJS,;t t s,@PADLL@,$PADLL,;t t s,@SHARED_FLAGS@,$SHARED_FLAGS,;t t s,@DLL_LIBS@,$DLL_LIBS,;t t s,@build@,$build,;t t s,@build_cpu@,$build_cpu,;t t s,@build_vendor@,$build_vendor,;t t s,@build_os@,$build_os,;t t s,@host@,$host,;t t s,@host_cpu@,$host_cpu,;t t s,@host_vendor@,$host_vendor,;t t s,@host_os@,$host_os,;t t CEOF EOF cat >>$CONFIG_STATUS <<\EOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" EOF cat >>$CONFIG_STATUS <<\EOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then { case "$ac_dir" in [\\/]* | ?:[\\/]* ) as_incr_dir=;; *) as_incr_dir=.;; esac as_dummy="$ac_dir" for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do case $as_mkdir_dir in # Skip DOS drivespec ?:) as_incr_dir=$as_mkdir_dir ;; *) as_incr_dir=$as_incr_dir/$as_mkdir_dir test -d "$as_incr_dir" || mkdir "$as_incr_dir" ;; esac done; } ac_dir_suffix="/`echo $ac_dir|sed 's,^\./,,'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo "$ac_dir_suffix" | sed 's,/[^/]*,../,g'` else ac_dir_suffix= ac_dots= fi case $srcdir in .) ac_srcdir=. if test -z "$ac_dots"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_dots | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_dots$srcdir$ac_dir_suffix ac_top_srcdir=$ac_dots$srcdir ;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_dots$INSTALL ;; esac if test x"$ac_file" != x-; then { echo "$as_me:2532: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated automatically by config.status. */ configure_input="Generated automatically from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:2550: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo $f;; *) # Relative if test -f "$f"; then # Build tree echo $f elif test -f "$srcdir/$f"; then # Source tree echo $srcdir/$f else # /dev/null tree { { echo "$as_me:2563: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } EOF cat >>$CONFIG_STATUS <>$CONFIG_STATUS <<\EOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done EOF cat >>$CONFIG_STATUS <<\EOF { (exit 0); exit 0; } EOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: exec 5>/dev/null $SHELL $CONFIG_STATUS || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi echo "" echo "Finished configure." echo "" echo "Type 'make' to build PortAudio and examples." portaudio-18.1.orig/configure.in0000644000175000000620000000312107622303110017272 0ustar mikaelstaff00000000000000dnl dnl PortAudio configure.in script dnl dnl Dominic Mazzoni dnl dnl Require autoconf >= 2.13 AC_PREREQ(2.13) dnl Init autoconf and make sure configure is being called dnl from the right directory AC_INIT([pa_common/portaudio.h]) dnl Checks for programs AC_PROG_CC AC_PROG_RANLIB AC_PROG_INSTALL AC_PATH_PROG(AR, ar, no) if [[ $AR = "no" ]] ; then AC_MSG_ERROR("Could not find ar - needed to create a library"); fi dnl Extra variables we want to substitute AC_SUBST(OTHER_OBJS) AC_SUBST(PADLL) AC_SUBST(SHARED_FLAGS) AC_SUBST(DLL_LIBS) dnl Determine the host operating system / platform AC_CANONICAL_HOST case "${host_os}" in darwin* ) dnl Mac OS X configuration OTHER_OBJS="pa_mac_core/pa_mac_core.o"; LIBS="-framework CoreAudio -lm"; PADLL="libportaudio.dylib"; SHARED_FLAGS="-framework CoreAudio -dynamiclib"; ;; mingw* ) dnl MingW configuration OTHER_OBJS="pa_win_wmme/pa_win_wmme.o"; LIBS="-lwinmm -lm"; PADLL="portaudio.dll"; SHARED_FLAGS="-shared -mthreads"; DLL_LIBS="-lwinmm"; ;; cygwin* ) dnl Cygwin configuration OTHER_OBJS="pa_win_wmme/pa_win_wmme.o"; LIBS="-lwinmm -lm"; PADLL="portaudio.dll"; SHARED_FLAGS="-shared -mthreads"; DLL_LIBS="-lwinmm"; ;; *) dnl Unix OSS configuration AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR([libpthread not found!])) OTHER_OBJS="pa_unix_oss/pa_unix_oss.o pa_unix_oss/pa_unix.o"; LIBS="-lm -lpthread"; PADLL="libportaudio.so"; SHARED_FLAGS="-shared"; esac AC_OUTPUT([Makefile]) echo "" echo "Finished configure." echo "" echo "Type 'make' to build PortAudio and examples." portaudio-18.1.orig/pa_win_wmme/0000755000175000000620000000000007700016422017272 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_win_wmme/Makefile.cygwin0000644000175000017500000000217707423043540022407 0ustar mikaelmikael00000000000000 # Makefile for PortAudio on cygwin # Contributed by Bill Eldridge on 6/13/2001 ARCH= pa_win_wmme TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) .c.o: -gcc -c -I./pa_common $< -o $*.o -gcc $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm all: sharedlib tests sharedlib: ./pa_common/pa_lib.c gcc -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o gcc -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o dlltool --export-all --output-def pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o gcc -shared -Wl,--enable-auto-image-base -o pa_win_wmme/portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/lib/w32api -lwinmm cp pa_win_wmme/portaudio.dll /usr/local/bin tests: $(TESTS:.c=.o) sine: gcc -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o gcc pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm clean: -rm ./pa_tests/*.exe nothing: gcc pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm portaudio-18.1.orig/pa_win_wmme/pa_win_wmme.c0000644000175000017500000020213207653202744022117 0ustar mikaelmikael00000000000000/* * $Id: pa_win_wmme.c,v 1.6.4.3 2003/04/28 17:43:48 philburk Exp $ * pa_win_wmme.c * Implementation of PortAudio for Windows MultiMedia Extensions (WMME) * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Authors: Ross Bencina and Phil Burk * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* All memory allocations and frees are marked with MEM for quick review. */ /* Modification History: PLB = Phil Burk JM = Julien Maillard RDB = Ross Bencina PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer) PLB20010413 - check for excessive numbers of channels PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC including condition including of memory.h, and explicit typecasting on memory allocation PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory PLB20010816 - pass process instead of thread to SetPriorityClass() PLB20010927 - use number of frames instead of real-time for CPULoad calculation. JM20020118 - prevent hung thread when buffers underflow. PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices refactoring, renaming and fixed a few edge case bugs PLB20020612 - added 8000.0 Hz to custom sampling rates array */ #pragma warning (disable: 4115) #include #include #include #include #include #include /* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */ #ifndef __MWERKS__ #include #include #endif /* __MWERKS__ */ #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" /************************************************* Constants ********/ #define PA_TRACK_MEMORY (0) #define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */ /* Switches for debugging. */ #define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */ /* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ #define PA_TRACE_RUN (0) #define PA_TRACE_START_STOP (1) #define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */ #if PA_USE_HIGH_LATENCY #define PA_MIN_MSEC_PER_HOST_BUFFER (100) #define PA_MAX_MSEC_PER_HOST_BUFFER (300) /* Do not exceed unless user buffer exceeds */ #define PA_MIN_NUM_HOST_BUFFERS (4) #define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ #define PA_WIN_9X_LATENCY (400) #else #define PA_MIN_MSEC_PER_HOST_BUFFER (10) #define PA_MAX_MSEC_PER_HOST_BUFFER (100) /* Do not exceed unless user buffer exceeds */ #define PA_MIN_NUM_HOST_BUFFERS (3) #define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */ #define PA_WIN_9X_LATENCY (200) #endif #define MIN_TIMEOUT_MSEC (1000) /* ** Use higher latency for NT because it is even worse at real-time ** operation than Win9x. */ #define PA_WIN_NT_LATENCY (PA_WIN_9X_LATENCY * 2) #define PA_WIN_WDM_LATENCY (PA_WIN_9X_LATENCY) #if PA_SIMULATE_UNDERFLOW static gUnderCallbackCounter = 0; #define UNDER_SLEEP_AT (40) #define UNDER_SLEEP_FOR (500) #endif #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ /************************************************* Definitions ********/ /************************************************************** * Structure for internal host specific stream data. * This is allocated on a per stream basis. */ typedef struct PaWMMEStreamData { /* Input -------------- */ HWAVEIN hWaveIn; WAVEHDR *inputBuffers; int currentInputBuffer; int bytesPerHostInputBuffer; int bytesPerUserInputBuffer; /* native buffer size in bytes */ /* Output -------------- */ HWAVEOUT hWaveOut; WAVEHDR *outputBuffers; int currentOutputBuffer; int bytesPerHostOutputBuffer; int bytesPerUserOutputBuffer; /* native buffer size in bytes */ /* Run Time -------------- */ PaTimestamp framesPlayed; long lastPosition; /* used to track frames played. */ /* For measuring CPU utilization. */ LARGE_INTEGER entryCount; double inverseTicksPerHostBuffer; /* Init Time -------------- */ int numHostBuffers; int framesPerHostBuffer; int userBuffersPerHostBuffer; CRITICAL_SECTION streamLock; /* Mutext to prevent threads from colliding. */ INT streamLockInited; #if PA_USE_TIMER_CALLBACK BOOL ifInsideCallback; /* Test for reentrancy. */ MMRESULT timerID; #else HANDLE abortEvent; int abortEventInited; HANDLE bufferEvent; int bufferEventInited; HANDLE engineThread; DWORD engineThreadID; #endif } PaWMMEStreamData; /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ static int sNumInputDevices = 0; static int sNumOutputDevices = 0; static int sNumDevices = 0; static PaDeviceInfo **sDevicePtrs = NULL; static int sDefaultInputDeviceID = paNoDevice; static int sDefaultOutputDeviceID = paNoDevice; static int sPaHostError = 0; static const char sMapperSuffixInput[] = " - Input"; static const char sMapperSuffixOutput[] = " - Output"; #if PA_TRACK_MEMORY static int sNumAllocations = 0; #endif /************************************************* Macros ********/ /* Convert external PA ID to an internal ID that includes WAVE_MAPPER */ #define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1)) /************************************************* Prototypes **********/ void Pa_InitializeNumDevices( void ); PaError Pa_AllocateDevicePtrs( void ); static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ); static PaError PaHost_BackgroundManager( internalPortAudioStream *past ); static void *PaHost_AllocateTrackedMemory( long numBytes ); static void PaHost_FreeTrackedMemory( void *addr ); /*******************************************************************/ static PaError PaHost_AllocateWMMEStreamData( internalPortAudioStream *stream ) { PaError result = paNoError; PaWMMEStreamData *wmmeStreamData; wmmeStreamData = (PaWMMEStreamData *) PaHost_AllocateFastMemory(sizeof(PaWMMEStreamData)); /* MEM */ if( wmmeStreamData == NULL ) { result = paInsufficientMemory; goto error; } memset( wmmeStreamData, 0, sizeof(PaWMMEStreamData) ); stream->past_DeviceData = (void *) wmmeStreamData; return result; error: return result; } /*******************************************************************/ static void PaHost_FreeWMMEStreamData( internalPortAudioStream *internalStream ) { PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) internalStream->past_DeviceData; PaHost_FreeFastMemory( wmmeStreamData, sizeof(PaWMMEStreamData) ); /* MEM */ internalStream->past_DeviceData = NULL; } /*************************************************************************/ static PaWMMEStreamData* PaHost_GetWMMEStreamData( internalPortAudioStream* internalStream ) { PaWMMEStreamData *result = NULL; if( internalStream != NULL ) { result = (PaWMMEStreamData *) internalStream->past_DeviceData; } return result; } /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ /* FIXME: the cpu usage code should be factored out into a common module */ static void Pa_InitializeCpuUsageScalar( internalPortAudioStream *stream ) { PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; LARGE_INTEGER frequency; if( QueryPerformanceFrequency( &frequency ) == 0 ) { wmmeStreamData->inverseTicksPerHostBuffer = 0.0; } else { wmmeStreamData->inverseTicksPerHostBuffer = stream->past_SampleRate / ( (double)frequency.QuadPart * stream->past_FramesPerUserBuffer * wmmeStreamData->userBuffersPerHostBuffer ); DBUG(("inverseTicksPerHostBuffer = %g\n", wmmeStreamData->inverseTicksPerHostBuffer )); } } static void Pa_StartUsageCalculation( internalPortAudioStream *stream ) { PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; if( wmmeStreamData == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ QueryPerformanceCounter( &wmmeStreamData->entryCount ); } static void Pa_EndUsageCalculation( internalPortAudioStream *stream ) { LARGE_INTEGER CurrentCount; PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; if( wmmeStreamData == NULL ) return; /* * Measure CPU utilization during this callback. Note that this calculation * assumes that we had the processor the whole time. */ #define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) if( QueryPerformanceCounter( &CurrentCount ) ) { LONGLONG InsideCount = CurrentCount.QuadPart - wmmeStreamData->entryCount.QuadPart; double newUsage = InsideCount * wmmeStreamData->inverseTicksPerHostBuffer; stream->past_Usage = (LOWPASS_COEFFICIENT_0 * stream->past_Usage) + (LOWPASS_COEFFICIENT_1 * newUsage); } } /****************************************** END CPU UTILIZATION *******/ static void Pa_InitializeNumDevices( void ) { sNumInputDevices = waveInGetNumDevs(); if( sNumInputDevices > 0 ) { sNumInputDevices += 1; /* add one extra for the WAVE_MAPPER */ sDefaultInputDeviceID = 0; } else { sDefaultInputDeviceID = paNoDevice; } sNumOutputDevices = waveOutGetNumDevs(); if( sNumOutputDevices > 0 ) { sNumOutputDevices += 1; /* add one extra for the WAVE_MAPPER */ sDefaultOutputDeviceID = sNumInputDevices; } else { sDefaultOutputDeviceID = paNoDevice; } sNumDevices = sNumInputDevices + sNumOutputDevices; } static PaError Pa_AllocateDevicePtrs( void ) { int numBytes; int i; /* Allocate structures to hold device info. */ /* PLB20010402 - was allocating too much memory. */ /* numBytes = sNumDevices * sizeof(PaDeviceInfo); // PLB20010402 */ if( sNumDevices > 0 ) { numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */ sDevicePtrs = (PaDeviceInfo **) PaHost_AllocateTrackedMemory( numBytes ); /* MEM */ if( sDevicePtrs == NULL ) return paInsufficientMemory; for( i = 0; i < sNumDevices; i++ ) sDevicePtrs[i] = NULL; /* RDB20020417 explicitly set each ptr to NULL */ } else { sDevicePtrs = NULL; } return paNoError; } /*************************************************************************/ long Pa_GetHostError() { return sPaHostError; } /*************************************************************************/ int Pa_CountDevices() { if( PaHost_IsInitialized() ) return sNumDevices; else return 0; } /************************************************************************* * If a PaDeviceInfo structure has not already been created, * then allocate one and fill it in for the selected device. * * We create one extra input and one extra output device for the WAVE_MAPPER. * [Does anyone know how to query the default device and get its name?] */ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { #define NUM_STANDARDSAMPLINGRATES 3 /* 11025, 22050, 44100 */ static DWORD customSamplingRates[] = { 8000, 32000, 48000, 64000, 88200, 96000 }; #define NUM_CUSTOMSAMPLINGRATES (sizeof(customSamplingRates)/sizeof(DWORD)) #define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES) PaDeviceInfo *deviceInfo; double *sampleRates; /* non-const ptr */ int i; char *s; DBUG(( "Pa_GetDeviceInfo( %d )\n", id )); if( id < 0 || id >= sNumDevices ) return NULL; if( sDevicePtrs[ id ] != NULL ) { return sDevicePtrs[ id ]; } deviceInfo = (PaDeviceInfo *)PaHost_AllocateTrackedMemory( sizeof(PaDeviceInfo) ); /* MEM */ if( deviceInfo == NULL ) return NULL; deviceInfo->structVersion = 1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->numSampleRates = 0; sampleRates = (double*)PaHost_AllocateTrackedMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */ deviceInfo->sampleRates = sampleRates; deviceInfo->nativeSampleFormats = paInt16; /* should query for higher bit depths below */ if( id < sNumInputDevices ) { /* input device */ int inputMmID = PaDeviceIdToWinId(id); WAVEINCAPS wic; if( waveInGetDevCaps( inputMmID, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR ) goto error; /* Append I/O suffix to WAVE_MAPPER device. */ if( inputMmID == WAVE_MAPPER ) { s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */ strcpy( s, wic.szPname ); strcat( s, sMapperSuffixInput ); } else { s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 ); /* MEM */ strcpy( s, wic.szPname ); } deviceInfo->name = s; deviceInfo->maxInputChannels = wic.wChannels; DBUG(( "Pa_GetDeviceInfo: input %s, maxChannels = %d\n", deviceInfo->name, deviceInfo->maxInputChannels )); /* Sometimes a device can return a rediculously large number of channels. * This happened with an SBLive card on a Windows ME box. * If that happens, then force it to 2 channels. PLB20010413 */ if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) ) { ERR_RPT(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels )); deviceInfo->maxInputChannels = 2; } /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on the format flags. */ if( wic.dwFormats & WAVE_FORMAT_1M16 ||wic.dwFormats & WAVE_FORMAT_1S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 11025.; if( wic.dwFormats & WAVE_FORMAT_2M16 ||wic.dwFormats & WAVE_FORMAT_2S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 22050.; if( wic.dwFormats & WAVE_FORMAT_4M16 ||wic.dwFormats & WAVE_FORMAT_4S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 44100.; /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on opening the device successfully. */ for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ) { WAVEFORMATEX wfx; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nSamplesPerSec = customSamplingRates[i]; wfx.wBitsPerSample = 16; wfx.cbSize = 0; /* ignored */ wfx.nChannels = (WORD)deviceInfo->maxInputChannels; wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); if( waveInOpen( NULL, inputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) { sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i]; } } } else if( id - sNumInputDevices < sNumOutputDevices ) { /* output device */ int outputMmID = PaDeviceIdToWinId(id); WAVEOUTCAPS woc; if( waveOutGetDevCaps( outputMmID, &woc, sizeof( WAVEOUTCAPS ) ) != MMSYSERR_NOERROR ) goto error; /* Append I/O suffix to WAVE_MAPPER device. */ if( outputMmID == WAVE_MAPPER ) { s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */ strcpy( s, woc.szPname ); strcat( s, sMapperSuffixOutput ); } else { s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 ); /* MEM */ strcpy( s, woc.szPname ); } deviceInfo->name = s; deviceInfo->maxOutputChannels = woc.wChannels; DBUG(( "Pa_GetDeviceInfo: output %s, maxChannels = %d\n", deviceInfo->name, deviceInfo->maxOutputChannels )); /* Sometimes a device can return a rediculously large number of channels. * This happened with an SBLive card on a Windows ME box. * It also happens on Win XP! */ if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) ) { #if 1 deviceInfo->maxOutputChannels = 2; #else /* If channel max is goofy, then query for max channels. PLB20020228 * This doesn't seem to help. Disable code for now. Remove it later. */ ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d!", deviceInfo->maxOutputChannels )); deviceInfo->maxOutputChannels = 0; /* Attempt to find the correct maximum by querying the device. */ for( i=2; i<16; i += 2 ) { WAVEFORMATEX wfx; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nSamplesPerSec = 44100; wfx.wBitsPerSample = 16; wfx.cbSize = 0; /* ignored */ wfx.nChannels = (WORD) i; wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) { deviceInfo->maxOutputChannels = i; } else { break; } } #endif ERR_RPT((" Changed to %d.\n", deviceInfo->maxOutputChannels )); } /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on the format flags. */ if( woc.dwFormats & WAVE_FORMAT_1M16 ||woc.dwFormats & WAVE_FORMAT_1S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 11025.; if( woc.dwFormats & WAVE_FORMAT_2M16 ||woc.dwFormats & WAVE_FORMAT_2S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 22050.; if( woc.dwFormats & WAVE_FORMAT_4M16 ||woc.dwFormats & WAVE_FORMAT_4S16 ) sampleRates[ deviceInfo->numSampleRates++ ] = 44100.; /* Add a sample rate to the list if we can do stereo 16 bit at that rate * based on opening the device successfully. */ for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ ) { WAVEFORMATEX wfx; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nSamplesPerSec = customSamplingRates[i]; wfx.wBitsPerSample = 16; wfx.cbSize = 0; /* ignored */ wfx.nChannels = (WORD)deviceInfo->maxOutputChannels; wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short); wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short)); DBUG(( "Pa_GetDeviceInfo: waveOutOpen( ... WAVE_FORMAT_QUERY at SR = %d\n", customSamplingRates[i] )); if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR ) { sampleRates[ deviceInfo->numSampleRates++ ] = customSamplingRates[i]; } } } DBUG(( "Pa_GetDeviceInfo: done.\n" )); sDevicePtrs[ id ] = deviceInfo; return deviceInfo; error: PaHost_FreeTrackedMemory( sampleRates ); /* MEM */ PaHost_FreeTrackedMemory( deviceInfo ); /* MEM */ return NULL; } /************************************************************************* * Returns recommended device ID. * On the PC, the recommended device can be specified by the user by * setting an environment variable. For example, to use device #1. * * set PA_RECOMMENDED_OUTPUT_DEVICE=1 * * The user should first determine the available device ID by using * the supplied application "pa_devs". */ #define PA_ENV_BUF_SIZE (32) #define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE") #define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE") static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) { DWORD hresult; char envbuf[PA_ENV_BUF_SIZE]; PaDeviceID recommendedID = paNoDevice; /* Let user determine default device by setting environment variable. */ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { recommendedID = atoi( envbuf ); } return recommendedID; } /********************************************************************** * Check for environment variable, else query devices and use result. */ PaDeviceID Pa_GetDefaultInputDeviceID( void ) { PaDeviceID result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); if( result == paNoDevice || result < 0 || result >= sNumInputDevices ) { result = sDefaultInputDeviceID; } return result; } PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { PaDeviceID result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); if( result == paNoDevice || result < sNumInputDevices || result >= sNumDevices ) { result = sDefaultOutputDeviceID; } return result; } /********************************************************************** * Initialize Host dependant part of API. */ PaError PaHost_Init( void ) { #if PA_TRACK_MEMORY PRINT(("PaHost_Init: sNumAllocations = %d\n", sNumAllocations )); #endif #if PA_SIMULATE_UNDERFLOW PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); #endif Pa_InitializeNumDevices(); return Pa_AllocateDevicePtrs(); } /********************************************************************** * Check WAVE buffers to see if they are done. * Fill any available output buffers and use any available * input buffers by calling user callback. * * This routine will loop until: * user callback returns !=0 OR * all output buffers are filled OR * past->past_StopSoon is set OR * an error occurs when calling WMME. * * Returns >0 when user requests a stop, <0 on error. * */ static PaError Pa_TimeSlice( internalPortAudioStream *stream ) { PaError result = paNoError; MMRESULT mmresult; char *inBufPtr; char *outBufPtr; int gotInput = 0; int gotOutput = 0; int i; int buffersProcessed = 0; int done = 0; PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; if( wmmeStreamData == NULL ) return paInternalError; stream->past_NumCallbacks += 1; #if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", stream->past_NumCallbacks ); #endif /* JM20020118 - prevent hung thread when buffers underflow. */ /* while( !done ) /* BAD */ while( !done && !stream->past_StopSoon ) /* GOOD */ { #if PA_SIMULATE_UNDERFLOW if(gUnderCallbackCounter++ == UNDER_SLEEP_AT) { Sleep(UNDER_SLEEP_FOR); } #endif /* If we are using output, then we need an empty output buffer. */ gotOutput = 0; outBufPtr = NULL; if( stream->past_NumOutputChannels > 0 ) { if((wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].dwFlags & WHDR_DONE) == 0) { break; /* If none empty then bail and try again later. */ } else { outBufPtr = wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].lpData; gotOutput = 1; } } /* Use an input buffer if one is available. */ gotInput = 0; inBufPtr = NULL; if( ( stream->past_NumInputChannels > 0 ) && (wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].dwFlags & WHDR_DONE) ) { inBufPtr = wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].lpData; gotInput = 1; #if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: got input buffer at ", (int)inBufPtr ); AddTraceMessage("Pa_TimeSlice: got input buffer # ", wmmeStreamData->currentInputBuffer ); #endif } /* If we can't do anything then bail out. */ if( !gotInput && !gotOutput ) break; buffersProcessed += 1; /* Each Wave buffer contains multiple user buffers so do them all now. */ /* Base Usage on time it took to process one host buffer. */ Pa_StartUsageCalculation( stream ); for( i=0; iuserBuffersPerHostBuffer; i++ ) { if( done ) { if( gotOutput ) { /* Clear remainder of wave buffer if we are waiting for stop. */ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); memset( outBufPtr, 0, wmmeStreamData->bytesPerUserOutputBuffer ); } } else { /* Convert 16 bit native data to user data and call user routine. */ result = Pa_CallConvertInt16( stream, (short *) inBufPtr, (short *) outBufPtr ); if( result != 0) done = 1; } if( gotInput ) inBufPtr += wmmeStreamData->bytesPerUserInputBuffer; if( gotOutput) outBufPtr += wmmeStreamData->bytesPerUserOutputBuffer; } Pa_EndUsageCalculation( stream ); /* Send WAVE buffer to Wave Device to be refilled. */ if( gotInput ) { mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { sPaHostError = mmresult; result = paHostError; break; } wmmeStreamData->currentInputBuffer = (wmmeStreamData->currentInputBuffer+1 >= wmmeStreamData->numHostBuffers) ? 0 : wmmeStreamData->currentInputBuffer+1; } /* Write WAVE buffer to Wave Device. */ if( gotOutput ) { #if PA_TRACE_START_STOP AddTraceMessage( "Pa_TimeSlice: writing buffer ", wmmeStreamData->currentOutputBuffer ); #endif mmresult = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { sPaHostError = mmresult; result = paHostError; break; } wmmeStreamData->currentOutputBuffer = (wmmeStreamData->currentOutputBuffer+1 >= wmmeStreamData->numHostBuffers) ? 0 : wmmeStreamData->currentOutputBuffer+1; } } #if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: buffersProcessed ", buffersProcessed ); #endif return (result != 0) ? result : done; } /*******************************************************************/ static PaError PaHost_BackgroundManager( internalPortAudioStream *stream ) { PaError result = paNoError; int i; int numQueuedoutputBuffers = 0; PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; /* Has someone asked us to abort by calling Pa_AbortStream()? */ if( stream->past_StopNow ) { stream->past_IsActive = 0; /* Will cause thread to return. */ } /* Has someone asked us to stop by calling Pa_StopStream() * OR has a user callback returned '1' to indicate finished. */ else if( stream->past_StopSoon ) { /* Poll buffer and when all have played then exit thread. */ /* Count how many output buffers are queued. */ numQueuedoutputBuffers = 0; if( stream->past_NumOutputChannels > 0 ) { for( i=0; inumHostBuffers; i++ ) { if( !( wmmeStreamData->outputBuffers[ i ].dwFlags & WHDR_DONE) ) { #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_BackgroundManager: waiting for buffer ", i ); #endif numQueuedoutputBuffers++; } } } #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_BackgroundManager: numQueuedoutputBuffers ", numQueuedoutputBuffers ); #endif if( numQueuedoutputBuffers == 0 ) { stream->past_IsActive = 0; /* Will cause thread to return. */ } } else { /* Process full input buffer and fill up empty output buffers. */ if( (result = Pa_TimeSlice( stream )) != 0) { /* User callback has asked us to stop. */ #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_BackgroundManager: TimeSlice() returned ", result ); #endif stream->past_StopSoon = 1; /* Request that audio play out then stop. */ result = paNoError; } } PaHost_UpdateStreamTime( wmmeStreamData ); return result; } #if PA_USE_TIMER_CALLBACK /*******************************************************************/ static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { internalPortAudioStream *stream; PaWMMEStreamData *wmmeStreamData; PaError result; stream = (internalPortAudioStream *) dwUser; if( stream == NULL ) return; wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; if( wmmeStreamData == NULL ) return; if( wmmeStreamData->ifInsideCallback ) { if( wmmeStreamData->timerID != 0 ) { timeKillEvent(wmmeStreamData->timerID); /* Stop callback timer. */ wmmeStreamData->timerID = 0; } return; } wmmeStreamData->ifInsideCallback = 1; /* Manage flags and audio processing. */ result = PaHost_BackgroundManager( stream ); if( result != paNoError ) { stream->past_IsActive = 0; } wmmeStreamData->ifInsideCallback = 0; } #else /* PA_USE_TIMER_CALLBACK */ /*******************************************************************/ static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg ) { internalPortAudioStream *stream; PaWMMEStreamData *wmmeStreamData; HANDLE events[2]; int numEvents = 0; DWORD result = 0; DWORD waitResult; DWORD numTimeouts = 0; DWORD timeOut; stream = (internalPortAudioStream *) pArg; wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; #if PA_TRACE_START_STOP AddTraceMessage( "WinMMPa_OutputThreadProc: timeoutPeriod", timeoutPeriod ); AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", stream->past_NumUserBuffers ); #endif /* Calculate timeOut as half the time it would take to play all buffers. */ timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( stream ) / stream->past_SampleRate); /* Get event(s) ready for wait. */ events[numEvents++] = wmmeStreamData->bufferEvent; if( wmmeStreamData->abortEventInited ) events[numEvents++] = wmmeStreamData->abortEvent; /* Stay in this thread as long as we are "active". */ while( stream->past_IsActive ) { /*******************************************************************/ /******** WAIT here for an event from WMME or PA *******************/ /*******************************************************************/ waitResult = WaitForMultipleObjects( numEvents, events, FALSE, timeOut ); /* Error? */ if( waitResult == WAIT_FAILED ) { sPaHostError = GetLastError(); result = paHostError; stream->past_IsActive = 0; } /* Timeout? Don't stop. Just keep polling for DONE.*/ else if( waitResult == WAIT_TIMEOUT ) { #if PA_TRACE_START_STOP AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedoutputBuffers ); #endif numTimeouts += 1; } /* Manage flags and audio processing. */ result = PaHost_BackgroundManager( stream ); if( result != paNoError ) { stream->past_IsActive = 0; } } return result; } #endif /*******************************************************************/ PaError PaHost_OpenInputStream( internalPortAudioStream *stream ) { PaError result = paNoError; MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData; int i; int inputMmId; int bytesPerInputFrame; WAVEFORMATEX wfx; const PaDeviceInfo *deviceInfo; wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_InputDeviceID)); deviceInfo = Pa_GetDeviceInfo( stream->past_InputDeviceID ); if( deviceInfo == NULL ) return paInternalError; switch( deviceInfo->nativeSampleFormats ) { case paInt32: case paFloat32: bytesPerInputFrame = sizeof(float) * stream->past_NumInputChannels; break; default: bytesPerInputFrame = sizeof(short) * stream->past_NumInputChannels; break; } wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = (WORD) stream->past_NumInputChannels; wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate; wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * stream->past_SampleRate); wfx.nBlockAlign = (WORD)bytesPerInputFrame; wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/stream->past_NumInputChannels) * 8); wfx.cbSize = 0; inputMmId = PaDeviceIdToWinId( stream->past_InputDeviceID ); #if PA_USE_TIMER_CALLBACK mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, 0, 0, CALLBACK_NULL ); #else mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx, (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); #endif if( mmresult != MMSYSERR_NOERROR ) { ERR_RPT(("PortAudio: PaHost_OpenInputStream() failed!\n")); result = paHostError; sPaHostError = mmresult; goto error; } /* Allocate an array to hold the buffer pointers. */ wmmeStreamData->inputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */ if( wmmeStreamData->inputBuffers == NULL ) { result = paInsufficientMemory; goto error; } /* Allocate each buffer. */ for( i=0; inumHostBuffers; i++ ) { wmmeStreamData->inputBuffers[i].lpData = (char *)PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostInputBuffer ); /* MEM */ if( wmmeStreamData->inputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; goto error; } wmmeStreamData->inputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostInputBuffer; wmmeStreamData->inputBuffers[i].dwUser = i; if( ( mmresult = waveInPrepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } } return result; error: return result; } /*******************************************************************/ PaError PaHost_OpenOutputStream( internalPortAudioStream *stream ) { PaError result = paNoError; MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData; int i; int outputMmID; int bytesPerOutputFrame; WAVEFORMATEX wfx; const PaDeviceInfo *deviceInfo; wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_OutputDeviceID)); deviceInfo = Pa_GetDeviceInfo( stream->past_OutputDeviceID ); if( deviceInfo == NULL ) return paInternalError; switch( deviceInfo->nativeSampleFormats ) { case paInt32: case paFloat32: bytesPerOutputFrame = sizeof(float) * stream->past_NumOutputChannels; break; default: bytesPerOutputFrame = sizeof(short) * stream->past_NumOutputChannels; break; } wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = (WORD) stream->past_NumOutputChannels; wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate; wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * stream->past_SampleRate); wfx.nBlockAlign = (WORD)bytesPerOutputFrame; wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/stream->past_NumOutputChannels) * 8); wfx.cbSize = 0; outputMmID = PaDeviceIdToWinId( stream->past_OutputDeviceID ); #if PA_USE_TIMER_CALLBACK mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, 0, 0, CALLBACK_NULL ); #else wmmeStreamData->abortEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); if( wmmeStreamData->abortEvent == NULL ) { result = paHostError; sPaHostError = GetLastError(); goto error; } wmmeStreamData->abortEventInited = 1; mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx, (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT ); #endif if( mmresult != MMSYSERR_NOERROR ) { ERR_RPT(("PortAudio: PaHost_OpenOutputStream() failed!\n")); result = paHostError; sPaHostError = mmresult; goto error; } /* Allocate an array to hold the buffer pointers. */ wmmeStreamData->outputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */ if( wmmeStreamData->outputBuffers == NULL ) { result = paInsufficientMemory; goto error; } /* Allocate each buffer. */ for( i=0; inumHostBuffers; i++ ) { wmmeStreamData->outputBuffers[i].lpData = (char *) PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostOutputBuffer ); /* MEM */ if( wmmeStreamData->outputBuffers[i].lpData == NULL ) { result = paInsufficientMemory; goto error; } wmmeStreamData->outputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostOutputBuffer; wmmeStreamData->outputBuffers[i].dwUser = i; if( (mmresult = waveOutPrepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } } return result; error: return result; } /*******************************************************************/ PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *stream ) { PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; return wmmeStreamData->numHostBuffers * wmmeStreamData->framesPerHostBuffer; } /******************************************************************* * Determine number of WAVE Buffers * and how many User Buffers we can put into each WAVE buffer. */ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *stream ) { PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData; unsigned int minNumBuffers; int minframesPerHostBuffer; int maxframesPerHostBuffer; int minTotalFrames; int userBuffersPerHostBuffer; int framesPerHostBuffer; int numHostBuffers; /* Calculate minimum and maximum sizes based on timing and sample rate. */ minframesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001); minframesPerHostBuffer = (minframesPerHostBuffer + 7) & ~7; DBUG(("PaHost_CalcNumHostBuffers: minframesPerHostBuffer = %d\n", minframesPerHostBuffer )); maxframesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001); maxframesPerHostBuffer = (maxframesPerHostBuffer + 7) & ~7; DBUG(("PaHost_CalcNumHostBuffers: maxframesPerHostBuffer = %d\n", maxframesPerHostBuffer )); /* Determine number of user buffers based on minimum latency. */ minNumBuffers = Pa_GetMinNumBuffers( stream->past_FramesPerUserBuffer, stream->past_SampleRate ); stream->past_NumUserBuffers = ( minNumBuffers > stream->past_NumUserBuffers ) ? minNumBuffers : stream->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", stream->past_NumUserBuffers )); minTotalFrames = stream->past_NumUserBuffers * stream->past_FramesPerUserBuffer; /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */ if( (int) stream->past_FramesPerUserBuffer < minframesPerHostBuffer ) { userBuffersPerHostBuffer = (minframesPerHostBuffer + stream->past_FramesPerUserBuffer - 1) / stream->past_FramesPerUserBuffer; } else { userBuffersPerHostBuffer = 1; } framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* Make sure we have anough WAVE buffers. */ if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) { numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; } else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) && ((int) stream->past_FramesPerUserBuffer < (maxframesPerHostBuffer/2) ) ) { /* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) { userBuffersPerHostBuffer += 1; framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* If we have gone too far, back up one. */ if( (framesPerHostBuffer > maxframesPerHostBuffer) || (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) ) { userBuffersPerHostBuffer -= 1; framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; break; } } } wmmeStreamData->userBuffersPerHostBuffer = userBuffersPerHostBuffer; wmmeStreamData->framesPerHostBuffer = framesPerHostBuffer; wmmeStreamData->numHostBuffers = numHostBuffers; DBUG(("PaHost_CalcNumHostBuffers: userBuffersPerHostBuffer = %d\n", wmmeStreamData->userBuffersPerHostBuffer )); DBUG(("PaHost_CalcNumHostBuffers: numHostBuffers = %d\n", wmmeStreamData->numHostBuffers )); DBUG(("PaHost_CalcNumHostBuffers: framesPerHostBuffer = %d\n", wmmeStreamData->framesPerHostBuffer )); DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", stream->past_NumUserBuffers )); } /*******************************************************************/ PaError PaHost_OpenStream( internalPortAudioStream *stream ) { PaError result = paNoError; PaWMMEStreamData *wmmeStreamData; result = PaHost_AllocateWMMEStreamData( stream ); if( result != paNoError ) return result; wmmeStreamData = PaHost_GetWMMEStreamData( stream ); /* Figure out how user buffers fit into WAVE buffers. */ PaHost_CalcNumHostBuffers( stream ); { int msecLatency = (int) ((PaHost_GetTotalBufferFrames(stream) * 1000) / stream->past_SampleRate); DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(stream), msecLatency )); } InitializeCriticalSection( &wmmeStreamData->streamLock ); wmmeStreamData->streamLockInited = 1; #if (PA_USE_TIMER_CALLBACK == 0) wmmeStreamData->bufferEventInited = 0; wmmeStreamData->bufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if( wmmeStreamData->bufferEvent == NULL ) { result = paHostError; sPaHostError = GetLastError(); goto error; } wmmeStreamData->bufferEventInited = 1; #endif /* (PA_USE_TIMER_CALLBACK == 0) */ /* ------------------ OUTPUT */ wmmeStreamData->bytesPerUserOutputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumOutputChannels * sizeof(short); wmmeStreamData->bytesPerHostOutputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserOutputBuffer; if( (stream->past_OutputDeviceID != paNoDevice) && (stream->past_NumOutputChannels > 0) ) { result = PaHost_OpenOutputStream( stream ); if( result < 0 ) goto error; } /* ------------------ INPUT */ wmmeStreamData->bytesPerUserInputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumInputChannels * sizeof(short); wmmeStreamData->bytesPerHostInputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserInputBuffer; if( (stream->past_InputDeviceID != paNoDevice) && (stream->past_NumInputChannels > 0) ) { result = PaHost_OpenInputStream( stream ); if( result < 0 ) goto error; } Pa_InitializeCpuUsageScalar( stream ); return result; error: PaHost_CloseStream( stream ); return result; } /*************************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *stream ) { PaError result = paNoError; MMRESULT mmresult; int i; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); if( wmmeStreamData == NULL ) return paInternalError; if( stream->past_OutputDeviceID != paNoDevice ) { if( (mmresult = waveOutPause( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } for( i=0; inumHostBuffers; i++ ) { ZeroMemory( wmmeStreamData->outputBuffers[i].lpData, wmmeStreamData->outputBuffers[i].dwBufferLength ); mmresult = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } stream->past_FrameCount += wmmeStreamData->framesPerHostBuffer; } wmmeStreamData->currentOutputBuffer = 0; if( (mmresult = waveOutRestart( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } } error: DBUG(("PaHost_StartOutput: wave returned mmresult = 0x%X.\n", mmresult)); return result; } /*************************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *internalStream ) { PaError result = paNoError; MMRESULT mmresult; int i; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); if( wmmeStreamData == NULL ) return paInternalError; if( internalStream->past_InputDeviceID != paNoDevice ) { for( i=0; inumHostBuffers; i++ ) { mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } } wmmeStreamData->currentInputBuffer = 0; mmresult = waveInStart( wmmeStreamData->hWaveIn ); DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult)); if( mmresult != MMSYSERR_NOERROR ) { result = paHostError; sPaHostError = mmresult; goto error; } } error: return result; } /*************************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *stream ) { PaError result = paNoError; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); #if PA_USE_TIMER_CALLBACK int resolution; int bufsPerTimerCallback; int msecPerBuffer; #endif /* PA_USE_TIMER_CALLBACK */ if( wmmeStreamData == NULL ) return paInternalError; stream->past_StopSoon = 0; stream->past_StopNow = 0; stream->past_IsActive = 1; wmmeStreamData->framesPlayed = 0.0; wmmeStreamData->lastPosition = 0; #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result ); #endif #if PA_USE_TIMER_CALLBACK /* Create timer that will wake us up so we can fill the DSound buffer. */ bufsPerTimerCallback = wmmeStreamData->numHostBuffers/4; if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1; msecPerBuffer = (1000 * bufsPerTimerCallback * wmmeStreamData->userBuffersPerHostBuffer * internalStream->past_FramesPerUserBuffer ) / (int) internalStream->past_SampleRate; if( msecPerBuffer < 10 ) msecPerBuffer = 10; else if( msecPerBuffer > 100 ) msecPerBuffer = 100; resolution = msecPerBuffer/4; wmmeStreamData->timerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback, (DWORD) stream, TIME_PERIODIC ); if( wmmeStreamData->timerID == 0 ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #else /* PA_USE_TIMER_CALLBACK */ ResetEvent( wmmeStreamData->abortEvent ); /* Create thread that waits for audio buffers to be ready for processing. */ wmmeStreamData->engineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, stream, 0, &wmmeStreamData->engineThreadID ); if( wmmeStreamData->engineThread == NULL ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: thread ", (int) wmmeStreamData->engineThread ); #endif /* I used to pass the thread which was failing. I now pass GetCurrentProcess(). * This fix could improve latency for some applications. It could also result in CPU * starvation if the callback did too much processing. * I also added result checks, so we might see more failures at initialization. * Thanks to Alberto di Bene for spotting this. */ if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */ { result = paHostError; sPaHostError = GetLastError();; goto error; } if( !SetThreadPriority( wmmeStreamData->engineThread, THREAD_PRIORITY_HIGHEST ) ) { result = paHostError; sPaHostError = GetLastError();; goto error; } #endif error: return result; } /*************************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *internalStream, int abort ) { int timeOut; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); if( wmmeStreamData == NULL ) return paNoError; /* Tell background thread to stop generating more data and to let current data play out. */ internalStream->past_StopSoon = 1; /* If aborting, tell background thread to stop NOW! */ if( abort ) internalStream->past_StopNow = 1; /* Calculate timeOut longer than longest time it could take to play all buffers. */ timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( internalStream ) / internalStream->past_SampleRate); if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; #if PA_USE_TIMER_CALLBACK if( (internalStream->past_OutputDeviceID != paNoDevice) && internalStream->past_IsActive && (wmmeStreamData->timerID != 0) ) { /* Wait for IsActive to drop. */ while( (internalStream->past_IsActive) && (timeOut > 0) ) { Sleep(10); timeOut -= 10; } timeKillEvent( wmmeStreamData->timerID ); /* Stop callback timer. */ wmmeStreamData->timerID = 0; } #else /* PA_USE_TIMER_CALLBACK */ #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StopEngine: thread ", (int) wmmeStreamData->engineThread ); #endif if( (internalStream->past_OutputDeviceID != paNoDevice) && (internalStream->past_IsActive) && (wmmeStreamData->engineThread != NULL) ) { DWORD got; /* Tell background thread to stop generating more data and to let current data play out. */ DBUG(("PaHost_StopEngine: waiting for background thread.\n")); got = WaitForSingleObject( wmmeStreamData->engineThread, timeOut ); if( got == WAIT_TIMEOUT ) { ERR_RPT(("PaHost_StopEngine: timed out while waiting for background thread to finish.\n")); return paTimedOut; } CloseHandle( wmmeStreamData->engineThread ); wmmeStreamData->engineThread = NULL; } #endif /* PA_USE_TIMER_CALLBACK */ internalStream->past_IsActive = 0; return paNoError; } /*************************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *stream, int abort ) { MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ (void) abort; /* unused parameter */ if( wmmeStreamData->hWaveIn != NULL ) { mmresult = waveInReset( wmmeStreamData->hWaveIn ); if( mmresult != MMSYSERR_NOERROR ) { sPaHostError = mmresult; return paHostError; } } return paNoError; } /*************************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *internalStream, int abort ) { MMRESULT mmresult; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */ (void) abort; /* unused parameter */ #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StopOutput: hWaveOut ", (int) wmmeStreamData->hWaveOut ); #endif if( wmmeStreamData->hWaveOut != NULL ) { mmresult = waveOutReset( wmmeStreamData->hWaveOut ); if( mmresult != MMSYSERR_NOERROR ) { sPaHostError = mmresult; return paHostError; } } return paNoError; } /*******************************************************************/ PaError PaHost_CloseStream( internalPortAudioStream *stream ) { int i; PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream ); if( stream == NULL ) return paBadStreamPtr; if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return no error? */ #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_CloseStream: hWaveOut ", (int) wmmeStreamData->hWaveOut ); #endif /* Free data and device for output. */ if( wmmeStreamData->hWaveOut ) { if( wmmeStreamData->outputBuffers ) { for( i=0; inumHostBuffers; i++ ) { waveOutUnprepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) ); PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers[i].lpData ); /* MEM */ } PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers ); /* MEM */ } waveOutClose( wmmeStreamData->hWaveOut ); } /* Free data and device for input. */ if( wmmeStreamData->hWaveIn ) { if( wmmeStreamData->inputBuffers ) { for( i=0; inumHostBuffers; i++ ) { waveInUnprepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) ); PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers[i].lpData ); /* MEM */ } PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers ); /* MEM */ } waveInClose( wmmeStreamData->hWaveIn ); } #if (PA_USE_TIMER_CALLBACK == 0) if( wmmeStreamData->abortEventInited ) CloseHandle( wmmeStreamData->abortEvent ); if( wmmeStreamData->bufferEventInited ) CloseHandle( wmmeStreamData->bufferEvent ); #endif if( wmmeStreamData->streamLockInited ) DeleteCriticalSection( &wmmeStreamData->streamLock ); PaHost_FreeWMMEStreamData( stream ); return paNoError; } /************************************************************************* * Determine minimum number of buffers required for this host based * on minimum latency. Latency can be optionally set by user by setting * an environment variable. For example, to set latency to 200 msec, put: * * set PA_MIN_LATENCY_MSEC=200 * * in the AUTOEXEC.BAT file and reboot. * If the environment variable is not set, then the latency will be determined * based on the OS. Windows NT has higher latency than Win95. */ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { char envbuf[PA_ENV_BUF_SIZE]; DWORD hresult; int minLatencyMsec = 0; double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; int minBuffers; /* Let user determine minimal latency by setting environment variable. */ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { minLatencyMsec = atoi( envbuf ); /* REVIEW: will we crash if the environment variable contains some nasty value? */ } else { /* Set minimal latency based on whether NT or other OS. * NT has higher latency. */ OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof( osvi ); GetVersionEx( &osvi ); DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); /* Check for NT */ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) { minLatencyMsec = PA_WIN_NT_LATENCY; } else if(osvi.dwMajorVersion >= 5) { minLatencyMsec = PA_WIN_WDM_LATENCY; } else { minLatencyMsec = PA_WIN_9X_LATENCY; } #if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); #endif } DBUG(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); if( minBuffers < 2 ) minBuffers = 2; return minBuffers; } /************************************************************************* * Cleanup device info. */ PaError PaHost_Term( void ) { int i; if( sNumDevices > 0 ) { if( sDevicePtrs != NULL ) { for( i=0; iname ); /* MEM */ PaHost_FreeTrackedMemory( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */ PaHost_FreeTrackedMemory( sDevicePtrs[i] ); /* MEM */ } } PaHost_FreeTrackedMemory( sDevicePtrs ); /* MEM */ sDevicePtrs = NULL; } sNumDevices = 0; } #if PA_TRACK_MEMORY PRINT(("PaHost_Term: sNumAllocations = %d\n", sNumAllocations )); #endif return paNoError; } /*************************************************************************/ void Pa_Sleep( long msec ) { Sleep( msec ); } /************************************************************************* FIXME: the following memory allocation routines should not be declared here * Allocate memory that can be accessed in real-time. * This may need to be held in physical memory so that it is not * paged to virtual memory. * This call MUST be balanced with a call to PaHost_FreeFastMemory(). * Memory will be set to zero. */ void *PaHost_AllocateFastMemory( long numBytes ) { return PaHost_AllocateTrackedMemory( numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */ } /************************************************************************* * Free memory that could be accessed in real-time. * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory( void *addr, long numBytes ) { (void) numBytes; /* unused parameter */ PaHost_FreeTrackedMemory( addr ); /* MEM */ } /************************************************************************* * Track memory allocations to avoid leaks. */ static void *PaHost_AllocateTrackedMemory( long numBytes ) { void *result = GlobalAlloc( GPTR, numBytes ); /* MEM */ #if PA_TRACK_MEMORY if( result != NULL ) sNumAllocations += 1; #endif return result; } static void PaHost_FreeTrackedMemory( void *addr ) { if( addr != NULL ) { GlobalFree( addr ); /* MEM */ #if PA_TRACK_MEMORY sNumAllocations -= 1; #endif } } /***********************************************************************/ PaError PaHost_StreamActive( internalPortAudioStream *internalStream ) { if( internalStream == NULL ) return paBadStreamPtr; return (PaError) internalStream->past_IsActive; } /************************************************************************* * This must be called periodically because mmtime.u.sample * is a DWORD and can wrap and lose sync after a few hours. */ static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData ) { MMRESULT mmresult; MMTIME mmtime; mmtime.wType = TIME_SAMPLES; if( wmmeStreamData->hWaveOut != NULL ) { mmresult = waveOutGetPosition( wmmeStreamData->hWaveOut, &mmtime, sizeof(mmtime) ); } else { mmresult = waveInGetPosition( wmmeStreamData->hWaveIn, &mmtime, sizeof(mmtime) ); } if( mmresult != MMSYSERR_NOERROR ) { sPaHostError = mmresult; return paHostError; } /* This data has two variables and is shared by foreground and background. * So we need to make it thread safe. */ EnterCriticalSection( &wmmeStreamData->streamLock ); wmmeStreamData->framesPlayed += ((long)mmtime.u.sample) - wmmeStreamData->lastPosition; wmmeStreamData->lastPosition = (long)mmtime.u.sample; LeaveCriticalSection( &wmmeStreamData->streamLock ); return paNoError; } /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *internalStream = PaHost_GetStreamRepresentation( stream ); PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream ); if( internalStream == NULL ) return paBadStreamPtr; if( wmmeStreamData == NULL ) return paInternalError; PaHost_UpdateStreamTime( wmmeStreamData ); return wmmeStreamData->framesPlayed; } /*************************************************************************/ portaudio-18.1.orig/index.html0000644000175000000620000000713707512407144017003 0ustar mikaelstaff00000000000000 PortAudio - Cross-Platform Audio API  

    PortAudio - Portable Audio Library

    Last updated 5/6/02.

    PortAudio is a cross platform, open-source, audio I/O library proposed by Ross Bencina to the music-dsp mailing list. It lets you write simple audio programs in 'C' that will compile and run on Windows, Macintosh, Unix, BeOS. PortAudio is intended to promote the exchange of audio synthesis software between developers on different platforms.

    For complete information on PortAudio and to download the latest releases, please visit "http://www.portaudio.com".
     
     

    Click here for Documentation

    Contacts and E-Mail List

    • If you are using or implementing PortAudio then please join the PortAudio mail list generously administered by Bill Eldridge.
    • If you find bugs in one of these implementations, or have suggestions, please e-mail them to Phil Burk.
    • If you make improvements to the library, please send them to us so we can incorporate the improvements.

    License

    PortAudio Portable Real-Time Audio Library
    Copyright (c) 1999-2000 Ross Bencina and Phil Burk

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    • The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
    • 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.
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ON INFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      portaudio-18.1.orig/config.guess0000644000175000000620000011262507622303110017310 0ustar mikaelstaff00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. timestamp='2001-10-05' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi dummy=dummy-$$ trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int dummy(){}" > $dummy.c ; for c in cc gcc c89 ; do ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ; if test $? = 0 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; rm -f $dummy.c $dummy.o $dummy.rel ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # Determine the machine/vendor (is the vendor relevant). case "${UNAME_MACHINE}" in amiga) machine=m68k-unknown ;; arm32) machine=arm-unknown ;; atari*) machine=m68k-atari ;; sun3*) machine=m68k-sun ;; mac68k) machine=m68k-apple ;; macppc) machine=powerpc-apple ;; hp3[0-9][05]) machine=m68k-hp ;; ibmrt|romp-ibm) machine=romp-ibm ;; sparc*) machine=`uname -p`-unknown ;; *) machine=${UNAME_MACHINE}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE}" in i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit 0 ;; amiga:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; arc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; hp300:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mac68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; macppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme68k:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvme88k:OpenBSD:*:*) echo m88k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; mvmeppc:OpenBSD:*:*) echo powerpc-unknown-openbsd${UNAME_RELEASE} exit 0 ;; pmax:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sgi:OpenBSD:*:*) echo mipseb-unknown-openbsd${UNAME_RELEASE} exit 0 ;; sun3:OpenBSD:*:*) echo m68k-unknown-openbsd${UNAME_RELEASE} exit 0 ;; wgrisc:OpenBSD:*:*) echo mipsel-unknown-openbsd${UNAME_RELEASE} exit 0 ;; *:OpenBSD:*:*) echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} exit 0 ;; alpha:OSF1:*:*) if test $UNAME_RELEASE = "V4.0"; then UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` fi # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. cat <$dummy.s .data \$Lformat: .byte 37,100,45,37,120,10,0 # "%d-%x\n" .text .globl main .align 4 .ent main main: .frame \$30,16,\$26,0 ldgp \$29,0(\$27) .prologue 1 .long 0x47e03d80 # implver \$0 lda \$2,-1 .long 0x47e20c21 # amask \$2,\$1 lda \$16,\$Lformat mov \$0,\$17 not \$1,\$18 jsr \$26,printf ldgp \$29,0(\$26) mov 0,\$16 jsr \$26,exit .end main EOF eval $set_cc_for_build $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null if test "$?" = 0 ; then case `./$dummy` in 0-0) UNAME_MACHINE="alpha" ;; 1-0) UNAME_MACHINE="alphaev5" ;; 1-1) UNAME_MACHINE="alphaev56" ;; 1-101) UNAME_MACHINE="alphapca56" ;; 2-303) UNAME_MACHINE="alphaev6" ;; 2-307) UNAME_MACHINE="alphaev67" ;; 2-1307) UNAME_MACHINE="alphaev68" ;; esac fi rm -f $dummy.s $dummy echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit 0 ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit 0 ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit 0 ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit 0;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit 0 ;; *:OS/390:*:*) echo i370-ibm-openedition exit 0 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit 0;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit 0;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit 0 ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit 0 ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit 0 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit 0 ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit 0 ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit 0 ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit 0 ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit 0 ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit 0 ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit 0 ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit 0 ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit 0 ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit 0 ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit 0 ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit 0 ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy \ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo mips-mips-riscos${UNAME_RELEASE} exit 0 ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit 0 ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit 0 ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit 0 ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit 0 ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit 0 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit 0 ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit 0 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit 0 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit 0 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit 0 ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit 0 ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit 0 ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo rs6000-ibm-aix3.2.5 elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit 0 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit 0 ;; *:AIX:*:*) echo rs6000-ibm-aix exit 0 ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit 0 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit 0 ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit 0 ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit 0 ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit 0 ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit 0 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`./$dummy` if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi rm -f $dummy.c $dummy fi ;; esac echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit 0 ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit 0 ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy echo unknown-hitachi-hiuxwe2 exit 0 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit 0 ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit 0 ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit 0 ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit 0 ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit 0 ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit 0 ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit 0 ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit 0 ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit 0 ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit 0 ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit 0 ;; CRAY*X-MP:*:*:*) echo xmp-cray-unicos exit 0 ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3D:*:*:*) echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit 0 ;; CRAY-2:*:*:*) echo cray2-cray-unicos exit 0 ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit 0 ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit 0 ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit 0 ;; *:FreeBSD:*:*) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit 0 ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit 0 ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit 0 ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit 0 ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i386-pc-interix exit 0 ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit 0 ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit 0 ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit 0 ;; *:GNU:*:*) echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit 0 ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit 0 ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux exit 0 ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; mips:Linux:*:*) case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in big) echo mips-unknown-linux-gnu && exit 0 ;; little) echo mipsel-unknown-linux-gnu && exit 0 ;; esac ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit 0 ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit 0 ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit 0 ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit 0 ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit 0 ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit 0 ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit 0 ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit 0 ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. ld_supported_targets=`cd /; ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit 0 ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit 0 ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit 0 ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build cat >$dummy.c < #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 printf ("%s-pc-linux-gnu\n", argv[1]); # else printf ("%s-pc-linux-gnulibc1\n", argv[1]); # endif # else printf ("%s-pc-linux-gnulibc1\n", argv[1]); # endif #else printf ("%s-pc-linux-gnuaout\n", argv[1]); #endif return 0; } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit 0 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit 0 ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit 0 ;; i*86:*:5:[78]*) case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit 0 ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit 0 ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit 0 ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit 0 ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit 0 ;; paragon:*:*:*) echo i860-intel-osf1 exit 0 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit 0 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit 0 ;; M68*:*:R3V[567]*:*) test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4.3${OS_REL} && exit 0 /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && echo i486-ncr-sysv4 && exit 0 ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit 0 ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit 0 ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit 0 ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit 0 ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit 0 ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit 0 ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit 0 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit 0 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit 0 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit 0 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit 0 ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit 0 ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit 0 ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit 0 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit 0 ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit 0 ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit 0 ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit 0 ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit 0 ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit 0 ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit 0 ;; *:Darwin:*:*) echo `uname -p`-apple-darwin${UNAME_RELEASE} exit 0 ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) if test "${UNAME_MACHINE}" = "x86pc"; then UNAME_MACHINE=pc fi echo `uname -p`-${UNAME_MACHINE}-nto-qnx exit 0 ;; *:QNX:*:4*) echo i386-pc-qnx exit 0 ;; NSR-[KW]:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit 0 ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit 0 ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit 0 ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit 0 ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit 0 ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit 0 ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit 0 ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit 0 ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit 0 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit 0 ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit 0 ;; *:ITS:*:*) echo pdp10-unknown-its exit 0 ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit 0 ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit 0 ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0 rm -f $dummy.c $dummy # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit 0 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit 0 ;; c34*) echo c34-convex-bsd exit 0 ;; c38*) echo c38-convex-bsd exit 0 ;; c4*) echo c4-convex-bsd exit 0 ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: portaudio-18.1.orig/install-sh0000644000175000000620000001273607622303110016776 0ustar mikaelstaff00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 portaudio-18.1.orig/pa_win_ds/0000755000175000000620000000000007700016422016733 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_win_ds/portaudio.def0000644000175000017500000000154307423043540021573 0ustar mikaelmikael00000000000000LIBRARY PortAudio DESCRIPTION 'PortAudio Portable interface to audio HW' EXPORTS ; Explicit exports can go here Pa_Initialize @1 Pa_Terminate @2 Pa_GetHostError @3 Pa_GetErrorText @4 Pa_CountDevices @5 Pa_GetDefaultInputDeviceID @6 Pa_GetDefaultOutputDeviceID @7 Pa_GetDeviceInfo @8 Pa_OpenStream @9 Pa_OpenDefaultStream @10 Pa_CloseStream @11 Pa_StartStream @12 Pa_StopStream @13 Pa_StreamActive @14 Pa_StreamTime @15 Pa_GetCPULoad @16 Pa_GetMinNumBuffers @17 Pa_Sleep @18 ;123456789012345678901234567890123456 ;000000000111111111122222222223333333 portaudio-18.1.orig/pa_win_ds/pa_dsound.c0000644000175000017500000011512107566431216021234 0ustar mikaelmikael00000000000000/* * $Id: pa_dsound.c,v 1.2.4.1 2002/11/19 20:46:06 philburk Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.softsynth.com/portaudio/ * DirectSound Implementation * * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* Modifications * 7/19/01 Mike Berry - casts for compiling with __MWERKS__ CodeWarrior * 9/27/01 Phil Burk - use number of frames instead of real-time for CPULoad calculation. * 4/19/02 Phil Burk - Check for Win XP for system latency calculation. */ /* Compiler flags: SUPPORT_AUDIO_CAPTURE - define this flag if you want to SUPPORT_AUDIO_CAPTURE */ #include #include #ifndef __MWERKS__ #include #include #endif //__MWERKS__ #include #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" #include "dsound_wrapper.h" #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ #define PA_USE_HIGH_LATENCY (0) #if PA_USE_HIGH_LATENCY #define PA_WIN_9X_LATENCY (500) #define PA_WIN_NT_LATENCY (600) #else #define PA_WIN_9X_LATENCY (140) #define PA_WIN_NT_LATENCY (280) #endif #define PA_WIN_WDM_LATENCY (120) /* Trigger an underflow for testing purposes. Should normally be (0). */ #define PA_SIMULATE_UNDERFLOW (0) #if PA_SIMULATE_UNDERFLOW static gUnderCallbackCounter = 0; #define UNDER_START_GAP (10) #define UNDER_STOP_GAP (UNDER_START_GAP + 4) #endif /************************************************* Definitions ********/ typedef struct internalPortAudioStream internalPortAudioStream; typedef struct internalPortAudioDevice { GUID pad_GUID; GUID *pad_lpGUID; double pad_SampleRates[10]; /* for pointing to from pad_Info FIXME?!*/ PaDeviceInfo pad_Info; } internalPortAudioDevice; /* Define structure to contain all DirectSound and Windows specific data. */ typedef struct PaHostSoundControl { DSoundWrapper pahsc_DSoundWrapper; MMRESULT pahsc_TimerID; BOOL pahsc_IfInsideCallback; /* Test for reentrancy. */ short *pahsc_NativeBuffer; unsigned int pahsc_BytesPerBuffer; /* native buffer size in bytes */ double pahsc_ValidFramesWritten; int pahsc_FramesPerDSBuffer; /* For measuring CPU utilization. */ LARGE_INTEGER pahsc_EntryCount; double pahsc_InverseTicksPerUserBuffer; } PaHostSoundControl; /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ static int sNumDevices = 0; static int sDeviceIndex = 0; static internalPortAudioDevice *sDevices = NULL; static int sDefaultInputDeviceID = paNoDevice; static int sDefaultOutputDeviceID = paNoDevice; static int sEnumerationError; static int sPaHostError = 0; /************************************************* Prototypes **********/ static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ); static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ); static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ); static Pa_QueryDevices( void ); static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2); /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); } static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { LARGE_INTEGER CurrentCount = { 0, 0 }; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* ** Measure CPU utilization during this callback. Note that this calculation ** assumes that we had the processor the whole time. */ #define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) if( QueryPerformanceCounter( &CurrentCount ) ) { LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerUserBuffer; past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + (LOWPASS_COEFFICIENT_1 * newUsage); } } /****************************************** END CPU UTILIZATION *******/ static PaError Pa_QueryDevices( void ) { int numBytes; sDefaultInputDeviceID = paNoDevice; sDefaultOutputDeviceID = paNoDevice; /* Enumerate once just to count devices. */ sNumDevices = 0; // for default device DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, NULL ); #if SUPPORT_AUDIO_CAPTURE DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, NULL ); #endif /* SUPPORT_AUDIO_CAPTURE */ /* Allocate structures to hold device info. */ numBytes = sNumDevices * sizeof(internalPortAudioDevice); sDevices = (internalPortAudioDevice *)PaHost_AllocateFastMemory( numBytes ); /* MEM */ if( sDevices == NULL ) return paInsufficientMemory; /* Enumerate again to fill in structures. */ sDeviceIndex = 0; sEnumerationError = 0; DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_EnumProc, (void *)0 ); #if SUPPORT_AUDIO_CAPTURE if( sEnumerationError != paNoError ) return sEnumerationError; sEnumerationError = 0; DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_EnumProc, (void *)1 ); #endif /* SUPPORT_AUDIO_CAPTURE */ return sEnumerationError; } /************************************************************************************/ long Pa_GetHostError() { return sPaHostError; } /************************************************************************************ ** Just count devices so we know how much memory to allocate. */ static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ) { sNumDevices++; return TRUE; } /************************************************************************************ ** Extract capabilities info from each device. */ static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ) { HRESULT hr; LPDIRECTSOUND lpDirectSound; #if SUPPORT_AUDIO_CAPTURE LPDIRECTSOUNDCAPTURE lpDirectSoundCapture; #endif /* SUPPORT_AUDIO_CAPTURE */ int isInput = (int) lpContext; /* Passed from Pa_CountDevices() */ internalPortAudioDevice *pad; if( sDeviceIndex >= sNumDevices ) { sEnumerationError = paInternalError; return FALSE; } pad = &sDevices[sDeviceIndex]; /* Copy GUID to static array. Set pointer. */ if( lpGUID == NULL ) { pad->pad_lpGUID = NULL; } else { memcpy( &pad->pad_GUID, lpGUID, sizeof(GUID) ); pad->pad_lpGUID = &pad->pad_GUID; } pad->pad_Info.sampleRates = pad->pad_SampleRates; /* Point to array. */ /* Allocate room for descriptive name. */ if( lpszDesc != NULL ) { int len = strlen(lpszDesc); pad->pad_Info.name = (char *)malloc( len+1 ); if( pad->pad_Info.name == NULL ) { sEnumerationError = paInsufficientMemory; return FALSE; } memcpy( (void *) pad->pad_Info.name, lpszDesc, len+1 ); } #if SUPPORT_AUDIO_CAPTURE if( isInput ) { /********** Input ******************************/ DSCCAPS caps; if( lpGUID == NULL ) sDefaultInputDeviceID = sDeviceIndex; hr = DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL ); if( hr != DS_OK ) { pad->pad_Info.maxInputChannels = 0; DBUG(("Cannot create Capture for %s. Result = 0x%x\n", lpszDesc, hr )); } else { /* Query device characteristics. */ caps.dwSize = sizeof(caps); IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps ); /* printf("caps.dwFormats = 0x%x\n", caps.dwFormats ); */ pad->pad_Info.maxInputChannels = caps.dwChannels; /* Determine sample rates from flags. */ if( caps.dwChannels == 2 ) { int index = 0; if( caps.dwFormats & WAVE_FORMAT_1S16) pad->pad_SampleRates[index++] = 11025.0; if( caps.dwFormats & WAVE_FORMAT_2S16) pad->pad_SampleRates[index++] = 22050.0; if( caps.dwFormats & WAVE_FORMAT_4S16) pad->pad_SampleRates[index++] = 44100.0; pad->pad_Info.numSampleRates = index; } else if( caps.dwChannels == 1 ) { int index = 0; if( caps.dwFormats & WAVE_FORMAT_1M16) pad->pad_SampleRates[index++] = 11025.0; if( caps.dwFormats & WAVE_FORMAT_2M16) pad->pad_SampleRates[index++] = 22050.0; if( caps.dwFormats & WAVE_FORMAT_4M16) pad->pad_SampleRates[index++] = 44100.0; pad->pad_Info.numSampleRates = index; } else pad->pad_Info.numSampleRates = 0; IDirectSoundCapture_Release( lpDirectSoundCapture ); } } else #endif /* SUPPORT_AUDIO_CAPTURE */ { /********** Output ******************************/ DSCAPS caps; if( lpGUID == NULL ) sDefaultOutputDeviceID = sDeviceIndex; /* Create interfaces for each object. */ hr = DirectSoundCreate( lpGUID, &lpDirectSound, NULL ); if( hr != DS_OK ) { pad->pad_Info.maxOutputChannels = 0; DBUG(("Cannot create dsound for %s. Result = 0x%x\n", lpszDesc, hr )); } else { /* Query device characteristics. */ caps.dwSize = sizeof(caps); IDirectSound_GetCaps( lpDirectSound, &caps ); pad->pad_Info.maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1; /* Get sample rates. */ pad->pad_SampleRates[0] = (double) caps.dwMinSecondarySampleRate; pad->pad_SampleRates[1] = (double) caps.dwMaxSecondarySampleRate; if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) pad->pad_Info.numSampleRates = -1; else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate ) { if( caps.dwMinSecondarySampleRate == 0 ) { /* ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !! ** But it supports continuous sampling. ** So fake range of rates, and hope it really supports it. */ pad->pad_SampleRates[0] = 11025.0f; pad->pad_SampleRates[1] = 48000.0f; pad->pad_Info.numSampleRates = -1; /* continuous range */ DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex )); } else { pad->pad_Info.numSampleRates = 1; } } else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) ) { /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000. ** But we know that they really support a range of rates! ** So when we see a ridiculous set of rates, assume it is a range. */ pad->pad_Info.numSampleRates = -1; DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex )); } else pad->pad_Info.numSampleRates = 2; IDirectSound_Release( lpDirectSound ); } } pad->pad_Info.nativeSampleFormats = paInt16; sDeviceIndex++; return( TRUE ); } /*************************************************************************/ int Pa_CountDevices() { if( sNumDevices <= 0 ) Pa_Initialize(); return sNumDevices; } static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ) { if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; return &sDevices[id]; } /*************************************************************************/ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { internalPortAudioDevice *pad; if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; pad = Pa_GetInternalDevice( id ); return &pad->pad_Info ; } static PaError Pa_MaybeQueryDevices( void ) { if( sNumDevices == 0 ) { return Pa_QueryDevices(); } return 0; } /************************************************************************* ** Returns recommended device ID. ** On the PC, the recommended device can be specified by the user by ** setting an environment variable. For example, to use device #1. ** ** set PA_RECOMMENDED_OUTPUT_DEVICE=1 ** ** The user should first determine the available device ID by using ** the supplied application "pa_devs". */ #define PA_ENV_BUF_SIZE (32) #define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE") #define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE") static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ) { DWORD hresult; char envbuf[PA_ENV_BUF_SIZE]; PaDeviceID recommendedID = paNoDevice; /* Let user determine default device by setting environment variable. */ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { recommendedID = atoi( envbuf ); } return recommendedID; } PaDeviceID Pa_GetDefaultInputDeviceID( void ) { PaError result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); if( result < 0 ) { result = Pa_MaybeQueryDevices(); if( result < 0 ) return result; result = sDefaultInputDeviceID; } return result; } PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { PaError result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); if( result < 0 ) { result = Pa_MaybeQueryDevices(); if( result < 0 ) return result; result = sDefaultOutputDeviceID; } return result; } /********************************************************************** ** Make sure that we have queried the device capabilities. */ PaError PaHost_Init( void ) { #if PA_SIMULATE_UNDERFLOW PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n")); #endif return Pa_MaybeQueryDevices(); } static PaError Pa_TimeSlice( internalPortAudioStream *past ) { PaError result = 0; long bytesEmpty = 0; long bytesFilled = 0; long bytesToXfer = 0; long numChunks; HRESULT hresult; PaHostSoundControl *pahsc; short *nativeBufPtr; past->past_NumCallbacks += 1; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; /* How much input data is available? */ #if SUPPORT_AUDIO_CAPTURE if( past->past_NumInputChannels > 0 ) { DSW_QueryInputFilled( &pahsc->pahsc_DSoundWrapper, &bytesFilled ); bytesToXfer = bytesFilled; } #endif /* SUPPORT_AUDIO_CAPTURE */ /* How much output room is available? */ if( past->past_NumOutputChannels > 0 ) { DSW_QueryOutputSpace( &pahsc->pahsc_DSoundWrapper, &bytesEmpty ); bytesToXfer = bytesEmpty; } AddTraceMessage( "bytesEmpty ", bytesEmpty ); /* Choose smallest value if both are active. */ if( (past->past_NumInputChannels > 0) && (past->past_NumOutputChannels > 0) ) { bytesToXfer = ( bytesFilled < bytesEmpty ) ? bytesFilled : bytesEmpty; } /* printf("bytesFilled = %d, bytesEmpty = %d, bytesToXfer = %d\n", bytesFilled, bytesEmpty, bytesToXfer); */ /* Quantize to multiples of a buffer. */ numChunks = bytesToXfer / pahsc->pahsc_BytesPerBuffer; if( numChunks > (long)(past->past_NumUserBuffers/2) ) { numChunks = (long)past->past_NumUserBuffers/2; } else if( numChunks < 0 ) { numChunks = 0; } AddTraceMessage( "numChunks ", numChunks ); nativeBufPtr = pahsc->pahsc_NativeBuffer; if( numChunks > 0 ) { while( numChunks-- > 0 ) { /* Measure usage based on time to process one user buffer. */ Pa_StartUsageCalculation( past ); #if SUPPORT_AUDIO_CAPTURE /* Get native data from DirectSound. */ if( past->past_NumInputChannels > 0 ) { hresult = DSW_ReadBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer ); if( hresult < 0 ) { ERR_RPT(("DirectSound ReadBlock failed, hresult = 0x%x\n",hresult)); sPaHostError = hresult; break; } } #endif /* SUPPORT_AUDIO_CAPTURE */ /* Convert 16 bit native data to user data and call user routine. */ result = Pa_CallConvertInt16( past, nativeBufPtr, nativeBufPtr ); if( result != 0) break; /* Pass native data to DirectSound. */ if( past->past_NumOutputChannels > 0 ) { /* static short DEBUGHACK = 0; DEBUGHACK += 0x0049; nativeBufPtr[0] = DEBUGHACK; /* Make buzz to see if DirectSound still running. */ hresult = DSW_WriteBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer ); if( hresult < 0 ) { ERR_RPT(("DirectSound WriteBlock failed, result = 0x%x\n",hresult)); sPaHostError = hresult; break; } } Pa_EndUsageCalculation( past ); } } return result; } /*******************************************************************/ static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { internalPortAudioStream *past; PaHostSoundControl *pahsc; #if PA_SIMULATE_UNDERFLOW gUnderCallbackCounter++; if( (gUnderCallbackCounter >= UNDER_START_GAP) && (gUnderCallbackCounter <= UNDER_STOP_GAP) ) { if( gUnderCallbackCounter == UNDER_START_GAP) { AddTraceMessage("Begin stall: gUnderCallbackCounter =======", gUnderCallbackCounter ); } if( gUnderCallbackCounter == UNDER_STOP_GAP) { AddTraceMessage("End stall: gUnderCallbackCounter =======", gUnderCallbackCounter ); } return; } #endif past = (internalPortAudioStream *) dwUser; if( past == NULL ) return; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; if( !pahsc->pahsc_IfInsideCallback && past->past_IsActive ) { if( past->past_StopNow ) { past->past_IsActive = 0; } else if( past->past_StopSoon ) { DSoundWrapper *dsw = &pahsc->pahsc_DSoundWrapper; if( past->past_NumOutputChannels > 0 ) { DSW_ZeroEmptySpace( dsw ); AddTraceMessage("Pa_TimerCallback: waiting - written ", (int) dsw->dsw_FramesWritten ); AddTraceMessage("Pa_TimerCallback: waiting - played ", (int) dsw->dsw_FramesPlayed ); /* clear past_IsActive when all sound played */ if( dsw->dsw_FramesPlayed >= past->past_FrameCount ) { past->past_IsActive = 0; } } else { past->past_IsActive = 0; } } else { pahsc->pahsc_IfInsideCallback = 1; if( Pa_TimeSlice( past ) != 0) /* Call time slice independant of timing method. */ { past->past_StopSoon = 1; } pahsc->pahsc_IfInsideCallback = 0; } } } /*******************************************************************/ PaError PaHost_OpenStream( internalPortAudioStream *past ) { HRESULT hr; PaError result = paNoError; PaHostSoundControl *pahsc; int numBytes, maxChannels; unsigned int minNumBuffers; internalPortAudioDevice *pad; DSoundWrapper *dsw; /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */ if( pahsc == NULL ) { result = paInsufficientMemory; goto error; } memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; pahsc->pahsc_TimerID = 0; dsw = &pahsc->pahsc_DSoundWrapper; DSW_Init( dsw ); /* Allocate native buffer. */ maxChannels = ( past->past_NumOutputChannels > past->past_NumInputChannels ) ? past->past_NumOutputChannels : past->past_NumInputChannels; pahsc->pahsc_BytesPerBuffer = past->past_FramesPerUserBuffer * maxChannels * sizeof(short); if( maxChannels > 0 ) { pahsc->pahsc_NativeBuffer = (short *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerBuffer); /* MEM */ if( pahsc->pahsc_NativeBuffer == NULL ) { result = paInsufficientMemory; goto error; } } else { result = paInvalidChannelCount; goto error; } DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; numBytes = pahsc->pahsc_BytesPerBuffer * past->past_NumUserBuffers; if( numBytes < DSBSIZE_MIN ) { result = paBufferTooSmall; goto error; } if( numBytes > DSBSIZE_MAX ) { result = paBufferTooBig; goto error; } pahsc->pahsc_FramesPerDSBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers; { int msecLatency = (int) ((pahsc->pahsc_FramesPerDSBuffer * 1000) / past->past_SampleRate); PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", pahsc->pahsc_FramesPerDSBuffer, msecLatency )); } /* ------------------ OUTPUT */ if( (past->past_OutputDeviceID >= 0) && (past->past_NumOutputChannels > 0) ) { DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL ); /* If this fails, then try each output device until we find one that works. */ if( hr != DS_OK ) { int i; ERR_RPT(("Creation of requested Audio Output device '%s' failed.\n", ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) )); for( i=0; ipad_Info.maxOutputChannels >= past->past_NumOutputChannels ) { DBUG(("Try device '%s' instead.\n", pad->pad_Info.name )); hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL ); if( hr == DS_OK ) { ERR_RPT(("Using device '%s' instead.\n", pad->pad_Info.name )); break; } } } } if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n")); result = paHostError; sPaHostError = hr; goto error; } hr = DSW_InitOutputBuffer( dsw, (unsigned long) (past->past_SampleRate + 0.5), past->past_NumOutputChannels, numBytes ); DBUG(("DSW_InitOutputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { result = paHostError; sPaHostError = hr; goto error; } past->past_FrameCount = pahsc->pahsc_DSoundWrapper.dsw_FramesWritten; } #if SUPPORT_AUDIO_CAPTURE /* ------------------ INPUT */ if( (past->past_InputDeviceID >= 0) && (past->past_NumInputChannels > 0) ) { pad = Pa_GetInternalDevice( past->past_InputDeviceID ); hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); /* If this fails, then try each input device until we find one that works. */ if( hr != DS_OK ) { int i; ERR_RPT(("Creation of requested Audio Capture device '%s' failed.\n", ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) )); for( i=0; ipad_Info.maxInputChannels >= past->past_NumInputChannels ) { PRINT(("Try device '%s' instead.\n", pad->pad_Info.name )); hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); if( hr == DS_OK ) break; } } } if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n")); result = paHostError; sPaHostError = hr; goto error; } hr = DSW_InitInputBuffer( dsw, (unsigned long) (past->past_SampleRate + 0.5), past->past_NumInputChannels, numBytes ); DBUG(("DSW_InitInputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr)); result = paHostError; sPaHostError = hr; goto error; } } #endif /* SUPPORT_AUDIO_CAPTURE */ /* Calculate scalar used in CPULoad calculation. */ { LARGE_INTEGER frequency; if( QueryPerformanceFrequency( &frequency ) == 0 ) { pahsc->pahsc_InverseTicksPerUserBuffer = 0.0; } else { pahsc->pahsc_InverseTicksPerUserBuffer = past->past_SampleRate / ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer ); DBUG(("pahsc_InverseTicksPerUserBuffer = %g\n", pahsc->pahsc_InverseTicksPerUserBuffer )); } } return result; error: PaHost_CloseStream( past ); return result; } /*************************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { HRESULT hr; PaHostSoundControl *pahsc; PaError result = paNoError; pahsc = (PaHostSoundControl *) past->past_DeviceData; /* Give user callback a chance to pre-fill buffer. */ result = Pa_TimeSlice( past ); if( result != paNoError ) return result; // FIXME - what if finished? hr = DSW_StartOutput( &pahsc->pahsc_DSoundWrapper ); DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr)); if( hr != DS_OK ) { result = paHostError; sPaHostError = hr; goto error; } error: return result; } /*************************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *past ) { PaError result = paNoError; #if SUPPORT_AUDIO_CAPTURE HRESULT hr; PaHostSoundControl *pahsc; pahsc = (PaHostSoundControl *) past->past_DeviceData; hr = DSW_StartInput( &pahsc->pahsc_DSoundWrapper ); DBUG(("Pa_StartStream: DSW_StartInput returned = 0x%X.\n", hr)); if( hr != DS_OK ) { result = paHostError; sPaHostError = hr; goto error; } error: #endif /* SUPPORT_AUDIO_CAPTURE */ return result; } /*************************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; PaError result = paNoError; pahsc = (PaHostSoundControl *) past->past_DeviceData; past->past_StopNow = 0; past->past_StopSoon = 0; past->past_IsActive = 1; /* Create timer that will wake us up so we can fill the DSound buffer. */ { int msecPerBuffer; int resolution; int bufsPerInterrupt; DBUG(("PaHost_StartEngine: past_NumUserBuffers = %d\n", past->past_NumUserBuffers)); /* Decide how often to wake up and fill the buffers. */ if( past->past_NumUserBuffers == 2 ) { /* Generate two timer interrupts per user buffer. */ msecPerBuffer = (500 * past->past_FramesPerUserBuffer) / (int) past->past_SampleRate; } else { if ( past->past_NumUserBuffers >= 16 ) bufsPerInterrupt = past->past_NumUserBuffers/8; else if ( past->past_NumUserBuffers >= 8 ) bufsPerInterrupt = 2; else bufsPerInterrupt = 1; msecPerBuffer = 1000 * (bufsPerInterrupt * past->past_FramesPerUserBuffer) / (int) past->past_SampleRate; DBUG(("PaHost_StartEngine: bufsPerInterrupt = %d\n", bufsPerInterrupt)); } DBUG(("PaHost_StartEngine: msecPerBuffer = %d\n", msecPerBuffer)); if( msecPerBuffer < 10 ) msecPerBuffer = 10; else if( msecPerBuffer > 100 ) msecPerBuffer = 100; DBUG(("PaHost_StartEngine: clipped msecPerBuffer = %d\n", msecPerBuffer)); resolution = msecPerBuffer/4; pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback, (DWORD) past, TIME_PERIODIC ); } if( pahsc->pahsc_TimerID == 0 ) { past->past_IsActive = 0; result = paHostError; sPaHostError = 0; goto error; } error: return result; } /*************************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { int timeoutMsec; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; if( abort ) past->past_StopNow = 1; past->past_StopSoon = 1; /* Set timeout at 20% beyond maximum time we might wait. */ timeoutMsec = (int) (1200.0 * pahsc->pahsc_FramesPerDSBuffer / past->past_SampleRate); while( past->past_IsActive && (timeoutMsec > 0) ) { Sleep(10); timeoutMsec -= 10; } if( pahsc->pahsc_TimerID != 0 ) { timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */ pahsc->pahsc_TimerID = 0; } return paNoError; } /*************************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { #if SUPPORT_AUDIO_CAPTURE HRESULT hr; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; (void) abort; hr = DSW_StopInput( &pahsc->pahsc_DSoundWrapper ); DBUG(("DSW_StopInput() result is %x\n", hr)); #endif /* SUPPORT_AUDIO_CAPTURE */ return paNoError; } /*************************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { HRESULT hr; PaHostSoundControl *pahsc; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; (void) abort; hr = DSW_StopOutput( &pahsc->pahsc_DSoundWrapper ); DBUG(("DSW_StopOutput() result is %x\n", hr)); return paNoError; } /*******************************************************************/ PaError PaHost_CloseStream( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; DSW_Term( &pahsc->pahsc_DSoundWrapper ); if( pahsc->pahsc_NativeBuffer ) { PaHost_FreeFastMemory( pahsc->pahsc_NativeBuffer, pahsc->pahsc_BytesPerBuffer ); /* MEM */ pahsc->pahsc_NativeBuffer = NULL; } PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */ past->past_DeviceData = NULL; return paNoError; } /* Set minimal latency based on whether NT or Win95. * NT has higher latency. */ static int PaHost_GetMinSystemLatency( void ) { int minLatencyMsec; /* Set minimal latency based on whether NT or other OS. * NT has higher latency. */ OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof( osvi ); GetVersionEx( &osvi ); DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId )); DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion )); DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion )); /* Check for NT */ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) ) { minLatencyMsec = PA_WIN_NT_LATENCY; } else if(osvi.dwMajorVersion >= 5) { minLatencyMsec = PA_WIN_WDM_LATENCY; } else { minLatencyMsec = PA_WIN_9X_LATENCY; } return minLatencyMsec; } /************************************************************************* ** Determine minimum number of buffers required for this host based ** on minimum latency. Latency can be optionally set by user by setting ** an environment variable. For example, to set latency to 200 msec, put: ** ** set PA_MIN_LATENCY_MSEC=200 ** ** in the AUTOEXEC.BAT file and reboot. ** If the environment variable is not set, then the latency will be determined ** based on the OS. Windows NT has higher latency than Win95. */ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { char envbuf[PA_ENV_BUF_SIZE]; DWORD hresult; int minLatencyMsec = 0; double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate; int minBuffers; /* Let user determine minimal latency by setting environment variable. */ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { minLatencyMsec = atoi( envbuf ); } else { minLatencyMsec = PaHost_GetMinSystemLatency(); #if PA_USE_HIGH_LATENCY PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec )); #endif } minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer)); if( minBuffers < 2 ) minBuffers = 2; return minBuffers; } /*************************************************************************/ PaError PaHost_Term( void ) { int i; /* Free names allocated during enumeration. */ for( i=0; ipast_DeviceData; if( pahsc == NULL ) return paInternalError; return (PaError) (past->past_IsActive); } /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { DSoundWrapper *dsw; internalPortAudioStream *past = (internalPortAudioStream *) stream; PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; dsw = &pahsc->pahsc_DSoundWrapper; return dsw->dsw_FramesPlayed; } portaudio-18.1.orig/pa_win_ds/dsound_wrapper.c0000644000175000017500000004561407423043536022321 0ustar mikaelmikael00000000000000/* * $Id: dsound_wrapper.c,v 1.1.1.1 2002/01/22 00:52:45 phil Exp $ * Simplified DirectSound interface. * * Author: Phil Burk & Robert Marsanyi * * PortAudio Portable Real-Time Audio Library * For more information see: http://www.softsynth.com/portaudio/ * DirectSound Implementation * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #define INITGUID // Needed to build IID_IDirectSoundNotify. See objbase.h for info. #include #include #include "dsound_wrapper.h" #include "pa_trace.h" /************************************************************************************/ void DSW_Term( DSoundWrapper *dsw ) { // Cleanup the sound buffers if (dsw->dsw_OutputBuffer) { IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer ); IDirectSoundBuffer_Release( dsw->dsw_OutputBuffer ); dsw->dsw_OutputBuffer = NULL; } #if SUPPORT_AUDIO_CAPTURE if (dsw->dsw_InputBuffer) { IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer ); IDirectSoundCaptureBuffer_Release( dsw->dsw_InputBuffer ); dsw->dsw_InputBuffer = NULL; } if (dsw->dsw_pDirectSoundCapture) { IDirectSoundCapture_Release( dsw->dsw_pDirectSoundCapture ); dsw->dsw_pDirectSoundCapture = NULL; } #endif /* SUPPORT_AUDIO_CAPTURE */ if (dsw->dsw_pDirectSound) { IDirectSound_Release( dsw->dsw_pDirectSound ); dsw->dsw_pDirectSound = NULL; } } /************************************************************************************/ HRESULT DSW_Init( DSoundWrapper *dsw ) { memset( dsw, 0, sizeof(DSoundWrapper) ); return 0; } /************************************************************************************/ HRESULT DSW_InitOutputDevice( DSoundWrapper *dsw, LPGUID lpGUID ) { // Create the DS object HRESULT hr = DirectSoundCreate( lpGUID, &dsw->dsw_pDirectSound, NULL ); if( hr != DS_OK ) return hr; return hr; } /************************************************************************************/ HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer ) { DWORD dwDataLen; DWORD playCursor; HRESULT result; LPDIRECTSOUNDBUFFER pPrimaryBuffer; HWND hWnd; HRESULT hr; WAVEFORMATEX wfFormat; DSBUFFERDESC primaryDesc; DSBUFFERDESC secondaryDesc; unsigned char* pDSBuffData; LARGE_INTEGER counterFrequency; dsw->dsw_OutputSize = bytesPerBuffer; dsw->dsw_OutputRunning = FALSE; dsw->dsw_OutputUnderflows = 0; dsw->dsw_FramesWritten = 0; dsw->dsw_BytesPerFrame = nChannels * sizeof(short); // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the // applications's window. Also if that window is closed before the Buffer is closed // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.) // So we will use GetDesktopWindow() which was suggested by Miller Puckette. // hWnd = GetForegroundWindow(); hWnd = GetDesktopWindow(); // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz. // Exclusize also prevents unexpected sounds from other apps during a performance. if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound, hWnd, DSSCL_EXCLUSIVE)) != DS_OK) { return hr; } // ----------------------------------------------------------------------- // Create primary buffer and set format just so we can specify our custom format. // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz. // Setup the primary buffer description ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC)); primaryDesc.dwSize = sizeof(DSBUFFERDESC); primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth primaryDesc.dwBufferBytes = 0; primaryDesc.lpwfxFormat = NULL; // Create the buffer if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound, &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result; // Define the buffer format wfFormat.wFormatTag = WAVE_FORMAT_PCM; wfFormat.nChannels = nChannels; wfFormat.nSamplesPerSec = nFrameRate; wfFormat.wBitsPerSample = 8 * sizeof(short); wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8; wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign; wfFormat.cbSize = 0; /* No extended format info. */ // Set the primary buffer's format if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result; // ---------------------------------------------------------------------- // Setup the secondary buffer description ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC)); secondaryDesc.dwSize = sizeof(DSBUFFERDESC); secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; secondaryDesc.dwBufferBytes = bytesPerBuffer; secondaryDesc.lpwfxFormat = &wfFormat; // Create the secondary buffer if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound, &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result; // Lock the DS buffer if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData, &dwDataLen, NULL, 0, 0)) != DS_OK) return result; // Zero the DS buffer ZeroMemory(pDSBuffData, dwDataLen); // Unlock the DS buffer if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result; if( QueryPerformanceFrequency( &counterFrequency ) ) { int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short)); dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate; AddTraceMessage("dsw_CounterTicksPerBuffer = %d\n", dsw->dsw_CounterTicksPerBuffer.LowPart ); } else { dsw->dsw_CounterTicksPerBuffer.QuadPart = 0; } // Let DSound set the starting write position because if we set it to zero, it looks like the // buffer is full to begin with. This causes a long pause before sound starts when using large buffers. hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset ); if( hr != DS_OK ) { return hr; } dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerFrame; /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */ return DS_OK; } /************************************************************************************/ HRESULT DSW_StartOutput( DSoundWrapper *dsw ) { HRESULT hr; QueryPerformanceCounter( &dsw->dsw_LastPlayTime ); dsw->dsw_LastPlayCursor = 0; dsw->dsw_FramesPlayed = 0; hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 ); if( hr != DS_OK ) { return hr; } // Start the buffer playback in a loop. if( dsw->dsw_OutputBuffer != NULL ) { hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING ); if( hr != DS_OK ) { return hr; } dsw->dsw_OutputRunning = TRUE; } return 0; } /************************************************************************************/ HRESULT DSW_StopOutput( DSoundWrapper *dsw ) { // Stop the buffer playback if( dsw->dsw_OutputBuffer != NULL ) { dsw->dsw_OutputRunning = FALSE; return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer ); } else return 0; } /************************************************************************************/ HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty ) { HRESULT hr; DWORD playCursor; DWORD writeCursor; long numBytesEmpty; long playWriteGap; // Query to see how much room is in buffer. // Note: Even though writeCursor is not used, it must be passed to prevent DirectSound from dieing // under WinNT. The Microsoft documentation says we can pass NULL but apparently not. // Thanks to Max Rheiner for the fix. hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor ); if( hr != DS_OK ) { return hr; } AddTraceMessage("playCursor", playCursor); AddTraceMessage("dsw_WriteOffset", dsw->dsw_WriteOffset); // Determine size of gap between playIndex and WriteIndex that we cannot write into. playWriteGap = writeCursor - playCursor; if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */ /* Attempt to detect playCursor wrap-around and correct it. */ if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) ) { /* How much time has elapsed since last check. */ LARGE_INTEGER currentTime; LARGE_INTEGER elapsedTime; long bytesPlayed; long bytesExpected; long buffersWrapped; QueryPerformanceCounter( ¤tTime ); elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart; dsw->dsw_LastPlayTime = currentTime; /* How many bytes does DirectSound say have been played. */ bytesPlayed = playCursor - dsw->dsw_LastPlayCursor; if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap dsw->dsw_LastPlayCursor = playCursor; /* Calculate how many bytes we would have expected to been played by now. */ bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart); buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize; if( buffersWrapped > 0 ) { AddTraceMessage("playCursor wrapped! bytesPlayed", bytesPlayed ); AddTraceMessage("playCursor wrapped! bytesExpected", bytesExpected ); playCursor += (buffersWrapped * dsw->dsw_OutputSize); bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize); } /* Maintain frame output cursor. */ dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerFrame); } numBytesEmpty = playCursor - dsw->dsw_WriteOffset; if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset /* Have we underflowed? */ if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) ) { if( dsw->dsw_OutputRunning ) { dsw->dsw_OutputUnderflows += 1; AddTraceMessage("underflow detected! numBytesEmpty", numBytesEmpty ); } dsw->dsw_WriteOffset = writeCursor; numBytesEmpty = dsw->dsw_OutputSize - playWriteGap; } *bytesEmpty = numBytesEmpty; return hr; } /************************************************************************************/ HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw ) { HRESULT hr; LPBYTE lpbuf1 = NULL; LPBYTE lpbuf2 = NULL; DWORD dwsize1 = 0; DWORD dwsize2 = 0; long bytesEmpty; hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed if (hr != DS_OK) return hr; if( bytesEmpty == 0 ) return DS_OK; // Lock free space in the DS hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1, (void **) &lpbuf2, &dwsize2, 0); if (hr == DS_OK) { // Copy the buffer into the DS ZeroMemory(lpbuf1, dwsize1); if(lpbuf2 != NULL) { ZeroMemory(lpbuf2, dwsize2); } // Update our buffer offset and unlock sound buffer dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize; IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerFrame; } return hr; } /************************************************************************************/ HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes ) { HRESULT hr; LPBYTE lpbuf1 = NULL; LPBYTE lpbuf2 = NULL; DWORD dwsize1 = 0; DWORD dwsize2 = 0; // Lock free space in the DS hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1, (void **) &lpbuf2, &dwsize2, 0); if (hr == DS_OK) { // Copy the buffer into the DS CopyMemory(lpbuf1, buf, dwsize1); if(lpbuf2 != NULL) { CopyMemory(lpbuf2, buf+dwsize1, dwsize2); } // Update our buffer offset and unlock sound buffer dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize; IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerFrame; } return hr; } /************************************************************************************/ DWORD DSW_GetOutputStatus( DSoundWrapper *dsw ) { DWORD status; if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK) return( DSERR_INVALIDPARAM ); else return( status ); } #if SUPPORT_AUDIO_CAPTURE /* These routines are used to support audio input. * Do NOT compile these calls when using NT4 because it does * not support the entry points. */ /************************************************************************************/ HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID ) { HRESULT hr = DirectSoundCaptureCreate( lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); if( hr != DS_OK ) return hr; return hr; } /************************************************************************************/ HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer ) { DSCBUFFERDESC captureDesc; WAVEFORMATEX wfFormat; HRESULT result; // Define the buffer format wfFormat.wFormatTag = WAVE_FORMAT_PCM; wfFormat.nChannels = nChannels; wfFormat.nSamplesPerSec = nFrameRate; wfFormat.wBitsPerSample = 8 * sizeof(short); wfFormat.nBlockAlign = wfFormat.nChannels * (wfFormat.wBitsPerSample / 8); wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign; wfFormat.cbSize = 0; /* No extended format info. */ dsw->dsw_InputSize = bytesPerBuffer; // ---------------------------------------------------------------------- // Setup the secondary buffer description ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC)); captureDesc.dwSize = sizeof(DSCBUFFERDESC); captureDesc.dwFlags = 0; captureDesc.dwBufferBytes = bytesPerBuffer; captureDesc.lpwfxFormat = &wfFormat; // Create the capture buffer if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture, &captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result; dsw->dsw_ReadOffset = 0; // reset last read position to start of buffer return DS_OK; } /************************************************************************************/ HRESULT DSW_StartInput( DSoundWrapper *dsw ) { // Start the buffer playback if( dsw->dsw_InputBuffer != NULL ) { return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING ); } else return 0; } /************************************************************************************/ HRESULT DSW_StopInput( DSoundWrapper *dsw ) { // Stop the buffer playback if( dsw->dsw_InputBuffer != NULL ) { return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer ); } else return 0; } /************************************************************************************/ HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled ) { HRESULT hr; DWORD capturePos; DWORD readPos; long filled; // Query to see how much data is in buffer. // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly // so let's pass a pointer just to be safe. hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos ); if( hr != DS_OK ) { return hr; } filled = readPos - dsw->dsw_ReadOffset; if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset *bytesFilled = filled; return hr; } /************************************************************************************/ HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes ) { HRESULT hr; LPBYTE lpbuf1 = NULL; LPBYTE lpbuf2 = NULL; DWORD dwsize1 = 0; DWORD dwsize2 = 0; // Lock free space in the DS hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1, (void **) &lpbuf2, &dwsize2, 0); if (hr == DS_OK) { // Copy from DS to the buffer CopyMemory( buf, lpbuf1, dwsize1); if(lpbuf2 != NULL) { CopyMemory( buf+dwsize1, lpbuf2, dwsize2); } // Update our buffer offset and unlock sound buffer dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize; IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2); } return hr; } #endif /* SUPPORT_AUDIO_CAPTURE */ portaudio-18.1.orig/pa_win_ds/dsound_wrapper.h0000644000175000017500000001016407423043536022316 0ustar mikaelmikael00000000000000#ifndef __DSOUND_WRAPPER_H #define __DSOUND_WRAPPER_H /* * $Id: dsound_wrapper.h,v 1.1.1.1 2002/01/22 00:52:45 phil Exp $ * Simplified DirectSound interface. * * Author: Phil Burk & Robert Marsanyi * * For PortAudio Portable Real-Time Audio Library * For more information see: http://www.softsynth.com/portaudio/ * DirectSound Implementation * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #if !defined(BOOL) #define BOOL short #endif #ifndef SUPPORT_AUDIO_CAPTURE #define SUPPORT_AUDIO_CAPTURE (1) #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define DSW_NUM_POSITIONS (4) #define DSW_NUM_EVENTS (5) #define DSW_TERMINATION_EVENT (DSW_NUM_POSITIONS) typedef struct { /* Output */ LPDIRECTSOUND dsw_pDirectSound; LPDIRECTSOUNDBUFFER dsw_OutputBuffer; DWORD dsw_WriteOffset; /* last write position */ INT dsw_OutputSize; INT dsw_BytesPerFrame; /* Try to detect play buffer underflows. */ LARGE_INTEGER dsw_CounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */ LARGE_INTEGER dsw_LastPlayTime; UINT dsw_LastPlayCursor; UINT dsw_OutputUnderflows; BOOL dsw_OutputRunning; /* use double which lets us can play for several thousand years with enough precision */ double dsw_FramesWritten; double dsw_FramesPlayed; #if SUPPORT_AUDIO_CAPTURE /* Input */ LPDIRECTSOUNDCAPTURE dsw_pDirectSoundCapture; LPDIRECTSOUNDCAPTUREBUFFER dsw_InputBuffer; UINT dsw_ReadOffset; /* last read position */ UINT dsw_InputSize; #endif /* SUPPORT_AUDIO_CAPTURE */ } DSoundWrapper; HRESULT DSW_Init( DSoundWrapper *dsw ); void DSW_Term( DSoundWrapper *dsw ); HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bufSize ); HRESULT DSW_StartOutput( DSoundWrapper *dsw ); HRESULT DSW_StopOutput( DSoundWrapper *dsw ); DWORD DSW_GetOutputStatus( DSoundWrapper *dsw ); HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes ); HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw ); HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty ); HRESULT DSW_Enumerate( DSoundWrapper *dsw ); #if SUPPORT_AUDIO_CAPTURE HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bufSize ); HRESULT DSW_StartInput( DSoundWrapper *dsw ); HRESULT DSW_StopInput( DSoundWrapper *dsw ); HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes ); HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled ); #endif /* SUPPORT_AUDIO_CAPTURE */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* __DSOUND_WRAPPER_H */ portaudio-18.1.orig/testcvs/0000755000175000000620000000000007700016422016463 5ustar mikaelstaff00000000000000portaudio-18.1.orig/testcvs/changeme.txt0000644000175000017500000000030607435222552021146 0ustar mikaelmikael00000000000000This is just a dopy little file used to test the CVS repository. Feel free to trash this file. Minor change. Another tweak. philburk tweak stephane test Phil changed this again on 2/21/02. Yawn... portaudio-18.1.orig/config.sub0000644000175000000620000006725407622303110016762 0ustar mikaelstaff00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 # Free Software Foundation, Inc. timestamp='2001-10-05' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit 0 ;; --version | -v ) echo "$version" ; exit 0 ;; --help | --h* | -h ) echo "$usage"; exit 0 ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit 0;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | storm-chaos* | os2-emx* | windows32-*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ | c4x | clipper \ | d10v | d30v | dsp16xx \ | fr30 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | m32r | m68000 | m68k | m88k | mcore \ | mips16 | mips64 | mips64el | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el | mips64vr4300 \ | mips64vr4300el | mips64vr5000 | mips64vr5000el \ | mipsbe | mipseb | mipsel | mipsle | mipstx39 | mipstx39el \ | mipsisa32 \ | mn10200 | mn10300 \ | ns16k | ns32k \ | openrisc \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | s390 | s390x \ | sh | sh[34] | sh[34]eb | shbe | shle \ | sparc | sparc64 | sparclet | sparclite | sparcv9 | sparcv9b \ | stormy16 | strongarm \ | tahoe | thumb | tic80 | tron \ | v850 \ | we32k \ | x86 | xscale \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alphapca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armv*-* \ | avr-* \ | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c54x-* \ | clipper-* | cray2-* | cydra-* \ | d10v-* | d30v-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | m32r-* \ | m68000-* | m680[01234]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | mcore-* \ | mips-* | mips16-* | mips64-* | mips64el-* | mips64orion-* \ | mips64orionel-* | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* | mipsbe-* | mipseb-* \ | mipsle-* | mipsel-* | mipstx39-* | mipstx39el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | s390-* | s390x-* \ | sh-* | sh[34]-* | sh[34]eb-* | shbe-* | shle-* \ | sparc-* | sparc64-* | sparc86x-* | sparclite-* \ | sparcv9-* | sparcv9b-* | stormy16-* | strongarm-* | sv1-* \ | t3e-* | tahoe-* | thumb-* | tic30-* | tic54x-* | tic80-* | tron-* \ | v850-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xmp-* | xps100-* | xscale-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | ymp) basic_machine=ymp-cray os=-unicos ;; cray2) basic_machine=cray2-cray os=-unicos ;; [cjt]90) basic_machine=${basic_machine}-cray os=-unicos ;; crds | unos) basic_machine=m68k-crds ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mipsel*-linux*) basic_machine=mipsel-unknown os=-linux-gnu ;; mips*-linux*) basic_machine=mips-unknown os=-linux-gnu ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; mmix*) basic_machine=mmix-knuth os=-mmixware ;; monitor) basic_machine=m68k-rom68k os=-coff ;; msdos) basic_machine=i386-pc os=-msdos ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon) basic_machine=i686-pc ;; pentiumii | pentium2) basic_machine=i686-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=t3e-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; tower | tower-32) basic_machine=m68k-ncr ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; windows32) basic_machine=i386-pc os=-windows32-msvcrt ;; xmp) basic_machine=xmp-cray os=-unicos ;; xps | xps100) basic_machine=xps100-honeywell ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; mips) if [ x$os = x-linux-gnu ]; then basic_machine=mips-unknown else basic_machine=mips-mips fi ;; romp) basic_machine=romp-ibm ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh3 | sh4 | sh3eb | sh4eb) basic_machine=sh-unknown ;; sparc | sparcv9 | sparcv9b) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; c4x*) basic_machine=c4x-none os=-coff ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto*) os=-nto-qnx ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -ptx*) vendor=sequent ;; -vxsim* | -vxworks*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: portaudio-18.1.orig/Makefile.solaris0000644000175000000620000000303507506124332020110 0ustar mikaelstaff00000000000000# Make PortAudio for Linux # Updated 2001/08/25 Bill Eldridge bill@rfa.org # Updated 2001/10/16, philburk@softsynth.com, s/unix_oss/unix_oss/ # Updated 2002/04/30 Bill Eldridge bill@rfa.org # Made the libinstall and tests compile a bit cleaner # A pretty bare makefile, that figures out all the test files # and compiles them against the library in the pa_unix_oss directory. # Do "make all" and then when happy, "make libinstall" # (if not happy, "make clean") # The ldconfig stuff in libinstall is the wrong way to do it - # someone tell me the right way, please LIBS = -lm -lpthread -lrt CDEFINES = -I../pa_common CFLAGS = -g LIBINST = /usr/local/lib TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) TESTO:= $(wildcard pa_tests/pa*.o pa_tests/debug*.o) LIBFILES:= ./pa_common/pa_lib.c ./pa_unix_oss/pa_unix_solaris.c ./pa_unix_oss/pa_unix.c #all: sharedlib libinstall tests all: sharedlib libinstall testo testq .c.o: -gcc $(CFLAGS) -c -I./pa_common $< -o $*.o .o: -gcc $*.o -o $* -Lpa_unix_oss -lportaudio $(LIBS) #.c.o: # -gcc -c -I./pa_common $< -o $*.o # -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio sharedlib: $(LIBFILES:.c=.o) gcc -shared -o ./pa_unix_oss/libportaudio.so ./pa_common/pa_lib.o ./pa_unix_oss/pa_unix_solaris.o ./pa_unix_oss/pa_unix.o libinstall: ./pa_unix_oss/libportaudio.so @cp -f ./pa_unix_oss/libportaudio.so $(LIBINST) @/sbin/ldconfig testo: $(TESTS:.c=.o) testq: $(TESTO:.o=) clean: -@rm -f $(TESTS:.c=.o) -@rm -f $(TESTS:.c=) -@rm -f $(LIBFILES:.c=.o) -@rm -f ./pa_unix_oss/libportaudio.so portaudio-18.1.orig/Makefile.in0000644000175000000620000000430707622303110017035 0ustar mikaelstaff00000000000000# # PortAudio Makefile.in # # Dominic Mazzoni # PREFIX = @prefix@ CC = @CC@ CFLAGS = @CFLAGS@ -Ipa_common LIBS = @LIBS@ AR = @AR@ RANLIB = @RANLIB@ INSTALL = @INSTALL@ SHARED_FLAGS = @SHARED_FLAGS@ DLL_LIBS = @DLL_LIBS@ OTHER_OBJS = @OTHER_OBJS@ PALIB = libportaudio.a PADLL = @PADLL@ PADLLV = $(PADLL).0.0.18 PAINC = pa_common/portaudio.h COMMON_OBJS = \ pa_common/pa_convert.o \ pa_common/pa_lib.o TESTS = \ bin/patest_buffer \ bin/patest_clip \ bin/patest_dither \ bin/patest_hang \ bin/patest_latency \ bin/patest_leftright \ bin/patest_longsine \ bin/patest_many \ bin/patest_maxsines \ bin/patest_multi_sine \ bin/patest_pink \ bin/patest_record \ bin/patest_ringmix \ bin/patest_saw \ bin/patest_sine8 \ bin/patest_sine \ bin/patest_sine_formats \ bin/patest_sine_time \ bin/patest_stop \ bin/patest_sync \ bin/patest_toomanysines \ bin/patest_underflow \ bin/patest_wire OBJS = $(COMMON_OBJS) $(OTHER_OBJS) all: lib/$(PALIB) lib/$(PADLLV) tests tests: bin/ $(TESTS) lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC) $(AR) ruv lib/$(PALIB) $(OBJS) $(RANLIB) lib/$(PALIB) lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC) $(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(DLL_LIBS) $(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c $(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS) install: lib/$(PALIB) lib/$(PADLLV) $(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV) $(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB) cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL) $(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h @echo "" @echo "------------------------------------------------------------" @echo "PortAudio was successfully installed." @echo "" @echo "On some systems (e.g. Linux) you should run 'ldconfig' now" @echo "to make the shared object available. You may also need to" @echo "modify your LD_LIBRARY_PATH environment variable to include" @echo "the directory $(PREFIX)/lib" @echo "------------------------------------------------------------" @echo "" clean: rm -f $(OBJS) $(TESTS) lib/$(PALIB) rm -f config.log config.status %.o: %.c Makefile $(PAINC) $(CC) -c $(CFLAGS) $< -o $@ bin: mkdir bin lib: mkdir lib portaudio-18.1.orig/fixdir.bat0000644000175000000620000000070107423043446016753 0ustar mikaelstaff00000000000000rem Use Astyle to fix style in 'C' files cd %1% fixlines -p *.c fixlines -p *.cpp fixlines -p *.cc astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cpp astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cc del *.orig @rem convert line terminators to Unix style LFs fixlines -u *.c fixlines -u *.cpp fixlines -u *.cc fixlines -u *.h del *.bak cd ..\ portaudio-18.1.orig/LICENSE.txt0000644000175000000620000000571407434437512016635 0ustar mikaelstaff00000000000000Portable header file to contain: /* * PortAudio Portable Real-Time Audio Library * PortAudio API Header File * Latest version available at: http://www.audiomulch.com/portaudio/ * * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Implementation files to contain: /* * PortAudio Portable Real-Time Audio Library * Latest version at: http://www.audiomulch.com/portaudio/ * Implementation * Copyright (c) 1999-2000 * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */portaudio-18.1.orig/pa_mac/0000755000175000000620000000000007700016420016206 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_mac/pa_mac.c0000644000175000017500000017175207552622620017765 0ustar mikaelmikael00000000000000/* * $Id: pa_mac.c,v 1.4.4.2 2002/10/15 03:14:08 dmazzoni Exp $ * Portable Audio I/O Library for Macintosh * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2000 Phil Burk * * Special thanks to Chris Rolfe for his many helpful suggestions, bug fixes, * and code contributions. * Thanks also to Tue Haste Andersen, Alberto Ricci, Nico Wald, * Roelf Toxopeus and Tom Erbe for testing the code and making * numerous suggestions. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Modification History PLB20010415 - ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID PLB20010415 - Device Scan was crashing for anything other than siBadSoundInDevice, but some Macs may return other errors! PLB20010420 - Fix TIMEOUT in record mode. PLB20010420 - Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON PLB20010907 - Pass unused event to WaitNextEvent to prevent Mac OSX crash. Thanks Dominic Mazzoni. PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. PLB20011009 - Use NewSndCallBackUPP() for CARBON PLB20020417 - I used to call Pa_GetMinNumBuffers() which doesn't take into account the variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will give lower latency when virtual memory is turned off. Thanks Kristoffer Jensen and Georgios Marentakis for spotting this bug. PLB20020423 - Use new method to calculate CPU load similar to other ports. Based on num frames calculated. Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer. Added PA_MAX_USAGE_ALLOWED to prevent Mac from hanging when CPU load approaches 100%. PLB20020424 - Fixed return value in Pa_StreamTime PLB20020612 - Fix allocation error on Mac 8600 by casting *nameH as uchar* so that we get a proper Str255 length. */ /* COMPATIBILITY This Macintosh implementation is designed for use with Mac OS 7, 8 and 9 on PowerMacs, and OS X if compiled with CARBON OUTPUT A circular array of CmpSoundHeaders is used as a queue. For low latency situations there will only be two small buffers used. For higher latency, more and larger buffers may be used. To play the sound we use SndDoCommand() with bufferCmd. Each buffer is followed by a callbackCmd which informs us when the buffer has been processsed. INPUT The SndInput Manager SPBRecord call is used for sound input. If only input is used, then the PA user callback is called from the Input completion proc. For full-duplex, or output only operation, the PA callback is called from the HostBuffer output completion proc. In that case, input sound is passed to the callback by a simple FIFO. TODO: O- Add support for native sample data formats other than int16. O- Review buffer sizing. Should it be based on result of siDeviceBufferInfo query? O- Determine default devices somehow. */ #include #include #include #include #include /* Mac specific includes */ #include "OSUtils.h" #include #include #include #include #include #include #include #include #include #include #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" #ifndef FALSE #define FALSE (0) #define TRUE (!FALSE) #endif /* #define TARGET_API_MAC_CARBON (1) */ /* * Define maximum CPU load that will be allowed. User callback will * be skipped if load exceeds this limit. This is to prevent the Mac * from hanging when the CPU is hogged by the sound thread. * On my PowerBook G3, the mac hung when I used 94% of CPU ( usage = 0.94 ). */ #define PA_MAX_USAGE_ALLOWED (0.92) /* Debugging output macros. */ #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ #define MAC_PHYSICAL_FRAMES_PER_BUFFER (512) /* Minimum number of stereo frames per SoundManager double buffer. */ #define MAC_VIRTUAL_FRAMES_PER_BUFFER (4096) /* Need this many when using Virtual Memory for recording. */ #define PA_MIN_NUM_HOST_BUFFERS (2) #define PA_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */ #define PA_MAX_DEVICE_INFO (32) /* Conversions for 16.16 fixed point code. */ #define DoubleToUnsignedFixed(x) ((UnsignedFixed) ((x) * 65536.0)) #define UnsignedFixedToDouble(fx) (((double)(fx)) * (1.0/(1<<16))) /************************************************************************************/ /****************** Structures ******************************************************/ /************************************************************************************/ /* Use for passing buffers from input callback to output callback for processing. */ typedef struct MultiBuffer { char *buffers[PA_MAX_NUM_HOST_BUFFERS]; int numBuffers; int nextWrite; int nextRead; } MultiBuffer; /* Define structure to contain all Macintosh specific data. */ typedef struct PaHostSoundControl { UInt64 pahsc_EntryCount; double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */ /* Use char instead of Boolean for atomic operation. */ volatile char pahsc_IsRecording; /* Recording in progress. Set by foreground. Cleared by background. */ volatile char pahsc_StopRecording; /* Signal sent to background. */ volatile char pahsc_IfInsideCallback; /* Input */ SPB pahsc_InputParams; SICompletionUPP pahsc_InputCompletionProc; MultiBuffer pahsc_InputMultiBuffer; int32 pahsc_BytesPerInputHostBuffer; int32 pahsc_InputRefNum; /* Output */ CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS]; int32 pahsc_BytesPerOutputHostBuffer; SndChannelPtr pahsc_Channel; SndCallBackUPP pahsc_OutputCompletionProc; int32 pahsc_NumOutsQueued; int32 pahsc_NumOutsPlayed; PaTimestamp pahsc_NumFramesDone; UInt64 pahsc_WhenFramesDoneIncremented; /* Init Time -------------- */ int32 pahsc_NumHostBuffers; int32 pahsc_FramesPerHostBuffer; int32 pahsc_UserBuffersPerHostBuffer; int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */ } PaHostSoundControl; /* Mac specific device information. */ typedef struct internalPortAudioDevice { long pad_DeviceRefNum; long pad_DeviceBufferSize; Component pad_Identifier; PaDeviceInfo pad_Info; } internalPortAudioDevice; /************************************************************************************/ /****************** Data ************************************************************/ /************************************************************************************/ static int sNumDevices = 0; static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 }; static int32 sPaHostError = 0; static int sDefaultOutputDeviceID; static int sDefaultInputDeviceID; /************************************************************************************/ /****************** Prototypes ******************************************************/ /************************************************************************************/ static PaError PaMac_TimeSlice( internalPortAudioStream *past, int16 *macOutputBufPtr ); static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr ); static PaError PaMac_RecordNext( internalPortAudioStream *past ); static void PaMac_StartLoadCalculation( internalPortAudioStream *past ); static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate ); static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h ); static PaError PaMac_ScanInputDevices( void ); static PaError PaMac_ScanOutputDevices( void ); static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad ); static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad ); static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader ); static void PaMac_EndLoadCalculation( internalPortAudioStream *past ); static void PaMac_PlayNext ( internalPortAudioStream *past, int index ); static long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index ); static pascal void PaMac_InputCompletionProc(SPBPtr recParams); static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCmd); static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index ); long PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); static int Mac_IsVirtualMemoryOn( void ); static void PToCString(unsigned char* inString, char* outString); static void CToPString(char *inString, unsigned char* outString); char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf ); char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf ); int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf ); int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf ); int MultiBuffer_IsWriteable( MultiBuffer *mbuf ); int MultiBuffer_IsReadable( MultiBuffer *mbuf ); void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf ); void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf ); /************************************************************************* ** Simple FIFO index control for multiple buffers. ** Read and Write indices range from 0 to 2N-1. ** This allows us to distinguish between full and empty. */ char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf ) { return mbuf->buffers[mbuf->nextWrite % mbuf->numBuffers]; } char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf ) { return mbuf->buffers[mbuf->nextRead % mbuf->numBuffers]; } int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf ) { return mbuf->nextRead % mbuf->numBuffers; } int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf ) { return mbuf->nextWrite % mbuf->numBuffers; } int MultiBuffer_IsWriteable( MultiBuffer *mbuf ) { int bufsFull = mbuf->nextWrite - mbuf->nextRead; if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers); return (bufsFull < mbuf->numBuffers); } int MultiBuffer_IsReadable( MultiBuffer *mbuf ) { int bufsFull = mbuf->nextWrite - mbuf->nextRead; if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers); return (bufsFull > 0); } void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf ) { int temp = mbuf->nextRead + 1; mbuf->nextRead = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp; } void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf ) { int temp = mbuf->nextWrite + 1; mbuf->nextWrite = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp; } /************************************************************************* ** String Utility by Chris Rolfe */ static void PToCString(unsigned char* inString, char* outString) { long i; for(i=0; i 255) len = 255; /* Length is stored in first char of Pascal string */ outString[0] = (unsigned char)len; for(i=0; isampleRates; if( (rates != NULL) ) free( rates ); /* MEM_011 */ dev->sampleRates = NULL; if( dev->name != NULL ) free( (void *) dev->name ); /* MEM_010 */ dev->name = NULL; } sNumDevices = 0; return paNoError; } /************************************************************************* PaHost_Init() is the library initialization function - call this before using the library. */ PaError PaHost_Init( void ) { PaError err; NumVersionVariant version; version.parts = SndSoundManagerVersion(); DBUG(("SndSoundManagerVersion = 0x%x\n", version.whole)); /* Have we already initialized the device info? */ err = (PaError) Pa_CountDevices(); if( err < 0 ) return err; else return paNoError; } /************************************************************************* PaMac_ScanOutputDevices() queries the properties of all output devices. */ static PaError PaMac_ScanOutputDevices( void ) { PaError err; Component identifier=0; ComponentDescription criteria = { kSoundOutputDeviceType, 0, 0, 0, 0 }; long numComponents, i; /* Search the system linked list for output components */ numComponents = CountComponents (&criteria); identifier = 0; sDefaultOutputDeviceID = sNumDevices; /* FIXME - query somehow */ for (i = 0; i < numComponents; i++) { /* passing nil returns first matching component. */ identifier = FindNextComponent( identifier, &criteria); sDevices[sNumDevices].pad_Identifier = identifier; /* Set up for default OUTPUT devices. */ err = PaMac_QueryOutputDeviceInfo( identifier, &sDevices[sNumDevices] ); if( err < 0 ) return err; else sNumDevices++; } return paNoError; } /************************************************************************* PaMac_ScanInputDevices() queries the properties of all input devices. */ static PaError PaMac_ScanInputDevices( void ) { Str255 deviceName; int count; Handle iconHandle; PaError err; OSErr oserr; count = 1; sDefaultInputDeviceID = sNumDevices; /* FIXME - query somehow */ /* PLB20010415 - was setting sDefaultOutputDeviceID */ while(true) { /* Thanks Chris Rolfe and Alberto Ricci for this trick. */ oserr = SPBGetIndexedDevice(count++, deviceName, &iconHandle); DBUG(("PaMac_ScanInputDevices: SPBGetIndexedDevice returned %d\n", oserr )); #if 1 /* PLB20010415 - was giving error for anything other than siBadSoundInDevice, but some Macs may return other errors! */ if(oserr != noErr) break; /* Some type of error is expected when count > devices */ #else if(oserr == siBadSoundInDevice) { /* it's expected when count > devices */ oserr = noErr; break; } if(oserr != noErr) { ERR_RPT(("ERROR: SPBGetIndexedDevice(%d,,) returned %d\n", count-1, oserr )); sPaHostError = oserr; return paHostError; } #endif DisposeHandle(iconHandle); /* Don't need the icon */ err = PaMac_QueryInputDeviceInfo( deviceName, &sDevices[sNumDevices] ); DBUG(("PaMac_ScanInputDevices: PaMac_QueryInputDeviceInfo returned %d\n", err )); if( err < 0 ) return err; else if( err == 1 ) sNumDevices++; } return paNoError; } /* Sample rate info returned by using siSampleRateAvailable selector in SPBGetDeviceInfo() */ /* Thanks to Chris Rolfe for help with this query. */ #pragma options align=mac68k typedef struct { int16 numRates; UnsignedFixed (**rates)[]; /* Handle created by SPBGetDeviceInfo */ } SRateInfo; #pragma options align=reset /************************************************************************* ** PaMac_QueryOutputDeviceInfo() ** Query information about a named output device. ** Clears contents of ipad and writes info based on queries. ** Return one if OK, ** zero if device cannot be used, ** or negative error. */ static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad ) { int len; OSErr err; PaDeviceInfo *dev = &ipad->pad_Info; SRateInfo srinfo = {0}; int numRates; ComponentDescription tempD; Handle nameH=nil, infoH=nil, iconH=nil; memset( ipad, 0, sizeof(internalPortAudioDevice) ); dev->structVersion = 1; dev->maxInputChannels = 0; dev->maxOutputChannels = 2; dev->nativeSampleFormats = paInt16; /* FIXME - query to see if 24 or 32 bit data can be handled. */ /* Get sample rates supported. */ err = GetSoundOutputInfo(identifier, siSampleRateAvailable, (Ptr) &srinfo); if(err != noErr) { ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetSoundOutputInfo siSampleRateAvailable returned %d\n", err )); goto error; } numRates = srinfo.numRates; DBUG(("PaMac_QueryOutputDeviceInfo: srinfo.numRates = %d\n", srinfo.numRates )); if( numRates == 0 ) { dev->numSampleRates = -1; numRates = 2; } else { dev->numSampleRates = numRates; } dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates ); if(dev->sampleRates == NULL) { DBUG(("PaMac_QueryOutputDeviceInfo: PaMac_GetSampleRatesFromHandle alloc failed.\n")); return paInsufficientMemory; } /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */ DisposeHandle((Handle) srinfo.rates); /* Device name */ /* we pass an existing handle for the component name; we don't care about the info (type, subtype, etc.) or icon, so set them to nil */ DBUG(("PaMac_QueryOutputDeviceInfo: get component name.\n")); infoH = nil; iconH = nil; nameH = NewHandle(0); if(nameH == nil) return paInsufficientMemory; err = GetComponentInfo(identifier, &tempD, nameH, infoH, iconH); if (err) { ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetComponentInfo returned %d\n", err )); goto error; } /* Cast as uchar* so that we get a proper pascal string length. */ len = ((unsigned char *)(*nameH))[0] + 1; /* PLB20020612 - fix allocation error on Mac 8600 */ DBUG(("PaMac_QueryOutputDeviceInfo: new len = %d\n", len )); dev->name = (char *) malloc(len); /* MEM_010 */ if( dev->name == NULL ) { DisposeHandle(nameH); return paInsufficientMemory; } else { PToCString((unsigned char *)(*nameH), (char *) dev->name); DisposeHandle(nameH); } DBUG(("PaMac_QueryOutputDeviceInfo: dev->name = %s\n", dev->name )); return paNoError; error: sPaHostError = err; return paHostError; } /************************************************************************* ** PaMac_QueryInputDeviceInfo() ** Query information about a named input device. ** Clears contents of ipad and writes info based on queries. ** Return one if OK, ** zero if device cannot be used, ** or negative error. */ static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad ) { PaError result = paNoError; int len; OSErr err; long mRefNum = 0; long tempL; int16 tempS; Fixed tempF; PaDeviceInfo *dev = &ipad->pad_Info; SRateInfo srinfo = {0}; int numRates; memset( ipad, 0, sizeof(internalPortAudioDevice) ); dev->maxOutputChannels = 0; /* Open device based on name. If device is in use, it may not be able to open in write mode. */ err = SPBOpenDevice( deviceName, siWritePermission, &mRefNum); if (err) { /* If device is in use, it may not be able to open in write mode so try read mode. */ err = SPBOpenDevice( deviceName, siReadPermission, &mRefNum); if (err) { ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBOpenDevice returned %d\n", err )); sPaHostError = err; return paHostError; } } /* Define macros for printing out device info. */ #define PrintDeviceInfo(selector,var) \ err = SPBGetDeviceInfo(mRefNum, selector, (Ptr) &var); \ if (err) { \ DBUG(("query %s failed\n", #selector )); \ }\ else { \ DBUG(("query %s = 0x%x\n", #selector, var )); \ } PrintDeviceInfo( siContinuous, tempS ); PrintDeviceInfo( siAsync, tempS ); PrintDeviceInfo( siNumberChannels, tempS ); PrintDeviceInfo( siSampleSize, tempS ); PrintDeviceInfo( siSampleRate, tempF ); PrintDeviceInfo( siChannelAvailable, tempS ); PrintDeviceInfo( siActiveChannels, tempL ); PrintDeviceInfo( siDeviceBufferInfo, tempL ); err = SPBGetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL); if (err == 0) DBUG(("%s = 0x%x\n", "siActiveChannels", tempL )); /* Can we use this device? */ err = SPBGetDeviceInfo(mRefNum, siAsync, (Ptr) &tempS); if (err) { ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siAsync returned %d\n", err )); goto error; } if( tempS == 0 ) goto useless; /* Does not support async recording so forget about it. */ err = SPBGetDeviceInfo(mRefNum, siChannelAvailable, (Ptr) &tempS); if (err) { ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siChannelAvailable returned %d\n", err )); goto error; } dev->maxInputChannels = tempS; /* Get sample rates supported. */ err = SPBGetDeviceInfo(mRefNum, siSampleRateAvailable, (Ptr) &srinfo); if (err) { ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleRateAvailable returned %d\n", err )); goto error; } numRates = srinfo.numRates; DBUG(("numRates = 0x%x\n", numRates )); if( numRates == 0 ) { dev->numSampleRates = -1; numRates = 2; } else { dev->numSampleRates = numRates; } dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates ); /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */ DisposeHandle((Handle) srinfo.rates); /* Get size of device buffer. */ err = SPBGetDeviceInfo(mRefNum, siDeviceBufferInfo, (Ptr) &tempL); if (err) { ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siDeviceBufferInfo returned %d\n", err )); goto error; } ipad->pad_DeviceBufferSize = tempL; DBUG(("siDeviceBufferInfo = %d\n", tempL )); /* Set format based on sample size. */ err = SPBGetDeviceInfo(mRefNum, siSampleSize, (Ptr) &tempS); if (err) { ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleSize returned %d\n", err )); goto error; } switch( tempS ) { case 0x0020: dev->nativeSampleFormats = paInt32; /* FIXME - warning, code probably won't support this! */ break; case 0x0010: default: /* FIXME - What about other formats? */ dev->nativeSampleFormats = paInt16; break; } DBUG(("nativeSampleFormats = %d\n", dev->nativeSampleFormats )); /* Device name */ len = deviceName[0] + 1; /* Get length of Pascal string */ dev->name = (char *) malloc(len); /* MEM_010 */ if( dev->name == NULL ) { result = paInsufficientMemory; goto cleanup; } PToCString(deviceName, (char *) dev->name); DBUG(("deviceName = %s\n", dev->name )); result = (PaError) 1; /* All done so close up device. */ cleanup: if( mRefNum ) SPBCloseDevice(mRefNum); return result; error: if( mRefNum ) SPBCloseDevice(mRefNum); sPaHostError = err; return paHostError; useless: if( mRefNum ) SPBCloseDevice(mRefNum); return (PaError) 0; } /************************************************************************* ** Allocate a double array and fill it with listed sample rates. */ static double * PaMac_GetSampleRatesFromHandle ( int numRates, Handle h ) { OSErr err = noErr; SInt8 hState; int i; UnsignedFixed *fixedRates; double *rates = (double *) malloc( numRates * sizeof(double) ); /* MEM_011 */ if( rates == NULL ) return NULL; /* Save and restore handle state as suggested by TechNote at: http://developer.apple.com/technotes/tn/tn1122.html */ hState = HGetState (h); if (!(err = MemError ())) { HLock (h); if (!(err = MemError ( ))) { fixedRates = (UInt32 *) *h; for( i=0; i= Pa_CountDevices()) ) return NULL; return &sDevices[id].pad_Info; } /*************************************************************************/ PaDeviceID Pa_GetDefaultInputDeviceID( void ) { return sDefaultInputDeviceID; } /*************************************************************************/ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { return sDefaultOutputDeviceID; } /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void PaMac_StartLoadCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; UnsignedWide widePad; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ Microseconds( &widePad ); pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad ); } /****************************************************************************** ** Measure fractional CPU load based on real-time it took to calculate ** buffers worth of output. */ /**************************************************************************/ static void PaMac_EndLoadCalculation( internalPortAudioStream *past ) { UnsignedWide widePad; UInt64 currentCount; long usecsElapsed; double newUsage; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Measure CPU utilization during this callback. Note that this calculation ** assumes that we had the processor the whole time. */ #define LOWPASS_COEFFICIENT_0 (0.95) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) Microseconds( &widePad ); currentCount = UnsignedWideToUInt64( widePad ); usecsElapsed = (long) U64Subtract(currentCount, pahsc->pahsc_EntryCount); /* Use inverse because it is faster than the divide. */ newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer; past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + (LOWPASS_COEFFICIENT_1 * newUsage); } /*********************************************************************** ** Called by Pa_StartStream() */ PaError PaHost_StartInput( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; pahsc->pahsc_IsRecording = 0; pahsc->pahsc_StopRecording = 0; pahsc->pahsc_InputMultiBuffer.nextWrite = 0; pahsc->pahsc_InputMultiBuffer.nextRead = 0; return PaMac_RecordNext( past ); } /*********************************************************************** ** Called by Pa_StopStream(). ** May be called during error recovery or cleanup code ** so protect against NULL pointers. */ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { int32 timeOutMsec; PaError result = paNoError; OSErr err = 0; long mRefNum; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; (void) abort; mRefNum = pahsc->pahsc_InputRefNum; DBUG(("PaHost_StopInput: mRefNum = %d\n", mRefNum )); if( mRefNum ) { DBUG(("PaHost_StopInput: pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording )); if( pahsc->pahsc_IsRecording ) { /* PLB20010420 - Fix TIMEOUT in record mode. */ pahsc->pahsc_StopRecording = 1; /* Request that we stop recording. */ err = SPBStopRecording(mRefNum); DBUG(("PaHost_StopInput: then pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording )); /* Calculate timeOut longer than longest time it could take to play one buffer. */ timeOutMsec = (int32) ((1500.0 * pahsc->pahsc_FramesPerHostBuffer) / past->past_SampleRate); /* Keep querying sound channel until it is no longer busy playing. */ while( !err && pahsc->pahsc_IsRecording && (timeOutMsec > 0)) { Pa_Sleep(20); timeOutMsec -= 20; } if( timeOutMsec <= 0 ) { ERR_RPT(("PaHost_StopInput: timed out!\n")); return paTimedOut; } } } if( err ) { sPaHostError = err; result = paHostError; } DBUG(("PaHost_StopInput: finished.\n", mRefNum )); return result; } /***********************************************************************/ static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader ) { sndHeader->numChannels = past->past_NumOutputChannels; sndHeader->sampleRate = DoubleToUnsignedFixed(past->past_SampleRate); sndHeader->loopStart = 0; sndHeader->loopEnd = 0; sndHeader->encode = cmpSH; sndHeader->baseFrequency = kMiddleC; sndHeader->markerChunk = nil; sndHeader->futureUse2 = nil; sndHeader->stateVars = nil; sndHeader->leftOverSamples = nil; sndHeader->compressionID = 0; sndHeader->packetSize = 0; sndHeader->snthID = 0; sndHeader->sampleSize = 8 * sizeof(int16); // FIXME - might be 24 or 32 bits some day; sndHeader->sampleArea[0] = 0; sndHeader->format = kSoundNotCompressed; } static void SetFramesDone( PaHostSoundControl *pahsc, PaTimestamp framesDone ) { UnsignedWide now; Microseconds( &now ); pahsc->pahsc_NumFramesDone = framesDone; pahsc->pahsc_WhenFramesDoneIncremented = UnsignedWideToUInt64( now ); } /***********************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { SndCommand pauseCommand; SndCommand resumeCommand; int i; OSErr error; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; if( pahsc->pahsc_Channel == NULL ) return paInternalError; past->past_StopSoon = 0; past->past_IsActive = 1; pahsc->pahsc_NumOutsQueued = 0; pahsc->pahsc_NumOutsPlayed = 0; SetFramesDone( pahsc, 0.0 ); /* Pause channel so it does not do back ground processing while we are still filling the queue. */ pauseCommand.cmd = pauseCmd; pauseCommand.param1 = pauseCommand.param2 = 0; error = SndDoCommand (pahsc->pahsc_Channel, &pauseCommand, true); if (noErr != error) goto exit; /* Queue all of the buffers so we start off full. */ for (i = 0; ipahsc_NumHostBuffers; i++) { PaMac_PlayNext( past, i ); } /* Resume channel now that the queue is full. */ resumeCommand.cmd = resumeCmd; resumeCommand.param1 = resumeCommand.param2 = 0; error = SndDoImmediate( pahsc->pahsc_Channel, &resumeCommand ); if (noErr != error) goto exit; return paNoError; exit: past->past_IsActive = 0; sPaHostError = error; ERR_RPT(("Error in PaHost_StartOutput: SndDoCommand returned %d\n", error )); return paHostError; } /*******************************************************************/ long PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; return (long) (pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer); } /*********************************************************************** ** Called by Pa_StopStream(). ** May be called during error recovery or cleanup code ** so protect against NULL pointers. */ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { int32 timeOutMsec; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; if( pahsc->pahsc_Channel == NULL ) return paNoError; DBUG(("PaHost_StopOutput()\n")); if( past->past_IsActive == 0 ) return paNoError; /* Set flags for callback function to see. */ if( abort ) past->past_StopNow = 1; past->past_StopSoon = 1; /* Calculate timeOut longer than longest time it could take to play all buffers. */ timeOutMsec = (int32) ((1500.0 * PaHost_GetTotalBufferFrames( past )) / past->past_SampleRate); /* Keep querying sound channel until it is no longer busy playing. */ while( past->past_IsActive && (timeOutMsec > 0)) { Pa_Sleep(20); timeOutMsec -= 20; } if( timeOutMsec <= 0 ) { ERR_RPT(("PaHost_StopOutput: timed out!\n")); return paTimedOut; } else return paNoError; } /***********************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *past ) { (void) past; /* Prevent unused variable warnings. */ return paNoError; } /***********************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { (void) past; /* Prevent unused variable warnings. */ (void) abort; /* Prevent unused variable warnings. */ return paNoError; } /***********************************************************************/ PaError PaHost_StreamActive( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; return (PaError) ( past->past_IsActive + pahsc->pahsc_IsRecording ); } int Mac_IsVirtualMemoryOn( void ) { long attr; OSErr result = Gestalt( gestaltVMAttr, &attr ); DBUG(("gestaltVMAttr : 0x%x\n", attr )); return ((attr >> gestaltVMHasPagingControl ) & 1); } /******************************************************************* * Determine number of host Buffers * and how many User Buffers we can put into each host buffer. */ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; int32 minNumBuffers; int32 minFramesPerHostBuffer; int32 minTotalFrames; int32 userBuffersPerHostBuffer; int32 framesPerHostBuffer; int32 numHostBuffers; minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer; minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); /* Determine number of user buffers based on minimum latency. */ /* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the ** variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will ** gove lower latency when virtual memory is turned off. */ /* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */ minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate ); past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; /* We cannot make the buffers too small because they may not get serviced quickly enough. */ if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) { userBuffersPerHostBuffer = (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / past->past_FramesPerUserBuffer; } else { userBuffersPerHostBuffer = 1; } framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; /* Calculate number of host buffers needed. Round up to cover minTotalFrames. */ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; /* Make sure we have enough host buffers. */ if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) { numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; } else { /* If we have too many host buffers, try to put more user buffers in a host buffer. */ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) { userBuffersPerHostBuffer += 1; framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; } } pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; pahsc->pahsc_NumHostBuffers = numHostBuffers; DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); } /*******************************************************************/ PaError PaHost_OpenStream( internalPortAudioStream *past ) { OSErr err; PaError result = paHostError; PaHostSoundControl *pahsc; int i; /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); if( pahsc == NULL ) { return paInsufficientMemory; } past->past_DeviceData = (void *) pahsc; /* If recording, and virtual memory is turned on, then use bigger buffers to prevent glitches. */ if( (past->past_NumInputChannels > 0) && Mac_IsVirtualMemoryOn() ) { pahsc->pahsc_MinFramesPerHostBuffer = MAC_VIRTUAL_FRAMES_PER_BUFFER; } else { pahsc->pahsc_MinFramesPerHostBuffer = MAC_PHYSICAL_FRAMES_PER_BUFFER; } PaHost_CalcNumHostBuffers( past ); /* Setup constants for CPU load measurement. */ pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer); /* ------------------ OUTPUT */ if( past->past_NumOutputChannels > 0 ) { /* Create sound channel to which we can send commands. */ pahsc->pahsc_Channel = 0L; err = SndNewChannel(&pahsc->pahsc_Channel, sampledSynth, 0, nil); /* FIXME - use kUseOptionalOutputDevice if not default. */ if(err != 0) { ERR_RPT(("Error in PaHost_OpenStream: SndNewChannel returned 0x%x\n", err )); goto error; } /* Install our callback function pointer straight into the sound channel structure */ /* Use new CARBON name for callback procedure. */ #if TARGET_API_MAC_CARBON pahsc->pahsc_OutputCompletionProc = NewSndCallBackUPP(PaMac_OutputCompletionProc); #else pahsc->pahsc_OutputCompletionProc = NewSndCallBackProc(PaMac_OutputCompletionProc); #endif pahsc->pahsc_Channel->callBack = pahsc->pahsc_OutputCompletionProc; pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumOutputChannels * sizeof(int16); for (i = 0; ipahsc_NumHostBuffers; i++) { char *buf = (char *)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer); if (buf == NULL) { ERR_RPT(("Error in PaHost_OpenStream: could not allocate output buffer. Size = \n", pahsc->pahsc_BytesPerOutputHostBuffer )); goto memerror; } PaMac_InitSoundHeader( past, &pahsc->pahsc_SoundHeaders[i] ); pahsc->pahsc_SoundHeaders[i].samplePtr = buf; pahsc->pahsc_SoundHeaders[i].numFrames = (unsigned long) pahsc->pahsc_FramesPerHostBuffer; } } #ifdef SUPPORT_AUDIO_CAPTURE /* ------------------ INPUT */ /* Use double buffer scheme that matches output. */ if( past->past_NumInputChannels > 0 ) { int16 tempS; long tempL; Fixed tempF; long mRefNum; Str255 namePString; #if TARGET_API_MAC_CARBON pahsc->pahsc_InputCompletionProc = NewSICompletionUPP((SICompletionProcPtr)PaMac_InputCompletionProc); #else pahsc->pahsc_InputCompletionProc = NewSICompletionProc((ProcPtr)PaMac_InputCompletionProc); #endif pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumInputChannels * sizeof(int16); for (i = 0; ipahsc_NumHostBuffers; i++) { char *buf = (char *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer); if ( buf == NULL ) { ERR_RPT(("PaHost_OpenStream: could not allocate input buffer. Size = \n", pahsc->pahsc_BytesPerInputHostBuffer )); goto memerror; } pahsc->pahsc_InputMultiBuffer.buffers[i] = buf; } pahsc->pahsc_InputMultiBuffer.numBuffers = pahsc->pahsc_NumHostBuffers; // err = SPBOpenDevice( (const unsigned char *) &noname, siWritePermission, &mRefNum); CToPString((char *)sDevices[past->past_InputDeviceID].pad_Info.name, namePString); err = SPBOpenDevice(namePString, siWritePermission, &mRefNum); if (err) goto error; pahsc->pahsc_InputRefNum = mRefNum; DBUG(("PaHost_OpenStream: mRefNum = %d\n", mRefNum )); /* Set input device characteristics. */ tempS = 1; err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS); if (err) { ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siContinuous returned %d\n", err )); goto error; } tempL = 0x03; err = SPBSetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL); if (err) { DBUG(("PaHost_OpenStream: setting siActiveChannels returned 0x%x. Error ignored.\n", err )); } /* PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. */ tempS = past->past_NumInputChannels; err = SPBSetDeviceInfo(mRefNum, siNumberChannels, (Ptr) &tempS); if (err) { ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siNumberChannels returned %d\n", err )); goto error; } tempF = ((unsigned long)past->past_SampleRate) << 16; err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF); if (err) { ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siSampleRate returned %d\n", err )); goto error; } /* Setup record-parameter block */ pahsc->pahsc_InputParams.inRefNum = mRefNum; pahsc->pahsc_InputParams.milliseconds = 0; // not used pahsc->pahsc_InputParams.completionRoutine = pahsc->pahsc_InputCompletionProc; pahsc->pahsc_InputParams.interruptRoutine = 0; pahsc->pahsc_InputParams.userLong = (long) past; pahsc->pahsc_InputParams.unused1 = 0; } #endif /* SUPPORT_AUDIO_CAPTURE */ DBUG(("PaHost_OpenStream: complete.\n")); return paNoError; error: PaHost_CloseStream( past ); ERR_RPT(("PaHost_OpenStream: sPaHostError = 0x%x.\n", err )); sPaHostError = err; return paHostError; memerror: PaHost_CloseStream( past ); return paInsufficientMemory; } /*********************************************************************** ** Called by Pa_CloseStream(). ** May be called during error recovery or cleanup code ** so protect against NULL pointers. */ PaError PaHost_CloseStream( internalPortAudioStream *past ) { PaError result = paNoError; OSErr err = 0; int i; PaHostSoundControl *pahsc; DBUG(("PaHost_CloseStream( 0x%x )\n", past )); if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; if( past->past_NumOutputChannels > 0 ) { /* TRUE means flush now instead of waiting for quietCmd to be processed. */ if( pahsc->pahsc_Channel != NULL ) SndDisposeChannel(pahsc->pahsc_Channel, TRUE); { for (i = 0; ipahsc_NumHostBuffers; i++) { Ptr p = (Ptr) pahsc->pahsc_SoundHeaders[i].samplePtr; if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerOutputHostBuffer ); } } } if( past->past_NumInputChannels > 0 ) { if( pahsc->pahsc_InputRefNum ) { err = SPBCloseDevice(pahsc->pahsc_InputRefNum); pahsc->pahsc_InputRefNum = 0; if( err ) { sPaHostError = err; result = paHostError; } } { for (i = 0; ipahsc_InputMultiBuffer.numBuffers; i++) { Ptr p = (Ptr) pahsc->pahsc_InputMultiBuffer.buffers[i]; if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerInputHostBuffer ); } } } past->past_DeviceData = NULL; PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); DBUG(("PaHost_CloseStream: complete.\n", past )); return result; } /*************************************************************************/ int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) { /* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording. ** This routine doesn't have enough information to determine the best value ** and is being depracated. */ return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate ); } /*************************************************************************/ static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerUserBuffer, double sampleRate ) { int minUserPerHost = ( minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer; int numBufs = PA_MIN_NUM_HOST_BUFFERS * minUserPerHost; if( numBufs < PA_MIN_NUM_HOST_BUFFERS ) numBufs = PA_MIN_NUM_HOST_BUFFERS; (void) sampleRate; return numBufs; } /*************************************************************************/ void Pa_Sleep( int32 msec ) { EventRecord event; int32 sleepTime, endTime; /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */ sleepTime = ((msec * 60) + 999) / 1000; if( sleepTime < 1 ) sleepTime = 1; endTime = TickCount() + sleepTime; do { DBUGX(("Sleep for %d ticks.\n", sleepTime )); /* Use WaitNextEvent() to sleep without getting events. */ /* PLB20010907 - Pass unused event to WaitNextEvent instead of NULL to prevent * Mac OSX crash. Thanks Dominic Mazzoni. */ WaitNextEvent( 0, &event, sleepTime, NULL ); sleepTime = endTime - TickCount(); } while( sleepTime > 0 ); } /*************************************************************************/ int32 Pa_GetHostError( void ) { int32 err = sPaHostError; sPaHostError = 0; return err; } /************************************************************************* * Allocate memory that can be accessed in real-time. * This may need to be held in physical memory so that it is not * paged to virtual memory. * This call MUST be balanced with a call to PaHost_FreeFastMemory(). */ void *PaHost_AllocateFastMemory( long numBytes ) { void *addr = NewPtrClear( numBytes ); if( (addr == NULL) || (MemError () != 0) ) return NULL; #if (TARGET_API_MAC_CARBON == 0) if( HoldMemory( addr, numBytes ) != noErr ) { DisposePtr( (Ptr) addr ); return NULL; } #endif return addr; } /************************************************************************* * Free memory that could be accessed in real-time. * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory( void *addr, long numBytes ) { if( addr == NULL ) return; #if TARGET_API_MAC_CARBON (void) numBytes; #else UnholdMemory( addr, numBytes ); #endif DisposePtr( (Ptr) addr ); } /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { PaTimestamp framesDone1; PaTimestamp framesDone2; UInt64 whenIncremented; UnsignedWide now; UInt64 now64; long microsElapsed; long framesElapsed; PaHostSoundControl *pahsc; internalPortAudioStream *past = (internalPortAudioStream *) stream; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; /* Capture information from audio thread. * We have to be careful that we don't get interrupted in the middle. * So we grab the pahsc_NumFramesDone twice and make sure it didn't change. */ do { framesDone1 = pahsc->pahsc_NumFramesDone; whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented; framesDone2 = pahsc->pahsc_NumFramesDone; } while( framesDone1 != framesDone2 ); /* Calculate how many microseconds have elapsed and convert to frames. */ Microseconds( &now ); now64 = UnsignedWideToUInt64( now ); microsElapsed = U64Subtract( now64, whenIncremented ); framesElapsed = microsElapsed * past->past_SampleRate * 0.000001; return framesDone1 + framesElapsed; } /************************************************************************** ** Callback for Input, SPBRecord() */ int gRecordCounter = 0; int gPlayCounter = 0; pascal void PaMac_InputCompletionProc(SPBPtr recParams) { PaError result = paNoError; int finished = 1; internalPortAudioStream *past; PaHostSoundControl *pahsc; gRecordCounter += 1; /* debug hack to see if engine running */ /* Get our PA data from Mac structure. */ past = (internalPortAudioStream *) recParams->userLong; if( past == NULL ) return; if( past->past_Magic != PA_MAGIC ) { AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, past", (long) past ); AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, magic", (long) past->past_Magic ); goto error; } pahsc = (PaHostSoundControl *) past->past_DeviceData; past->past_NumCallbacks += 1; /* Have we been asked to stop recording? */ if( (recParams->error == abortErr) || pahsc->pahsc_StopRecording ) goto error; /* If there are no output channels, then we need to call the user callback function from here. * Otherwise we will call the user code during the output completion routine. */ if(past->past_NumOutputChannels == 0) { SetFramesDone( pahsc, pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer ); result = PaMac_CallUserLoop( past, NULL ); } /* Did user code ask us to stop? If not, issue another recording request. */ if( (result == paNoError) && (pahsc->pahsc_StopRecording == 0) ) { result = PaMac_RecordNext( past ); if( result != paNoError ) pahsc->pahsc_IsRecording = 0; } else goto error; return; error: pahsc->pahsc_IsRecording = 0; pahsc->pahsc_StopRecording = 0; return; } /*********************************************************************** ** Called by either input or output completion proc. ** Grabs input data if any present, and calls PA conversion code, ** that in turn calls user code. */ static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr ) { PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; int16 *inPtr = NULL; int i; /* Advance read index for sound input FIFO here, independantly of record/write process. */ if(past->past_NumInputChannels > 0) { if( MultiBuffer_IsReadable( &pahsc->pahsc_InputMultiBuffer ) ) { inPtr = (int16 *) MultiBuffer_GetNextReadBuffer( &pahsc->pahsc_InputMultiBuffer ); MultiBuffer_AdvanceReadIndex( &pahsc->pahsc_InputMultiBuffer ); } } /* Call user code enough times to fill buffer. */ if( (inPtr != NULL) || (outPtr != NULL) ) { PaMac_StartLoadCalculation( past ); /* CPU usage */ #ifdef PA_MAX_USAGE_ALLOWED /* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */ if( past->past_Usage > PA_MAX_USAGE_ALLOWED ) { past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer; } else #endif { for( i=0; ipahsc_UserBuffersPerHostBuffer; i++ ) { result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr ); if( result != 0) { /* Recording might be in another process, so tell it to stop with a flag. */ pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording; break; } /* Advance sample pointers. */ if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels; if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels; } } PaMac_EndLoadCalculation( past ); } return result; } /*********************************************************************** ** Setup next recording buffer in FIFO and issue recording request to Snd Input Manager. */ static PaError PaMac_RecordNext( internalPortAudioStream *past ) { PaError result = paNoError; OSErr err; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; /* Get pointer to next buffer to record into. */ pahsc->pahsc_InputParams.bufferPtr = MultiBuffer_GetNextWriteBuffer( &pahsc->pahsc_InputMultiBuffer ); /* Advance write index if there is room. Otherwise keep writing same buffer. */ if( MultiBuffer_IsWriteable( &pahsc->pahsc_InputMultiBuffer ) ) { MultiBuffer_AdvanceWriteIndex( &pahsc->pahsc_InputMultiBuffer ); } AddTraceMessage("PaMac_RecordNext: bufferPtr", (long) pahsc->pahsc_InputParams.bufferPtr ); AddTraceMessage("PaMac_RecordNext: nextWrite", pahsc->pahsc_InputMultiBuffer.nextWrite ); /* Setup parameters and issue an asynchronous recording request. */ pahsc->pahsc_InputParams.bufferLength = pahsc->pahsc_BytesPerInputHostBuffer; pahsc->pahsc_InputParams.count = pahsc->pahsc_BytesPerInputHostBuffer; err = SPBRecord(&pahsc->pahsc_InputParams, true); if( err ) { AddTraceMessage("PaMac_RecordNext: SPBRecord error ", err ); sPaHostError = err; result = paHostError; } else { pahsc->pahsc_IsRecording = 1; } return result; } /************************************************************************** ** Callback for Output Playback() ** Return negative error, 0 to continue, 1 to stop. */ long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index ) { PaHostSoundControl *pahsc; long result = 0; int finished = 1; char *outPtr; gPlayCounter += 1; /* debug hack */ past->past_NumCallbacks += 1; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return -1; /* Are we nested?! */ if( pahsc->pahsc_IfInsideCallback ) return 0; pahsc->pahsc_IfInsideCallback = 1; /* Get pointer to buffer to fill. */ outPtr = pahsc->pahsc_SoundHeaders[index].samplePtr; /* Combine with any sound input, and call user callback. */ result = PaMac_CallUserLoop( past, (int16 *) outPtr ); pahsc->pahsc_IfInsideCallback = 0; return result; } /************************************************************************************* ** Called by SoundManager when ready for another buffer. */ static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd) { internalPortAudioStream *past; PaHostSoundControl *pahsc; (void) theChannel; (void) theCallBackCmd; /* Get our data from Mac structure. */ past = (internalPortAudioStream *) theCallBackCmd->param2; if( past == NULL ) return; pahsc = (PaHostSoundControl *) past->past_DeviceData; pahsc->pahsc_NumOutsPlayed += 1; SetFramesDone( pahsc, pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer ); PaMac_BackgroundManager( past, theCallBackCmd->param1 ); } /*******************************************************************/ static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index ) { PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; /* Has someone asked us to abort by calling Pa_AbortStream()? */ if( past->past_StopNow ) { SndCommand command; /* Clear the queue of any pending commands. */ command.cmd = flushCmd; command.param1 = command.param2 = 0; SndDoImmediate( pahsc->pahsc_Channel, &command ); /* Then stop currently playing buffer, if any. */ command.cmd = quietCmd; SndDoImmediate( pahsc->pahsc_Channel, &command ); past->past_IsActive = 0; } /* Has someone asked us to stop by calling Pa_StopStream() * OR has a user callback returned '1' to indicate finished. */ else if( past->past_StopSoon ) { if( (pahsc->pahsc_NumOutsQueued - pahsc->pahsc_NumOutsPlayed) <= 0 ) { past->past_IsActive = 0; /* We're finally done. */ } } else { PaMac_PlayNext( past, index ); } return result; } /************************************************************************************* ** Fill next buffer with sound and queue it for playback. */ static void PaMac_PlayNext ( internalPortAudioStream *past, int index ) { OSErr error; long result; SndCommand playCmd; SndCommand callbackCmd; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; /* If this was the last buffer, or abort requested, then just be done. */ if ( past->past_StopSoon ) goto done; /* Load buffer with sound. */ result = PaMac_FillNextOutputBuffer ( past, index ); if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */ else if( result < 0 ) goto done; /* Play the next buffer. */ playCmd.cmd = bufferCmd; playCmd.param1 = 0; playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ]; error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true ); if( error != noErr ) goto gotError; /* Ask for a callback when it is done. */ callbackCmd.cmd = callBackCmd; callbackCmd.param1 = index; callbackCmd.param2 = (long)past; error = SndDoCommand (pahsc->pahsc_Channel, &callbackCmd, true ); if( error != noErr ) goto gotError; pahsc->pahsc_NumOutsQueued += 1; return; gotError: sPaHostError = error; done: return; } portaudio-18.1.orig/pa_sgi/0000755000175000000620000000000007700016420016230 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_sgi/Makefile0000644000175000017500000000547207634421742020061 0ustar mikaelmikael00000000000000# Makefile for pa_sgi. PortAudio for Silicon Graphics IRIX 6.2-6.5. # Pieter suurmond, march 15, 2003. (pa-V18-patch). # Tested under IRIX 6.5 with both GCC and MIPS compilers. # Based on SGI-specific sproc()-method to spawn children, not on POSIX-threads. # Choose compiler in combination with options: CC = cc CFLAGS = -O2 # Possible options with MIPSpro compiler are: -32, -o32, -n32, -64, # -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging. # For GCC, use -Wall. And use for example -O2 or -O3 for better optimization: #CC = gcc #CFLAGS = -O2 -Wall # Instead of "-lpthread", as with linux, just the audio- and math-library for SGI: LIBS = -laudio -lm # So sourcefiles can find included headerfiles in pa_common: CDEFINES = -I../pa_common PASRC = ../pa_common/pa_lib.c pa_sgi.c PAINC = ../pa_common/portaudio.h # Tests performed on SGI Indy with R5000 @ 180MHz running IRIX 6.5: # Used GCC compiler version 3.0.4. and MIPS. TESTC = $(PASRC) ../pa_tests/patest_record.c ## OK GCC march 2003 (MIPS sees errors in patest_record.c, refuses compilation). #TESTC = $(PASRC) ../pa_tests/patest_latency.c ## OK GCC march 2003. (MIPS doesn't like //) #TESTC = $(PASRC) ../pa_tests/patest_longsine.c ## OK GCC march 2003. #TESTC = $(PASRC) ../pa_tests/patest_wire.c ## OK GCC Click free now. march 2003. #TESTC = $(PASRC) ../pa_tests/pa_fuzz.c ## OK GCC march 2003. #TESTC = $(PASRC) ../pa_tests/pa_devs.c # Never knew my Indy had 16 input- and output-channels! #TESTC = $(PASRC) ../pa_tests/patest_saw.c ## - Pa_sleep doesn't work anymore?! #TESTC = $(PASRC) ../pa_tests/patest_sine.c # - Pa_sleep doesn't work anymore?! #TESTC = $(PASRC) ../pa_tests/patest_many.c ## - Pa_sleep doesn't work anymore?! #TESTC = $(PASRC) ../pa_tests/patest_sine_time.c ## Silence for 2 seconds doesn't work, sine sounds ok. #TESTC = $(PASRC) ../pa_tests/patest_sine8.c ## Silence for 2 seconds doesn't work, sine sounds ok. #TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK GCC and MIPS-CC march 2003. #TESTC = $(PASRC) ../pa_tests/patest_pink.c ## OK GCC march 2003 #TESTC = $(PASRC) ../pa_tests/patest_clip.c # #TESTC = $(PASRC) ../pa_tests/patest_stop.c # MIPS doesn't like patest_stop.c Worked before but now # error AL_BAD_QSIZE on IRIX 6.5 (with GCC). #TESTC = $(PASRC) ../pa_tests/patest_dither.c # #TESTC = $(PASRC) ../pa_tests/patest_sync.c # I don't hear the 6th beep, not really in sync @500ms lat. #TESTC = $(PASRC) ../pa_tests/paqa_devs.c # A lot of error messages but no coredump. #TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Segmentation fault (core dumped)! TESTH = $(PAINC) all: patest patest: $(TESTC) $(TESTH) Makefile $(CC) $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest run: patest ./patest portaudio-18.1.orig/pa_sgi/pa_sgi.c0000644000175000017500000016561107633663320020030 0ustar mikaelmikael00000000000000/* * $Id: pa_sgi.c,v 1.2.4.2 2003/03/13 00:56:47 pieter Exp $ * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk. * Latest Version at: http://www.portaudio.com * * Silicon Graphics (SGI) IRIX implementation by Pieter Suurmond. * This implementation uses sproc()-spawning, not the POSIX-threads. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * MODIFICATIONS: 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. 8/17/2001 - v15, first unstable alpha release for IRIX, sent to Phil & Ross. 9/23/2001 - Many fixes and changes: POLLIN for input, not POLLOUT! 7/04/2002 - Implemented multiple user buffers per host buffer to allow clients that request smaller buffersizes. 3/13/2003 - Fixed clicks in full-duplex (wire) mode. Fixed some uninitialised vars, got rid of all GCC-warnings (-Wall). Tested with MIPS compiler and GCC 3.0.4. on IRIX 6.5 (AL v7). TODO: - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), and maybe also the other natively supported formats? (might increase performance) - Implement fancy callback block adapter as described in the PDF by Stephane Letz in the ASIO dir. REFERENCES: - IRIX 6.2 man pages regarding SGI AL library. - IRIS Digital Media Programming Guide (online books and man-pages come with IRIX 6.2 and may not be publically available on the internet). */ #include /* Standard libraries. */ #include #include "../pa_common/portaudio.h" /* (Makefile fails to find in subdirs, -I doesn't work?). */ #include "../pa_common/pa_host.h" #include "../pa_common/pa_trace.h" #include /* Needed for int oserror(void);. */ #include #include #include #include /* For schedctl(NDPRI, NDPHIMIN). */ #include /* fcntl.h needed. */ #include /* For streams, ioctl(), etc. */ #include #include #include /* System specific (IRIX 6.2-6.5). */ /*----------------- MACROS --------------------*/ #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ #define MAX_CHARS_DEVNAME (16) #define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7. */ /* Constants used in 'Pa_GetMinNumBuffers()' below: */ #define MIN_LATENCY_MSEC (200) /* Used if 'getenv("PA_MIN_LATENCY_MSEC")' fails. */ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") /* Same names as in file pa_unix.h. */ /*------------------------------- IRIX AL specific device info: --------------------------------------*/ typedef struct internalPortAudioDevice { PaDeviceID pad_DeviceID; /* THIS "ID" IS NEW HERE. */ long pad_ALdevice; /* SGI-number! */ double pad_SampleRates[MAX_SAMPLE_RATES]; /* For pointing to from pad_Info */ char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ struct internalPortAudioDevice* pad_Next; /* Singly linked list (NULL=end). */ } internalPortAudioDevice; /*----------------- Structure containing all SGI IRIX specific data: ---------------------------------------*/ typedef struct PaHostSoundControl { ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */ pahsc_ALconfigOUT; /* stucts separate for input and output ports. */ ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ unsigned int pahsc_UserBuffersPerHostBuffer, pahsc_SamplesPerInputHostBuffer, /* Channels per frame are accounted for. */ pahsc_SamplesPerOutputHostBuffer, pahsc_BytesPerInputHostBuffer, /* Size per sample are accounted for. */ pahsc_BytesPerOutputHostBuffer; short *pahsc_InputHostBuffer, /* Allocated here, in this file, if necessary. */ *pahsc_OutputHostBuffer; struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ pahsc_LastExitTime; long pahsc_InsideCountSum, pahsc_TotalCountSum; } PaHostSoundControl; /*-------------------------------------------------------- Shared Data -------------------------------*/ static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ usema_t *SendSema, /* These variables are shared between the */ *RcvSema; /* audio handling process and main process. */ /*--------------------------*/ long Pa_GetHostError(void) { return (long)sPaHostError; } /*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ /* (copied from source pa_linux_oss/pa_linux_oss.c) */ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); } static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) { long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; long usecs = secs * 1000000; usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); return usecs; } static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { struct itimerval currentTime; long insideCount; long totalCount; /* Measure CPU utilization during this callback. */ #define LOWPASS_COEFFICIENT_0 (0.95) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if (pahsc == NULL) return; if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) { if (past->past_IfLastExitValid) { insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); pahsc->pahsc_InsideCountSum += insideCount; totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); pahsc->pahsc_TotalCountSum += totalCount; /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ /* Low pass filter the result because sometimes we get called several times in a row. */ /* That can cause the TotalCount to be very low which can cause the usage to appear */ /* unnaturally high. So we must filter numerator and denominator separately!!! */ if (pahsc->pahsc_InsideCountSum > 0) { past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; pahsc->pahsc_InsideCountSum = 0; pahsc->pahsc_TotalCountSum = 0; } } past->past_IfLastExitValid = 1; } pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); past->past_IfLastExitValid = 1; } /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ /*--------------------------------------------------------------------------------------*/ PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */ { /* call to report via ERR_RPT(), yields a PaError-num. */ const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ { case AL_BAD_OUT_OF_MEM: ERR_RPT(("%sout of memory.\n", a)); return paInsufficientMemory; /* Known PaError. */ case AL_BAD_CONFIG: ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_CHANNELS: ERR_RPT(("%schannels not 1,2 or 4.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_NO_PORTS: ERR_RPT(("%sout of audio ports.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_DEVICE: ERR_RPT(("%swrong device number.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_DEVICE_ACCESS: ERR_RPT(("%swrong device access.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_DIRECTION: ERR_RPT(("%sinvalid direction.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_SAMPFMT: ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_FLOATMAX: ERR_RPT(("%smax float value is zero.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_WIDTH: ERR_RPT(("%sunsupported samplewidth.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_QSIZE: ERR_RPT(("%sinvalid queue size.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_PVBUFFER: ERR_RPT(("%sPVbuffer null.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_BUFFERLENGTH_NEG: ERR_RPT(("%snegative bufferlength.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_BUFFERLENGTH_ODD: ERR_RPT(("%sodd bufferlength.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_PARAM: ERR_RPT(("%sparameter not valid for device.\n", a)); return paHostError; /* Generic PaError. */ default: ERR_RPT(("%sunknown error.\n", a)); return paHostError; /* Generic PaError. */ } } /*------------------------------------------------------------------------------------------*/ /* Tries to set various rates and formats and fill in the device info structure. */ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */ PaDeviceID id, /* (DefaultI|ODeviceID()) */ char* name, /* (for example "SGI AL") */ internalPortAudioDevice* pad) /* Result written to pad. */ { long min, max; /* To catch hardware characteristics. */ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ /*--------------------------------------------------------------------------------------*/ pad->pad_ALdevice = ALdev; /* Set the AL device number. */ pad->pad_DeviceID = id; /* Set the PA device number. */ if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ { ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); return paHostError; } strcpy(pad->pad_DeviceName, name); /* Write name-string. */ pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ /*--------------------------------- natively supported sample formats: -----------------*/ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ /* Then also choose other CallConvertXX()! */ /*--------------------------------- number of available i/o channels: ------------------*/ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) return translateSGIerror(); pad->pad_Info.maxInputChannels = max; DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) return translateSGIerror(); pad->pad_Info.maxOutputChannels = max; DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) /*--------------------------------- supported samplerates: ----------------------*/ pad->pad_Info.numSampleRates = 7; pad->pad_Info.sampleRates = pad->pad_SampleRates; pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ pad->pad_SampleRates[1] = (double)AL_RATE_11025; pad->pad_SampleRates[2] = (double)AL_RATE_16000; pad->pad_SampleRates[3] = (double)AL_RATE_22050; pad->pad_SampleRates[4] = (double)AL_RATE_32000; pad->pad_SampleRates[5] = (double)AL_RATE_44100; pad->pad_SampleRates[6] = (double)AL_RATE_48000; if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */ return translateSGIerror(); /* double -> long. */ if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */ goto weird; if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ return translateSGIerror(); if (max != (long)(0.5 + pad->pad_SampleRates[6])) { weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); return paHostError; /* Or make it a warning and just carry on... */ } /*-------------------------------------------------------------------------------*/ return paNoError; } /*--------------------------------------------------------------------------------*/ int Pa_CountDevices() /* Name of this function suggests it only counts and */ { /* is NOT destructive, it however resets whole PA ! */ int numDevices = 0; /* Let 's not do that here. */ internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ #if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */ Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ #endif /* friendly to clients that forgot to initialize PA. */ while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ { numDevices++; currentDevice = currentDevice->pad_Next; } return numDevices; } /*-------------------------------------------------------------------------------*/ static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) { int numDevices = 0; internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ while (pad) /* pad may be NULL, that's ok, return 0. */ { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ if (pad->pad_DeviceID == id) /* This the device we were looking for? */ res = pad; /* But keep on(!) counting so we don't */ numDevices++; /* have to call Pa_CountDevices() later. */ pad = pad->pad_Next; /* Advance to the next device or NULL. */ } /* No assumptions about order of ID's in */ if (!res) /* the list. */ ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); if ((id < 0) || (id >= numDevices)) { ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); #if 1 /* Be strict, even when found, */ res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ #endif } return res; } /*----------------------------------------------------------------------*/ const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) { PaDeviceInfo* res = (PaDeviceInfo*)NULL; internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ if (pad) res = &pad->pad_Info; /* Not finding the specified ID is not */ if (!res) /* the same as &pad->pad_Info == NULL. */ ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); return res; /* So (maybe) a second/third ERR_RPT(). */ } /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultInputDeviceID(void) { return 0; /* 0 is the default device ID. */ } /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultOutputDeviceID(void) { return 0; } /*-------------------------------------------------------------------------------------------------*/ /* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */ PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ { internalPortAudioDevice* pad; PaError r = paNoError; int audioLibFileID; /* To test for the presence of audio. */ if (sDeviceList) /* Allow re-init, only warn, no error. */ { ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); return r; } /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/ audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ if (audioLibFileID < 0) /* IO port. On failure, machine */ { /* has no audio ability. */ ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); return paHostError; } close(audioLibFileID); /* Allocate fast mem to hold device info. */ pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); if (pad == NULL) return paInsufficientMemory; memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ "AL default", /* A suitable name. */ pad); /* Write args and queried info into pad. */ if (r != paNoError) { ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ } else sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ /*---------------------------------------------------------------------------------------------*/ return r; } /*--------------------------------------------------------------------------------------------*/ #define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */ #define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */ #define kPollOUT 1 /* numbers. */ #define kPollIN 2 void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */ { /* as a separate thread. (Argument must be void*). */ short evtLoop; /* Reset by parent indirectly, or at local errors. */ PaError result; struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */ internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument. */ PaHostSoundControl *pahsc; short n, inputEvent, outputEvent, ioEvent, semaEvent = 0; short *inBuffer, *outBuffer; /* Only 16 bit for now, may change... */ unsigned int samplesPerInputUserBuffer, samplesPerOutputUserBuffer; DBUG(("Entering sproc-thread.\n")); if (!past) { sPaHostError = paInternalError; /* Or paBadStreamPtr ? */ ERR_RPT(("argument NULL!\n")); goto noPast; } pahsc = (PaHostSoundControl*)past->past_DeviceData; if (!pahsc) { sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */ ERR_RPT(("past_DeviceData NULL!\n")); goto noPahsc; /* Sproc-ed threads MAY NOT RETURN paInternalError. */ } /*----------------------------- open AL-ports here, after sproc(): -----------------------*/ if (past->past_NumInputChannels > 0) /* Open input port. */ { pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN); if (!pahsc->pahsc_ALportIN) { ERR_RPT(("Failed to open AL input port.\n")); sPaHostError = paInternalError; goto skip; } DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels)); samplesPerInputUserBuffer = pahsc->pahsc_SamplesPerInputHostBuffer / pahsc->pahsc_UserBuffersPerHostBuffer; } else samplesPerInputUserBuffer = 0; /* Added 2003. */ if (past->past_NumOutputChannels > 0) /* Open output port. */ { pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT); if (!pahsc->pahsc_ALportOUT) { ERR_RPT(("Failed to open AL output port.\n")); sPaHostError = paInternalError; /* Assume pahsc_ALconfigs are the */ goto skip; /* same for IN and OUT in case */ } /* both ports are opened (bidir). */ DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels)); samplesPerOutputUserBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer / pahsc->pahsc_UserBuffersPerHostBuffer; DBUG(("samplesPerOutputUserBuffer = %d\n", samplesPerOutputUserBuffer)); } else samplesPerOutputUserBuffer = 0; /* Added 2003. */ /*-----------------------------------------------------------------------*/ past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */ PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */ PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT); PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */ schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */ PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */ PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */ uspsema(SendSema); /* Blocks until ... MUST be here, this uspsema(). */ evtLoop = ((past->past_StopNow | past->past_StopSoon) == 0); while (evtLoop) { /*----------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ---------*/ if (pahsc->pahsc_InputHostBuffer) /* Then pahsc_ALportIN should also be there. */ { /* For input port, fill point is number of locations in the sample queue that must be */ /* filled in order to trigger a return from select(). (or poll()) */ /* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/ if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputHostBuffer)) { /* Multiple amount as transferred per time. */ ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n")); sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ goto skip; } } /* 'else' added march 2003: set only one of both fillpoints: input or output. When */ /* setting both fillpoints (as in earlier version) clicks occur at full duplex-mode. */ else if (pahsc->pahsc_OutputHostBuffer) /* Then pahsc_ALportOUT should also be there. */ { /* For output port, fill point is number of locations that must be free in order to */ /* wake up from select(). (or poll()) */ if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputHostBuffer)) { ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n")); sPaHostError = paInternalError; goto skip; } } /* poll() with timeout=-1 makes it block until a requested */ poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */ /* array <0, events is ignored and revents is set to 0. */ /*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/ semaEvent = PollFD[kPollSEMA].revents & POLLIN; if (semaEvent) { if (past->past_StopSoon) evtLoop = 0; if (past->past_StopNow) goto skip; } /*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/ inputEvent = PollFD[kPollIN].revents & POLLIN; if (inputEvent) /* Don't need to check (pahsc->pahsc_InputHostBuffer): */ { /* if buffer was not there, ALport not there, no events! */ if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_InputHostBuffer, pahsc->pahsc_SamplesPerInputHostBuffer)) { /* Here again: number of samples instead of number of frames. */ ERR_RPT(("ALreadsamps() failed.\n")); sPaHostError = paInternalError; goto skip; } } outputEvent = PollFD[kPollOUT].revents & POLLOUT; ioEvent = (inputEvent | outputEvent); /* Binary or is ok. */ /*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/ if (ioEvent) /* Always true? Or can some other system-event awaken the */ { /* poll? Sure it wasn't just a "sema"- (i.e. user)-event? */ Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ /* user data and call user routine. */ inBuffer = pahsc->pahsc_InputHostBuffer; /* Short pointers for now, care! */ outBuffer = pahsc->pahsc_OutputHostBuffer; n = pahsc->pahsc_UserBuffersPerHostBuffer; /* 'n' may never start at NULL ! */ do { result = Pa_CallConvertInt16(past, inBuffer, outBuffer); if (result) /* This is apparently NOT an error! Just letting the userCallBack stop us. */ { DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); goto skip; } inBuffer += samplesPerInputUserBuffer; /* Num channels is accounted for. */ outBuffer += samplesPerOutputUserBuffer; } while (--n); Pa_EndUsageCalculation(past); } /*------------------------------------ FREE-EVENT FROM OUTPUT BUFFER: ---------------------------*/ if (pahsc->pahsc_OutputHostBuffer && ioEvent) /* Don't wait for outputEvent solely (that may cause clicks). */ { /* Just assume it's time to write, outputEvent may not yet be there. */ if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_OutputHostBuffer, pahsc->pahsc_SamplesPerOutputHostBuffer)) { ERR_RPT(("ALwritesamps() failed.\n")); /* Better use SEMAS for messaging back to parent! */ sPaHostError = paInternalError; goto skip; } } } skip: /*------------------------------- close AL-ports ----------------------------*/ if (pahsc->pahsc_ALportIN) { if (ALcloseport(pahsc->pahsc_ALportIN)) translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ else /* But go on anyway... to release other stuff... */ pahsc->pahsc_ALportIN = (ALport)0; } if (pahsc->pahsc_ALportOUT) { if (ALcloseport(pahsc->pahsc_ALportOUT)) translateSGIerror(); else pahsc->pahsc_ALportOUT = (ALport)0; } noPahsc: past->past_IsActive = 0; if (semaEvent) { uspsema(SendSema); /* StopEngine() was still waiting for this acknowledgement. */ usvsema(RcvSema); /* (semaEvent initialized with 0.) */ } noPast: DBUG(("Leaving sproc-thread.\n")); } /*--------------------------------------------------------------------------------------*/ PaError PaHost_OpenStream(internalPortAudioStream *past) { PaError result = paNoError; PaHostSoundControl *pahsc; unsigned int minNumBuffers; internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ long pvbuf[8], sr, alq; /* To get/set hardware configs. */ DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ if (!past) { ERR_RPT(("Streampointer NULL!\n")); result = paBadStreamPtr; goto done; } pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); if (pahsc == NULL) { ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ } memset(pahsc, 0, sizeof(PaHostSoundControl)); pahsc->pahsc_threadPID = -1; /* Should pahsc_threadPID be inited to */ past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ pvbuf[0] = AL_INPUT_RATE; pvbuf[2] = AL_INPUT_COUNT; pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ pvbuf[6] = AL_OUTPUT_COUNT; sr = (long)(past->past_SampleRate + 0.5); /* Common for both input and output :-) */ /*-----------------------------------------------------------------------------*/ /* OVERWRITE 'past_NumUserBuffers'-field in the struct supplied by the caller. */ /* This field may be set to zero by a client application to ask for minimum */ /* latency. It is used below, to set both input- and output-AL-queuesizes. */ minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, past->past_SampleRate); /* Take biggest. */ past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ? minNumBuffers : past->past_NumUserBuffers; DBUG(("past->past_NumUserBuffers=%d\n", past->past_NumUserBuffers)); /*----------------------------------------------------------------------------------*/ pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers >> 1; DBUG(("pahsc_UserBuffersPerHostBuffer=%d\n",pahsc->pahsc_UserBuffersPerHostBuffer)); /* 1 is minimum because Pa_GetMinNumBuffers() returns >= 2. Callback will be called 'pahsc_UserBuffersPerHostBuffer' times (with 'past_FramesPerUserBuffer') per host transfer. */ /*---------------------------------------------------- SET INPUT CONFIGURATION: ---------------------*/ if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ { /* sponding native AL-number(s). */ /*--------------------------------------------------- Allocate native buffers: --------------*/ pahsc->pahsc_SamplesPerInputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * past->past_FramesPerUserBuffer * /* Needed by the */ past->past_NumInputChannels; /* audio-thread. */ DBUG(("pahsc_SamplesPerInputHostBuffer=%d\n", pahsc->pahsc_SamplesPerInputHostBuffer)); pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_SamplesPerInputHostBuffer * sizeof(short); pahsc->pahsc_InputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer); if (!pahsc->pahsc_InputHostBuffer) { ERR_RPT(("Fast memory allocation failed (in).\n")); result = paInsufficientMemory; goto done; } padIN = Pa_GetInternalDevice(past->past_InputDeviceID); if (!padIN) { ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); result = paHostError; goto done; } if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ goto sgiError; /* the same AL-device, the AL-library might */ if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ { ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ another process is currently using input at %ld Hz.\n", sr, pvbuf[1])); result = paHostError; goto done; } pvbuf[1] = sr; /* Then set input-rate. */ if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */ pahsc->pahsc_ALconfigIN = ALnewconfig(); /* Released at PaHost_CloseStream(). */ if (pahsc->pahsc_ALconfigIN == (ALconfig)0) goto sgiError; if (ALsetsampfmt(pahsc->pahsc_ALconfigIN, AL_SAMPFMT_TWOSCOMP))/* Choose paInt16 as native i/o-format. */ goto sgiError; if (ALsetwidth (pahsc->pahsc_ALconfigIN, AL_SAMPLE_16)) /* Only meaningful when sample format for */ goto sgiError; /* config is set to two's complement format. */ /************************ Future versions might (dynamically) switch to 32-bit floats? ******* if (ALsetsampfmt(pahsc_ALconfigIN, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) goto sgiError; if (ALsetfloatmax (pahsc_ALconfigIN, 1.0)) Only meaningful when sample format for config goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ /*--------- Set internal AL queuesize (in samples, not in frames!) -------------------------------*/ alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumInputChannels; DBUG(("AL input queuesize = %ld samples.\n", alq)); if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, alq)) goto sgiError; if (ALsetchannels (pahsc->pahsc_ALconfigIN, (long)(past->past_NumInputChannels))) goto sgiError; /* Returns 0 on success, -1 on failure. */ } else pahsc->pahsc_InputHostBuffer = (short*)NULL; /* Added 2003! Is checked in callback-routine. */ /*---------------------------------------------------- SET OUTPUT CONFIGURATION: ------------------------*/ if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ { /* We use padOUT/IN later on, or at least 1 of both. */ pahsc->pahsc_SamplesPerOutputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * past->past_FramesPerUserBuffer * /* Needed by the */ past->past_NumOutputChannels; /* audio-thread. */ DBUG(("pahsc_SamplesPerOutputHostBuffer=%d\n", pahsc->pahsc_SamplesPerOutputHostBuffer)); pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer * sizeof(short); pahsc->pahsc_OutputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer); if (!pahsc->pahsc_OutputHostBuffer) { ERR_RPT(("Fast memory allocation failed (out).\n")); result = paInsufficientMemory; goto done; } padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); if (!padOUT) { ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); result = paHostError; goto done; } if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) goto sgiError; if (pvbuf[5] != sr) { /* Output needed and rate different from current harware-rate. */ if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ { ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ another process is currently using output at %ld Hz.\n", sr, pvbuf[5])); result = paHostError; goto done; /* Will free again the inputbuffer */ } /* that was just created above. */ pvbuf[5] = sr; /* Then set output-rate. */ if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) goto sgiError; } pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */ if (pahsc->pahsc_ALconfigOUT == (ALconfig)0) goto sgiError; if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ goto sgiError; if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */ goto sgiError; /* config is set to two's complement format. */ /** Future versions might (dynamically) switch to 32-bit floats. **/ alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumOutputChannels; DBUG(("AL output queuesize = %ld samples.\n", alq)); if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, alq)) goto sgiError; if (ALsetchannels (pahsc->pahsc_ALconfigOUT, (long)(past->past_NumOutputChannels))) goto sgiError; } else pahsc->pahsc_OutputHostBuffer = (short*)NULL; /*----------------------------------------------- TEST DEVICE ID's: --------------------*/ if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */ (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) { ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); result = paHostError; goto done; } goto done; /* (no errors occured) */ sgiError: result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ done: if (result != paNoError) PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ return result; } /*-----------------------------------------------------*/ PaError PaHost_StartOutput(internalPortAudioStream *past) { return paNoError; /* Hmm, not implemented yet? */ } PaError PaHost_StartInput(internalPortAudioStream *past) { return paNoError; } /*------------------------------------------------------------------------------*/ PaError PaHost_StartEngine(internalPortAudioStream *past) { PaHostSoundControl *pahsc; usptr_t *arena; if (!past) /* Test argument. */ { ERR_RPT(("PaHost_StartEngine(NULL)!\n")); return paBadStreamPtr; } pahsc = (PaHostSoundControl*)past->past_DeviceData; if (!pahsc) { ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n")); return paHostError; } past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */ past->past_IsActive = 1; /* Although the pthread_create() function, as well as , may be */ /* available in IRIX, use sproc() on SGI to create audio-background-thread. */ /* (Linux/oss uses pthread_create() instead of __clone() because: */ /* - pthread_create also works for other UNIX systems like Solaris, */ /* - Java HotSpot VM crashes in pthread_setcanceltype() using __clone().) */ usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* (From SGI-AL-examples, file */ arena = usinit(tmpnam(0)); /* motifexample.c, function */ SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */ RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process will be permitted through a semaphore at a time. Values > 1 imply that up to val resources may be simultaneously used, but requests for more than val resources cause the calling process to block until a resource comes free (by a process holding a resource performing a usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */ prctl(PR_SETEXITSIG, 0); /* No not (void*)9, but 0, which doesn't kill the parent! */ /* PR_SETEXITSIG controls whether all members of a share group will be signaled if any one of them leaves the share group (either via exit() or exec()). If 2nd arg, interpreted as an int is 0, then normal IRIX process termination rules apply, namely that the parent is sent a SIGCLD upon death of child, but no indication of death of parent is given. If the second argument is a valid signal number then if any member of a share group leaves the share group, a signal is sent to ALL surviving members of the share group. */ /* SPAWN AUDIO-CHILD: */ pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */ PR_SALL, /* new process, or -1. */ (void*)past); /* Pass past as optional */ /* IS THIS SAFE, will past never */ if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ /* be moved around in memory???? */ { ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); sPaHostError = oserror(); /* Pass native error-number to shared area. */ return paHostError; /* But return the generic error-number. */ } return paNoError; /* Hmmm, errno may come from other threads in same group! */ } /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */ /*------------------------------------------------------------------------------*/ PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) { PaError result = paNoError; PaHostSoundControl *pahsc; DBUG(("PaHost_StopEngine() called.\n")); if (!past) return paBadStreamPtr; pahsc = (PaHostSoundControl*)past->past_DeviceData; /* Prevent from doing this twice!! */ if ((!pahsc) || /* Some tests call this CLOSE twice!! */ (!past->past_IsActive) || past->past_StopSoon || past->past_StopNow) return result; /* paNoError (already stopped, no err?). */ past->past_StopSoon = 1; /* Tell background thread to stop generating */ if (abort) /* more and to let current data play out. If */ past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/ usvsema(SendSema); /* Increments count associated with SendSema. */ /* Wait for the response. */ uspsema(RcvSema); /* Decrements count of previously allocated */ /* semaphore specified by RcvSema. */ while (past->past_IsActive) /* REALLY WAIT. */ { /* DBUG(("wait 1 ms for audio-thread to stop.\n")); */ Pa_Sleep(1); } #if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */ if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */ { DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n")); if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */ { /* Returns -1 in case of error. */ result = paHostError; sPaHostError = oserror(); /* Hmmm, other threads may also write here! */ ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n")); } else pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */ } #endif past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */ return result; } /*---------------------------------------------------------------*/ PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) { return paNoError; /* Not implemented yet? */ } PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) { return paNoError; } /*******************************************************************/ PaError PaHost_CloseStream(internalPortAudioStream *past) { PaHostSoundControl *pahsc; PaError result = paNoError; DBUG(("PaHost_CloseStream() called.\n")); if (!past) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ return result; /* This test prevents from freeing NULL-pointers. */ if (pahsc->pahsc_ALconfigIN) { /* Release configuration structs, only if allocated. */ ALfreeconfig(pahsc->pahsc_ALconfigIN); pahsc->pahsc_ALconfigIN = NULL; } if (pahsc->pahsc_ALconfigOUT) { ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */ pahsc->pahsc_ALconfigOUT = NULL; } if (pahsc->pahsc_InputHostBuffer) { PaHost_FreeFastMemory(pahsc->pahsc_InputHostBuffer, pahsc->pahsc_BytesPerInputHostBuffer); pahsc->pahsc_InputHostBuffer = NULL; } if (pahsc->pahsc_OutputHostBuffer) { PaHost_FreeFastMemory(pahsc->pahsc_OutputHostBuffer, pahsc->pahsc_BytesPerOutputHostBuffer); pahsc->pahsc_OutputHostBuffer = NULL; } PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */ return result; } /*------------------------------------------------------------------------*/ /* Determine minimum number of buffers required for (SGI) host based on */ /* minimum latency. Latency can be optionally set by user by setting an */ /* environment variable. For example, to set my latency to 200 msec, I've */ /* put this line in my '.cshrc' file: setenv PA_MIN_LATENCY_MSEC 200 */ /* It always calls the 'PRINT' macro. */ /* The minimum number that is returned is 2. */ /* This number is directly proportional to the AL-queue sizes to set up. */ /* It is one more than the number of user buffers per host buffer - in */ /* case minimum is returned, or, twice the user buffers per host buffer. */ /*------------------------------------------------------------------------*/ int Pa_GetMinNumBuffers(int framesPerUserBuffer, double framesPerSecond) { int minBuffers, minLatencyMsec; char *minLatencyText; double actualLatency; minLatencyText = getenv(PA_LATENCY_ENV_NAME); /* Defined at top of file. */ if (minLatencyText) { minLatencyMsec = atoi(minLatencyText); if (minLatencyMsec < 10) { /* 10 is the minimum. */ minLatencyMsec = 10; PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' below minimum of %d milliseconds.\n", minLatencyMsec)); } else if (minLatencyMsec > 4000) { /* 4000 is the maximum. */ minLatencyMsec = 4000; PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' above maximum of %d milliseconds.\n", minLatencyMsec)); } else PRINT (("Using environment variable 'PA_MIN_LATENCY_MSEC' (set to %d milliseconds).\n", minLatencyMsec)); } else { minLatencyMsec = MIN_LATENCY_MSEC; /* Defined at top of this file. */ PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' not found.\nUsing default of %d milliseconds\n", minLatencyMsec)); } minBuffers = (int)((minLatencyMsec * framesPerSecond) / (1000.0 * framesPerUserBuffer)); if (minBuffers < 2) minBuffers = 2; actualLatency = 1000.0 * minBuffers * framesPerUserBuffer / framesPerSecond; PRINT (("Actual AL latency set to %.2f milliseconds\n", actualLatency)); return minBuffers; } /*---------------------------------------------------------------------*/ PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ { /* Called by Pa_Terminate() from pa_lib.c. */ internalPortAudioDevice *pad = sDeviceList, *nxt; while (pad) { DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); nxt = pad->pad_Next; PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); pad = nxt; /* PaHost_Init allocated this fast mem.*/ } sDeviceList = (internalPortAudioDevice*)NULL; return 0; } /***********************************************************************/ void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ { #if 0 struct timeval timeout; timeout.tv_sec = msec / 1000; timeout.tv_usec = (msec % 1000) * 1000; select(0, NULL, NULL, NULL, &timeout); #else long usecs = msec * 1000; usleep( usecs ); #endif } /*---------------------------------------------------------------------------------------*/ /* Allocate memory that can be accessed in real-time. This may need to be held in physi- */ /* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */ /* a call to PaHost_FreeFastMemory(). */ void *PaHost_AllocateFastMemory(long numBytes) { void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */ if (addr) /* range and locks the pages into memory. A counter */ { /* is incremented each time the page is locked. The */ if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */ { /* others are limited to the configurable PLOCK_MA. */ ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n")); #if 1 free(addr); /* You MAY cut out these 2 lines to be less strict, */ addr = NULL; /* you then only get the warning but PA goes on... */ #endif /* Only problem then may be corresponding munpin() */ } /* call at PaHost_FreeFastMemory(), below. */ memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */ } /* a child process after a fork. Furthermore, IRIX- */ return addr; /* man-pages warn against mixing both mpin and mlock */ } /* in 1 piece of code, so stick to mpin()/munpin() ! */ /*---------------------------------------------------------------------------------------*/ /* Free memory that could be accessed in real-time. This call MUST be balanced with a */ /* call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory(void *addr, long numBytes) { if (addr) { if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */ ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n")); free(addr); /* But go on, try to release it, just warn... */ } } /*----------------------------------------------------------*/ PaError PaHost_StreamActive( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; if (past == NULL) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if (pahsc == NULL) return paInternalError; return (PaError)(past->past_IsActive != 0); } /*-------------------------------------------------------------------*/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *past = (internalPortAudioStream *) stream; /* FIXME - return actual frames played, not frames generated. ** Need to query the output device somehow. */ return past->past_FrameCount; } portaudio-18.1.orig/pa_sgi/pthread-Makefile0000644000175000017500000000500507464762142021501 0ustar mikaelmikael00000000000000# Make PortAudio for Silicon Graphics IRIX (6.2) # Pieter suurmond, september 22, 2001. (v15 pa_sgi sub-version #0.18) # pthread, math (as with linux) and SGI audio library: # SGI-books say -lpthread should be the last on the line. LIBS = -lm -laudio -lpthread CDEFINES = -I../pa_common # Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64, # -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging. # And use for example -O2 or -O3 for better optimization: CFLAGS = -O2 PASRC = ../pa_common/pa_lib.c pa_sgi.c PAINC = ../pa_common/portaudio.h # Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). #TESTC = $(PASRC) ../pa_tests/patest_record.c # OK #TESTC = $(PASRC) ../pa_tests/patest_many.c # OK #TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK #TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches. TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?). #TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK #TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK #TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK #TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK #TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK #TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK #TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK #TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK #TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK #TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK #TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. # Tests that do not yet work. #TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default #TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default #TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS FUZZ CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-( # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH. # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON??? # ANYWAY, I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS! TESTH = $(PAINC) all: patest # "cc" for the MIPSpro compiler, may be changed to "gcc": patest: $(TESTC) $(TESTH) Makefile cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest run: patest ./patest portaudio-18.1.orig/pa_sgi/pthread-pa_sgi.c0000644000175000017500000013321607464762142021455 0ustar mikaelmikael00000000000000/* * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * SGI IRIX implementation by Pieter Suurmond, september 22, 2001 (#0.18). * * Copyright (c) 1999-2001 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Modfication History: 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. 8/17/2001 - alpha release with IRIX sproc()-method, may sometimes let IRIX6.2 crash at closing audiostream. 9/22/2001 - #0.18 pthread starts to work a bit: BUT UNDER IRIX6.2, I DON'T GET IT TO WORK REALLY CORRECTLY, this POSIX-attempt, DON'T USE THIS FILE FOR RELIABLE OPERATION, IT IS HERE JUST FOR DOCUMENTATION/ARCHIVE... OR FOR ANYONE WHO WANTS TO FIX...... TODO: - Test under IRIX 6.5. - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), and maybe also the other natively supported formats? (might increase performance) - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet, seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?) - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4. REFERENCES: - IRIX 6.2 man pages regarding SGI AL library. - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and may not be publically available on the internet). */ #include /* Standard libraries. */ #include #include "../pa_common/portaudio.h" /* Portaudio headers. */ #include "../pa_common/pa_host.h" #include "../pa_common/pa_trace.h" /* #include #include #include Not needed #include #include #include #include Needed? #include #include sched_param struct and related functions used in setting thread priorities. #include Some POSIX constants such as _POSIX_THREAD_THREADS_MAX */ #include /* Pthreads are supported by IRIX 6.2 after */ /* patches 1361, 1367, and 1429 are applied. */ #include /* fcntl.h needed for "O_RDONLY". */ #include /* For usleep() and constants used when calling sysconf() */ /* to query POSIX limits (see the sysconf(3) ref. page. */ #include /* SGI-specific audio library. */ /*--------------------------------------------*/ #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) PRINT(x) #define DBUGX(x) /* PRINT(x) */ #define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */ #define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */ typedef struct internalPortAudioDevice /* IRIX specific device info: */ { PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ long pad_ALdevice; /* SGI-number! */ double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ /* int structVersion; */ /* const char* name; */ /* int maxInputChannels, maxOutputChannels; */ /* int numSampleRates; Num rates, or -1 if range supprtd. */ /* const double* sampleRates; Array of supported sample rates, */ /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ } internalPortAudioDevice; typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */ { ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ pthread_t pahsc_ThreadPID; short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ *pahsc_NativeOutputBuffer; unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ pahsc_LastExitTime; long pahsc_InsideCountSum, pahsc_TotalCountSum; } PaHostSoundControl; /*----------------------------- Shared Data ------------------------------------------------------*/ static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ long Pa_GetHostError(void) { return (long)sPaHostError; } /*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ /* (copied from source pa_linux_oss/pa_linux_oss.c) */ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { struct itimerval itimer; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); } static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) { long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; long usecs = secs * 1000000; usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); return usecs; } static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { struct itimerval currentTime; long insideCount; long totalCount; /* Measure CPU utilization during this callback. */ #define LOWPASS_COEFFICIENT_0 (0.95) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if (pahsc == NULL) return; if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) { if (past->past_IfLastExitValid) { insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); pahsc->pahsc_InsideCountSum += insideCount; totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); pahsc->pahsc_TotalCountSum += totalCount; /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ /* Low pass filter the result because sometimes we get called several times in a row. */ /* That can cause the TotalCount to be very low which can cause the usage to appear */ /* unnaturally high. So we must filter numerator and denominator separately!!! */ if (pahsc->pahsc_InsideCountSum > 0) { past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; pahsc->pahsc_InsideCountSum = 0; pahsc->pahsc_TotalCountSum = 0; } } past->past_IfLastExitValid = 1; } pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); past->past_IfLastExitValid = 1; } /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ /*--------------------------------------------------------------------------------------*/ PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */ { /* call to report via ERR_RPT(), yields a PaError-num. */ const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ { case AL_BAD_OUT_OF_MEM: ERR_RPT(("%sout of memory.\n", a)); return paInsufficientMemory; /* Known PaError. */ case AL_BAD_CONFIG: ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_CHANNELS: ERR_RPT(("%schannels not 1,2 or 4.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_NO_PORTS: ERR_RPT(("%sout of audio ports.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_DEVICE: ERR_RPT(("%swrong device number.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_DEVICE_ACCESS: ERR_RPT(("%swrong device access.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_DIRECTION: ERR_RPT(("%sinvalid direction.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_SAMPFMT: ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_FLOATMAX: ERR_RPT(("%smax float value is zero.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_WIDTH: ERR_RPT(("%sunsupported samplewidth.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_QSIZE: ERR_RPT(("%sinvalid queue size.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_PVBUFFER: ERR_RPT(("%sPVbuffer null.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_BUFFERLENGTH_NEG: ERR_RPT(("%snegative bufferlength.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_BUFFERLENGTH_ODD: ERR_RPT(("%sodd bufferlength.\n", a)); return paHostError; /* Generic PaError. */ case AL_BAD_PARAM: ERR_RPT(("%sparameter not valid for device.\n", a)); return paHostError; /* Generic PaError. */ default: ERR_RPT(("%sunknown error.\n", a)); return paHostError; /* Generic PaError. */ } } /*------------------------------------------------------------------------------------------*/ /* Tries to set various rates and formats and fill in the device info structure. */ static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */ PaDeviceID id, /* (DefaultI|ODeviceID()) */ char* name, /* (for example "SGI AL") */ internalPortAudioDevice* pad) /* Result written to pad. */ { int format; long min, max; /* To catch hardware characteristics. */ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ /*--------------------------------------------------------------------------------------*/ pad->pad_ALdevice = ALdev; /* Set the AL device number. */ pad->pad_DeviceID = id; /* Set the PA device number. */ if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ { ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); return paHostError; } strcpy(pad->pad_DeviceName, name); /* Write name-string. */ pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ /*--------------------------------- natively supported sample formats: -----------------*/ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ /* Then also choose other CallConvertXX()! */ /*--------------------------------- number of available i/o channels: ------------------*/ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) return translateSGIerror(); pad->pad_Info.maxInputChannels = max; DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) return translateSGIerror(); pad->pad_Info.maxOutputChannels = max; DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) /*--------------------------------- supported samplerates: ----------------------*/ pad->pad_Info.numSampleRates = 7; pad->pad_Info.sampleRates = pad->pad_SampleRates; pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ pad->pad_SampleRates[1] = (double)AL_RATE_11025; pad->pad_SampleRates[2] = (double)AL_RATE_16000; pad->pad_SampleRates[3] = (double)AL_RATE_22050; pad->pad_SampleRates[4] = (double)AL_RATE_32000; pad->pad_SampleRates[5] = (double)AL_RATE_44100; pad->pad_SampleRates[6] = (double)AL_RATE_48000; if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */ return translateSGIerror(); /* double -> long. */ if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */ goto weird; if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ return translateSGIerror(); if (max != (long)(0.5 + pad->pad_SampleRates[6])) { weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); return paHostError; /* Or make it a warning and just carry on... */ } /*-------------------------------------------------------------------------------*/ return paNoError; } /*--------------------------------------------------------------------------------*/ int Pa_CountDevices() /* Name of this function suggests it only counts and */ { /* is NOT destructive, it however resets whole PA ! */ int numDevices = 0; /* Let 's not do that here. */ internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ #if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */ Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ #endif /* friendly to clients that forgot to initialize PA. */ while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ { numDevices++; currentDevice = currentDevice->pad_Next; } return numDevices; } /*-------------------------------------------------------------------------------*/ static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) { int numDevices = 0; internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ while (pad) /* pad may be NULL, that's ok, return 0. */ { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ if (pad->pad_DeviceID == id) /* This the device we were looking for? */ res = pad; /* But keep on(!) counting so we don't */ numDevices++; /* have to call Pa_CountDevices() later. */ pad = pad->pad_Next; /* Advance to the next device or NULL. */ } /* No assumptions about order of ID's in */ if (!res) /* the list. */ ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); if ((id < 0) || (id >= numDevices)) { ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); #if 1 /* Be strict, even when found, */ res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ #endif } return res; } /*----------------------------------------------------------------------*/ const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) { PaDeviceInfo* res = (PaDeviceInfo*)NULL; internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ if (pad) res = &pad->pad_Info; /* Not finding the specified ID is not */ if (!res) /* the same as &pad->pad_Info == NULL. */ ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); return res; /* So (maybe) a second/third ERR_RPT(). */ } /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultInputDeviceID(void) { return 0; /* 0 is the default device ID. */ } /*------------------------------------------------*/ PaDeviceID Pa_GetDefaultOutputDeviceID(void) { return 0; } /*-------------------------------------------------------------------------------------------------*/ /* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */ PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ { internalPortAudioDevice* pad; PaError r = paNoError; int audioLibFileID; /* To test for the presence of audio. */ if (sDeviceList) /* Allow re-init, only warn, no error. */ { ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); return r; } /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/ audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ if (audioLibFileID < 0) /* IO port. On failure, machine */ { /* has no audio ability. */ ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); return paHostError; } close(audioLibFileID); /* Allocate fast mem to hold device info. */ pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); if (pad == NULL) return paInsufficientMemory; memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ "AL default", /* A suitable name. */ pad); /* Write args and queried info into pad. */ if (r != paNoError) { ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ } else sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ /*---------------------------------------------------------------------------------------------*/ return r; } /*---------------------------------------------------------------------------------------------------*/ static PaError Pa_SgiAudioProcess(internalPortAudioStream *past) /* Spawned by PaHost_StartEngine(). */ { PaError result = paNoError; PaHostSoundControl *pahsc; if (!past) return paBadStreamPtr; pahsc = (PaHostSoundControl*)past->past_DeviceData; if (!pahsc) return paInternalError; past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ DBUG(("entering thread.\n")); while (!past->past_StopSoon) /* OR-ing StopSoon and StopNow here gives problems! */ { /*---------------------------------------- INPUT: ------------------------------------*/ if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */ { while (ALgetfilled(pahsc->pahsc_ALportIN) < pahsc->pahsc_SamplesPerInputBuffer) { /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */ if (past->past_StopNow) /* Don't let ALreadsamps() block */ goto done; } if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_SamplesPerInputBuffer)) /* Number of samples instead */ { /* of number of frames. */ ERR_RPT(("ALreadsamps() failed.\n")); result = paInternalError; goto done; } } /*---------------------------------------------------- USER CALLBACK ROUTINE: ----------*/ /* DBUG(("Calling Pa_CallConvertInt16()...\n")); */ Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ result = Pa_CallConvertInt16(past, /* user data and call user routine. */ pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer); Pa_EndUsageCalculation(past); if (result) { DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); goto done; /* This is apparently NOT an error! */ } /* Just letting the userCallBack stop us. */ /*---------------------------------------- OUTPUT: ------------------------------------*/ if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */ { while (ALgetfillable(pahsc->pahsc_ALportOUT) < pahsc->pahsc_SamplesPerOutputBuffer) { /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */ if (past->past_StopNow) /* Don't let ALwritesamps() block */ goto done; } if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_SamplesPerOutputBuffer)) { ERR_RPT(("ALwritesamps() failed.\n")); result = paInternalError; goto done; } } /*-------------------------------------------------------------------------------------*/ } done: /* pahsc->pahsc_ThreadPID = -1; Hu? doesn't help!! (added by Pieter) */ past->past_IsActive = 0; DBUG(("leaving thread.\n")); return result; } /*--------------------------------------------------------------------------------------*/ PaError PaHost_OpenStream(internalPortAudioStream *past) { PaError result = paNoError; PaHostSoundControl *pahsc; unsigned int minNumBuffers; internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ ALconfig sgiALconfig = NULL; /* IRIX-datatype. */ long pvbuf[8]; /* To get/set hardware configs. */ long sr, ALqsize; DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ if (!past) { ERR_RPT(("Streampointer NULL!\n")); result = paBadStreamPtr; goto done; } pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); if (pahsc == NULL) { ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ } memset(pahsc, 0, sizeof(PaHostSoundControl)); /* pahsc->pahsc_threadPID = -1; Should pahsc_threadPID be inited to */ past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ /*--------------------------------------------------- Allocate native buffers: --------*/ pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ past->past_NumInputChannels; /* audio-thread. */ pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */ { pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer); if( pahsc->pahsc_NativeInputBuffer == NULL ) { ERR_RPT(("Fast memory allocation for input-buffer failed.\n")); result = paInsufficientMemory; goto done; } } pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ past->past_NumOutputChannels; /* audio-thread. */ pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */ { pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer); if (pahsc->pahsc_NativeOutputBuffer == NULL) { ERR_RPT(("Fast memory allocation for output-buffer failed.\n")); result = paInsufficientMemory; goto done; } } /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ ALseterrorhandler(0); /* 0 = turn off the default error handler. */ pvbuf[0] = AL_INPUT_RATE; pvbuf[2] = AL_INPUT_COUNT; pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ pvbuf[6] = AL_OUTPUT_COUNT; sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */ if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ { /* sponding native AL-number(s). */ padIN = Pa_GetInternalDevice(past->past_InputDeviceID); if (!padIN) { ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); result = paHostError; goto done; } if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ goto sgiError; /* the same AL-device, the AL-library might */ if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ { ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); result = paHostError; goto done; } pvbuf[1] = sr; /* Then set input-rate. */ if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */ } if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ { /* We use padOUT/IN later on, or at least 1 of both. */ padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); if (!padOUT) { ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); result = paHostError; goto done; } if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) goto sgiError; if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr)) { /* Output needed and rate different from current harware-rate. */ if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ { ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); result = paHostError; goto done; /* Will free again the inputbuffer */ } /* that was just created above. */ pvbuf[5] = sr; /* Then set output-rate. */ if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) goto sgiError; } } /*------------------------------------------ Construct an audio-port-configuration ----------*/ sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */ if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */ goto sgiError; /* See that sgiALconfig is NOT released! */ if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ goto sgiError; if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */ goto sgiError; /* config is set to two's complement format. */ /************************ Future versions might (dynamically) switch to 32-bit floats? ******* if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) goto sgiError; if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ /*---------- ?? --------------------*/ /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */ minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, past->past_SampleRate); past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ? minNumBuffers : past->past_NumUserBuffers; /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/ if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer) ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer; else /* Take the largest of the two amounts. */ ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer; ALqsize *= 4; /* 4 times as large as amount per transfer! */ if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */ goto sgiError; /* Using 2 times may give glitches... */ /* Have to work on ALsetqueuesize() above. */ /* Do ALsetchannels() later, apart per input and/or output. */ /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/ if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */ { if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) { DBUG(("PaHost_OpenStream: opening both input and output channels.\n")); /*------------------------- open output port: ----------------------------------*/ if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) goto sgiError; /* Returns 0 on success, -1 on failure. */ pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); if (pahsc->pahsc_ALportOUT == (ALport)0) goto sgiError; /*------------------------- open input port: -----------------------------------*/ if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) goto sgiError; /* Returns 0 on success, -1 on failure. */ pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); if (pahsc->pahsc_ALportIN == (ALport)0) goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */ } /* Probably due to too small buffersizes?.... */ else { ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); result = paHostError; goto done; } } else /* (OutputDeviceID != InputDeviceID) */ { if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */ { /*------------------------- open output port: ----------------------------------*/ DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n", past->past_NumOutputChannels, padOUT->pad_DeviceName)); if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) goto sgiError; /* Returns 0 on success, -1 on failure. */ pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); if (pahsc->pahsc_ALportOUT == (ALport)0) goto sgiError; } if (past->past_NumInputChannels > 0) /* READ-ONLY: */ { /*------------------------- open input port: -----------------------------------*/ DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n", past->past_NumInputChannels, padIN->pad_DeviceName)); if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) goto sgiError; /* Returns 0 on success, -1 on failure. */ pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); if (pahsc->pahsc_ALportIN == (ALport)0) goto sgiError; } } DBUG(("PaHost_OpenStream() succeeded.\n")); goto done; /* (no errors occured) */ sgiError: result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ done: if (sgiALconfig) ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */ if (result != paNoError) PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ return result; } /*-----------------------------------------------------*/ PaError PaHost_StartOutput(internalPortAudioStream *past) { return paNoError; /* Hmm, not implemented yet? */ } PaError PaHost_StartInput(internalPortAudioStream *past) { return paNoError; } /*------------------------------------------------------------------------------*/ PaError PaHost_StartEngine(internalPortAudioStream *past) { PaHostSoundControl *pahsc; int hres; PaError result = paNoError; if (!past) /* Test argument. */ { ERR_RPT(("PaHost_StartEngine(NULL)!\n")); return paBadStreamPtr; } pahsc = (PaHostSoundControl*)past->past_DeviceData; if (!pahsc) { ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData == NULL!\n")); return paHostError; } past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ past->past_StopNow = 0; past->past_IsActive = 1; DBUG(("PaHost_StartEngine() called.\n")); /* Use pthread_create() instead of __clone() because: */ /* - pthread_create also works for other UNIX systems like Solaris, */ /* - Java HotSpot VM crashes in pthread_setcanceltype() when using __clone(). */ hres = pthread_create(&(pahsc->pahsc_ThreadPID), /* SPAWN AUDIO-CHILD. */ NULL, /* pthread_attr_t * attr */ (void*)Pa_SgiAudioProcess, past); if (hres) { result = paHostError; sPaHostError = hres; ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); } return result; } /*------------------------------------------------------------------------------*/ PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) { int hres; PaError result = paNoError; PaHostSoundControl *pahsc; DBUG(("PaHost_StopEngine() called.\n")); if (!past) return paBadStreamPtr; pahsc = (PaHostSoundControl*)past->past_DeviceData; if (pahsc == NULL) return result; /* paNoError (already stopped, no err?). */ past->past_StopSoon = 1; /* Tell background thread to stop generating */ if (abort) /* more and to let current data play out. If */ past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ if (pahsc->pahsc_ThreadPID != -1) /* Join thread to recover memory resources. */ { DBUG(("pthread_join() called.\n")); hres = pthread_join(pahsc->pahsc_ThreadPID, NULL); if (hres) { result = paHostError; sPaHostError = hres; ERR_RPT(("PaHost_StopEngine() failed pthread_join().\n")); } pahsc->pahsc_ThreadPID = -1; } past->past_IsActive = 0; return result; } /*---------------------------------------------------------------*/ PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) { return paNoError; /* Not implemented yet? */ } PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) { return paNoError; } /*******************************************************************/ PaError PaHost_CloseStream(internalPortAudioStream *past) { PaHostSoundControl *pahsc; PaError result = paNoError; DBUG(("PaHost_CloseStream() called.\n")); if (past == NULL) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ return result; /* This test prevents from freeing NULL-pointers. */ if (pahsc->pahsc_ALportIN) { if (ALcloseport(pahsc->pahsc_ALportIN)) result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ else /* But go on anyway... to release other stuff... */ pahsc->pahsc_ALportIN = (ALport)0; } if (pahsc->pahsc_ALportOUT) { if (ALcloseport(pahsc->pahsc_ALportOUT)) result = translateSGIerror(); else pahsc->pahsc_ALportOUT = (ALport)0; } if (pahsc->pahsc_NativeInputBuffer) { PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer); pahsc->pahsc_NativeInputBuffer = NULL; } if (pahsc->pahsc_NativeOutputBuffer) { PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); pahsc->pahsc_NativeOutputBuffer = NULL; } PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST. */ return result; } /************************************************************************* ** Determine minimum number of buffers required for this host based ** on minimum latency. Latency can be optionally set by user by setting ** an environment variable. For example, to set latency to 200 msec, put: ** set PA_MIN_LATENCY_MSEC=200 ** in the AUTOEXEC.BAT file and reboot. ** If the environment variable is not set, then the latency will be ** determined based on the OS. Windows NT has higher latency than Win95. */ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) { return 2; } /* Hmmm, the note above isn't appropriate for SGI I'm afraid... */ /* Do we HAVE to do it this way under IRIX???.... */ /*--------------------------------------------------------------*/ /*---------------------------------------------------------------------*/ PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ { /* Called by Pa_Terminate() from pa_lib.c. */ internalPortAudioDevice *pad = sDeviceList, *nxt; while (pad) { DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); nxt = pad->pad_Next; PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ } sDeviceList = (internalPortAudioDevice*)NULL; return 0; /* Got rid of sNumDevices=0; */ } /***********************************************************************/ void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ { #if 0 struct timeval timeout; timeout.tv_sec = msec / 1000; timeout.tv_usec = (msec % 1000) * 1000; select(0, NULL, NULL, NULL, &timeout); #else long usecs = msec * 1000; usleep( usecs ); #endif } /*---------------------------------------------------------------------------------------*/ /* Allocate memory that can be accessed in real-time. This may need to be held in physi- */ /* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */ /* a call to PaHost_FreeFastMemory(). */ void *PaHost_AllocateFastMemory(long numBytes) { void *addr = malloc(numBytes); if (addr) memset(addr, 0, numBytes); return addr; } /*---------------------------------------------------------------------------------------*/ /* Free memory that could be accessed in real-time. This call MUST be balanced with a */ /* call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory(void *addr, long numBytes) { if (addr) free(addr); } /*----------------------------------------------------------*/ PaError PaHost_StreamActive (internalPortAudioStream *past) { PaHostSoundControl *pahsc; if (past == NULL) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if (pahsc == NULL) return paInternalError; return (PaError)(past->past_IsActive != 0); } /*-------------------------------------------------------------------*/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *past = (internalPortAudioStream *) stream; /* FIXME - return actual frames played, not frames generated. ** Need to query the output device somehow. */ return past->past_FrameCount; } portaudio-18.1.orig/pablio/0000755000175000000620000000000007700016422016236 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pablio/pablio.c0000644000175000017500000002623607634047502020036 0ustar mikaelmikael00000000000000/* * $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $ * pablio.c * Portable Audio Blocking Input/Output utility. * * Author: Phil Burk, http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* History: * PLB021214 - check for valid stream in CloseAudioStream() to prevent hang. * add timeOutMSec to CloseAudioStream() to prevent hang. */ #include #include #include #include "portaudio.h" #include "ringbuffer.h" #include "pablio.h" #include /************************************************************************/ /******** Constants *****************************************************/ /************************************************************************/ #define FRAMES_PER_BUFFER (256) /************************************************************************/ /******** Prototypes ****************************************************/ /************************************************************************/ static int blockingIOCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame ); static PaError PABLIO_TermFIFO( RingBuffer *rbuf ); /************************************************************************/ /******** Functions *****************************************************/ /************************************************************************/ /* Called from PortAudio. * Read and write data only if there is room in FIFOs. */ static int blockingIOCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { PABLIO_Stream *data = (PABLIO_Stream*)userData; long numBytes = data->bytesPerFrame * framesPerBuffer; (void) outTime; /* This may get called with NULL inputBuffer during initial setup. */ if( inputBuffer != NULL ) { RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes ); } if( outputBuffer != NULL ) { int i; int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes ); /* Zero out remainder of buffer if we run out of data. */ for( i=numRead; ibuffer ) free( rbuf->buffer ); rbuf->buffer = NULL; return paNoError; } /************************************************************ * Write data to ring buffer. * Will not return until all the data has been written. */ long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) { long bytesWritten; char *p = (char *) data; long numBytes = aStream->bytesPerFrame * numFrames; while( numBytes > 0) { bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes ); numBytes -= bytesWritten; p += bytesWritten; if( numBytes > 0) Pa_Sleep(10); } return numFrames; } /************************************************************ * Read data from ring buffer. * Will not return until all the data has been read. */ long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) { long bytesRead; char *p = (char *) data; long numBytes = aStream->bytesPerFrame * numFrames; while( numBytes > 0) { bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes ); numBytes -= bytesRead; p += bytesRead; if( numBytes > 0) Pa_Sleep(10); } return numFrames; } /************************************************************ * Return the number of frames that could be written to the stream without * having to wait. */ long GetAudioStreamWriteable( PABLIO_Stream *aStream ) { int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); return bytesEmpty / aStream->bytesPerFrame; } /************************************************************ * Return the number of frames that are available to be read from the * stream without having to wait. */ long GetAudioStreamReadable( PABLIO_Stream *aStream ) { int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO ); return bytesFull / aStream->bytesPerFrame; } /************************************************************/ static unsigned long RoundUpToNextPowerOf2( unsigned long n ) { long numBits = 0; if( ((n-1) & n) == 0) return n; /* Already Power of two. */ while( n > 0 ) { n= n>>1; numBits++; } return (1<samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2; aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame; /* Initialize PortAudio */ err = Pa_Initialize(); if( err != paNoError ) goto error; /* Warning: numFrames must be larger than amount of data processed per interrupt * inside PA to prevent glitches. Just to be safe, adjust size upwards. */ minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); numFrames = minNumBuffers * FRAMES_PER_BUFFER; /* The PortAudio callback runs in a high priority thread. But PABLIO * runs in a normal foreground thread. So we may have much worse * latency in PABLIO. So adjust latency to a safe level. */ { const int safeLatencyMSec = 200; int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate); if( minLatencyMSec < safeLatencyMSec ) { numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000); } } numFrames = RoundUpToNextPowerOf2( numFrames ); /* Initialize Ring Buffers */ doRead = ((flags & PABLIO_READ) != 0); doWrite = ((flags & PABLIO_WRITE) != 0); if(doRead) { err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame ); if( err != paNoError ) goto error; } if(doWrite) { long numBytes; err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame ); if( err != paNoError ) goto error; /* Make Write FIFO appear full initially. */ numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes ); } /* Open a PortAudio stream that we will use to communicate with the underlying * audio drivers. */ err = Pa_OpenStream( &aStream->stream, (doRead ? Pa_GetDefaultInputDeviceID() : paNoDevice), (doRead ? aStream->samplesPerFrame : 0 ), format, NULL, (doWrite ? Pa_GetDefaultOutputDeviceID() : paNoDevice), (doWrite ? aStream->samplesPerFrame : 0 ), format, NULL, sampleRate, FRAMES_PER_BUFFER, minNumBuffers, paClipOff, /* we won't output out of range samples so don't bother clipping them */ blockingIOCallback, aStream ); if( err != paNoError ) goto error; err = Pa_StartStream( aStream->stream ); if( err != paNoError ) goto error; *rwblPtr = aStream; return paNoError; error: CloseAudioStream( aStream ); *rwblPtr = NULL; return err; } /************************************************************/ PaError CloseAudioStream( PABLIO_Stream *aStream ) { PaError err = paNoError; int bytesEmpty; int byteSize = aStream->outFIFO.bufferSize; if( aStream->stream != NULL ) /* Make sure stream was opened. PLB021214 */ { /* If we are writing data, make sure we play everything written. */ if( byteSize > 0 ) { int timeOutMSec = 2000; bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); while( (bytesEmpty < byteSize) && (timeOutMSec > 0) ) { Pa_Sleep( 20 ); timeOutMSec -= 20; bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); } } err = Pa_StopStream( aStream->stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( aStream->stream ); } error: Pa_Terminate(); PABLIO_TermFIFO( &aStream->inFIFO ); PABLIO_TermFIFO( &aStream->outFIFO ); free( aStream ); return err; } portaudio-18.1.orig/pablio/pablio.h0000644000175000017500000000736407423043546020044 0ustar mikaelmikael00000000000000#ifndef _PABLIO_H #define _PABLIO_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $ * PABLIO.h * Portable Audio Blocking read/write utility. * * Author: Phil Burk, http://www.softsynth.com/portaudio/ * * Include file for PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "portaudio.h" #include "ringbuffer.h" #include typedef struct { RingBuffer inFIFO; RingBuffer outFIFO; PortAudioStream *stream; int bytesPerFrame; int samplesPerFrame; } PABLIO_Stream; /* Values for flags for OpenAudioStream(). */ #define PABLIO_READ (1<<0) #define PABLIO_WRITE (1<<1) #define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE) #define PABLIO_MONO (1<<2) #define PABLIO_STEREO (1<<3) /************************************************************ * Write data to ring buffer. * Will not return until all the data has been written. */ long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); /************************************************************ * Read data from ring buffer. * Will not return until all the data has been read. */ long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); /************************************************************ * Return the number of frames that could be written to the stream without * having to wait. */ long GetAudioStreamWriteable( PABLIO_Stream *aStream ); /************************************************************ * Return the number of frames that are available to be read from the * stream without having to wait. */ long GetAudioStreamReadable( PABLIO_Stream *aStream ); /************************************************************ * Opens a PortAudio stream with default characteristics. * Allocates PABLIO_Stream structure. * * flags parameter can be an ORed combination of: * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, * and either PABLIO_MONO or PABLIO_STEREO */ PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate, PaSampleFormat format, long flags ); PaError CloseAudioStream( PABLIO_Stream *aStream ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _PABLIO_H */ portaudio-18.1.orig/pablio/test_w_saw8.c0000644000175000017500000000727207423043550021031 0ustar mikaelmikael00000000000000/* * $Id: test_w_saw8.c,v 1.1.1.1 2002/01/22 00:52:55 phil Exp $ * test_w_saw8.c * Generate stereo 8 bit sawtooth waveforms. * * Author: Phil Burk, http://www.softsynth.com * * This program uses PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "pablio.h" #include #define SAMPLE_RATE (22050) #define NUM_SECONDS (6) #define SAMPLES_PER_FRAME (2) #define FRAMES_PER_BLOCK (100) unsigned char samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME]; unsigned char phases[SAMPLES_PER_FRAME]; /*******************************************************************/ int main(void); int main(void) { int i,j; PaError err; PABLIO_Stream *aOutStream; printf("Generate unsigned 8 bit sawtooth waves using PABLIO.\n"); fflush(stdout); /* Open simplified blocking I/O layer on top of PortAudio. */ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paUInt8, (PABLIO_WRITE | PABLIO_STEREO) ); if( err != paNoError ) goto error; /* Initialize oscillator phases to "ground" level for paUInt8. */ phases[0] = 128; phases[1] = 128; for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) { /* Generate sawtooth waveforms in a block for efficiency. */ for( j=0; j #include #include #include "ringbuffer.h" #include /*************************************************************************** * Initialize FIFO. * numBytes must be power of 2, returns -1 if not. */ long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr ) { if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */ rbuf->bufferSize = numBytes; rbuf->buffer = (char *)dataPtr; RingBuffer_Flush( rbuf ); rbuf->bigMask = (numBytes*2)-1; rbuf->smallMask = (numBytes)-1; return 0; } /*************************************************************************** ** Return number of bytes available for reading. */ long RingBuffer_GetReadAvailable( RingBuffer *rbuf ) { return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); } /*************************************************************************** ** Return number of bytes available for writing. */ long RingBuffer_GetWriteAvailable( RingBuffer *rbuf ) { return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf)); } /*************************************************************************** ** Clear buffer. Should only be called when buffer is NOT being read. */ void RingBuffer_Flush( RingBuffer *rbuf ) { rbuf->writeIndex = rbuf->readIndex = 0; } /*************************************************************************** ** Get address of region(s) to which we can write data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ) { long index; long available = RingBuffer_GetWriteAvailable( rbuf ); if( numBytes > available ) numBytes = available; /* Check to see if write is not contiguous. */ index = rbuf->writeIndex & rbuf->smallMask; if( (index + numBytes) > rbuf->bufferSize ) { /* Write data in two blocks that wrap the buffer. */ long firstHalf = rbuf->bufferSize - index; *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = firstHalf; *dataPtr2 = &rbuf->buffer[0]; *sizePtr2 = numBytes - firstHalf; } else { *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = numBytes; *dataPtr2 = NULL; *sizePtr2 = 0; } return numBytes; } /*************************************************************************** */ long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes ) { return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask; } /*************************************************************************** ** Get address of region(s) from which we can read data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ) { long index; long available = RingBuffer_GetReadAvailable( rbuf ); if( numBytes > available ) numBytes = available; /* Check to see if read is not contiguous. */ index = rbuf->readIndex & rbuf->smallMask; if( (index + numBytes) > rbuf->bufferSize ) { /* Write data in two blocks that wrap the buffer. */ long firstHalf = rbuf->bufferSize - index; *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = firstHalf; *dataPtr2 = &rbuf->buffer[0]; *sizePtr2 = numBytes - firstHalf; } else { *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = numBytes; *dataPtr2 = NULL; *sizePtr2 = 0; } return numBytes; } /*************************************************************************** */ long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes ) { return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask; } /*************************************************************************** ** Return bytes written. */ long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes ) { long size1, size2, numWritten; void *data1, *data2; numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); if( size2 > 0 ) { memcpy( data1, data, size1 ); data = ((char *)data) + size1; memcpy( data2, data, size2 ); } else { memcpy( data1, data, size1 ); } RingBuffer_AdvanceWriteIndex( rbuf, numWritten ); return numWritten; } /*************************************************************************** ** Return bytes read. */ long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes ) { long size1, size2, numRead; void *data1, *data2; numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); if( size2 > 0 ) { memcpy( data, data1, size1 ); data = ((char *)data) + size1; memcpy( data, data2, size2 ); } else { memcpy( data, data1, size1 ); } RingBuffer_AdvanceReadIndex( rbuf, numRead ); return numRead; } portaudio-18.1.orig/pablio/ringbuffer.h0000644000175000017500000001022307653203116020707 0ustar mikaelmikael00000000000000#ifndef _RINGBUFFER_H #define _RINGBUFFER_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* * $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $ * ringbuffer.h * Ring Buffer utility.. * * Author: Phil Burk, http://www.softsynth.com * * This program is distributed with the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "ringbuffer.h" #include typedef struct { long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */ /* These are declared volatile because they are written by a different thread than the reader. */ volatile long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */ volatile long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */ long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */ long smallMask; /* Used for fitting indices to buffer. */ char *buffer; } RingBuffer; /* * Initialize Ring Buffer. * numBytes must be power of 2, returns -1 if not. */ long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr ); /* Clear buffer. Should only be called when buffer is NOT being read. */ void RingBuffer_Flush( RingBuffer *rbuf ); /* Return number of bytes available for writing. */ long RingBuffer_GetWriteAvailable( RingBuffer *rbuf ); /* Return number of bytes available for read. */ long RingBuffer_GetReadAvailable( RingBuffer *rbuf ); /* Return bytes written. */ long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes ); /* Return bytes read. */ long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes ); /* Get address of region(s) to which we can write data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ); long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes ); /* Get address of region(s) from which we can read data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be read or numBytes, whichever is smaller. */ long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ); long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes ); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _RINGBUFFER_H */ portaudio-18.1.orig/pablio/test_rw_echo.c0000644000175000017500000001044007423043546021243 0ustar mikaelmikael00000000000000/* * $Id: test_rw_echo.c,v 1.1.1.1 2002/01/22 00:52:54 phil Exp $ * test_rw_echo.c * Echo delayed input to output. * * Author: Phil Burk, http://www.softsynth.com/portaudio/ * * This program uses PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * * Note that if you need low latency, you should not use PABLIO. * Use the PA_OpenStream callback technique which is lower level * than PABLIO. * * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "pablio.h" #include /* ** Note that many of the older ISA sound cards on PCs do NOT support ** full duplex audio (simultaneous record and playback). ** And some only support full duplex at lower sample rates. */ #define SAMPLE_RATE (22050) #define NUM_SECONDS (20) #define SAMPLES_PER_FRAME (2) /* Select whether we will use floats or shorts. */ #if 1 #define SAMPLE_TYPE paFloat32 typedef float SAMPLE; #else #define SAMPLE_TYPE paInt16 typedef short SAMPLE; #endif #define NUM_ECHO_FRAMES (2*SAMPLE_RATE) SAMPLE samples[NUM_ECHO_FRAMES][SAMPLES_PER_FRAME] = {0.0}; /*******************************************************************/ int main(void); int main(void) { int i; PaError err; PABLIO_Stream *aInStream; PABLIO_Stream *aOutStream; int index; printf("Full duplex sound test using PABLIO\n"); fflush(stdout); /* Open simplified blocking I/O layer on top of PortAudio. */ /* Open input first so it can start to fill buffers. */ err = OpenAudioStream( &aInStream, SAMPLE_RATE, SAMPLE_TYPE, (PABLIO_READ | PABLIO_STEREO) ); if( err != paNoError ) goto error; /* printf("opened input\n"); fflush(stdout); /**/ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, SAMPLE_TYPE, (PABLIO_WRITE | PABLIO_STEREO) ); if( err != paNoError ) goto error; /* printf("opened output\n"); fflush(stdout); /**/ /* Process samples in the foreground. */ index = 0; for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ ) { /* Write old frame of data to output. */ /* samples[index][1] = (i&256) * (1.0f/256.0f); /* sawtooth */ WriteAudioStream( aOutStream, &samples[index][0], 1 ); /* Read one frame of data into sample array for later output. */ ReadAudioStream( aInStream, &samples[index][0], 1 ); index += 1; if( index >= NUM_ECHO_FRAMES ) index = 0; if( (i & 0xFFFF) == 0 ) printf("i = %d\n", i ); fflush(stdout); /**/ } CloseAudioStream( aOutStream ); CloseAudioStream( aInStream ); printf("R/W echo sound test complete.\n" ); fflush(stdout); return 0; error: fprintf( stderr, "An error occured while using PortAudio\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; } portaudio-18.1.orig/pablio/pablio.def0000644000175000017500000000203007611223062020324 0ustar mikaelmikael00000000000000LIBRARY PABLIOV18 DESCRIPTION 'PABLIO Portable Audio Blocking I/O' EXPORTS ; Explicit exports can go here Pa_Initialize @1 Pa_Terminate @2 Pa_GetHostError @3 Pa_GetErrorText @4 Pa_CountDevices @5 Pa_GetDefaultInputDeviceID @6 Pa_GetDefaultOutputDeviceID @7 Pa_GetDeviceInfo @8 Pa_OpenStream @9 Pa_OpenDefaultStream @10 Pa_CloseStream @11 Pa_StartStream @12 Pa_StopStream @13 Pa_StreamActive @14 Pa_StreamTime @15 Pa_GetCPULoad @16 Pa_GetMinNumBuffers @17 Pa_Sleep @18 OpenAudioStream @19 CloseAudioStream @20 WriteAudioStream @21 ReadAudioStream @22 Pa_GetSampleSize @23 ;123456789012345678901234567890123456 ;000000000111111111122222222223333333 portaudio-18.1.orig/pablio/README.txt0000644000175000017500000000307707423043544020116 0ustar mikaelmikael00000000000000README for PABLIO Portable Audio Blocking I/O Library Author: Phil Burk PABLIO is a simplified interface to PortAudio that provide read/write style blocking I/O. Please see the .DOC file for documentation. /* * More information on PortAudio at: http://www.portaudio.com * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ portaudio-18.1.orig/pablio/test_w_saw.c0000644000175000017500000000750207622237536020747 0ustar mikaelmikael00000000000000/* * $Id: test_w_saw.c,v 1.1.1.1.4.1 2003/02/12 02:22:21 philburk Exp $ * test_w_saw.c * Generate stereo sawtooth waveforms. * * Author: Phil Burk, http://www.softsynth.com * * This program uses PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "pablio.h" #include #define SAMPLE_RATE (44100) #define NUM_SECONDS (15) #define SAMPLES_PER_FRAME (2) #define FREQUENCY (220.0f) #define PHASE_INCREMENT (2.0f * FREQUENCY / SAMPLE_RATE) #define FRAMES_PER_BLOCK (100) float samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME]; float phases[SAMPLES_PER_FRAME]; /*******************************************************************/ int main(void); int main(void) { int i,j; PaError err; PABLIO_Stream *aOutStream; printf("Generate sawtooth waves using PABLIO.\n"); fflush(stdout); /* Open simplified blocking I/O layer on top of PortAudio. */ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paFloat32, (PABLIO_WRITE | PABLIO_STEREO) ); if( err != paNoError ) goto error; /* Initialize oscillator phases. */ phases[0] = 0.0; phases[1] = 0.0; for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) { /* Generate sawtooth waveforms in a block for efficiency. */ for( j=0; j 1.0f ) phases[0] -= 2.0f; samples[j][0] = phases[0]; /* On the second channel, generate a sawtooth wave a fifth higher. */ phases[1] += PHASE_INCREMENT * (3.0f / 2.0f); if( phases[1] > 1.0f ) phases[1] -= 2.0f; samples[j][1] = phases[1]; } /* Write samples to output. */ WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK ); } CloseAudioStream( aOutStream ); printf("Sawtooth sound test complete.\n" ); fflush(stdout); return 0; error: fprintf( stderr, "An error occured while using PABLIO\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; } portaudio-18.1.orig/pablio/test_rw.c0000644000175000017500000000704107435450140020243 0ustar mikaelmikael00000000000000/* * $Id: test_rw.c,v 1.2 2002/02/22 22:06:23 philburk Exp $ * test_rw.c * Read input from one stream and write it to another. * * Author: Phil Burk, http://www.softsynth.com/portaudio/ * * This program uses PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "pablio.h" /* ** Note that many of the older ISA sound cards on PCs do NOT support ** full duplex audio (simultaneous record and playback). ** And some only support full duplex at lower sample rates. */ #define SAMPLE_RATE (44100) #define NUM_SECONDS (5) #define SAMPLES_PER_FRAME (2) #define FRAMES_PER_BLOCK (64) /* Select whether we will use floats or shorts. */ #if 1 #define SAMPLE_TYPE paFloat32 typedef float SAMPLE; #else #define SAMPLE_TYPE paInt16 typedef short SAMPLE; #endif /*******************************************************************/ int main(void); int main(void) { int i; SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK]; PaError err; PABLIO_Stream *aStream; printf("Full duplex sound test using PortAudio and RingBuffers\n"); fflush(stdout); /* Open simplified blocking I/O layer on top of PortAudio. */ err = OpenAudioStream( &aStream, SAMPLE_RATE, SAMPLE_TYPE, (PABLIO_READ_WRITE | PABLIO_STEREO) ); if( err != paNoError ) goto error; /* Process samples in the foreground. */ for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) { /* Read one block of data into sample array from audio input. */ ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK ); /* Write that same block of data to output. */ WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK ); } CloseAudioStream( aStream ); printf("Full duplex sound test complete.\n" ); fflush(stdout); return 0; error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; } portaudio-18.1.orig/README.txt0000644000175000000620000000721607434437512016507 0ustar mikaelstaff00000000000000README for PortAudio Implementations for PC DirectSound and Mac SoundManager /* * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com// * * Copyright (c) 1999-2000 Phil Burk and Ross Bencina * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ PortAudio is a portable audio I/O library designed for cross-platform support of audio. It uses a callback mechanism to request audio processing. Audio can be generated in various formats, including 32 bit floating point, and will be converted to the native format internally. Documentation: See "pa_common/portaudio.h" for API spec. See docs folder for a tutorial. Also see http://www.portaudio.com/docs/ And see "pa_tests/patest_saw.c" for an example. For information on compiling programs with PortAudio, please see the tutorial at: http://www.portaudio.com/docs/pa_tutorial.html Important Files and Folders: pa_common/ = platform independant code pa_common/portaudio.h = header file for PortAudio API. Specifies API. pa_common/pa_lib.c = host independant code for all implementations. pablio = simple blocking read/write interface Platform Implementations pa_asio = ASIO for Windows and Macintosh pa_beos = BeOS pa_mac = Macintosh Sound Manager for OS 8,9 and Carbon pa_mac_core = Macintosh Core Audio for OS X pa_sgi = Silicon Graphics AL pa_unix_oss = OSS implementation for various Unixes pa_win_ds = Windows Direct Sound pa_win_wmme = Windows MME (most widely supported) Test Programs pa_tests/pa_fuzz.c = guitar fuzz box pa_tests/pa_devs.c = print a list of available devices pa_tests/pa_minlat.c = determine minimum latency for your machine pa_tests/paqa_devs.c = self test that opens all devices pa_tests/paqa_errs.c = test error detection and reporting pa_tests/patest_clip.c = hear a sine wave clipped and unclipped pa_tests/patest_dither.c = hear effects of dithering (extremely subtle) pa_tests/patest_pink.c = fun with pink noise pa_tests/patest_record.c = record and playback some audio pa_tests/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad(). pa_tests/patest_sine.c = output a sine wave in a simple PA app pa_tests/patest_sync.c = test syncronization of audio and video pa_tests/patest_wire.c = pass input to output, wire simulator portaudio-18.1.orig/pa_beos/0000755000175000000620000000000007700016420016376 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_beos/pa_beos_mk.cc0000644000175000017500000003404307423043472021165 0ustar mikaelmikael00000000000000/* * $Id: pa_beos_mk.cc,v 1.1.1.1 2002/01/22 00:52:09 phil Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * BeOS Media Kit Implementation by Joshua Haberman * * Copyright (c) 2001 Joshua Haberman * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include #include #include #include #include "portaudio.h" #include "pa_host.h" #include "PlaybackNode.h" #define PRINT(x) { printf x; fflush(stdout); } #ifdef DEBUG #define DBUG(x) PRINT(x) #else #define DBUG(x) #endif typedef struct PaHostSoundControl { /* These members are common to all modes of operation */ media_node pahsc_TimeSource; /* the sound card's DAC. */ media_format pahsc_Format; /* These methods are specific to playing mode */ media_node pahsc_OutputNode; /* output to the mixer */ media_node pahsc_InputNode; /* reads data from user callback -- PA specific */ media_input pahsc_MixerInput; /* input jack on the soundcard's mixer. */ media_output pahsc_PaOutput; /* output jack from the PA node */ PaPlaybackNode *pahsc_InputNodeInstance; } PaHostSoundControl; /*************************************************************************/ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { /* stub */ return 0; } /*************************************************************************/ PaDeviceID Pa_GetDefaultInputDeviceID( void ) { /* stub */ return 0; } /*************************************************************************/ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { /* stub */ return NULL; } /*************************************************************************/ int Pa_CountDevices() { /* stub */ return 1; } /*************************************************************************/ PaError PaHost_Init( void ) { /* we have to create this in order to use BMediaRoster. I hope it doesn't * cause problems */ be_app = new BApplication("application/x-vnd.portaudio-app"); return paNoError; } PaError PaHost_Term( void ) { delete be_app; return paNoError; } /*************************************************************************/ PaError PaHost_StreamActive( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; DBUG(("IsRunning returning: %s\n", pahsc->pahsc_InputNodeInstance->IsRunning() ? "true" : "false")); return (PaError)pahsc->pahsc_InputNodeInstance->IsRunning(); } PaError PaHost_StartOutput( internalPortAudioStream *past ) { return paNoError; } /*************************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *past ) { return paNoError; } /*************************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { return paNoError; } /*************************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { return paNoError; } /*************************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *past ) { bigtime_t very_soon, start_latency; status_t err; BMediaRoster *roster = BMediaRoster::Roster(&err); PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; /* for some reason, err indicates an error (though nothing it wrong) * when the DBUG macro in pa_lib.c is enabled. It's reproducably * linked. Weird. */ if( !roster /* || err != B_OK */ ) { DBUG(("No media server! err=%d, roster=%x\n", err, roster)); return paHostError; } /* tell the node when to start -- since there aren't any other nodes * starting that we have to wait for, just tell it to start now */ BTimeSource *timeSource = roster->MakeTimeSourceFor(pahsc->pahsc_TimeSource); very_soon = timeSource->PerformanceTimeFor( BTimeSource::RealTime() ); timeSource->Release(); /* Add the latency of starting the network of nodes */ err = roster->GetStartLatencyFor( pahsc->pahsc_TimeSource, &start_latency ); very_soon += start_latency; err = roster->StartNode( pahsc->pahsc_InputNode, very_soon ); /* No need to start the mixer -- it's always running */ return paNoError; } /*************************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; BMediaRoster *roster = BMediaRoster::Roster(); if( !roster ) { DBUG(("No media roster!\n")); return paHostError; } if( !pahsc ) return paHostError; /* this crashes, and I don't know why yet */ // if( abort ) // pahsc->pahsc_InputNodeInstance->mAborted = true; roster->StopNode(pahsc->pahsc_InputNode, 0, /* immediate = */ true); return paNoError; } /*************************************************************************/ PaError PaHost_OpenStream( internalPortAudioStream *past ) { status_t err; BMediaRoster *roster = BMediaRoster::Roster(&err); PaHostSoundControl *pahsc; /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); if( pahsc == NULL ) { goto error; } memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; if( !roster /* || err != B_OK */ ) { /* no media server! */ DBUG(("No media server.\n")); goto error; } if ( past->past_NumInputChannels > 0 && past->past_NumOutputChannels > 0 ) { /* filter -- not implemented yet */ goto error; } else if ( past->past_NumInputChannels > 0 ) { /* recorder -- not implemented yet */ goto error; } else { /* player ****************************************************************/ status_t err; int32 num; /* First we need to create the three components (like components in a stereo * system). The mixer component is our interface to the sound card, data * we write there will get played. The BePA_InputNode component is the node * which represents communication with the PA client (it is what calls the * client's callbacks). The time source component is the sound card's DAC, * which allows us to slave the other components to it instead of the system * clock. */ err = roster->GetAudioMixer( &pahsc->pahsc_OutputNode ); if( err != B_OK ) { DBUG(("Couldn't get default mixer.\n")); goto error; } err = roster->GetTimeSource( &pahsc->pahsc_TimeSource ); if( err != B_OK ) { DBUG(("Couldn't get time source.\n")); goto error; } pahsc->pahsc_InputNodeInstance = new PaPlaybackNode(2, 44100, past->past_FramesPerUserBuffer, past->past_Callback, past->past_UserData ); pahsc->pahsc_InputNodeInstance->SetSampleFormat(0, past->past_OutputSampleFormat); err = roster->RegisterNode( pahsc->pahsc_InputNodeInstance ); if( err != B_OK ) { DBUG(("Unable to register node.\n")); goto error; } roster->GetNodeFor( pahsc->pahsc_InputNodeInstance->Node().node, &pahsc->pahsc_InputNode ); if( err != B_OK ) { DBUG(("Unable to get input node.\n")); goto error; } /* Now we have three components (nodes) sitting next to each other. The * next step is to look at them and find their inputs and outputs so we can * wire them together. */ err = roster->GetFreeInputsFor( pahsc->pahsc_OutputNode, &pahsc->pahsc_MixerInput, 1, &num, B_MEDIA_RAW_AUDIO ); if( err != B_OK || num < 1 ) { DBUG(("Couldn't get the mixer input.\n")); goto error; } err = roster->GetFreeOutputsFor( pahsc->pahsc_InputNode, &pahsc->pahsc_PaOutput, 1, &num, B_MEDIA_RAW_AUDIO ); if( err != B_OK || num < 1 ) { DBUG(("Couldn't get PortAudio output.\n")); goto error; } /* We've found the input and output -- the final step is to run a wire * between them so they are connected. */ /* try to make the mixer input adapt to what PA sends it */ pahsc->pahsc_Format = pahsc->pahsc_PaOutput.format; roster->Connect( pahsc->pahsc_PaOutput.source, pahsc->pahsc_MixerInput.destination, &pahsc->pahsc_Format, &pahsc->pahsc_PaOutput, &pahsc->pahsc_MixerInput ); /* Actually, there's one final step -- tell them all to sync to the * sound card's DAC */ roster->SetTimeSourceFor( pahsc->pahsc_InputNode.node, pahsc->pahsc_TimeSource.node ); roster->SetTimeSourceFor( pahsc->pahsc_OutputNode.node, pahsc->pahsc_TimeSource.node ); } return paNoError; error: PaHost_CloseStream( past ); return paHostError; } /*************************************************************************/ PaError PaHost_CloseStream( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; status_t err; BMediaRoster *roster = BMediaRoster::Roster(&err); if( !roster ) { DBUG(("Couldn't get media roster\n")); return paHostError; } if( !pahsc ) return paHostError; /* Disconnect all the connections we made when opening the stream */ roster->Disconnect(pahsc->pahsc_InputNode.node, pahsc->pahsc_PaOutput.source, pahsc->pahsc_OutputNode.node, pahsc->pahsc_MixerInput.destination); DBUG(("Calling ReleaseNode()")); roster->ReleaseNode(pahsc->pahsc_InputNode); /* deleting the node shouldn't be necessary -- it is reference counted, and will * delete itself when its references drop to zero. the call to ReleaseNode() * above should decrease its reference count */ pahsc->pahsc_InputNodeInstance = NULL; return paNoError; } /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *past = (internalPortAudioStream *) stream; PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData; return pahsc->pahsc_InputNodeInstance->GetStreamTime(); } /*************************************************************************/ void Pa_Sleep( long msec ) { /* snooze() takes microseconds */ snooze( msec * 1000 ); } /************************************************************************* * Allocate memory that can be accessed in real-time. * This may need to be held in physical memory so that it is not * paged to virtual memory. * This call MUST be balanced with a call to PaHost_FreeFastMemory(). * Memory will be set to zero. */ void *PaHost_AllocateFastMemory( long numBytes ) { /* BeOS supports non-pagable memory through pools -- a pool is an area * of physical memory that is locked. It would be best to pre-allocate * that pool and then hand out memory from it, but we don't know in * advance how much we'll need. So for now, we'll allocate a pool * for every request we get, storing a pointer to the pool at the * beginning of the allocated memory */ rtm_pool *pool; void *addr; long size = numBytes + sizeof(rtm_pool *); static int counter = 0; char pool_name[100]; /* Every pool needs a unique name. */ sprintf(pool_name, "PaPoolNumber%d", counter++); if( rtm_create_pool( &pool, size, pool_name ) != B_OK ) return 0; addr = rtm_alloc( pool, size ); if( addr == NULL ) return 0; memset( addr, 0, numBytes ); *((rtm_pool **)addr) = pool; // store the pointer to the pool addr = (rtm_pool **)addr + 1; // and return the next location in memory return addr; } /************************************************************************* * Free memory that could be accessed in real-time. * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory( void *addr, long numBytes ) { rtm_pool *pool; if( addr == NULL ) return; addr = (rtm_pool **)addr - 1; pool = *((rtm_pool **)addr); rtm_free( addr ); rtm_delete_pool( pool ); } portaudio-18.1.orig/pa_beos/PlaybackNode.cc0000644000175000017500000004163407423043470021424 0ustar mikaelmikael00000000000000/* * $Id: PlaybackNode.cc,v 1.1.1.1 2002/01/22 00:52:07 phil Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * BeOS Media Kit Implementation by Joshua Haberman * * Copyright (c) 2001 Joshua Haberman * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * --- * * Significant portions of this file are based on sample code from Be. The * Be Sample Code Licence follows: * * Copyright 1991-1999, Be Incorporated. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions, and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "PlaybackNode.h" #define PRINT(x) { printf x; fflush(stdout); } #ifdef DEBUG #define DBUG(x) PRINT(x) #else #define DBUG(x) #endif PaPlaybackNode::PaPlaybackNode(uint32 channels, float frame_rate, uint32 frames_per_buffer, PortAudioCallback* callback, void *user_data) : BMediaNode("PortAudio input node"), BBufferProducer(B_MEDIA_RAW_AUDIO), BMediaEventLooper(), mAborted(false), mRunning(false), mBufferGroup(NULL), mDownstreamLatency(0), mStartTime(0), mCallback(callback), mUserData(user_data), mFramesPerBuffer(frames_per_buffer) { DBUG(("Constructor called.\n")); mPreferredFormat.type = B_MEDIA_RAW_AUDIO; mPreferredFormat.u.raw_audio.channel_count = channels; mPreferredFormat.u.raw_audio.frame_rate = frame_rate; mPreferredFormat.u.raw_audio.byte_order = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; mPreferredFormat.u.raw_audio.buffer_size = media_raw_audio_format::wildcard.buffer_size; mOutput.destination = media_destination::null; mOutput.format = mPreferredFormat; /* The amount of time it takes for this node to produce a buffer when * asked. Essentially, it is how long the user's callback takes to run. * We set this to be the length of the sound data each buffer of the * requested size can hold. */ //mInternalLatency = (bigtime_t)(1000000 * frames_per_buffer / frame_rate); /* ACK! it seems that the mixer (at least on my machine) demands that IT * specify the buffer size, so for now I'll just make a generic guess here */ mInternalLatency = 1000000 / 20; } PaPlaybackNode::~PaPlaybackNode() { DBUG(("Destructor called.\n")); Quit(); /* Stop the BMediaEventLooper thread */ } /************************* * * Local methods * */ bool PaPlaybackNode::IsRunning() { return mRunning; } PaTimestamp PaPlaybackNode::GetStreamTime() { BTimeSource *timeSource = TimeSource(); PaTimestamp time = (timeSource->Now() - mStartTime) * mPreferredFormat.u.raw_audio.frame_rate / 1000000; return time; } void PaPlaybackNode::SetSampleFormat(PaSampleFormat inFormat, PaSampleFormat outFormat) { uint32 beOutFormat; switch(outFormat) { case paFloat32: beOutFormat = media_raw_audio_format::B_AUDIO_FLOAT; mOutputSampleWidth = 4; break; case paInt16: beOutFormat = media_raw_audio_format::B_AUDIO_SHORT; mOutputSampleWidth = 2; break; case paInt32: beOutFormat = media_raw_audio_format::B_AUDIO_INT; mOutputSampleWidth = 4; break; case paInt8: beOutFormat = media_raw_audio_format::B_AUDIO_CHAR; mOutputSampleWidth = 1; break; case paUInt8: beOutFormat = media_raw_audio_format::B_AUDIO_UCHAR; mOutputSampleWidth = 1; break; case paInt24: case paPackedInt24: case paCustomFormat: DBUG(("Unsupported output format: %x\n", outFormat)); break; default: DBUG(("Unknown output format: %x\n", outFormat)); } mPreferredFormat.u.raw_audio.format = beOutFormat; mFramesPerBuffer * mPreferredFormat.u.raw_audio.channel_count * mOutputSampleWidth; } BBuffer *PaPlaybackNode::FillNextBuffer(bigtime_t time) { /* Get a buffer from the buffer group */ BBuffer *buf = mBufferGroup->RequestBuffer( mOutput.format.u.raw_audio.buffer_size, BufferDuration()); unsigned long frames = mOutput.format.u.raw_audio.buffer_size / mOutputSampleWidth / mOutput.format.u.raw_audio.channel_count; bigtime_t start_time; int ret; if( !buf ) { DBUG(("Unable to allocate a buffer\n")); return NULL; } start_time = mStartTime + (bigtime_t)((double)mSamplesSent / (double)mOutput.format.u.raw_audio.frame_rate / (double)mOutput.format.u.raw_audio.channel_count * 1000000.0); /* Now call the user callback to get the data */ ret = mCallback(NULL, /* Input buffer */ buf->Data(), /* Output buffer */ frames, /* Frames per buffer */ mSamplesSent / mOutput.format.u.raw_audio.channel_count, /* timestamp */ mUserData); if( ret ) mAborted = true; media_header *hdr = buf->Header(); hdr->type = B_MEDIA_RAW_AUDIO; hdr->size_used = mOutput.format.u.raw_audio.buffer_size; hdr->time_source = TimeSource()->ID(); hdr->start_time = start_time; return buf; } /************************* * * BMediaNode methods * */ BMediaAddOn *PaPlaybackNode::AddOn( int32 * ) const { DBUG(("AddOn() called.\n")); return NULL; /* we don't provide service to outside applications */ } status_t PaPlaybackNode::HandleMessage( int32 message, const void *data, size_t size ) { DBUG(("HandleMessage() called.\n")); return B_ERROR; /* we don't define any custom messages */ } /************************* * * BMediaEventLooper methods * */ void PaPlaybackNode::NodeRegistered() { DBUG(("NodeRegistered() called.\n")); /* Start the BMediaEventLooper thread */ SetPriority(B_REAL_TIME_PRIORITY); Run(); /* set up as much information about our output as we can */ mOutput.source.port = ControlPort(); mOutput.source.id = 0; mOutput.node = Node(); ::strcpy(mOutput.name, "PortAudio Playback"); } void PaPlaybackNode::HandleEvent( const media_timed_event *event, bigtime_t lateness, bool realTimeEvent ) { // DBUG(("HandleEvent() called.\n")); status_t err; switch(event->type) { case BTimedEventQueue::B_START: DBUG((" Handling a B_START event\n")); if( RunState() != B_STARTED ) { mStartTime = event->event_time + EventLatency(); mSamplesSent = 0; mAborted = false; mRunning = true; media_timed_event firstEvent( mStartTime, BTimedEventQueue::B_HANDLE_BUFFER ); EventQueue()->AddEvent( firstEvent ); } break; case BTimedEventQueue::B_STOP: DBUG((" Handling a B_STOP event\n")); mRunning = false; EventQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER ); break; case BTimedEventQueue::B_HANDLE_BUFFER: //DBUG((" Handling a B_HANDLE_BUFFER event\n")); /* make sure we're started and connected */ if( RunState() != BMediaEventLooper::B_STARTED || mOutput.destination == media_destination::null ) break; BBuffer *buffer = FillNextBuffer(event->event_time); /* make sure we weren't aborted while this routine was running. * this can happen in one of two ways: either the callback returned * nonzero (in which case mAborted is set in FillNextBuffer() ) or * the client called AbortStream */ if( mAborted ) { if( buffer ) buffer->Recycle(); Stop(0, true); break; } if( buffer ) { err = SendBuffer(buffer, mOutput.destination); if( err != B_OK ) buffer->Recycle(); } mSamplesSent += mOutput.format.u.raw_audio.buffer_size / mOutputSampleWidth; /* Now schedule the next buffer event, so we can send another * buffer when this one runs out. We calculate when it should * happen by calculating when the data we just sent will finish * playing. * * NOTE, however, that the event will actually get generated * earlier than we specify, to account for the latency it will * take to produce the buffer. It uses the latency value we * specified in SetEventLatency() to determine just how early * to generate it. */ /* totalPerformanceTime includes the time represented by the buffer * we just sent */ bigtime_t totalPerformanceTime = (bigtime_t)((double)mSamplesSent / (double)mOutput.format.u.raw_audio.channel_count / (double)mOutput.format.u.raw_audio.frame_rate * 1000000.0); bigtime_t nextEventTime = mStartTime + totalPerformanceTime; media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER); EventQueue()->AddEvent(nextBufferEvent); break; } } /************************* * * BBufferProducer methods * */ status_t PaPlaybackNode::FormatSuggestionRequested( media_type type, int32 /*quality*/, media_format* format ) { /* the caller wants to know this node's preferred format and provides * a suggestion, asking if we support it */ DBUG(("FormatSuggestionRequested() called.\n")); if(!format) return B_BAD_VALUE; *format = mPreferredFormat; /* we only support raw audio (a wildcard is okay too) */ if ( type == B_MEDIA_UNKNOWN_TYPE || type == B_MEDIA_RAW_AUDIO ) return B_OK; else return B_MEDIA_BAD_FORMAT; } status_t PaPlaybackNode::FormatProposal( const media_source& output, media_format* format ) { /* This is similar to FormatSuggestionRequested(), but it is actually part * of the negotiation process. We're given the opportunity to specify any * properties that are wildcards (ie. properties that the other node doesn't * care one way or another about) */ DBUG(("FormatProposal() called.\n")); /* Make sure this proposal really applies to our output */ if( output != mOutput.source ) return B_MEDIA_BAD_SOURCE; /* We return two things: whether we support the proposed format, and our own * preferred format */ *format = mPreferredFormat; if( format->type == B_MEDIA_UNKNOWN_TYPE || format->type == B_MEDIA_RAW_AUDIO ) return B_OK; else return B_MEDIA_BAD_FORMAT; } status_t PaPlaybackNode::FormatChangeRequested( const media_source& source, const media_destination& destination, media_format* io_format, int32* ) { /* we refuse to change formats, supporting only 1 */ DBUG(("FormatChangeRequested() called.\n")); return B_ERROR; } status_t PaPlaybackNode::GetNextOutput( int32* cookie, media_output* out_output ) { /* this is where we allow other to enumerate our outputs -- the cookie is * an integer we can use to keep track of where we are in enumeration. */ DBUG(("GetNextOutput() called.\n")); if( *cookie == 0 ) { *out_output = mOutput; *cookie = 1; return B_OK; } return B_BAD_INDEX; } status_t PaPlaybackNode::DisposeOutputCookie( int32 cookie ) { DBUG(("DisposeOutputCookie() called.\n")); return B_OK; } void PaPlaybackNode::LateNoticeReceived( const media_source& what, bigtime_t how_much, bigtime_t performance_time ) { /* This function is called as notification that a buffer we sent wasn't * received by the time we stamped it with -- it got there late. Basically, * it means we underestimated our own latency, so we should increase it */ DBUG(("LateNoticeReceived() called.\n")); if( what != mOutput.source ) return; if( RunMode() == B_INCREASE_LATENCY ) { mInternalLatency += how_much; SetEventLatency( mDownstreamLatency + mInternalLatency ); DBUG(("Increasing latency to %Ld\n", mDownstreamLatency + mInternalLatency)); } else DBUG(("I don't know what to do with this notice!")); } void PaPlaybackNode::EnableOutput( const media_source& what, bool enabled, int32* ) { DBUG(("EnableOutput() called.\n")); /* stub -- we don't support this yet */ } status_t PaPlaybackNode::PrepareToConnect( const media_source& what, const media_destination& where, media_format* format, media_source* out_source, char* out_name ) { /* the final stage of format negotiations. here we _must_ make specific any * remaining wildcards */ DBUG(("PrepareToConnect() called.\n")); /* make sure this really refers to our source */ if( what != mOutput.source ) return B_MEDIA_BAD_SOURCE; /* make sure we're not already connected */ if( mOutput.destination != media_destination::null ) return B_MEDIA_ALREADY_CONNECTED; if( format->type != B_MEDIA_RAW_AUDIO ) return B_MEDIA_BAD_FORMAT; if( format->u.raw_audio.format != mPreferredFormat.u.raw_audio.format ) return B_MEDIA_BAD_FORMAT; if( format->u.raw_audio.buffer_size == media_raw_audio_format::wildcard.buffer_size ) { DBUG(("We were left to decide buffer size: choosing 2048")); format->u.raw_audio.buffer_size = 2048; } else DBUG(("Using consumer specified buffer size of %lu.\n", format->u.raw_audio.buffer_size)); /* Reserve the connection, return the information */ mOutput.destination = where; mOutput.format = *format; *out_source = mOutput.source; strncpy( out_name, mOutput.name, B_MEDIA_NAME_LENGTH ); return B_OK; } void PaPlaybackNode::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name) { DBUG(("Connect() called.\n")); portaudio-18.1.orig/pa_beos/PlaybackNode.h0000644000175000017500000001040407423043470021255 0ustar mikaelmikael00000000000000/* * $Id: PlaybackNode.h,v 1.1.1.1 2002/01/22 00:52:08 phil Exp $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * BeOS Media Kit Implementation by Joshua Haberman * * Copyright (c) 2001 Joshua Haberman * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include "portaudio.h" class PaPlaybackNode : public BBufferProducer, public BMediaEventLooper { public: PaPlaybackNode( uint32 channels, float frame_rate, uint32 frames_per_buffer, PortAudioCallback *callback, void *user_data ); ~PaPlaybackNode(); /* Local methods ******************************************/ BBuffer *FillNextBuffer(bigtime_t time); void SetSampleFormat(PaSampleFormat inFormat, PaSampleFormat outFormat); bool IsRunning(); PaTimestamp GetStreamTime(); /* BMediaNode methods *************************************/ BMediaAddOn* AddOn( int32 * ) const; status_t HandleMessage( int32 message, const void *data, size_t size ); /* BMediaEventLooper methods ******************************/ void HandleEvent( const media_timed_event *event, bigtime_t lateness, bool realTimeEvent ); void NodeRegistered(); /* BBufferProducer methods ********************************/ status_t FormatSuggestionRequested( media_type type, int32 quality, media_format* format ); status_t FormatProposal( const media_source& output, media_format* format ); status_t FormatChangeRequested( const media_source& source, const media_destination& destination, media_format* io_format, int32* ); status_t GetNextOutput( int32* cookie, media_output* out_output ); status_t DisposeOutputCookie( int32 cookie ); void LateNoticeReceived( const media_source& what, bigtime_t how_much, bigtime_t performance_time ); void EnableOutput( const media_source& what, bool enabled, int32* _deprecated_ ); status_t PrepareToConnect( const media_source& what, const media_destination& where, media_format* format, media_source* out_source, char* out_name ); void Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name); void Disconnect(const media_source& what, const media_destination& where); status_t SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup); bool mAborted; private: media_output mOutput; media_format mPreferredFormat; uint32 mOutputSampleWidth, mFramesPerBuffer; BBufferGroup *mBufferGroup; bigtime_t mDownstreamLatency, mInternalLatency, mStartTime; uint64 mSamplesSent; PortAudioCallback *mCallback; void *mUserData; bool mRunning; }; portaudio-18.1.orig/pa_asio/0000755000175000000620000000000007700016420016401 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_asio/pa_asio.cpp0000644000175000017500000047562707700001156020711 0ustar mikaelmikael00000000000000/* * $Id: pa_asio.cpp,v 1.7.4.5 2003/06/30 16:27:10 stephane Exp $ * Portable Audio I/O Library for ASIO Drivers * * Author: Stephane Letz * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 2000-2001 Stephane Letz, Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Modification History 08-03-01 First version : Stephane Letz 08-06-01 Tweaks for PC, use C++, buffer allocation, Float32 to Int32 conversion : Phil Burk 08-20-01 More conversion, PA_StreamTime, Pa_GetHostError : Stephane Letz 08-21-01 PaUInt8 bug correction, implementation of ASIOSTFloat32LSB and ASIOSTFloat32MSB native formats : Stephane Letz 08-24-01 MAX_INT32_FP hack, another Uint8 fix : Stephane and Phil 08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when the stream is stopped : Stephane Letz 08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when the stream is stopped : Stephane Letz 10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz 10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz 10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil 10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk 10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz 11-06-01 Rename functions : Stephane Letz 11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz 12-04-02 Add Mac includes for and : Phil Burk 13-04-02 Removes another compiler warning : Stephane Letz 30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz 01-12-02 Fix Pa_GetDefaultInputDeviceID and Pa_GetDefaultOuputDeviceID result when no driver are available : S Letz 05-12-02 More debug messages : S Letz 01-23-03 Increased max channels to 128. Fixed comparison of (OutputChannels > kMaxInputChannels) : P Burk 02-17-03 Better termination handling : PaHost_CloseStream is called in PaHost_term is the the stream was not explicitely closed by the application : S Letz 04-02-03 More robust ASIO driver buffer size initialization : some buggy drivers (like the Hoontech DSP24) give incorrect [min, preferred, max] values They should work with the preferred size value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize computed in PaHost_CalcNumHostBuffers, we try again with the preferred size. Fix an old (never detected?) bug in the buffer adapdation code : S Letz 30-06-03 The audio callback was not protected against reentrancy : some drivers (like the Hoontech DSP24) seems to cause this behaviour that corrupted the buffer adapdation state and finally caused crashes. The reentrancy state is now checked in bufferSwitchTimeInfo : S Letz TO DO : - Check Pa_StopSteam and Pa_AbortStream - Optimization for Input only or Ouput only (really necessary ??) */ #include #include #include #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" #include "asiosys.h" #include "asio.h" #include "asiodrivers.h" #if MAC #include #include #include #else #include #include #include #endif enum { // number of input and outputs supported by the host application // you can change these to higher or lower values kMaxInputChannels = 128, kMaxOutputChannels = 128 }; /* ASIO specific device information. */ typedef struct internalPortAudioDevice { PaDeviceInfo pad_Info; } internalPortAudioDevice; /* ASIO driver internal data storage */ typedef struct PaHostSoundControl { // ASIOInit() ASIODriverInfo pahsc_driverInfo; // ASIOGetChannels() int32 pahsc_NumInputChannels; int32 pahsc_NumOutputChannels; // ASIOGetBufferSize() - sizes in frames per buffer int32 pahsc_minSize; int32 pahsc_maxSize; int32 pahsc_preferredSize; int32 pahsc_granularity; // ASIOGetSampleRate() ASIOSampleRate pahsc_sampleRate; // ASIOOutputReady() bool pahsc_postOutput; // ASIOGetLatencies () int32 pahsc_inputLatency; int32 pahsc_outputLatency; // ASIOCreateBuffers () ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's // ASIOGetChannelInfo() ASIOChannelInfo pahsc_channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's // The above two arrays share the same indexing, as the data in them are linked together // Information from ASIOGetSamplePosition() // data is converted to double floats for easier use, however 64 bit integer can be used, too double nanoSeconds; double samples; double tcSamples; // time code samples // bufferSwitchTimeInfo() ASIOTime tInfo; // time info state unsigned long sysRefTime; // system reference time, when bufferSwitch() was called // Signal the end of processing in this example bool stopped; ASIOCallbacks pahsc_asioCallbacks; int32 pahsc_userInputBufferFrameOffset; // Position in Input user buffer int32 pahsc_userOutputBufferFrameOffset; // Position in Output user buffer int32 pahsc_hostOutputBufferFrameOffset; // Position in Output ASIO buffer int32 past_FramesPerHostBuffer; // Number of frames in ASIO buffer int32 pahsc_InputBufferOffset; // Number of null frames for input buffer alignement int32 pahsc_OutputBufferOffset; // Number of null frames for ouput buffer alignement #if MAC UInt64 pahsc_EntryCount; UInt64 pahsc_LastExitCount; #elif WINDOWS LARGE_INTEGER pahsc_EntryCount; LARGE_INTEGER pahsc_LastExitCount; #endif PaTimestamp pahsc_NumFramesDone; internalPortAudioStream *past; int32 reenterCount; // Counter of audio callback reentrancy int32 reenterError; // Counter of audio callback reentrancy detection } PaHostSoundControl; //---------------------------------------------------------- #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ /* We are trying to be compatible with CARBON but this has not been thoroughly tested. */ #define CARBON_COMPATIBLE (0) #define PA_MAX_DEVICE_INFO (32) #define MIN_INT8 (-0x80) #define MAX_INT8 (0x7F) #define MIN_INT8_FP ((float)-0x80) #define MAX_INT8_FP ((float)0x7F) #define MIN_INT16_FP ((float)-0x8000) #define MAX_INT16_FP ((float)0x7FFF) #define MIN_INT16 (-0x8000) #define MAX_INT16 (0x7FFF) #define MAX_INT32_FP (2147483520.0f) /* 0x0x7FFFFF80 - seems safe */ /************************************************************************************/ /****************** Data ************************************************************/ /************************************************************************************/ static int sNumDevices = 0; static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 }; static int32 sPaHostError = 0; static int sDefaultOutputDeviceID = 0; static int sDefaultInputDeviceID = 0; PaHostSoundControl asioDriverInfo = {0}; #ifdef MAC static bool swap = true; #elif WINDOWS static bool swap = false; #endif // Prototypes static void bufferSwitch(long index, ASIOBool processNow); static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); static void sampleRateChanged(ASIOSampleRate sRate); static long asioMessages(long selector, long value, void* message, double* opt); static void Pa_StartUsageCalculation( internalPortAudioStream *past ); static void Pa_EndUsageCalculation( internalPortAudioStream *past ); static void Pa_ASIO_Convert_Inter_Input( ASIOBufferInfo* nativeBuffer, void* inputBuffer, long NumInputChannels, long NumOuputChannels, long framePerBuffer, long hostFrameOffset, long userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, long index); static void Pa_ASIO_Convert_Inter_Output( ASIOBufferInfo* nativeBuffer, void* outputBuffer, long NumInputChannels, long NumOuputChannels, long framePerBuffer, long hostFrameOffset, long userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, long index); static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, ASIOSampleType nativeFormat, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset, long frames); static void Pa_ASIO_Callback_Input(long index); static void Pa_ASIO_Callback_Output(long index, long framePerBuffer); static void Pa_ASIO_Callback_End(); static void Pa_ASIO_Clear_User_Buffers(); // Some external references extern AsioDrivers* asioDrivers ; bool loadAsioDriver(char *name); unsigned long get_sys_reference_time(); /************************************************************************************/ /****************** Macro ************************************************************/ /************************************************************************************/ #define SwapLong(v) ((((v)>>24)&0xFF)|(((v)>>8)&0xFF00)|(((v)&0xFF00)<<8)|(((v)&0xFF)<<24)) ; #define SwapShort(v) ((((v)>>8)&0xFF)|(((v)&0xFF)<<8)) ; #define ClipShort(v) (((v)MAX_INT16)?MAX_INT16:(v))) #define ClipChar(v) (((v)MAX_INT8)?MAX_INT8:(v))) #define ClipFloat(v) (((v)<-1.0f)?-1.0f:(((v)>1.0f)?1.0f:(v))) #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #endif #ifndef max #define max(a,b) ((a)>=(b)?(a):(b)) #endif static bool Pa_ASIO_loadAsioDriver(char *name) { #ifdef WINDOWS CoInitialize(0); #endif return loadAsioDriver(name); } // Utilities for alignement buffer size computation static int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);} static int PPCM (int a, int b) {return (a*b) / PGCD (a,b);} // Takes the size of host buffer and user buffer : returns the number of frames needed for buffer adaptation static int Pa_ASIO_CalcFrameShift (int M, int N) { int res = 0; for (int i = M; i < PPCM (M,N) ; i+=M) { res = max (res, i%N); } return res; } // We have the following relation : // Pa_ASIO_CalcFrameShift (M,N) + M = Pa_ASIO_CalcFrameShift (N,M) + N /* ASIO sample type to PortAudio sample type conversion */ static PaSampleFormat Pa_ASIO_Convert_SampleFormat(ASIOSampleType type) { switch (type) { case ASIOSTInt16MSB: case ASIOSTInt16LSB: case ASIOSTInt32MSB16: case ASIOSTInt32LSB16: return paInt16; case ASIOSTFloat32MSB: case ASIOSTFloat32LSB: case ASIOSTFloat64MSB: case ASIOSTFloat64LSB: return paFloat32; case ASIOSTInt32MSB: case ASIOSTInt32LSB: case ASIOSTInt32MSB18: case ASIOSTInt32MSB20: case ASIOSTInt32MSB24: case ASIOSTInt32LSB18: case ASIOSTInt32LSB20: case ASIOSTInt32LSB24: return paInt32; case ASIOSTInt24MSB: case ASIOSTInt24LSB: return paInt24; default: return paCustomFormat; } } //-------------------------------------------------------------------------------------------------------------------- static void PaHost_CalcBufferOffset(internalPortAudioStream *past) { if (asioDriverInfo.past_FramesPerHostBuffer > past->past_FramesPerUserBuffer){ // Computes the MINIMUM value of null frames shift for the output buffer alignement asioDriverInfo.pahsc_OutputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer); asioDriverInfo.pahsc_InputBufferOffset = 0; DBUG(("PaHost_CalcBufferOffset : Minimum BufferOffset for Output = %d\n", asioDriverInfo.pahsc_OutputBufferOffset)); }else{ //Computes the MINIMUM value of null frames shift for the input buffer alignement asioDriverInfo.pahsc_InputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer); asioDriverInfo.pahsc_OutputBufferOffset = 0; DBUG(("PaHost_CalcBufferOffset : Minimum BufferOffset for Input = %d\n", asioDriverInfo.pahsc_InputBufferOffset)); } } //-------------------------------------------------------------------------------------------------------------------- /* Allocate ASIO buffers, initialise channels */ static ASIOError Pa_ASIO_CreateBuffers (PaHostSoundControl *asioDriverInfo, long InputChannels, long OutputChannels, long framesPerBuffer) { ASIOError err; int i; ASIOBufferInfo *info = asioDriverInfo->bufferInfos; // Check parameters if ((InputChannels > kMaxInputChannels) || (OutputChannels > kMaxOutputChannels)) return ASE_InvalidParameter; for(i = 0; i < InputChannels; i++, info++){ info->isInput = ASIOTrue; info->channelNum = i; info->buffers[0] = info->buffers[1] = 0; } for(i = 0; i < OutputChannels; i++, info++){ info->isInput = ASIOFalse; info->channelNum = i; info->buffers[0] = info->buffers[1] = 0; } // Set up the asioCallback structure and create the ASIO data buffer asioDriverInfo->pahsc_asioCallbacks.bufferSwitch = &bufferSwitch; asioDriverInfo->pahsc_asioCallbacks.sampleRateDidChange = &sampleRateChanged; asioDriverInfo->pahsc_asioCallbacks.asioMessage = &asioMessages; asioDriverInfo->pahsc_asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo; DBUG(("Pa_ASIO_CreateBuffers : ASIOCreateBuffers with inputChannels = %ld \n", InputChannels)); DBUG(("Pa_ASIO_CreateBuffers : ASIOCreateBuffers with OutputChannels = %ld \n", OutputChannels)); DBUG(("Pa_ASIO_CreateBuffers : ASIOCreateBuffers with size = %ld \n", framesPerBuffer)); err = ASIOCreateBuffers( asioDriverInfo->bufferInfos, InputChannels+OutputChannels, framesPerBuffer, &asioDriverInfo->pahsc_asioCallbacks); if (err != ASE_OK) return err; // Initialise buffers for (i = 0; i < InputChannels + OutputChannels; i++) { asioDriverInfo->pahsc_channelInfos[i].channel = asioDriverInfo->bufferInfos[i].channelNum; asioDriverInfo->pahsc_channelInfos[i].isInput = asioDriverInfo->bufferInfos[i].isInput; err = ASIOGetChannelInfo(&asioDriverInfo->pahsc_channelInfos[i]); if (err != ASE_OK) break; } err = ASIOGetLatencies(&asioDriverInfo->pahsc_inputLatency, &asioDriverInfo->pahsc_outputLatency); DBUG(("Pa_ASIO_CreateBuffers : InputLatency = %ld latency = %ld msec \n", asioDriverInfo->pahsc_inputLatency, (long)((asioDriverInfo->pahsc_inputLatency*1000)/ asioDriverInfo->past->past_SampleRate))); DBUG(("Pa_ASIO_CreateBuffers : OuputLatency = %ld latency = %ld msec \n", asioDriverInfo->pahsc_outputLatency, (long)((asioDriverInfo->pahsc_outputLatency*1000)/ asioDriverInfo->past->past_SampleRate))); return err; } /* Query ASIO driver info : First we get all available ASIO drivers located in the ASIO folder, then try to load each one. For each loaded driver, get all needed informations. */ static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad ) { #define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */ #define NUM_CUSTOMSAMPLINGRATES 9 /* must be the same number of elements as in the array below */ #define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES) ASIOSampleRate possibleSampleRates[] = {8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0}; ASIOChannelInfo channelInfos; long InputChannels,OutputChannels; double *sampleRates; char* names[PA_MAX_DEVICE_INFO] ; PaDeviceInfo *dev; int i; int numDrivers; ASIOError asioError; /* Allocate names */ for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) { names[i] = (char*)PaHost_AllocateFastMemory(32); /* check memory */ if(!names[i]) return paInsufficientMemory; } /* MUST BE CHECKED : to force fragments loading on Mac */ Pa_ASIO_loadAsioDriver("dummy"); /* Get names of all available ASIO drivers */ asioDrivers->getDriverNames(names,PA_MAX_DEVICE_INFO); /* Check all available ASIO drivers */ #if MAC numDrivers = asioDrivers->getNumFragments(); #elif WINDOWS numDrivers = asioDrivers->asioGetNumDev(); #endif DBUG(("PaASIO_QueryDeviceInfo: number of installed drivers = %d\n", numDrivers )); for (int driver = 0 ; driver < numDrivers ; driver++) { #if WINDOWS asioDriverInfo.pahsc_driverInfo.asioVersion = 2; // FIXME - is this right? PLB asioDriverInfo.pahsc_driverInfo.sysRef = GetDesktopWindow(); // FIXME - is this right? PLB #endif DBUG(("---------------------------------------\n")); DBUG(("PaASIO_QueryDeviceInfo: Driver name = %s\n", names[driver])); /* If the driver can be loaded : */ if ( !Pa_ASIO_loadAsioDriver(names[driver]) ){ DBUG(("PaASIO_QueryDeviceInfo could not loadAsioDriver %s\n", names[driver])); } else { DBUG(("PaASIO_QueryDeviceInfo: loadAsioDriver OK\n")); if((asioError = ASIOInit(&asioDriverInfo.pahsc_driverInfo)) != ASE_OK){ DBUG(("PaASIO_QueryDeviceInfo: ASIOInit returned %d for %s\n", asioError, names[driver])); }else { DBUG(("PaASIO_QueryDeviceInfo: ASIOInit OK \n")); if(ASIOGetChannels(&InputChannels, &OutputChannels) != ASE_OK){ DBUG(("PaASIO_QueryDeviceInfo could not ASIOGetChannels for %s\n", names[driver])); }else { DBUG(("PaASIO_QueryDeviceInfo: ASIOGetChannels OK \n")); /* Gets the name */ dev = &(ipad[sNumDevices].pad_Info); dev->name = names[driver]; names[driver] = 0; /* Gets Input and Output channels number */ dev->maxInputChannels = InputChannels; dev->maxOutputChannels = OutputChannels; DBUG(("PaASIO_QueryDeviceInfo: InputChannels = %d\n", InputChannels )); DBUG(("PaASIO_QueryDeviceInfo: OutputChannels = %d\n", OutputChannels )); /* Make room in case device supports all rates. */ sampleRates = (double*)PaHost_AllocateFastMemory(MAX_NUMSAMPLINGRATES * sizeof(double)); /* check memory */ if (!sampleRates) { ASIOExit(); return paInsufficientMemory; } dev->sampleRates = sampleRates; dev->numSampleRates = 0; /* Loop through the possible sampling rates and check each to see if the device supports it. */ for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) { if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) { DBUG(("PaASIO_QueryDeviceInfo: possible sample rate = %d\n", (long)possibleSampleRates[index])); dev->numSampleRates += 1; *sampleRates = possibleSampleRates[index]; sampleRates++; } } /* We assume that all channels have the same SampleType, so check the first */ channelInfos.channel = 0; channelInfos.isInput = 1; if ((asioError = ASIOGetChannelInfo(&channelInfos)) == ASE_NotPresent) { DBUG(("PaASIO_QueryDeviceInfo: ASIOGetChannelInfo returned %d \n",asioError)); } dev->nativeSampleFormats = Pa_ASIO_Convert_SampleFormat(channelInfos.type); /* unload the driver */ if ((asioError = ASIOExit()) != ASE_OK) { DBUG(("PaASIO_QueryDeviceInfo: ASIOExit returned %d \n",asioError)); } sNumDevices++; } } } } /* free only unused names */ for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) if (names[i]) PaHost_FreeFastMemory(names[i],32); return paNoError; } //---------------------------------------------------------------------------------- // TAKEN FROM THE ASIO SDK: void sampleRateChanged(ASIOSampleRate sRate) { // do whatever you need to do if the sample rate changed // usually this only happens during external sync. // Audio processing is not stopped by the driver, actual sample rate // might not have even changed, maybe only the sample rate status of an // AES/EBU or S/PDIF digital input at the audio device. // You might have to update time/sample related conversion routines, etc. } //---------------------------------------------------------------------------------- // TAKEN FROM THE ASIO SDK: long asioMessages(long selector, long value, void* message, double* opt) { // currently the parameters "value", "message" and "opt" are not used. long ret = 0; switch(selector) { case kAsioSelectorSupported: if(value == kAsioResetRequest || value == kAsioEngineVersion || value == kAsioResyncRequest || value == kAsioLatenciesChanged // the following three were added for ASIO 2.0, you don't necessarily have to support them || value == kAsioSupportsTimeInfo || value == kAsioSupportsTimeCode || value == kAsioSupportsInputMonitor) ret = 1L; break; case kAsioBufferSizeChange: //printf("kAsioBufferSizeChange \n"); break; case kAsioResetRequest: // defer the task and perform the reset of the driver during the next "safe" situation // You cannot reset the driver right now, as this code is called from the driver. // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction // Afterwards you initialize the driver again. asioDriverInfo.stopped; // In this sample the processing will just stop ret = 1L; break; case kAsioResyncRequest: // This informs the application, that the driver encountered some non fatal data loss. // It is used for synchronization purposes of different media. // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the // Windows Multimedia system, which could loose data because the Mutex was hold too long // by another thread. // However a driver can issue it in other situations, too. ret = 1L; break; case kAsioLatenciesChanged: // This will inform the host application that the drivers were latencies changed. // Beware, it this does not mean that the buffer sizes have changed! // You might need to update internal delay data. ret = 1L; //printf("kAsioLatenciesChanged \n"); break; case kAsioEngineVersion: // return the supported ASIO version of the host application // If a host applications does not implement this selector, ASIO 1.0 is assumed // by the driver ret = 2L; break; case kAsioSupportsTimeInfo: // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback // is supported. // For compatibility with ASIO 1.0 drivers the host application should always support // the "old" bufferSwitch method, too. ret = 1; break; case kAsioSupportsTimeCode: // informs the driver wether application is interested in time code info. // If an application does not need to know about time code, the driver has less work // to do. ret = 0; break; } return ret; } //---------------------------------------------------------------------------------- // conversion from 64 bit ASIOSample/ASIOTimeStamp to double float #if NATIVE_INT64 #define ASIO64toDouble(a) (a) #else const double twoRaisedTo32 = 4294967296.; #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32) #endif static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow) { // the actual processing callback. // Beware that this is normally in a seperate thread, hence be sure that you take care // about thread synchronization. This is omitted here for simplicity. // store the timeInfo for later use asioDriverInfo.tInfo = *timeInfo; // get the time stamp of the buffer, not necessary if no // synchronization to other media is required if (timeInfo->timeInfo.flags & kSystemTimeValid) asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime); else asioDriverInfo.nanoSeconds = 0; if (timeInfo->timeInfo.flags & kSamplePositionValid) asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition); else asioDriverInfo.samples = 0; if (timeInfo->timeCode.flags & kTcValid) asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples); else asioDriverInfo.tcSamples = 0; // get the system reference time asioDriverInfo.sysRefTime = get_sys_reference_time(); #if 0 // a few debug messages for the Windows device driver developer // tells you the time when driver got its interrupt and the delay until the app receives // the event notification. static double last_samples = 0; char tmp[128]; sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples)); OutputDebugString (tmp); last_samples = asioDriverInfo.samples; #endif // To avoid the callback accessing a desallocated stream if (asioDriverInfo.past == NULL) return 0L; // Keep sample position asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo; // Reentrancy control if( ++asioDriverInfo.reenterCount) { asioDriverInfo.reenterError++; DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError)); return 0L; } do { /* Has a user callback returned '1' to indicate finished at the last ASIO callback? */ if( asioDriverInfo.past->past_StopSoon ) { Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos, asioDriverInfo.pahsc_channelInfos[0].type, asioDriverInfo.pahsc_NumInputChannels , asioDriverInfo.pahsc_NumOutputChannels, index, 0, asioDriverInfo.past_FramesPerHostBuffer); asioDriverInfo.past->past_IsActive = 0; // Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady(); }else { /* CPU usage */ Pa_StartUsageCalculation(asioDriverInfo.past); Pa_ASIO_Callback_Input(index); // Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady(); Pa_ASIO_Callback_End(); /* CPU usage */ Pa_EndUsageCalculation(asioDriverInfo.past); } } while(asioDriverInfo.reenterCount--); return 0L; } //---------------------------------------------------------------------------------- void bufferSwitch(long index, ASIOBool processNow) { // the actual processing callback. // Beware that this is normally in a seperate thread, hence be sure that you take care // about thread synchronization. This is omitted here for simplicity. // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created // though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags ASIOTime timeInfo; memset (&timeInfo, 0, sizeof (timeInfo)); // get the time stamp of the buffer, not necessary if no // synchronization to other media is required if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK) timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid; // Call the real callback bufferSwitchTimeInfo (&timeInfo, index, processNow); } //---------------------------------------------------------------------------------- unsigned long get_sys_reference_time() { // get the system reference time #if WINDOWS return timeGetTime(); #elif MAC static const double twoRaisedTo32 = 4294967296.; UnsignedWide ys; Microseconds(&ys); double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo); return (unsigned long)(r / 1000.); #endif } /************************************************************* ** Calculate 2 LSB dither signal with a triangular distribution. ** Ranged properly for adding to a 32 bit integer prior to >>15. */ #define DITHER_BITS (15) #define DITHER_SCALE (1.0f / ((1<>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS)); /* High pass filter to reduce audibility. */ highPass = current - previous; previous = current; return highPass; } // TO BE COMPLETED WITH ALL SUPPORTED PA SAMPLE TYPES //------------------------------------------------------------------------------------------------------------------------------------------------------- static void Input_Int16_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap) { long temp; int i,j; for( j=0; j>16); userBufPtr += NumInputChannels; } } } else { for( j=0; j> 1) + Pa_TriangularDither(); temp = temp >> 15; temp = (short) ClipShort(temp); *userBufPtr = (short)temp; userBufPtr += NumInputChannels; } } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE TESTED static void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) { unsigned long temp; int i,j; if( flags & paDitherOff ) { for( j=0; j>8); userBufPtr += NumInputChannels; } } } else { for( j=0; j> 8; temp = ClipShort(temp); *userBufPtr = (char)(temp>>8); userBufPtr += NumInputChannels; } } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- static void Input_Int32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset, uint32 flags,bool swap) { long temp; int i,j; if( flags & paDitherOff ) { for( j=0; j>24); userBufPtr += NumInputChannels; } } } else { for( j=0; j>16; // Shift to get a 16 bit value, then use the 16 bits to 8 bits code (MUST BE CHECHED) temp += Pa_TriangularDither() >> 8; temp = ClipShort(temp); *userBufPtr = (char)(temp >> 8); userBufPtr += NumInputChannels; } } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE TESTED static void Input_Float32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap) { unsigned long temp; int i,j; if( flags & paDitherOff ) { for( j=0; j>8) + 0x80); userBufPtr += NumInputChannels; } } } else { for( j=0; j> 8; temp = ClipShort(temp); *userBufPtr = (unsigned char)((temp>>8) + 0x80); userBufPtr += NumInputChannels; } } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- static void Input_Int32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap) { long temp; int i,j; if( flags & paDitherOff ) { for( j=0; j>24) + 0x80); userBufPtr += NumInputChannels; } } } else { for( j=0; j>16; // Shift to get a 16 bit value, then use the 16 bits to 8 bits code (MUST BE CHECHED) temp += Pa_TriangularDither() >> 8; temp = ClipShort(temp); *userBufPtr = (unsigned char)((temp>>8) + 0x80); userBufPtr += NumInputChannels; } } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- // MUST BE TESTED static void Input_Float32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap) { unsigned long temp; int i,j; if( flags & paDitherOff ) { for( j=0; j> 16); if (swap) temp = SwapShort(temp); asioBufPtr[i] = (short)temp; userBufPtr += NumOuputChannels; } } } else { for (j= 0; j < NumOuputChannels; j++) { short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset]; long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)]; for( i=0; i> 1) + Pa_TriangularDither(); temp = temp >> 15; temp = (short) ClipShort(temp); if (swap) temp = SwapShort(temp); asioBufPtr[i] = (short)temp; userBufPtr += NumOuputChannels; } } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- static void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap) { long temp; int i,j; for (j= 0; j < NumOuputChannels; j++) { long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset]; long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)]; for( i=0; ipast_FramesPerUserBuffer <= asioDriverInfo.past_FramesPerHostBuffer) { asioDriverInfo.pahsc_hostOutputBufferFrameOffset = asioDriverInfo.pahsc_OutputBufferOffset; asioDriverInfo.pahsc_userInputBufferFrameOffset = 0; // empty asioDriverInfo.pahsc_userOutputBufferFrameOffset = asioDriverInfo.past->past_FramesPerUserBuffer; // empty DBUG(("Pa_ASIO_Adaptor_Init : shift output\n")); DBUG(("Pa_ASIO_Adaptor_Init : userInputBufferFrameOffset %d\n",asioDriverInfo.pahsc_userInputBufferFrameOffset)); DBUG(("Pa_ASIO_Adaptor_Init : userOutputBufferFrameOffset %d\n",asioDriverInfo.pahsc_userOutputBufferFrameOffset)); DBUG(("Pa_ASIO_Adaptor_Init : hostOutputBufferFrameOffset %d\n",asioDriverInfo.pahsc_hostOutputBufferFrameOffset)); }else { asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0; // empty asioDriverInfo.pahsc_userInputBufferFrameOffset = asioDriverInfo.pahsc_InputBufferOffset; asioDriverInfo.pahsc_userOutputBufferFrameOffset = asioDriverInfo.past->past_FramesPerUserBuffer; // empty DBUG(("Pa_ASIO_Adaptor_Init : shift input\n")); DBUG(("Pa_ASIO_Adaptor_Init : userInputBufferFrameOffset %d\n",asioDriverInfo.pahsc_userInputBufferFrameOffset)); DBUG(("Pa_ASIO_Adaptor_Init : userOutputBufferFrameOffset %d\n",asioDriverInfo.pahsc_userOutputBufferFrameOffset)); DBUG(("Pa_ASIO_Adaptor_Init : hostOutputBufferFrameOffset %d\n",asioDriverInfo.pahsc_hostOutputBufferFrameOffset)); } } //------------------------------------------------------------------------------------------------------------------------------------------------------- // FIXME : optimization for Input only or output only modes (really necessary ??) static void Pa_ASIO_Callback_Input(long index) { internalPortAudioStream *past = asioDriverInfo.past; long framesInputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer; // number of frames available into the host input buffer long framesInputUserBuffer; // number of frames needed to complete the user input buffer long framesOutputHostBuffer; // number of frames needed to complete the host output buffer long framesOuputUserBuffer; // number of frames available into the user output buffer long userResult; long tmp; /* Fill host ASIO output with remaining frames in user output */ framesOutputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer - asioDriverInfo.pahsc_hostOutputBufferFrameOffset; framesOuputUserBuffer = asioDriverInfo.past->past_FramesPerUserBuffer - asioDriverInfo.pahsc_userOutputBufferFrameOffset; tmp = min(framesOutputHostBuffer, framesOuputUserBuffer); framesOutputHostBuffer -= tmp; Pa_ASIO_Callback_Output(index,tmp); /* Available frames in hostInputBuffer */ while (framesInputHostBuffer > 0) { /* Number of frames needed to complete an user input buffer */ framesInputUserBuffer = asioDriverInfo.past->past_FramesPerUserBuffer - asioDriverInfo.pahsc_userInputBufferFrameOffset; if (framesInputHostBuffer >= framesInputUserBuffer) { /* Convert ASIO input to user input */ Pa_ASIO_Convert_Inter_Input (asioDriverInfo.bufferInfos, past->past_InputBuffer, asioDriverInfo.pahsc_NumInputChannels , asioDriverInfo.pahsc_NumOutputChannels, framesInputUserBuffer, asioDriverInfo.past_FramesPerHostBuffer - framesInputHostBuffer, asioDriverInfo.pahsc_userInputBufferFrameOffset, asioDriverInfo.pahsc_channelInfos[0].type, past->past_InputSampleFormat, past->past_Flags, index); /* Call PortAudio callback */ userResult = asioDriverInfo.past->past_Callback(past->past_InputBuffer, past->past_OutputBuffer, past->past_FramesPerUserBuffer,past->past_FrameCount,past->past_UserData ); /* User callback has asked us to stop in the middle of the host buffer */ if( userResult != 0) { /* Put 0 in the end of the output buffer */ Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos, asioDriverInfo.pahsc_channelInfos[0].type, asioDriverInfo.pahsc_NumInputChannels , asioDriverInfo.pahsc_NumOutputChannels, index, asioDriverInfo.pahsc_hostOutputBufferFrameOffset, asioDriverInfo.past_FramesPerHostBuffer - asioDriverInfo.pahsc_hostOutputBufferFrameOffset); past->past_StopSoon = 1; return; } /* Full user ouput buffer : write offset */ asioDriverInfo.pahsc_userOutputBufferFrameOffset = 0; /* Empty user input buffer : read offset */ asioDriverInfo.pahsc_userInputBufferFrameOffset = 0; /* Fill host ASIO output */ tmp = min (past->past_FramesPerUserBuffer,framesOutputHostBuffer); Pa_ASIO_Callback_Output(index,tmp); framesOutputHostBuffer -= tmp; framesInputHostBuffer -= framesInputUserBuffer; }else { /* Convert ASIO input to user input */ Pa_ASIO_Convert_Inter_Input (asioDriverInfo.bufferInfos, past->past_InputBuffer, asioDriverInfo.pahsc_NumInputChannels , asioDriverInfo.pahsc_NumOutputChannels, framesInputHostBuffer, asioDriverInfo.past_FramesPerHostBuffer - framesInputHostBuffer, asioDriverInfo.pahsc_userInputBufferFrameOffset, asioDriverInfo.pahsc_channelInfos[0].type, past->past_InputSampleFormat, past->past_Flags, index); /* Update pahsc_userInputBufferFrameOffset */ asioDriverInfo.pahsc_userInputBufferFrameOffset += framesInputHostBuffer; /* Update framesInputHostBuffer */ framesInputHostBuffer = 0; } } } //------------------------------------------------------------------------------------------------------------------------------------------------------- static void Pa_ASIO_Callback_Output(long index, long framePerBuffer) { internalPortAudioStream *past = asioDriverInfo.past; if (framePerBuffer > 0) { /* Convert user output to ASIO ouput */ Pa_ASIO_Convert_Inter_Output (asioDriverInfo.bufferInfos, past->past_OutputBuffer, asioDriverInfo.pahsc_NumInputChannels, asioDriverInfo.pahsc_NumOutputChannels, framePerBuffer, asioDriverInfo.pahsc_hostOutputBufferFrameOffset, asioDriverInfo.pahsc_userOutputBufferFrameOffset, asioDriverInfo.pahsc_channelInfos[0].type, past->past_InputSampleFormat, past->past_Flags, index); /* Update hostOuputFrameOffset */ asioDriverInfo.pahsc_hostOutputBufferFrameOffset += framePerBuffer; /* Update userOutputFrameOffset */ asioDriverInfo.pahsc_userOutputBufferFrameOffset += framePerBuffer; } } //------------------------------------------------------------------------------------------------------------------------------------------------------- static void Pa_ASIO_Callback_End() { /* Empty ASIO ouput : write offset */ asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0; } //------------------------------------------------------------------------------------------------------------------------------------------------------- static void Pa_ASIO_Clear_User_Buffers() { if( asioDriverInfo.past->past_InputBuffer != NULL ) { memset( asioDriverInfo.past->past_InputBuffer, 0, asioDriverInfo.past->past_InputBufferSize ); } if( asioDriverInfo.past->past_OutputBuffer != NULL ) { memset( asioDriverInfo.past->past_OutputBuffer, 0, asioDriverInfo.past->past_OutputBufferSize ); } } //------------------------------------------------------------------------------------------------------------------------------------------------------- static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer, ASIOSampleType nativeFormat, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset, long frames) { switch (nativeFormat) { case ASIOSTInt16MSB: case ASIOSTInt16LSB: case ASIOSTInt32MSB16: case ASIOSTInt32LSB16: Pa_ASIO_Clear_Output_16(nativeBuffer, frames, NumInputChannels, NumOuputChannels, index, hostFrameOffset); break; case ASIOSTFloat64MSB: case ASIOSTFloat64LSB: break; case ASIOSTFloat32MSB: case ASIOSTFloat32LSB: case ASIOSTInt32MSB: case ASIOSTInt32LSB: case ASIOSTInt32MSB18: case ASIOSTInt32MSB20: case ASIOSTInt32MSB24: case ASIOSTInt32LSB18: case ASIOSTInt32LSB20: case ASIOSTInt32LSB24: Pa_ASIO_Clear_Output_32(nativeBuffer, frames, NumInputChannels, NumOuputChannels, index, hostFrameOffset); break; case ASIOSTInt24MSB: case ASIOSTInt24LSB: break; default: break; } } //--------------------------------------------------------------------------------------- static void Pa_ASIO_Convert_Inter_Input( ASIOBufferInfo* nativeBuffer, void* inputBuffer, long NumInputChannels, long NumOuputChannels, long framePerBuffer, long hostFrameOffset, long userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, long index) { if((NumInputChannels > 0) && (nativeBuffer != NULL)) { /* Convert from native format to PA format. */ switch(paFormat) { case paFloat32: { float *inBufPtr = (float *) inputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap); break; case ASIOSTInt16MSB: Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTInt32LSB: Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); break; case ASIOSTInt32MSB: Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap); break; case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } case paInt32: { long *inBufPtr = (long *)inputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Input_Int16_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt16MSB: Input_Int16_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt32LSB: Input_Int32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt32MSB: Input_Int32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } case paInt16: { short *inBufPtr = (short *) inputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Input_Int16_Int16(nativeBuffer, inBufPtr, framePerBuffer , NumInputChannels, index , hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt16MSB: Input_Int16_Int16(nativeBuffer, inBufPtr, framePerBuffer , NumInputChannels, index , hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt32LSB: Input_Int32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); break; case ASIOSTInt32MSB: Input_Int32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); break; case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } case paInt8: { /* Convert 16 bit data to 8 bit chars */ char *inBufPtr = (char *) inputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Input_Int16_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap); break; case ASIOSTInt16MSB: Input_Int16_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTInt32LSB: Input_Int32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); break; case ASIOSTInt32MSB: Input_Int32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); break; case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } case paUInt8: { /* Convert 16 bit data to 8 bit unsigned chars */ unsigned char *inBufPtr = (unsigned char *)inputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Input_Int16_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); break; case ASIOSTInt16MSB: Input_Int16_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTInt32LSB: Input_Int32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap); break; case ASIOSTInt32MSB: Input_Int32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap); break; case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture Input_Float32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,!swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } default: break; } } } //--------------------------------------------------------------------------------------- static void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer, void* outputBuffer, long NumInputChannels, long NumOuputChannels, long framePerBuffer, long hostFrameOffset, long userFrameOffset, ASIOSampleType nativeFormat, PaSampleFormat paFormat, PaStreamFlags flags, long index) { if((NumOuputChannels > 0) && (nativeBuffer != NULL)) { /* Convert from PA format to native format */ switch(paFormat) { case paFloat32: { float *outBufPtr = (float *) outputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Output_Float32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags, swap); break; case ASIOSTInt16MSB: Output_Float32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags,!swap); break; case ASIOSTInt32LSB: Output_Float32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags,swap); break; case ASIOSTInt32MSB: Output_Float32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTFloat32LSB: Output_Float32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset,flags,swap); break; case ASIOSTFloat32MSB: Output_Float32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } case paInt32: { long *outBufPtr = (long *) outputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Output_Int32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); break; case ASIOSTInt16MSB: Output_Int32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTInt32LSB: Output_Int32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); break; case ASIOSTInt32MSB: Output_Int32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTFloat32LSB: Output_Int32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap); break; case ASIOSTFloat32MSB: Output_Int32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } case paInt16: { short *outBufPtr = (short *) outputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Output_Int16_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt16MSB: Output_Int16_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt32LSB: Output_Int16_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt32MSB: Output_Int16_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTFloat32LSB: Output_Int16_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTFloat32MSB: Output_Int16_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } case paInt8: { char *outBufPtr = (char *) outputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Output_Int8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt16MSB: Output_Int8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt32LSB: Output_Int8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt32MSB: Output_Int8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTFloat32LSB: Output_Int8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTFloat32MSB: Output_Int8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } case paUInt8: { unsigned char *outBufPtr = (unsigned char *) outputBuffer; switch (nativeFormat) { case ASIOSTInt16LSB: Output_IntU8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt16MSB: Output_IntU8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt32LSB: Output_IntU8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTInt32MSB: Output_IntU8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTFloat32LSB: Output_IntU8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap); break; case ASIOSTFloat32MSB: Output_IntU8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap); break; case ASIOSTInt24LSB: // used for 20 bits as well case ASIOSTInt24MSB: // used for 20 bits as well case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture // these are used for 32 bit data buffer, with different alignment of the data inside // 32 bit PCI bus systems can more easily used with these case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment DBUG(("Not yet implemented : please report the problem\n")); break; } break; } default: break; } } } /* Load a ASIO driver corresponding to the required device */ static PaError Pa_ASIO_loadDevice (long device) { PaDeviceInfo * dev = &(sDevices[device].pad_Info); if (!Pa_ASIO_loadAsioDriver((char *) dev->name)) return paHostError; if (ASIOInit(&asioDriverInfo.pahsc_driverInfo) != ASE_OK) return paHostError; if (ASIOGetChannels(&asioDriverInfo.pahsc_NumInputChannels, &asioDriverInfo.pahsc_NumOutputChannels) != ASE_OK) return paHostError; if (ASIOGetBufferSize(&asioDriverInfo.pahsc_minSize, &asioDriverInfo.pahsc_maxSize, &asioDriverInfo.pahsc_preferredSize, &asioDriverInfo.pahsc_granularity) != ASE_OK) return paHostError; if(ASIOOutputReady() == ASE_OK) asioDriverInfo.pahsc_postOutput = true; else asioDriverInfo.pahsc_postOutput = false; return paNoError; } //--------------------------------------------------- static int GetHighestBitPosition (unsigned long n) { int pos = -1; while( n != 0 ) { pos++; n = n >> 1; } return pos; } //------------------------------------------------------------------------------------------ static int GetFirstMultiple(long min, long val ){ return ((min + val - 1) / val) * val; } //------------------------------------------------------------------------------------------ static int GetFirstPossibleDivisor(long max, long val ) { for (int i = 2; i < 20; i++) {if (((val%i) == 0) && ((val/i) <= max)) return (val/i); } return val; } //------------------------------------------------------------------------ static int IsPowerOfTwo( unsigned long n ) { return ((n & (n-1)) == 0); } /******************************************************************* * Determine size of native ASIO audio buffer size * Input parameters : FramesPerUserBuffer, NumUserBuffers * Output values : FramesPerHostBuffer, OutputBufferOffset or InputtBufferOffset */ static PaError PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; long requestedBufferSize; long firstMultiple, firstDivisor; // Compute requestedBufferSize if( past->past_NumUserBuffers < 1 ){ requestedBufferSize = past->past_FramesPerUserBuffer; }else{ requestedBufferSize = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; } // Adjust FramesPerHostBuffer using requestedBufferSize, ASIO minSize and maxSize, if (requestedBufferSize < asioDriverInfo.pahsc_minSize){ firstMultiple = GetFirstMultiple(asioDriverInfo.pahsc_minSize, requestedBufferSize); if (firstMultiple <= asioDriverInfo.pahsc_maxSize) asioDriverInfo.past_FramesPerHostBuffer = firstMultiple; else asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_minSize; }else if (requestedBufferSize > asioDriverInfo.pahsc_maxSize){ firstDivisor = GetFirstPossibleDivisor(asioDriverInfo.pahsc_maxSize, requestedBufferSize); if ((firstDivisor >= asioDriverInfo.pahsc_minSize) && (firstDivisor <= asioDriverInfo.pahsc_maxSize)) asioDriverInfo.past_FramesPerHostBuffer = firstDivisor; else asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_maxSize; }else{ asioDriverInfo.past_FramesPerHostBuffer = requestedBufferSize; } // If ASIO buffer size needs to be a power of two if( asioDriverInfo.pahsc_granularity < 0 ){ // Needs to be a power of two. if( !IsPowerOfTwo( asioDriverInfo.past_FramesPerHostBuffer ) ) { int highestBit = GetHighestBitPosition(asioDriverInfo.past_FramesPerHostBuffer); asioDriverInfo.past_FramesPerHostBuffer = 1 << (highestBit + 1); } } DBUG(("----------------------------------\n")); DBUG(("PaHost_CalcNumHostBuffers : minSize = %ld \n",asioDriverInfo.pahsc_minSize)); DBUG(("PaHost_CalcNumHostBuffers : preferredSize = %ld \n",asioDriverInfo.pahsc_preferredSize)); DBUG(("PaHost_CalcNumHostBuffers : maxSize = %ld \n",asioDriverInfo.pahsc_maxSize)); DBUG(("PaHost_CalcNumHostBuffers : granularity = %ld \n",asioDriverInfo.pahsc_granularity)); DBUG(("PaHost_CalcNumHostBuffers : User buffer size = %d\n", asioDriverInfo.past->past_FramesPerUserBuffer )); DBUG(("PaHost_CalcNumHostBuffers : ASIO buffer size = %d\n", asioDriverInfo.past_FramesPerHostBuffer )); return paNoError; } /***********************************************************************/ int Pa_CountDevices() { PaError err ; if( sNumDevices <= 0 ) { /* Force loading of ASIO drivers */ err = Pa_ASIO_QueryDeviceInfo(sDevices); if( err != paNoError ) goto error; } return sNumDevices; error: PaHost_Term(); DBUG(("Pa_CountDevices: returns %d\n", err )); return err; } /***********************************************************************/ PaError PaHost_Init( void ) { /* Have we already initialized the device info? */ PaError err = (PaError) Pa_CountDevices(); return ( err < 0 ) ? err : paNoError; } /***********************************************************************/ PaError PaHost_Term( void ) { int i; PaDeviceInfo *dev; double *rates; PaError result = paNoError; if (sNumDevices > 0) { /* Free allocated sample rate arrays and names*/ for( i=0; isampleRates; if ((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double)); dev->sampleRates = NULL; if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32); dev->name = NULL; } sNumDevices = 0; /* If the stream has been closed with PaHost_CloseStream, asioDriverInfo.past == null, otherwise close it now */ if(asioDriverInfo.past != NULL) Pa_CloseStream(asioDriverInfo.past); /* remove the loaded ASIO driver */ asioDrivers->removeCurrentDriver(); } return result; } /***********************************************************************/ PaError PaHost_OpenStream( internalPortAudioStream *past ) { PaError result = paNoError; ASIOError err; int32 device; /* Check if a stream already runs */ if (asioDriverInfo.past != NULL) return paHostError; /* Check the device number */ if ((past->past_InputDeviceID != paNoDevice) &&(past->past_OutputDeviceID != paNoDevice) &&(past->past_InputDeviceID != past->past_OutputDeviceID)) { return paInvalidDeviceId; } /* Allocation */ memset(&asioDriverInfo, 0, sizeof(PaHostSoundControl)); past->past_DeviceData = (void*) &asioDriverInfo; /* Reentrancy counter initialisation */ asioDriverInfo.reenterCount = -1; asioDriverInfo.reenterError = 0; /* FIXME */ asioDriverInfo.past = past; /* load the ASIO device */ device = (past->past_InputDeviceID < 0) ? past->past_OutputDeviceID : past->past_InputDeviceID; result = Pa_ASIO_loadDevice(device); if (result != paNoError) goto error; /* Check ASIO parameters and input parameters */ if ((past->past_NumInputChannels > asioDriverInfo.pahsc_NumInputChannels) || (past->past_NumOutputChannels > asioDriverInfo.pahsc_NumOutputChannels)) { result = paInvalidChannelCount; goto error; } /* Set sample rate */ if (ASIOSetSampleRate(past->past_SampleRate) != ASE_OK) { result = paInvalidSampleRate; goto error; } /* if OK calc buffer size */ result = PaHost_CalcNumHostBuffers( past ); if (result != paNoError) goto error; /* Allocating input and output buffers number for the real past_NumInputChannels and past_NumOutputChannels optimize the data transfer. */ asioDriverInfo.pahsc_NumInputChannels = past->past_NumInputChannels; asioDriverInfo.pahsc_NumOutputChannels = past->past_NumOutputChannels; /* Allocate ASIO buffers and callback*/ err = Pa_ASIO_CreateBuffers(&asioDriverInfo, asioDriverInfo.pahsc_NumInputChannels, asioDriverInfo.pahsc_NumOutputChannels, asioDriverInfo.past_FramesPerHostBuffer); /* Some buggy drivers (like the Hoontech DSP24) give incorrect [min, preferred, max] values They should work with the preferred size value, thus if Pa_ASIO_CreateBuffers fails with the hostBufferSize computed in PaHost_CalcNumHostBuffers, we try again with the preferred size. */ if (err != ASE_OK) { DBUG(("PaHost_OpenStream : Pa_ASIO_CreateBuffers failed with the requested framesPerBuffer = %ld \n", asioDriverInfo.past_FramesPerHostBuffer)); err = Pa_ASIO_CreateBuffers(&asioDriverInfo, asioDriverInfo.pahsc_NumInputChannels, asioDriverInfo.pahsc_NumOutputChannels, asioDriverInfo.pahsc_preferredSize); if (err == ASE_OK) { // Adjust FramesPerHostBuffer to take the preferredSize instead of the value computed in PaHost_CalcNumHostBuffers asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_preferredSize; DBUG(("PaHost_OpenStream : Adjust FramesPerHostBuffer to take the preferredSize instead of the value computed in PaHost_CalcNumHostBuffers\n")); } else { DBUG(("PaHost_OpenStream : Pa_ASIO_CreateBuffers failed with the preferred framesPerBuffer = %ld \n", asioDriverInfo.pahsc_preferredSize)); } } /* Compute buffer adapdation offset */ PaHost_CalcBufferOffset(past); if (err == ASE_OK) return paNoError; else if (err == ASE_NoMemory) result = paInsufficientMemory; else if (err == ASE_InvalidParameter) result = paInvalidChannelCount; else if (err == ASE_InvalidMode) result = paBufferTooBig; else result = paHostError; error: ASIOExit(); return result; } /***********************************************************************/ PaError PaHost_CloseStream( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; PaError result = paNoError; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); #endif /* Free data and device for output. */ past->past_DeviceData = NULL; asioDriverInfo.past = NULL; /* Dispose */ if(ASIODisposeBuffers() != ASE_OK) result = paHostError; if(ASIOExit() != ASE_OK) result = paHostError; return result; } /***********************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { /* Clear the index 0 host output buffer */ Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos, asioDriverInfo.pahsc_channelInfos[0].type, asioDriverInfo.pahsc_NumInputChannels, asioDriverInfo.pahsc_NumOutputChannels, 0, 0, asioDriverInfo.past_FramesPerHostBuffer); /* Clear the index 1 host output buffer */ Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos, asioDriverInfo.pahsc_channelInfos[0].type, asioDriverInfo.pahsc_NumInputChannels, asioDriverInfo.pahsc_NumOutputChannels, 1, 0, asioDriverInfo.past_FramesPerHostBuffer); Pa_ASIO_Clear_User_Buffers(); Pa_ASIO_Adaptor_Init(); return paNoError; } /***********************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { /* Nothing to do ?? */ return paNoError; } /***********************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *past ) { /* Nothing to do ?? */ return paNoError; } /***********************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { /* Nothing to do */ return paNoError; } /***********************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *past ) { // TO DO : count of samples past->past_IsActive = 1; return (ASIOStart() == ASE_OK) ? paNoError : paHostError; } /***********************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { // TO DO : count of samples past->past_IsActive = 0; return (ASIOStop() == ASE_OK) ? paNoError : paHostError; } /***********************************************************************/ // TO BE CHECKED PaError PaHost_StreamActive( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; return (PaError) past->past_IsActive; } /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { PaHostSoundControl *pahsc; internalPortAudioStream *past = (internalPortAudioStream *) stream; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; return pahsc->pahsc_NumFramesDone; } /************************************************************************* * Allocate memory that can be accessed in real-time. * This may need to be held in physical memory so that it is not * paged to virtual memory. * This call MUST be balanced with a call to PaHost_FreeFastMemory(). */ void *PaHost_AllocateFastMemory( long numBytes ) { #if MAC void *addr = NewPtrClear( numBytes ); if( (addr == NULL) || (MemError () != 0) ) return NULL; #if (CARBON_COMPATIBLE == 0) if( HoldMemory( addr, numBytes ) != noErr ) { DisposePtr( (Ptr) addr ); return NULL; } #endif return addr; #elif WINDOWS void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */ if( addr != NULL ) memset( addr, 0, numBytes ); return addr; #endif } /************************************************************************* * Free memory that could be accessed in real-time. * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory( void *addr, long numBytes ) { #if MAC if( addr == NULL ) return; #if CARBON_COMPATIBLE (void) numBytes; #else UnholdMemory( addr, numBytes ); #endif DisposePtr( (Ptr) addr ); #elif WINDOWS if( addr != NULL ) free( addr ); #endif } /*************************************************************************/ void Pa_Sleep( long msec ) { #if MAC int32 sleepTime, endTime; /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */ sleepTime = ((msec * 60) + 999) / 1000; if( sleepTime < 1 ) sleepTime = 1; endTime = TickCount() + sleepTime; do{ DBUGX(("Sleep for %d ticks.\n", sleepTime )); WaitNextEvent( 0, NULL, sleepTime, NULL ); /* Use this just to sleep without getting events. */ sleepTime = endTime - TickCount(); } while( sleepTime > 0 ); #elif WINDOWS Sleep( msec ); #endif } /*************************************************************************/ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; return &sDevices[id].pad_Info; } /*************************************************************************/ PaDeviceID Pa_GetDefaultInputDeviceID( void ) { return (sNumDevices > 0) ? sDefaultInputDeviceID : paNoDevice; } /*************************************************************************/ PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { return (sNumDevices > 0) ? sDefaultOutputDeviceID : paNoDevice; } /*************************************************************************/ int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) { // TO BE IMPLEMENTED : using the ASIOGetLatency call?? return 2; } /*************************************************************************/ int32 Pa_GetHostError( void ) { int32 err = sPaHostError; sPaHostError = 0; return err; } #ifdef MAC /**************************************************************************/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; UnsignedWide widePad; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ Microseconds( &widePad ); pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad ); } /**************************************************************************/ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { UnsignedWide widePad; UInt64 CurrentCount; long InsideCount; long TotalCount; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Measure CPU utilization during this callback. Note that this calculation ** assumes that we had the processor the whole time. */ #define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) Microseconds( &widePad ); CurrentCount = UnsignedWideToUInt64( widePad ); if( past->past_IfLastExitValid ) { InsideCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_EntryCount); TotalCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_LastExitCount); /* Low pass filter the result because sometimes we get called several times in a row. * That can cause the TotalCount to be very low which can cause the usage to appear * unnaturally high. So we must filter numerator and denominator separately!!! */ past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + (LOWPASS_COEFFICIENT_1 * InsideCount)); past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + (LOWPASS_COEFFICIENT_1 * TotalCount)); past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; } pahsc->pahsc_LastExitCount = CurrentCount; past->past_IfLastExitValid = 1; } #elif WINDOWS /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ QueryPerformanceCounter( &pahsc->pahsc_EntryCount ); } static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { LARGE_INTEGER CurrentCount = { 0, 0 }; LONGLONG InsideCount; LONGLONG TotalCount; /* ** Measure CPU utilization during this callback. Note that this calculation ** assumes that we had the processor the whole time. */ #define LOWPASS_COEFFICIENT_0 (0.9) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; if( QueryPerformanceCounter( &CurrentCount ) ) { if( past->past_IfLastExitValid ) { InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart; TotalCount = CurrentCount.QuadPart - pahsc->pahsc_LastExitCount.QuadPart; /* Low pass filter the result because sometimes we get called several times in a row. * That can cause the TotalCount to be very low which can cause the usage to appear * unnaturally high. So we must filter numerator and denominator separately!!! */ past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + (LOWPASS_COEFFICIENT_1 * InsideCount)); past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + (LOWPASS_COEFFICIENT_1 * TotalCount)); past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; } pahsc->pahsc_LastExitCount = CurrentCount; past->past_IfLastExitValid = 1; } } #endif portaudio-18.1.orig/pa_asio/Callback_adaptation_.pdf0000644000175000017500000014253707423043452023322 0ustar mikaelmikael00000000000000%PDF-1.2 %âãÏÓ 2 0 obj << /Length 1731 /Filter /FlateDecode >> stream H‰¬WÛrÛ6ýýÃ>Ê‹!À›˜¾ÔvO2±“‰Õétâs¿ C|ªÖp(¡áò0" s9¼ýŒg}øíã-\‰Tü‰ÄšˆÌÀ1ߺ‘£Ÿ?o¢³Vàå[nE2ã fÈnGdØŸ^,+­’•¶‹=»Ø…ÇÌ‘×`Žlœ¾LÛ¬‚T®êB”RQ­T¶$°úQqåƒÈåN¤°– ôVÀ'©ôEfv8\}q÷î£æ„Bè­L­Ý1qKãÜ·0Ìi.`Y¯×BU ×f4$€UöÀ•)lêD%¥r¹•†<Ñ¢\nЍ–‡Æ€Ù2ðÁ1:2ûŒ ]HBÅã¤`ð®ÔJ¦õŠ,X~ÛŒídLû}ÖeD«Æü–iñ$§;%—¹(`ŸT€ÈRèÁ~›åèV*³rƒá°¤®¨¾øô®ešÆ˜å³˜9ói¿Â¸»xa@µ˜‚˜YL™ ´’U5Û!Êòl©uÀƒMà2T ´DR(ÆlVbΘ@ÈZãðÜb0o’UVjYmÍü¯Y™Ê}e ÁøAƒÆ÷šüùg':p)õÖ˜Ålë©]&•HÏ1úŠäu%O jˆÈm¥èF‘EDÚiÜåÈNa(5©’|#U¦·Å ´ÄǨÉaŒ—Bï…(Mðxµ:TZÕ$éSV4’l4e$Éá‚Ì=­¹ê´0ý°-Õ¬-ÕŒ‘ZaZ$°–KYVEÖÉu•= xL)rÙpY¢_Òï§äÚ½ÇùVVÿ{ÝÜýÆ ÆóÈæ&­Qï·ÔãíDþm•î KFé ê¦8 ó †îð-f\Kâ@£ˆ´Ô‡€W£ÒéQ ÔC¯Í/h‹Ú¿ê½zYú¬ö.~ÎìCYŸ!LXSµ¾­éòéV¡üÔëD'÷g?5Qnâ3;Æ·Äž…òË•ƒ÷H­Ê6ñ[—Ïͧd·Ëñª6 #0_RÒ^“*)kò¥I);g“ÇL:XÖ:ÌÊ£úl !;¾Ž?Ͷm‚: 4ݦ¥ñðJ0dT0¢ŸÍ9 "”%ùÜ‹ùf¤\׉}ß®™:öê(ˆ£]nÛ™BB˶K‰ÍË@˜Ð*“Bq¬L’wVì°þbJ÷Ò2K¼ü…µQõ¼Faãï)ì•جïY†±Äk á#!üëó¹ãù.âÛ£câbÌcÇ ±)’¶9œ÷¥ŠÜíã»ÏPÓKÑküD%¶Ž¥°å¹©Õf©'÷Ó¾V£(:ã¸v)žjZú¨ò&ªS"qƒ)Qn²ï;IÅÕ2¹—ƒ ¨o eVÂF”B¡‚Ç«½L7fí­3ª ¼mÁ¹uù ê²4WÄa…Uv,âW&vo|·˜°Ðز†€Æ”˜P÷x¿ï1Pß0p{ºMnàËWRÜ’íqlàC‡öQðm¼›\ÒKMp|Ÿqæï_jŽ+À^ØŒq×âhÎáþÅú¡;fðÊ„­6G„u+¹Æ&G`G6ñÑó6¹ÏOÚ$œ,`q²È}'UÁS8lZœÏØ$œ§lÎ8ŵÁÉÝ'â6s{£]ˆhÏ…GH+6½9ŽândgóÉú} ’n›±ÇqªQÈ£^…!Pî™.Ü\Å”Q&ámØ"òXWÇ62ìv‰NˆÅøæê™†Ê”a²nNyÆ:3ÖÛ0 aŲ40ì%, íÈÎh`~ÔÑÀxÔÓÀr×32i^&úWÍÀ¼¶MG5ðì vâˆwvúd9…­ó¨u ÙÙ¡È_ç@47xXì©©,&œØÅªžã³°ÙYc?PŽE3¦—£Ó,xسØkYÚ ¸ƒfíTñ_…Œáµy®%8Až9zÎûxÇfÅÔPÓsÖÐø—º2ÊŽ endstream endobj 3 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 4 0 R /F2 5 0 R /F3 6 0 R /F5 7 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 11 0 obj << /Length 2123 /Filter /FlateDecode >> stream H‰¤WÛŽÛFýýC?*ƨ;ðf q²$€f±°€}Èæ[3Œ)R!©‘µ_¿U}!›G͈ͪS·sª?oÿÉ#›ý‚ÿÁG‘8ŽÈæ°ÈËâãÏ_yi 'wøKS²9/–ÿå2$Ý«"¯Y“Ÿ³F‘}Q–­þê»Í`ë)•1Xßü¤íní&ÐÎoË׺íHQOÙžö{Õ|÷ûæ×\L…^g‰ƒ…æuRïI[üO‘µ~oÅ"𰀑£Ì½å|²Dޱ€rÊx0øb:b ïǬ,·Ùî«9n…4–" ñÔzቃV´d¯ªÜ@‹iI>F&ÜK"A!c4 ½òȽrëé*‰dšÅ$Â3Ñûå¶ }u×dU VTNºÚdʘs€MYìÕE¸ö…tjÄMDQ ɘ J&cDÏ&{<¥‚Cýýô±¾²Œß®,ÐÆº´Ñ•–ŒjÁ¡ õÚ.í;È`;œ ß[eË‹I:6u~Ú)’]§Jĉ_=Ù§>ñRUŸn/bÑ,6Ÿ*ð3J•sË„¸“ªÈó…mi +ß{UVî7Ædô¼y}ž4ZQÍ·§q¦ssKAH× L(ÐE8[‚hÒý&" ¾1Jà@=¶n×ÉÑ 8WŠ¡ýX(ý©½QøÒžÚ¯0ò€¦ ™S>SdÛŸÕ.T0ÖY•CÎeQ‘U©&+I^ [UuOðœdù1ë²®¨+Ò^ÚNˆëó\½©²>ªœ’/õA‘F²¢*ª²o²}ò‡<¼Ùòc–Ë ‚JƒÑ¯êØ‘üÔ ™º‚aºìJEÌ3Àœ»g˜âJ}ëÌJ6ø÷é°ÅFÜÝ;7ÆøK‹ªl÷j-jlUÝh›&UR¤8ÍÊsv1ÖBT´ÅOñ@9FL;.ËúŒXwuÕBSC3·}òÕÕ®ƒ€>éa4›tPR¯¯²Î„ {¤/›vVIoÚRÛ™d‚×¶8㦊@æ¼ÒÞ»p²å³6 i£vªxSùdþ´\t“qiFs`Ì/wõáXªN•]ã í&¡¯ö#Ÿ@è9]>!½útµ’0©èÄo·^ÛR;h£lŒÎEaé;§ãd¹fé£ädöÇí§ÍÙ6äá\t¯ÓÒ±”rÉSoÝ`~ížÚ÷7#T–”{¢>´´[@pæu÷¿§NP­8bž‰© ö80í+‘ЈÁâæg;t ÆÖíûêÒP†®Àú5í„jãö¡o;Мk’=ª;V=gE!6 ʬSÕîœÔZJ9a€@óI9¼$s»‘S{ä“L×e•Ÿ {¿Aa[E§Be¶hN¢€„ÈñmN:݉†¶ä³é=ÍæYžsùڽVÅŸ'˜X*†õ ãîr˜L7+ùF‡™m ‰¢áN·hw®ûmŸÎ×Q´†µMнŠ\Ëñ'B&;èDjâ^mã ¨Û`Î2´µõâ<œÊ®€Üõ”í=Ô‰üÇf·O‘ ° 6Î{Pmò3üÿ’ð?c*Öä·ß’Ã+ÁwhHd’ÂOÆ@¶á¶/~ÑÆ¬3¾1sX$ñôðg¼…Ób Ø€d»;‘×µëwªÄ€v$ÎÂa±Ò™Òý´ü¥ÂóåŸ š#cw-ø@çÿ!ºlð€S„ÎŽöº,&h :iÏŸæª7‹0áÂë걓³EÌH"ßG˜ê¥€ªßG()nrî,úŒz!Ô­w]bz@B”Çý.C W&wÛ=âP1þ^»¯$…¾ Þ"~}𜠑jç@SÎ9|58OGÎ}ŸØQÂù46kXAs„°ãÀ':[O"PšëHa1¾Št`ÐÏóƒa¡§ë°Œ§›a¡‚ùaÍð…á‘Ö‹¥•Y T ='\ÏEN–£ÀÊÛs »ì›HæÅ¸•¼m?ͯz¹_ö‰y´Ûmû›|øúù‰¬?>O7ûÕ0 æWfzs²WÞ"dÖÄ·Ž€Õ§nØèmºº x¨ˆÏ P^¼mÝ<¢?ò}ÕWæçTÅq_½š çIû²pÆ ‹gÜŒ­3èÄQûºF•ÁÔ&|õ€M÷–ÍI:ŒÍÙtŒmòxÞ¦N1*‹QŽå Ê|ΪÀÜN˜ÂÏh’ÌYeÁ]«,f­þåø²½øAsb+¸ë[{Ò;{.¼¿7X;í öìßÛ°*÷÷.[gp+°goí ÷¶¼sÞßXú(»5سo ñ­…Ñ[ “‡·wö¡­aÅB òƒÑKMâöú$´´úK¥oÇF½õ©ÆDâ&ê[¦?Ï(> /ExtGState << /GS1 8 0 R >> >> endobj 14 0 obj << /Length 1921 /Filter /FlateDecode >> stream H‰œWÛnÛFýýÃ<*©Eswy5šq›KƒÚE}Hò@I+‹ Eª¼Xq¿¾3{¡Hš¢"ˆE‰³3g®göz9»|ÇÁr;c.Ð?ü=Öû™ w³Ë÷ŸÜU3×q]æÁrMOŒG°<Î>Ï…#à—¤’ à vEUêÙne Uú¯„ª9È2-J(¶ÐTøkç勯˳·Ë*ŸñH@è¢YœC)g[4ýÿDDßß‘pÝÀç¯.lðD tÄñ!ä¾ú ÎèܧÙ5¹ä—¸v‰ƒ`!„øi|r•äÁüöÅò[†‡XÐâ0v†ó{†:úÇ“‘Õ?¿h „ÑøÞ“ZׄݥQô8$ýH¡ßêTþ_¾cÃ"`1*ñb’[¨Ô ŠÙü·Ü`øgÆb*DþEKC®lµ:¸‹åá¶zTÔç£àÏ¡läðXXÙySwˉÎ,˜#Hb!œ–¿jXäÉ,ªâ` ‹Ø© ž€ÅܶxV§-,’èÁÒ¨þhꬓ…i; +v"ô¾ÍÎ,æ9aYYm“©£ã0Ž a@IØõÆŠ"ï,BF­ÏPêùd¾CóÂÊ’ÍÀLW¨ÖK1¶3²Á<ù…O^l†Îr—VÀ¾(%¬‹ý!“?`MC踓¹}Q«ÓuRËMo*%›äP'uZäP=TµÜþ!¶E“oxSC½ÃoiYˆjX¹€‘d„ž…”m‚µN²l•¬¿_ „î(Äá§ìÞÂ.åZ¦÷­\Ëu‚™ÂŸ_Ãí…²¨gÕàCN è;z°.òªÙ§ùܶLöCo4²åK„Ab^` ÊbÓ¬éê*šúЯ‚fµ! †‚ AÝÂÏpCŽèøÖÒžî:¦l·âq,/ׄ‡Å&kXŬ'‡¼PqVê@'¤‚™ÌçªB4|t~“bÜêì¡7¬"Çž8™ôCcÒ÷û,1ª+y—æ9Ý=%¶U®\2îåÍ~…žµ‘ªØÓz‡¯²ÌÄêŒ B·.Ú²ˆ• ŪNRe\Y.²¬8Ò·j½“{ WÝ‘Ž$áEqo¤ é>öÝsXŽ#xqøË¡ ôøHÛñÄ$ñˆƒ/Üq>"ðî˜V?­Õc­#Œ$‚­ó FPøÎ3’ÅHFÏäSŒdd§É›`$‚åÅÁ#,b$5áž‹øÆÈN3’7ÁH VÀ'ID\1’xÏ€*F2²Ïa¤¾Fx†‘B7š`$+1R[?“#ÅHV–lÆ–‘xx†’P0¸ðîgÜGy þ†E‹d™µo³Ùö%V<êLj¡¨ðÕ à!¬JódއöIPÇgBÆà¾yf Ù·ÊÀ©ª l:mHIeH=éã¤^?©ÚP/.Ì6&*kBE=êÑ=O6‚ùgCSéÔùž7Úø4mßëA¢h’¦œ°âœÃv—çÓSÎWu{fÊLŽ€:¬Mz`“„±¦‰ONâRîÍ 6ìºKî%ÔÑÀwy¨aÓ”ŠCr¤ä‡ufßaioì;ñ¹üQU´‘æ(×’{šËŒ¬nhKÑ7[Ž!Y"ùö¸a)ýÊwESÂ}’5´ ” šÛÈj]¦ŽV¸ëHK}fá¹êS7-† îð–ÄÃ…!ï/ÜóᵆöÀ4ˆÖÒò1óc¯åãr­^éiŽEDv¹OÒ,YaÄÒ\IìÎ2pÆRo³Ë%óÂä¿NA?™E§bä‚{󡨪t•=èÚ0¸›¡5,ú(q)­…Úà亩qýk×eÞú¡zŽGÃöSѰ[a¥kÜDB/~j×а‘cÎ÷Jfè}á>yï·1ü¿Î÷¬õ¼·+“==>ô¸©§½ç6õ¼—úµnÜû¬S®¬­×xÚýc™Ö5ºÕ¶¶Ù –Œã~€&:­Å"£ûw‰—Œä;ÞFpò$È -ÚzÕ¼AËÌuUïßâsèâ&«¦ê’º8­åƒ‹JézÔdxwØE%ûúà:sʽ޽odY¸½™êáêóÑ~1…w¡@“e\÷7iuÈ’‡³c(Ñ­Ó‚n‡ÄO•Éz×/€áäZDÝéXP7õpݽ´ªX¿L5 [Â^\=ŒKö1Qn½™RûŒ„’Û™6<²…™ ËÕøø£‹ãéW—UìÄ\D}öh™È€~4ø´Û¹,ºÖMWõúÜÌŠ<¢·â§ënØ ËànWðh]ÀkOÙ)ÔGâöÒwšä¾ñåͶ&pH¼É&9l’:-rM±ÝjÒ†¡êß´®É2Ö¡€zz«‹î‰úè4Š8_*ýsw£XÑ@$¢YÚœÄÞù,ªŸ¶•nµ;_æúõFO-¬ÃËÐýò¢›ýç%½íO$W«ŸÕã¼û„»‹ÝÓÌezæR§ ÅAgÌp[ÞÜ®l¯^½Ÿ½½fi÷ÇX-ƒ1ðا}Ð^ôâ(ÌBûŸ`Dæ endstream endobj 15 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 4 0 R /F2 5 0 R /F5 7 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 17 0 obj << /Length 2160 /Filter /FlateDecode >> stream H‰¤WÙŽÛ8ýÿ_¸:e7mÁä¡3Ó“ž\7ú!΃,Ó¶YªÑ’šÌ×Ͻ)‘²+UÁ¤”­ˆw9<çðòÝfq÷ONÙŒü_%q‘ÍyAÉqq÷þ##ÇvAJ™$›?1kŸ–ïÔ±¨ª¢:’ú@ò¬,wYþ•pòQR©Grh²³jIÖ(Ò¨\ßÔþæóæH̆Ĕ¬xÀÉæ:OL ~¯ÛŽÕCß‘]8¨†¼%&€©<  Ô>„`T`ˆ%p³ù2åaA(hb^ÓI0Á’àK«4ˆd˜ ˜­„Ʀ*„~óÏ’Ï*Z5-~U|®Ï¤;)òШoEÝ·$ÿž— “l~@´aåµî½¨Ôys MD.Vxø˜F6DÄøâ·jïo˜¿%6udSËèéÍRS;Z¢Èaá5ì"Ä®Q笨öˆÁlqÓÈk@u{sÓaŸ-l¶ Ƙs†Ãœ\Â6Ò±,M ìce^søÔ}°§Ö…aðæ¤€ühHQïJu&úÉNåYß*xœ×ç‡RuŠœ.’äYEª¾"£ê}Ÿ«=Àd—B+ȶ7~ß’A! w¸¾ üži"2£²yd«î"‘¿ee¯`W8¤‰ð ’©Y*³1§ VÖXr~ªëVUøíØgMVuJAЬ#™_1 1U“XÄ©Aÿ9ˆ\x ºÊò“žGliœ$S¦ÐÅNAÙu_îÉ—2iw€¶9.ó¢ía™í÷YÛI;kg"ÖÒ[Þ“ª/KcÞ–@ia$§¥ŽÕ"Œm—51˜:Wmw”&ìÄFðµëÐøàP4З±spÜ.õÎQ‡ÍŽƒ(‚<]‹Q„†&í©8tC?žêR™Íi»FeçíÍ-È>‡­èt,ë]V’2ëT•È MŒŠ‡Œ@oLY|UˆÅŒCÇœqI`}á„dl%Kaª>ƒó)@ êÏ»Á{Ümñ8á’$™ÂÅRÚí@¸ÎȤ_Îè lÀÕ@„¡æZ©¬=Cø™\0lÖï‹ÚàŠˆXþïëJds‚ý$kžê`Ú}‡ì>견ñÁ©5=ÞÌ`ADVdyqÊPSyËáïݜTã¡òÆ?~A^‘#Ñ^!øJ0°±Ù‰e·ñ<õÒÊ@¦)»œ} u€x{àÛ¿m0é-¸H‰ŒB‚‡c°Q œ'ÞÃß? ÀøˆSâš|úLÉ–×!‘IàºÔÌpáÇÅ;œ0CÃ>L˜œpðR 6iFÌåÚI/Àc¤¤Dò1;<ÂèÙ|Š)À/%¢nbÞ?ÓÒJ~¾R8?m\¿Vö¢V]FÌ.^Ùó­ñ$ºlíÊàžÂk@.| ëzBuÛª¼Í;w>÷ÇÑ m¸7Ÿ”dõkµ4ÎÃÓ9âá¿XÑ{êÅ|§íH…¶Åå<[ßêóß”¯Òó̵]B6˜'ï‡TωßÔ­8™§ë º ×Z'Û«û@÷d ˜&DÈØ'`šÀ¦‹(y™fp¹CKGÅžzbT÷ÔsÌ#ÅÕ“@t¸Ì\UÏOÿdÍ^¥,áQáÙ ¢r¸|>{˜÷/è úe<Ù?xÀ,& Ç6VÿßfTÍÌhˆb,É$¾:«™9ègí¨ú;òÇõ¦j¨®ÛQåÚÑJuΨY‡b6»÷µªÃr p2­™nW…?cOc»PrßÙÙlø–uE]ã2N«¤¯º¢$ãàršÑ³»’13fuÖír} ÃÔëµ—Fý8Ž‘oh S²o çn7ÊÇAÃãnÓÈw¸Øè&?yù>òo‰ó¾¿ÖÃó[`‡OÄŸCe hèŠì0zf ÀPÀä¬Ô÷ \Å¥¸Î-.´ #3h|¬5ƒFÚàvø#l<´¹9×{xÙ“Wq¤Î%Lko¸#ÚÛXah ²±Wݳ†HÄù0°ßÍvÊRéäî¦&ñ-¤ò%3¥ÕÀµãua%8t‘ê¡´ð™ËiU?Nšß©<[™ZË¿ç¥nÐÄn»¬ž!c@Þë+ž¶¹õ-( NÒ? ‹`- ƒ0\° Þ¦P¦6ã+ÜNyÜÚô” Ú¨w$2†²ÌÿàÍíòžÂâ œóÞUªõ>muÆÛù¥‘9¦ÙÚ,TƒHÛSÝ—{t•lÖ PÖÒ­û¬É€ÊvÎäÈ>»º –ÌkÓý»/ˆ:9´¹§¶ø¯£1®÷ÐÔû>p°êiDX ;=oj\ÒöqšæjŸN6v«‰q{elCêÀ(äx10µœ³ÿèв]6<6œ–»”MõQ¾6&—˜K÷œ¶ráÆÆ ?Õu«€³~±Ì/dvζ3gr讞ž—ºzbƒáþ¡h ±ž2ÜSÒÚ†šIŽÓ»$Ñú™ÎØñØ3 4ÊsU h™é>Õ“RJx’ÈÌSãX/Íh÷?;-©˜ endstream endobj 18 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 4 0 R /F2 5 0 R /F5 7 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 20 0 obj << /Length 1738 /Filter /FlateDecode >> stream H‰¬WÛnÛFýþüP‹â^xK¹´©ØM}Hò@‰+‰ Eª¼Xu‹þ{gv¹)K²QAì59{æì\Î_ÏÙOÌWó€þá¯PB0ß:¬Ù» ֵ㹞‡†K½ˆb˜ïOáJx“Ô $¼€MY7°hW+UAý¥ +p™•”+hk|:xùìËü½óãÜAl‡GBC(€s¨”³BÏïðÿ{$ôéí‰Ö |úâAŠ;2 -®¡ïÑOSÎhßGç5ÈïNÄ͉8üŠÐÉÓÇ LnžÍ¿i±Æ‚žGç‡Iüɘ?r4ÀˆOÑ1ø“ÛcTß7¨bˆ„aÊO¢âÎ@ô¨¸þGT9B}À•ÑÊÇ7àá˜éì'v\Y,ÆÒÙMu= ÊÄäºè8üá°ˆ¼X€ Còô;ÚWÁ=î Ï·8:—“]ðë±mèrÌhg;i›a‘Òž)sYL…‹ôßZ¡ŠV#µà-±C«IB7ô©û®ô¨¤%X!óãÐÙ|£ N¶ )&uYdÅ–I EçNQÉ Ùd5>«Õ$E {¥ êM¹ÇWIƒ?ì*u—•m߃ús—'Y{“|]VY³Ùê I^—«õÏ #ëÃ÷òÊ +í»)aYnwm£´B©ŸÞ%y«\É(ê…/¼Q÷ ê^ßgO’IŽ¥äÛ¶:/“‚ªMŽ¥Gû‘qp,=ÚØ;ÁIòœÆT¤=ª(‰øÒ» ("ˆõ¡Î+ŠˆŒ¢t8+PDFQ:ÛKŠâ_T¢%I/Î* Ñ"E‘‘x-Ò‹Îö²¢ÄEÓ’—EDFQ¤|\QDl¥³ý_E3ô.)ŠˆŒ¢ôõs‘¡Qkû$EA2ð1~[‡®Èq…µˆXyÿ6wVϱÞðQÑGZ‘m û•ÙÛ•Þ¡·;K×8xÁš÷B°Î‘}« $l Œ›q$È¥vdVæY`Wz‡qtFPІhä`43àì#{45 N-îG§&-ý“™ÁÒ9¥2RŒæ›SÆ Ôצø„–X½¤»’¤¤¦E›ç°ªð¨u)FØ»SÆÜþÆÀ–0E¡ …´ùgUu‚|Ø û רî•› ´FælìT Aìûö*’Ì/Ô:+ô „c3í_eUÝuKVà=`+ÑÀ²™õ°4ìjXáw£úÔåá¦ÒhË$ÏÉò›½ê4âTH—î%{tŠö©Ô܃e¡L{”íšÜUeÚ.Uê«eÓâ®{í¨jUVÛ¤X",Œî¢épŸ½´¡â0\èsmU³)SX·I•R‡|äI£Šå}W8‹ûÑwÔ ^8ƒy½¥Ô × ¬³;d•`´ÑsûäžjïĈÁm.¹×•Å·B08ødëMcÆ ÚÜ¥â ÔB·¦×8ÑPr,[dÓÖ&¯šÑ Ï] )”ó×ð q˜Mf›€‰nÓç¾!kœÈ´ïšéø;nM¦j§ŠtÐ5ú$5bÐ[4:ÅßÖÜŽÐogÜטí!=/«ë"UÔ×u&?‡z6Y¹2Š}Im¬¢)͸}³PÝ ÷X+z­ÄK† ß^Qe:^ ×TÕ[lÍãÌ´D(¬¿è¸:ƒ)xUæy¹§@f#HŠ|«a¢ÃŸ5Zrôkñùü])LK/ðò%xøè¬–@¸ôô*ùí¾ÿGVº¾7 «vœ§‰£UGóÛ›4í[ƒ¢y^¤˜<§¿g–[rÕ3ëG ú<‰qz˜Æ®ÔãëÛnô»)å_Í­¿ë endstream endobj 21 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 4 0 R /F2 5 0 R /F5 7 0 R /F7 22 0 R /F9 23 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 25 0 obj << /Length 1283 /Filter /FlateDecode >> stream H‰ÜWÛnÛFýýà @J•(îrÉ%«º@âĽJ ˜}ªú@I¤­F"’Š›þ÷Î^H.© âÂ}©ü`‰Ú9sÎÜô6Lo(ˆÒq@üá?ßÎ}ˆvîÓŸîÜ—Çv‚OWâa!Dƒß­é¢øSRBõ@¹ù;<…‡¼¬`yHÓ¤€8[áÄ7úó÷P$Õ¡ÈÔì°[âC¼“ñÍdI²NÖæÍ…x»¹ÏvIV ÿˆ~E¸\Á %ÚP‚õ˜‹@´6YÃèO<ªÓÔfÄW¢wò•X×ñvu#ß=lÒJÝÐö›¹œ´7”eñŽS:,¤ŸùÄ¿‹¡8!ް€À„Ø_ò¾¼*nY_…“h4˜ %æ‡è—0S WàÌÌcéÜ(×<:Ÿá¿àöözŽOçcÄøè»«9¾ùªííâ¿ðK|X_ã‰<™xǾÒGܬQHüÖ“âçTºø:]jžç2b‘!_ö‰„-$ëM«x»]Æ«Oe‡tCTßój“nu®'©·*´·NRIØÂêÍípChŰôy­]v<Šó«Ï·2¡˜xjBˆ¸>5µ4YXŸóÍF›l¨ÞÊtƒz”*㙪ü6)̃#Yïâ*FQ.ð+²O‘Aê<$~ï¸eUV¨œbºæâu¼¯âj“gç˜öÉ´Ê¿å fY™¹ &XJøÒüÂ$é6«Q·æ˜í†^ÐHA¹ÒBüKKX–ijX3¥ƒkÄó;5…Î)¹àœ9¼õúï†2çX¸gÞ ïh Ý›¡«òUîQ€iZ&X™j}2tÿœ>pBε)ÏÃ0kØn Ú™0jP¦¼u±»ÈœÏÚ¼÷\&•Úš¨`<;äÇmè~O~hãº'`îù0æ6`”q…Iþ©0˜M #'$ðmì4ì.b9lLLÄ4<˜´Ýž‰Fsœ«§‰÷<ÂO"&. ¾ñËpÜOðÅq·Â~ Ûs¹Û¨¬|ßá6Щ!e'ü›q7è×È3ýŠÈ_¯CNŒŒ^s ‘Ŧ5Î ê' ul`ï7ÒSmìèáyqa@¸¢Þõ´¤õ´tx³£Ý²•˜På°L`_äŸ7bϸ¡m¨Š8+Sµ‹•ñn¿ÅÅa™TI¢›@o‘+áì>æ >Ô@¡Žšr(öd ÂzðZ×ùþËoh›þŒžzÔy®§©“IÛ¨pöëÖ/Ë} ú“,%sèâ&¤wp©ë).áÕ³­_«ªýNGIÚV¹à¥BÞFÓ΂¦Ru_ ËQ½êă+ïëõb‘½×h”úìÇ…‹þ§ Ka…ÂÆê~Aa* <[aA´üOnây…‰ß,ÑõðÆîÐüf»ÍWq…¢Åø+鮥:µ(„y¶;Ša„ÕV˜¨Gd³ÛMtG‡Ih{D ¬n3"œµzôÒºŠ ö®÷7kŽ¿ {ºƒˆà¾å°Vy¢7ÄÞ«1ôzq½ÛÖ¢S‚38 ß,ºÞÞ‚‰51W ÿåb¸‹…ø•ø•›§GGC-»saQÔ"Š:Å*4ÛéÑž¨ ªI ‘M~ì-$ªª‰àÂú0ªÊo\˜Ë]Cæ¢ð,KÓO—8µ‰Xf'é¾8ñ>ü#Àä@© endstream endobj 26 0 obj << /ProcSet [/PDF /Text ] /Font << /F2 5 0 R /F5 7 0 R /F7 22 0 R /F9 23 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 28 0 obj << /Length 1309 /Filter /FlateDecode >> stream H‰¼WÛnã6ýÿÃ<Ê©ÅÔ}Ý,ÐMº»)°ÙqŸÖ}Pl*Q+K†,'Øù÷IQ7KNûR%€pf8—3gFV³Ë0X%³(þDùø>¬v3 ³ËO÷ 3›êz¬6øïÕËÌŠ·ñ¾*Jûýñ Êë8ËâÍŸp›úër¾úEmF8>°ºÑ&|.M´ÚOÅ¡úpLQÞ§ Ôÿ¢Wƒz2wFF™ e²ձ̡ÖR¶Û½Ÿ*±Wypù‘ë UQㇿQ¤Â&”z®Š”PÏqe¸ß¬ËK¸.vûc%P= 8<¥IÏqv€n!)Ju¤å¡‚∢𠼆w€'é¡–Æ/J¡* ÍÓ*3•T})ÓJ@‘$QÌ_ý¢³ÈTèšñ̉´cRQfå;WÖÎÈôÖ¾˜“­Ø‹|›æx|8ߺæ 2%~ Sb«‹ƒ¶úÏEºEïT*#­å/à>*¢ŸÖ-f@ñ“®ˆ®¯`Œ8ÌáZZ[Wز`m ô.LI×su¡Í\†^xZÚ¿å±;„÷ušæ$e¼÷ªrW}ï#¬vØ|l${~‡ÂAë6×-a­§½˜@ñz®Ê2D°Í‰‹OÓ'ÆéÖ“ðãLÜŠ©O†t^ÇÒ?=·CÚÎW Ã+ K˜Û̧®K<Ùs0KìöÕwÓ†ž?BÒæ×cuj´­D¯—µ{ Ôø'£?ëŸG"éŸr ú¾EY6buÔɬËËP‹Î]öI²=ÞfäUdq¾(ãQ¿Y•é¨}¿5ë˜ [Ûõ܈*›c•žªÎD¡ÿÿŠÐN1N‡Ã¹¹àú¡™ <ªÛ‡ªPòÆ‘ ¤í®¥ CžŒ9„¡íV™±PϾiZ´±˜È)]6ÐÔ¦øv@· ,-RUK{s–{9ñ"#´6ÿòëjžò¤RôoI×ÕØá¯F¥’Rˆ³Í6pj©‹‘ S}‘u-¤R£c8ù¿m N‹ŸÕèð ¨·y%Ê<Î 9æ›*-r=ýj6x âDaÇg:‡Ÿ±UMuúhAˆŒ†ÃáÁuƒŽ€†“0àõø²tr~Ã4qyÅ`Îù,d9×iùi¬, ÉŠ¸ºÍ.MêÐ ßÃÝq÷ T1âFtj”7<¦óø(t Á{ fÚ5¥õyótŽyÇ v»´]Šý÷ñìÄõMi“Áp ¢oqš“~>–MB¤–á$¡Q/¤“:Ý£·þ‡«Þ½Ë‰îuû[ú%ƒ^ÐxøZ{þfWqîš®rÌÊâàÒ×ìâæ#Þîã*V}õ¶E½«½lµ׋oUÆù¿¥,·_)Ù¬ÏæÅe¡ÿDee¤V,âªêTgÞØíA¤³C³ˆ›P¢h’Í™JFÓ‘¾õây˜ :lzAöI@]~ZTVƒT^š]€þ×DËþj¦­‘“ ºÁ¬×]<—SSA‡Õa‰Ž8á×õvtçÀðö7kœ^úŠƒåÜær‘aVS¿ñ5{ŠÐ”åááznâ_öj(a-É·†+~afEÈ5W!ätF!~ŽÓ,~È„LsÑB¶û×çú©&¥º%`îâ0À›GŽK++ð OߦRù¹yA0KY[×%Ôoš-öJ*£b&*9•&¢Ê…ØêÛM±Û«­hôíTGæÕ3‰†ÏÉΣHÙŸW³¥¡? endstream endobj 29 0 obj << /ProcSet [/PDF /Text ] /Font << /F2 5 0 R /F5 7 0 R /F7 22 0 R /F9 23 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 31 0 obj << /Length 1378 /Filter /FlateDecode >> stream H‰¬WÛnÛFýýÃ<Ê®Hí.¹¼Øp€ÄIšAR4Ê“ÕÚ¢,¶¼"Á-üï½â’”e×¥“wçÌœ93;|·˜Ì?ú@a±ž„@ð/„Ðß÷a‘MÜOæ?£p_N,b×c°¸ÃŸûÉ4-ò{Xï¢,.É·uõ½Œwïêõ:Þ]ž-þD³¡2KÀ¢6à ï'h„qG±ñ!–æsÈëì6ÞA±Ö!ãU¼‚ª€»"Û¦qCµ‰aS”u…xp+Á–aq®ý¤£~~•?¡ í(€á*nza(,ÜŒ:ýˆ’4ºMcHrôR8W—b…áœECß±Ý)œý±øõà§Kl2Žt#'ÂcÊ+§¬fM‡½Nn̸zü[œ¸ÜvÖev¨Ñ59œHrÔþ*Û^*´>ešÐåînŸ[Â\ Í 5knÀUVÏác’¦FÊöIµ]œEIž´Þ#uçs#§C×\~Hï G]› n ³ýéxæáJƒÿÖD«h[;ëpYíPï¾®×e\]6, LFÑv{³˜ã˜æÑt Vk¹ný–üw1Å›'0UÜŽJ½Ä凛‚÷¦˜MË’|y$ìÙ¸`–g&Ž*ñȈ¯YãbÓc”â{‚lXWÍ“WÇ®ç]•JI¬#’žBn2c¨"°ßãÝ=²j§Ë©ft¦’Øò9Z µS¦¶÷…º­æÕ¥•?V#EàÝÚðÁiŠàmÛ(r¾É¦©©{†äCSòª©˜7!y±ß$ˆÖh@âtÒôÈò þ1®ÉD.wBã­<·™CÖêæICÞ2ðåÍ=Ò= ÉÝs@‹pc¨J^£çÒó ±“›¦Bp½¾JÌ«»”;ÆÒd}<-WãNË\uTH†ÉЯXöý2RåÙ,@YÊTM¯‹íƒ@gÉ`Ù·]ÆýCe±)³ËiO¶³£¤ÍŽÅ¢Ëϱ}2Ìã“*t˜"ºÐ#‡R¤T릋•xá$uv‡O·ÑÝ_BcÆÑliC=ç4 ¦ÊÄÕR`xC©vg*¯5 Áµgœð.×ÙÅF˜=zbÌ$!ܦ?˜Ô¡ßl6å?ƒ/ß?n²Ã†³À¸è„]æŒæ¬%™f‡´4c>ÐvL¨›¬u§ú/`¿K°5²Í@[4÷DžÆZì Ä(ò'Åø¿„ý!ÛV#]ï'¤hõÒ°½g„=hkƒ¨ýa\ÞÆkÚÁzÊíhl|jТӶ©w’WB¸æõÄ|àóî|@½^eÍàÉÛ¾G½´(EÍ Gùòœ’šÙûÈYqØÜ?*¬#GEcm\½æ­ðÓ ['Î×7#~ŒÓ2~ÅÕïéwù8±œ—ŸX£T·rÀoŠ€ «.©–¥r¢ Í|t>U_Û¡­W)º/JÑIŒ½)éÑdɘ¬; âw"ˆv1C¿= ß=ªŒ3•q\Àl/Ý_‰õÇ­h¯sXlpâ.Ò´ØËOÍ:¿«’"/!ÚÅ¢éÊñ³L²:Äø)zn åCYÅ\0J@üáÍÃÿ¢}dÊÕPŽêä7«€¥ÃXcŸ¨íV{˜äU¼ÛÕÛ »»zƒÌ™m•pÇ9¬“4W3HpÎÊÅÇÒSBé\(}ôeê+ÈQÇü"Y™¥Äpqõœ>ýÏ—^þŒ‚ÂéÅq™®(u¦,§ÍóV‰î¼Q¨MàŒæwkD¥Nvƒ‘/fL$G4,e… K ¤©êt‡˜Z.\ïá(†"_ÝXña1ùW€)o endstream endobj 32 0 obj << /ProcSet [/PDF /Text ] /Font << /F2 5 0 R /F5 7 0 R /F7 22 0 R /F9 23 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 34 0 obj << /Length 1284 /Filter /FlateDecode >> stream H‰ÄWÙnÛVýýà €I¦(ÞKÜHœ¥) Ø¨UôÁÌ-‘ ‰2HªF[ôß;w¡¸‰¶ôT°irîåœ9sùv9š @`™Œˆòÿ¸xž Ëíȯ£ùÇ;_‹‘c;ç+yǸ€åÓè~<ŸÃr!£´H·ûMTÆxÏ ü÷(_?Ey iVÆy¾,áµ~±+JØí÷%<ì“$ÎÑ´€‡8Î`_Äk ÒÒ²ÝÄÛÇò/˜|Yþ‚z:Ð@Ũ0…ÐabTã?wé&Ë?Ð2Ж Cv/ßf2~GÅ?þ=OËøf_b?c,oUz¥ñA¨-‡ë¥ŽLuޝ£Íæ!Z}³ŽË]>…Hß„åvF„\ÀŒØ/³ýý#_óæs T½5»Ì~’uÑQéˆn’¤ˆKøœ+À:ëZ˜â•uõ®”sÞwû¯NÉàëÀŒÚ /e Áä0=•!ú¸Í¬B¡T”&ìõO'u|™ïWå>[U[NÕÆÄƃ Ï Q†ÊiÇÃôÞ†DØ„9´^Íü*~O¼ˆÈ·‰}€4À %LAc£B»Äsü5£ããGháøUU‡× OY³‹ÍÂ0{eA Ýža8¹RäF·'úºÙŸè«Ï¤óœa+æ'%vÔð|_'%¦ ŸIìó[Ê&¢$CÒÏð‡ûnÅÿ%r]ú€•aR‹‚ ånPmhºcVm¶£„0áøÊX ì~Ãí¯íîÙ®ãùÉ©h©µÅµ g^_Bt…ºÙ¦i ƒúÑ®Q-KÆImãâ6Λ†S•ö»¨ŒL¯ôäÊ´/h÷ ­údÆ8ÇmàÛÌAîø… ƒnçyÌ–Û#jÆñªÔÀ­ÔÌ•Ï4šã,Σ ÈÑ•é.ƒdŸ­ÔMW·¤+Býá¢vÀ\WC3¾3ƒ®µ·ÝÀwëQC˜×€0TìXXrÂgSaÄ›aùNœÔ=°,µ2 ­…íqb⻽½^´b£6 \^ÇFýÀ°faa0óÅ%Ñ3Ä—ZÚóL˜²ÒÖn(¨Ó¾ U±Ñ÷¸³²­ê%™½Â©àà³MIj4]ͨ'‘­Êüô`ý”¥Ý±Òõ0ŸÔJ¸q}º.•aƒrŠü®¦&2íÍf³[iŠáÄT3ZçBnàôûV×4Ùì¢r Ý!‚% «wádÉͱÓ"ý;Þ%æU81á!{[5õñ¼ZMÕhdlÓÙ—jëzË:õÆ–¦‰LÁ*Qqêþbm]¬¿hõ—D8¡Æ@c–à"ì2}XJ€ ðÏå%Í_ºê€žÍ¢R;—vV¯Ä,í®8ÇÍØú Uñø×8Z+v VOäqÝ7B·ú†qÿ¼ó˜ï‘ öê{/y5+ºÊFtÉìŽF×x5õ‚ÊS§o¬.ý­…5ŒÙô¯€\çø§~–0›rŸ×9P,O}ǧhÉ»x—ÏëöÉ‘Ã^ßêZ%y÷p<¦z‘ÛYÔ»ò8”uO;¯ž©½yïRó¡2ÞFiÖ™§Ì«>DÔÈ"ºO±¿Íhø¡EÏøìªÄó‚Û¦“EuXhª8Ùø¤:Ù(ÛJ\¨C\KÚc¹YÑ&¹Ãƒg}° h|2ãdÎZm÷’–¿ÏÖ²E]ŽFîƒü˜_> /ExtGState << /GS1 8 0 R >> >> endobj 37 0 obj << /Length 692 /Filter /FlateDecode >> stream H‰|TÛrÚ0üþá<’8’ÍÍ}s®¥“4 ø-Ƀ, ¬ÆXT’Ë$_ß#É4M:Ì%íÙ³»Çgyïô* ùºGc øÃ¿ étù¶G`Ó;½^Qؘ‰%cÈ9®pwö½þÎUÃëÖHÕœä?vh$ 6žz´ˆ$$!3‡pßÏ€³º.V²e±À ^5òW+ b !ØiaDcEÁÜÞQ{VAkؽ:ÂàËŠYÿºh×k¡ ¨5”Ò-ñ>ù"ÌNóïØàFHøÂ“ëº#£4ÜXS¦ešaY,R À¢ÂX¨™ FÆ¥(¡xî*yì7mDWÒ|ÔŒi9Ƭۺ~vTKX+í+x^ùOˆN;FtœF;¥­kÇ\à:kK© [ÌEËVó;(…áZˆ(¸¿öbDzŒò'~SÚ9Dg3W³¿^.$ù¹¯“Yrðõ@t’ŽÑ{O&Óô2ÌÄ@weµ`[Ùl`ÞìZ w­{^ˆß¢V;±u&=Iá9!›Bè <ôùà Ðñð‘¾ÙY©µ…áQµ¡÷qâØø% 9mÑÈŠé=Ó®·Å·È5åÍŸvæÇIZˆ:éZ8ÃþeÃpÖê§ ",•qv‹JÖa÷!‰ãWC¾kàn‡F¯T«¹€síî-07èó޶áµ>ÊâèÆ tZq!J”Í0Ç\êÆGÕ8Š[ÔSx‹óÈÝdvzêƒÿŸÎŒQ\úͬý_Š:Š+œ. WÿêGú‘„"ð>gØ®bÿî –‹À‡)²\/³ÛK4÷Õ%~˜æܰ'Ìÿ{=ñä}~(+’Ð!¥C2 á‡p§>Û)Äiââí£M) ½SâÎ^æ½? P‰Ò endstream endobj 38 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 4 0 R /F2 5 0 R /F5 7 0 R >> /ExtGState << /GS1 8 0 R >> >> endobj 39 0 obj << /Type /Halftone /HalftoneType 1 /HalftoneName (Default) /Frequency 60 /Angle 45 /SpotFunction /Round >> endobj 8 0 obj << /Type /ExtGState /SA false /OP false /HT /Default >> endobj 40 0 obj << /Type /FontDescriptor /Ascent 695 /CapHeight 662 /Descent -216 /Flags 6 /FontBBox [-167 -216 1009 913] /FontName /HDMHLH+TimesNewRomanPSMT /ItalicAngle 0 /StemV 0 /XHeight 447 /CharSet (/less/three/i/G/t/S/eacute/equal/asterisk/bracketleft/j/u/I/quotedblleft/U/d/greater/five/k/v/comma/plus/bracketright/D/six/m/L/hyphen/w/W/l/seven/n/M/y/period/x/at/H/b/o/N/z/B/eight/Y/bullet/c/C/p/nin\ e/O/slash/T/zero/e/q/P/colon/parenleft/one/A/space/E/r/a/f/percent/two/quotedblright/h/s/R/F/g/parenright) /FontFile3 41 0 R >> endobj 41 0 obj << /Filter /FlateDecode /Length 10588 /Subtype /Type1C >> stream H‰d”iTSWÇ屑úXÞ{}Å­â6zÜ·º V@A ;b ! ! ÈÆbXœ:Ù„Bd—M¤²+Z+ÎqÐqµ¶q:ž¶ÚÎx#—Ú‰æÓ|øûážÿ=¿{ïÿ^;„eØÙÙy>t8ð°o˜P"Pd—JRƒCƒÂ>Ln°.îð‡ù£$êFrƒØTrX÷û¹sÿ]¸Àά\¢•’ë¼Ý>dÜþ%$ÏÕYެrÞÌÞeÿ©c ë¸CÂG¢$Á«± ÷ìì&mYÄA8â茸³‘í‘%ŽÈZ²ÉÙ† ;d‚ìAý^È4‚¤#ˆA2$ȶ d²Âî ]—=ápÂAî0ãð ˃µžõˆ½‰=ÊÑq]¹·¸oчŽEŽ¿8¹9­v pqvÉ_ÌÃxžXøƒëõEù‹þævÌíùGa½^\……¸ïv7{óÄ<{='=¿õšÂSð·Äer9K­¥æésÞ;½_¹´ÄÇÏçî2óò˜åoV´®t]yq¶ªëÑjjuš¯³ï~ßß× Í"Ùˆ»÷$Dæ*¸ïÓIÖ7Ø\ ?}F²Æ9OOS‰ˆ Ui•–V•͹ݨf(ÿÞ?q°¸ú¹¥ê³´;‰v‹Jh¢ß•ýFÙ ’ãe!¨,äƒÁê@K(e íJ¸*A%W5ÃÄéö¯oз[þœðéìIÙMJv#y ºmŽ®‰&¢c4R›ˆü(ÖίÝáÐY½UE%)¤J !’Öu2´xPó ¸àÀ½æ»ÖAª«±ÙÐN´7PàMZŰ KKW\—ßȘU½D€æwàƒjàf ( péýyüñØ£éÛO¯¢ý\¸mô‚¼åpjã$ §p¸ÔÉ1èAÙ¸9¯VOù?~}íæúžNEy“ ‰dÍ`—#:›šBö×­GMЩbp)=³¡› . dÐåôÊð]á{nA“¸`Û}àxoÀnô Ø3 B@"–Ê<(ûgÍþÓ[¿Z1‚&p§£¯EöŸDyV7’•%õ‹[zT/O/cˆL¥N£¡5š|µÕÈZª^;ª~ªÉ»¢íR&ª³Oé´§ò”:iN¦Z«DµÊ¥Ï*WÕj(um}~#a0”Th³¾ûÒðõ–öΖ>K‘ð¬¼HU¤ÊkbQul¾@„‹Ë½–Ê4šÎ4†º C-]k(o¼ˆ7ç\S<¦´ºþ/zúR;Å͢ˑb³Õšó„±®¬¦†®Ñ—Œ¸%Û,7QrS¸ag ¿"^/4têû«Çª¾«¿^o2¢¦úJSnÔ45TFYÎéL~C3ٔ؉0Ešœ~þË Ã†k¨áZE+Þ¡³h ”A­¬È$g”jZ­Ô¥ qyelãª6¦"¶8FÐ(èHî·\‡‚%˜µÈzöéüYkÁÎù‚ùÂíÖÂù¢'\ž7øÆbC·Ìw¦ñI娰‡êž6ÆÉâœt9-WäHE¸°"͘EeÕ[ò:ˆêêâÒ*Zo®--'Ηœ-(¡KuŹÙxx_I ¢Ã?÷OG㸿t>ºikÈ3ëb̪¾ózèk{»ÀlÁ&O&ÆÅd&†Ê0YrÛˆVKeƒ‰6™*-mxk®%ÃD™Y¥˜Ër3šÇ·ž!ÙÅØ|9Î~±æì6öN€ ®}ñv/p'þ¹ ìÑ/}£­eq-žÔ¶­÷!‚˜øcôî° m1…FCVº­÷ëpx¤ ®Ÿ…‹)À~׎Õ§Žo‡&оK} W‰žŽ\¦™îµ…™÷¢í>µ¶vÛ5Ü"*s¯$L BE§“ÔÉÄÞÐáŸt pJkÀ1pË£8S›S>;Dú,~.D»9MzoŒ÷¢½ã·ŒSÄì¤4lœ ½è·‡ì(èê IÊܘ‚&½»Ìýг“l×ññÜìリø•¸3Î$\¡¯$˜Býñðœ(E¥ˆ;-‡‹Â³" PI;wl4—¡G˜^E‹Ì˜Y/5$¡üªˆü€,A…óƒeþ„4­¸\A«Ï§U%6$6ȪrÏ£%JU±š`²tZ[é5ùª,\V+ï`(¦ãvÎK‚%€õ#}ÿEÏkÛÿú”¹—ð5+pp[ \ÿ}ûÍOø-f"nœš ÙÚbÓ>9?˜æGú 6t¨=yÖ•$;ƒÕóf°¨ð'Õ¬ÄëåéÙ°ñƒèØÁ‹{·ã[$‚ƒ©à`ÿÔÝD¿îŸ™˜êìR´$[S¬"6- ­Öæ«”¸Ð é–RiÝ_iŸO×w=¤¯Y†;® ü—ê2ŠâJã8(Ýóˆ ÆÝ6ØÍv‹®†Cq… ¢°¢œr8œ2Ã#‡0¢¦¬òHPDÀ9GA’ QT£Vâ‚Wíšã›™7RûØM¶Ü®úªºúõëúÞ÷õÿ÷OÙ¦nC•7ÇhhýÞ~š]þ-½‰<ÿ€[Ì4«È‡ÐÐï%M´?›‰Ôf·¼TgÎIòEÐZǵ뼬#! 9ˆ‡Ð(è;´þ Íc·LJ^0Ð@ò 7ú¢õ-$ihœôš=Ž¿þâÆÚ&Ùdž«›nœl»Ùv³k¸_ýŠÅXÕ³RÐÈÓ{˜G•5Ö­`žŒº¹.ÇZ+DÒ+ölˆ a·G…§2‚¸Êæ$.òJâ`Æ8È/¼3B÷}ïä;Ðz¹¶ñ0™ÐUS…-#]Wš–T5÷–N0cRoeŽ\hDjÂ͉MÄÅbZŒî&p«&—ŠÈ ð§Ý<¯û²ëÇÞÄCŠŸ¼º0zmÿá5=.Û1Ê&¨7ÜEÆÓ¼;~£­´©«Ô*z"é–Ï;èm2ˆX+öås|ߤöt`åö¦P¶)ä¶4°·Üìµ%>Àh/•Ü´ûBN+Èi)nm¥Õg»/w²ÊêQf´7+¾“눯ñ¢C #3…¬L¸#Øe3r‚æf𥾟:—PAÊvÄÆ³q1AY›™MþçÔ‘\¤zÏíé‘òÁú~VÑI5pþ‘¯l{¼€ tN£à"hÜzpÐìÇ·Ðà>\ p´C hCC´°†$ûÜeU7šË ³¥AÈÈ™ãÛ&Y OhdÒb5êÁzŒþ°ë5óå—†Œ#–zY{Ymæ{ìܸs}–æÅ5ž&\kJå Eû%ŒohÃõXÎ2«ß‚~W3ÙÕÇö^Q×1ªîÙ5vÆ7Öl5OxùÒa¼ Xqº(S(&; H·ü?˜–üŽiY¢hÓe5aZö_LKf1-“q‡>ÍÎI—ü?Úë?F{½ì#´ã9Øœ:´+(ݰ>™˜âÍØi¬uvš•ÄO¼™a½ˆððx»VIéFÏŒ8“hÒè÷;ü\÷Om53¬I&þÆÓÙë­gìõ+ žnX#"¾á™˜ýjnôLçJ%£9…ÝY-’Ú%µÑÉÆïïiÛݹåîŽÖ[Ñ|€#ÚОUAíBVئÌìaºÔ§Û†¸ÁÖÉÿ‚óA߈Ž9™¬È`3 TÌô³úþ§ÜÓ¾Û?õáq p4¡¡i*p‹cÝ4÷¸†æ¢…ˆe+²‹u@V²r@ÍsF«€Z‡œ'Ö·#› IJãè/¿Y@swàEüy´g`4ô¾ hÇA;Hb˜[Á- Ü€¼‘!bѲÕ`5Z†ì"þ2dvá;dÂ!ÓïW½âÃOŽdÈA[:_„ö -û®~¡ÙcðšÁå— -ƒSŸ+ {ý {èÑoú­–a¹£y»‰9Ãbθò#€€ÁÈrŽWÊ9yÅþªºîXsY'[Ú©xyZCcÍr3´VFXRuÒòÄÚ;ÛAdÁʶ%ùEùEúEG S$6NžÀH¤åŠ .CQت¤¯ŸyØùší…Ÿü:ñ¨Uªúo™–óùÒ:£Ow ž¤¾Q©´¬(;;ÍÎݵ/ä¶Åæv^ðÑØÊ”ú”ú¤Á„i}ŠNo–Hê¥3? ­D[’ÄKöæŠòƒ‹ð›îí<Ÿc²¬S ëÔ¾ª³´âDGm/û&šò1 #ô÷`  5]p¯¾‹ÐcÓè>hÕÔ¥¾³Ã£ôdú°a6tØýòçuà”} &Œþ‰HEª:òRÜYY¨#=cÀs/Þ‘·‡Ýµ;.'˜ iÿLbÿ'+îs÷».ßÊ5xƒõ,yÜ÷yÅ«yuõ#Åp‡²|ÓDR½C%·¸ðeZð÷ÜHð¾+–)e¥1 bA&Èl*²fsâ#iÇ2¾š*ž^kTu´öÈù#àpcëa%óê‘< OO»º³14*ÃÃh1kâ»&ÍgÜÝK«Ü8M//ÑܨuöU,.ؽ7äËóä0YÇ+Ó¸›:+-BÆâmœÅ6G{D?DJÐBÄÐȵ­|Ž²ÈšÂMNP†ó† ÓÜÔÀ£g£pAJµÙzdä±Ñ;$ðÝrì™këz\9מ€Û;§@üTöoД†–ÕðSåVùæÚؽnÐ=ö¸vŠyÿ<Åÿ7á7h©D,h"S4B"qÖµÔbx †ßË Åa,ºŽåHÃ¥Ép¡/4`}߯{`¿blkQ4£ÿæ ªú£AnŹ ¡âr‚pƒ4oI”†ñ@™¸]6ÄÀ/àg!Èàîd B–ÈŸF~áÈr2`‘á D… [&гôŒ#gnT„Ë7_{Éœ˜Cݺz°¨ž» ?—yZz:ý” Âtyð[b漨‡è”ãÿøtVi¨=Cð|¾Œ)Îd‹eòÜÌ"›*Ù/f"Dºó$–ã "žŒqn‹‹‹“2“Š@abðAwí%v-Éçä%ûÊ–ƒå‡Ú‡hM0Tñ”ûó¸zyuÎÉ=¥Ù¥Â2ЮI‘_nÈ I’€ iX¡ƒTxç0*OkãfÓ½£ÞŸßµÈ2k%µ’ꨪ­ •̇*bæN·¹©8·‘«.¨È;ž Jd_EñgËæ\ž›É&KãsƒqºšÉv)N)ù7ÝÕÔÔ•‡wZrï]ì2³Ú°poöޱ뎶uv¤Ú‚¬mµ —"b@DB7!^*>0!$! IL Þ(oñý~ ˆ::»®ÖÙ>vÛs“sÁ½í²N;sÿºsîï~ç;ß÷û~GEå)ØTƒI µ7qú3P‡تÄ'¨bm¡2W)” ǰ˜RɆ¢Ø!&ÌIG°Ž¶‚Ñ—ƒÇY·¦Uï—ˆ1±¤¼FL” ¥ªjƒ9B›$ÃdI;í ØIó×Y+(¸(èOËC 7ßÚ¸‡kG࿃‹I¸Žm—|ÐD<{$ož¢î6O[ïõbôjôÎñ!•‰´5Ûµ£„©“1$#ãÕål•«Käù˜<ÿxBÎðÐáÎÂx1VǯŽ%>0RÛgbÄbOàƒÕðûi€‘€÷üî&Ø@€Åÿ|úšØ6h_Ê™J¯wÏÀÎoéµ®o¸×ŽõË ¤Ì R뱦Ö6Y;1ä`fÜ<[+K¬ yÆg_¼ÉóÌ+ž÷½Á³ŸÓ“ñC×J^/Žr/¾çà¿:”ü…‹/ÐkG_£0¼F1è`î½Ba¡ô Q0>³ž´êu™~ààþÌÏ]¿BÊF4²ÝÔ­™øÅíüœlÜÛa]ã:¶rSÉÙ‰¥XIâU V «cŽJK¨âãâÆJV®«éœÀÏÑõ#R®×i-*Le9~‡p0®”t¡«YÚ>­Ú!Ê'“…ó®vDF{¤KSýS¿Jø²3@—zÓ:žGgŽd›´{ujnRq„Õ¤#Ù&PµæR…:ÉècÜå‰NK› ¤ÍØ£=Gœv0ï"LáÜ)¦ÜuŠÃ¼›‚œé®*3Q¦2M‰¼SfKw…ãsž?UÝ]¼Õ]5ƒ=ùªEóUI”Öó`§Ã-Žlg9·Ër ZGu•YE:‘®ÔšÙÍm\P'‚ˆ›¯ÍÖ¾ªãœF]‹çîqì<ä5În'{¢)§‘±.Ñ>¥Í—Çà³'ÐÙ[®#Æã¥"ÁÏã4.‡¼/ØKÛ^î¹ ×³Wú‚%À/„»ïMÝ`}äMoÀ» >»q·B.ÀI€³—Þ•×á&Õ[ '\B9‹÷rŸAäÜKq˜žýVËÞÛ—ðžm¤V‚Eqà3 ÄAÆøxO'ÿ9¼Àý6Þï.;ýiè.ÚÅ­éçò±#à‚€K³€ÓÐ^®™Ö'ú3*£¯Î¦7”˜ÂÐ*µ³Mÿ}Ô͸À͸Ý\S©¥´•J±\„ÉKë‹‹ðŒ‚¸¤¯HØÌ|ít(g÷¥‚~#nQZšHU‹…;«;îSsmµŠÊm/P—¨‹­‰ý¡4Æ\õwßlÞ“Ž$*É-‡ùHÏQð€Vt_é8Ýjñ5·Z 65ÖÔa’i‰“ÉŠî2ýø ûxˆôÝgÂxô :l†}?Åãð¸ çÔÀ¾ut}‹ [‡x>Ú©ææ5·ˆ;ˆ·‡¿™¢&Ф¤l¡¨«©¬8XATHŽJ+©Êã5Ê:¬Vwhì ® OªÏ‹-daV»@™c¾TKrùÔ~VôVßçù>¿ŸO†QÊL¿9,ÆEaMÿÚëì „1¸7ôA¨Ë}¾ëó~@ÝCR7¥òsay11¾–™Ï :©å®Òx¢3PßÝM“'Œª: ¨“Ô¦½„~ÅBNŸPʼnIÃ$$÷oÝÁÉgîN’+É(‰—’qÛ®c×·mø\ûê;Ô÷“ñ¹Ÿ#÷™ÞžGNO vMà»:’¨(õÃërXXjN&?r8.Îõ”y0;‚ ôGÚ;\€öan’üŠYú÷\!ÈÏÙ-Û µuàfžu³üßdúeÇ­Éil¼2x„ ò6)ú/u¶ ჾáÈÈû€Z‰P¿#ã˜[Y=—éº,ºOB”\úüÌ%lbt¢ãOðHØ èÆ»b_‰s¸ÈžæËßgî¦ÃÉÏf/2Éxþ?X±‹¬_G^†TÂ+ìä<%y?•@­G©—û(df¶aæ_…düüæÑ+ñ WþæúŒþ- S8™l>à³sTé0éÍÞžzÿå!2Ì=ϘŸ$ Ì¡áqÿIè+i² ÈSBH í`þMFÃÕàÔðH87÷ÊÜß™—)ý4B¾hÿ”ˆ`ŽHs»ß Ü­íŽ#00ëZqŸ6Pä¶q[%=Ð{Ü7ôy½^Üãu´øÐ£ò'„ìN lƒoïÓ—­8ÿ=Ñ. LÓüf=šNmßJnŸ¿‹°,l“ 3IÕU2-ÐÈ*ªËawv8º‰QÈw…è¥ß8I_ò»¤I ·‘û˜ ñ€­lP¸T˜KTôÈÓX<®µšË–òôÀ¤:¨R¡Ü ïËø„\&"™L!Çÿó~i:ú—+è ÅHI/Vr4/ðŽ£¨þ5;õcûom{mUµ»¬QïzÂâ<Œ6Õ¹‰ŒhñùCí@óþhõ($ãn‡ÎLã秺?¼…~¤8[2†‘Ï2:=‡luxÍn³ÙAm½í°m®qZë±»Õfµ›EyH ©lÆ`ÚÛþ×ášdþÎøï­$4½9+”‡…ò†8'lÏ`³e`–5˜£éM/ ›•»ŒÃ/TäÂ,¶˜‡ï;-»ñ½ážŠôc}ݾcðƒa;‚Y¸Ã¼WógcD4žŠRt(?³+ÊL–QÏAêëZXxq›¢3Œ;Ü]˜;8Ž\דÀD®³Ò+Ü‹ªc)\Žê]Ð㲘ˆ¯oÄÂ%$ÃÊ1Ua&…^«­Z‰ z?äÎæE‘½ü:B+m“Ù ÌÍûΡ³ d|b°'êžžˆ£†;LªîWy¤D õ;‚Rל? j ˜¹\§PiV)¬.„•ÜÙì(£@d'T¸Ê¡kªvC«µÿ4J^CÈxóŒn«:#)évsdè¤8[š‘³å 0÷Ú>$!—”&Æ`ÊåF©Ÿ“ûÚ °3@ø|¸ÏG´u¢†€Ü‡ùäRB Eƒ\Ž“Ë糘T O´êZC05¨ë*A½°6í§(õÉ´pŒrÌ(שÕ&`T ­lBFa —$k]¦`j±öžFç¤ìGrÊi9†ŠoÈ >-'¸(§‚–#^’ƒÌg§¨ÕÒÖ ¯Zw™…˜I¬¯Tk^¥6« LÜÜ)À¡JÎUJ{”)LJ%®VåTÚ,í’a²Ðˆ~ >¸Ý{õ>}5B® ×£Y@¯Ùàâ4©åžÒxggëÒ4Ÿä£>5/  W, Ç@ﮊ~ ›NRjÙGƒ(‰"9üºF5®jÔ5Å@x­}S(y !#ßÎsU¨Q­Å`4cf£ÒZ±„®Pû»JbŸ ,õ³'v~LéÈc«H)êëWG›GOØ@xþE¬ñZœà4Ô뵨é ÉbÂL:‘(/ŸÒP¼U×.ŽÀíÅ&Ú› ÚýBžxª‰]kÑ…cnšžrSl-¤%eE‘=;¡Ä«ˆ%7½17—Oä# ‹ÈOne0bÞ4ǼñËaÌêþ“âZÊŒJÑbñÜ(’˳;Š÷¡YŠvŸ –ž(…²Âîç;³¶ óòn ÿ 3I´U Ð)J«séJûožük›ÇBj†lÎccCá¨wµ7;ë§e…ô»Ì‘½X-«FP£Ç̽Rm*Y™¹*¸³ïEE¢:¢*ÖuSu30¶ZûNÇ~Q›Îhú0ÙIá‡þAr šöÀÜ`rì;‹ÎÊ‘[3¾G?îç8Óé·þ³HvMÙ£@Q>Åb vÙã@1{€Á ”YHwvVÓÉN‰¸ÿc¾ÚÚ:Ïp•Ä>g¿ nŠ'8';'[Õl‘V!­Ý’6ÓÈšBÒ´$M @HbÀ6|Á6¾á;i€ñý؀CÁ d$4 ËÚ­iX¶vÖ¦‘¦µÛ1|FÚçd?LÚ?0}¿?ßó~ßû>ïóÀÊx—Ü•øþ—Ö^’.‡¤Ó[«¤îÌ;ìƒ(û üà  ‰—î`Ç#zÇšÀÿ!0{Ÿ¼?{c-õ~ìûãF£¼¯ßúœøæØµ¼èˆ¼®„ÌìØÇZeì?ÃÀwe…ìrâ,û¬èþZñÂWådùжáü °DG'“0ø&'œIüw·šO,yŽÍËò[à–õt]¤ËhÓ¨P‹ªS†mÿ )íb›”„I­×j¨FÔlâábn¦m’YÙði¦Œ^ØjÝ©;C₨|Dj’³¦k8ÍøböO‘ŸÿcšÄŸ`ô÷94rø3âÁÉ¢d!^^©l†Ñ«ùüéó‡Pº‰ƒ€ Àt532Eí,ïx &ƒå뢊Ëäí¢ñ½`/^þøl Q‹+Åß«¡¢Ð2޵% Ó¨9Øþ£¿D~}+• ¹Ð¼Í Ø< WÊQˆü­Þf'\ h¸ÀΪý…dáþðPˆ= ðÂú!âõ‡uÁ®Ráyr.²tíö4×Ê]\8bF\IFT/o5sñvn¦Þd±+I¥ª,|ðù{ Þžg)ù Æzü¥±5hSׄ£_ÄèÝ‘'7ÖˆÕ¥µØGøì¤^ž ãò ØÝŠº[¬õ•XöMDPÏo(¡A¢/Cê v9žk³ÿ™BÂ_ÑÛÔýr´_žSH@çæ¬;7gZ¥JªÛL9…l„zÇpII©Kåóß1O]Ç2'Øñ¹è(ê¦ÜVNùµmcdÛXDÂC>ûscˆ`cÚˆ$@$|ãçGÁ÷ŠHº– {õèæNHʨ2éÌ]h§ÙVjq4’žŠK6þú1QeYqNüöaì”§:Ê!¢õ«—¾ª~R}·.ÆGc̓œŒ£njÂnG ^Z\¨ ˯òÖ_ Mà“8sÐæ²{qj¨Ë åÖô7ñ×#×VÉÕë±{0á½Pò)Àß'À¾ßžˆ²Çä£Òˆ>6…E©‘±0r_Åo_S4¤È/VÙÆé»ML¨Ô‹{vÝ`µ–ÈjÔbAu›Ó˜§A›è—³Y¤ÔZE5T³_U¢ª±¨aŸ»âCϧCï£õL­P%—kPLf–âB©ÃÝgLAIý+Ý´šè|$/³¸õ#¹Õ3­V Ã GC–õ"•ç.6ò¨‚×dhÅÙ<÷ˆ€D47¡ãÜr‘…x—aˆ2PjWZ—°ì+ÈO­¥ž‚:áL Ж©+êE|þ²30KÎn-=ü3 Êçz„fh`I:åÿ›Aþ‰eÁ]$opk'+ntºÌ>Ý`¥r«(±‡G²MåÏ0é7G†æý‰¯Àí Y'úÐI°ÈEÁž.éì²›mzÔbî30¹±UÍ%@S63} MÌ4Âüƒ”›pQ>kÌá2ó6ÿ cÃÊ!åp“¯š¾ºíÌŸdҾ̭Èn0à­+›Ñ‘õËÓËö‚I0ËE¦zÂn=êÖ[µZLjjíààl¶Ôg‚ 3Õ㦰 ¼ÈIø< ûB/:™=ÆER=#f!¢ò ½u‹Ï•Ù_‚s™C;ÖöcCÓA8Á$¬)»›‹ääx%ôŠrD1uáÚúM`Ég€íÝC—ªÄí Ì(éFyôbüªÍªv£j·ÉãÅœäüm‚þ!}ŽÆÀ9ÆìÉ@½S™´Z¡Q¶™pÞÞJ"œ^¾]â•xëÒï=íô£|úÛô¡›¿ŸKǃ!ï¨=‰ƒU.êÔ÷…ÆBƒ)$µÕ¥Äá—Ž­èMÎI\öb‹ ’·;‡-£xîU‘<äž0†ô^½ÃHAà{E9½±]’¼*)“ÔIdr‰L'ÇMJ‹CDz8«opÕªr&µÅ%Š´ÒpL›ÂoÜ Î-“Ëó ÷’Ÿe¾µµ/ß;ë 8¼ÊCÙܶaK8×׹Ȩ¯ûY#ØÌ&´ßÜgÐbB³P'$;Û$™Z†t^—Œ`ÃV¯ÇM¸=Ak÷Of‹`#À¤yN°ŒG ô2•@.CS!>ßYŒƒO™™­Í%Æä¶1+#ÅìM;g†®à ×gCm¾YË]œ^bf¿Ù¾Îàm¦'`42ÿ_²+]œyÈúxÊH0éú)´1óžÒ'7¿dUUIÊŽbÅ¡²tQ•^‘¬ã÷WBé4™N‡WÖ±û╪4‘®* Å‹ßWU“°"º`Ï®'¬‹§¤'K±ÓCÕIQŸLµÏáÉqg0L†‚n¨ÆtÏ}»Ä)ĵšîN Ù©Ööqƒ©ßa&M¶no›v%# "Ÿ­Œ£3ÈÖãì‹§ÐL[/ëÂ)éÛÅØéÁó›3‘j¿‚OŽ»B2rƱQ]è9¶Cˆ«Õ9l³Z×cÂÆ~‡‰4Ú»©alÆ‘ Œþ蕉¦Ñ)äuɉZˆ#ÿ›-kn9¸¶Ž-+xSį~ø"Îåk%"R$Ѷ6c-ÿ•E(O´PÎ>+n³ul䀾_£Àju<Ÿñ/6ã läQhufnrïg]YÞ¹‡Ý„ØÓÄ4¯ÖwçñµmR,Ñ sØbˆ-{†ít÷x!¶«ïßš"=yR[ó$ÙÕ%RÉué…™r…™I9¹@³ï/;½uûQ¾_SD~ü0dwìæ endstream endobj 42 0 obj << /Type /FontDescriptor /Ascent 662 /CapHeight 662 /Descent -216 /Flags 6 /FontBBox [-184 -226 1009 913] /FontName /HDMHMJ+TimesNewRomanPS-BoldMT /ItalicAngle 0 /StemV 0 /XHeight 457 /CharSet (/three/bracketright/i/t/asterisk/quotedblright/G/equal/R/four/I/u/U/plus/d/quotedblleft/five/k/v/comma/m/w/hyphen/l/seven/n/M/y/period/percent/x/H/b/o/B/N/z/bullet/slash/c/p/C/zero/T/e/D/q/colon/parenl\ eft/one/A/space/r/f/a/semicolon/E/two/parenright/h/s/g/P/bracketleft/F) /FontFile3 43 0 R >> endobj 43 0 obj << /Filter /FlateDecode /Length 8304 /Subtype /Type1C >> stream H‰tTmPSW¾’üˆFñÞë½,ÕêŽRݪÅÅ‚H«¸TP #… _@B>€€IDÄZ1Æð $|J@ ¨˜"‚‹b« ­nG«Î¨Ûm§ÚÙθ³ë 9Áݰ;»ÿöœyß3gæ¼ÏyÞ3Ïs˜ÿ<ŒÁ`P»?NØ¿.Y$% 5û d™ùûxá±Òì„ä¹ÝÄÂeÞEÞ,,!Ù Lª Û]ñÏ/¾øïº ÁMP¼ØD®¾2;)³³¡³ÙÌ5õgšˆÆúªcfzææl%÷“8éæP<Ô±y*ŽŠ›z,ú™øùI¿Çôx¼ÿ9~ššŽì_G¬ÿP´{ »\Ky½bŽGºiû;øÚÊútª"ïˆB[**ô'tD¹Îh® KštÇúaäø÷pþÚømÍehè´4ùhÔ‰¦Óà܆՞+\ä¶&£$$‘ô(ú£HÊ—~Iä·¤€QvÂÀÁ‹"WÚ=Áù|QÃáA -0Â¨Ž—ç¹n9._þÖ\lôA "ù¡­€sÛ½s+úí0 Šp(åAò‡‘Ô\B$ôC›¯ƒ4ö×¹#Yçù£qƒ›zø¢ …£4åhQ„Pò÷r£3öŠ?;pxðÙpóuHÂy>ÜÀq¿ïiáêÌŠáÊX3 ™Â ÑÐÍQe!.«W´«)U{¯ÁI4v:=D[ZNµoªd2•¦L¿B«+(¨ªU™”©ÉqyÒZB[íG»‰žÎ:»¶Ùš.Õ|ufÀÔe¶žmmê² Xóå¦ßÌ7e›-™ö"PdïÔ÷]ö«•nµÖ¶÷àÇÚtÍT‰­À–mX }*ÒÖ+í} zôBuGKËI ñy¿ýd#1訳uÐí¶†_‘Á®±R­Em>‘-PfdÒ‘R¥Õku…GrÊNÏ™¬&kù¶A`uÖõuãýúnµ²©u„¼H§TѪ"C¡ /ª•Ø2)[fƒÔ¤1iŒ²jaŽEÞ ­÷½Ø•!·›ëVy árw¡[C¼*·-÷*½*âóô Ü›ßõ<…?R%¦†³Ú÷é‚R±˜‰´Â <³1·GFI{úˆˆîvS•6šM§„ñ̉ãghcåé ž\’’—Bå¥ò>‹ 6dž~ýæw>QÌ,rßçzŸ û ÌÝGÁz®D¬Íæã|‹À!¡¤Ž¡Rálîí£Žæ!î*”ôQ‰ ™Oð¥ ÍIs§Ì9ÝË#=j&\Êr'‘Ì“LÌâxXž\ÉÄ]×ãvtEQ±)»è)¢D«A& Ò ­Á£1¬g5eÛÞ±÷Üá¡„/ÓÇÅ@<6Y:MÜoì¼Jt _pºœ®ÞIûà„­0’8\«„d\L¡Ïg¿çVEi“ r€ªTaR…ÙRB[Ê{ # |ªra2ÿn„Y5“”y²ùbG;°XìæâB—^ÝLwˆ-{ÎnÕ‚jD!^åerf|¿X×[…Š[r™m#—êú‰¶ÖJ½…¶è똴À¤=€ÏòØ[ާT(©£E¥%EG@¹"«2‰ÈÍ™9|AÊJÍ9Û¤¤‹ËZÙA…ýÄø3ÜóRÌæx6ºIn.KÉ/‘–ûF‰AU *UüÈÅ‚jX×À˜{0\ý©ãÇ¿à#Ú1É%™8<ÌsÇþ=–8bÝÒÄXzGBJx.ZzáHÈë‰'c#¾/âÓ—ù¶¤øºÂµ©k¨ÔwÑoÑt ÕÌ û¡›drÜOÝÍÜ;ÑŽˆøÞ’´¼l*;7³ø ±?±s<žŽöL F£9£"òz•OÆ*½\†g¶æ9å”pìY1d0®¼úëkúõ¯cp! ß©¿Éš ²&ö}å¼uþÊÅnèv5]ÅJï&Þ¤n$F÷„" x1t /1"ùù8ÿuêñèKâÖ¨F0D Ú%ã½@M©²ùùŲâTÍvÈcÃ@ÙËOïDÎ5xƒëÖ¡°Þ€AP€‚ff‡52;ËD¶[7SÊõ:¼ÛM¹LÎ73›¹]§Z¸ ®Í‰…ói°cr= Àyšt¡€iR|N5š5´¬6Ï*莿Âï–×ÚB¹Iþ¿Þ ò\h_ʧ²&Ÿ«¡ñú•íÒ úÅåéÑ^õAM¤gܲûöjÑ2†ñv3»zŠÖ™óÔ©å<{~qˆE@h> !h„I1ð£*Ÿ!¾¿ ‰€  Ä+ bÕQOÏÓóœ«Z±Vw“w“éæô\©ô')J-­j·K,–פha¥(x%ÅýÎÞ]¾ç¨$Çì·„ê|=”úe¨’h|³@ͣ䮿üG;í&®ãåíº½8âñêÝÓ>æX@ɸe|Ã΃Y 'ý V‹¥dª5:"M!Ò‡ã;DöYV$îÔ¨¨”œ~Æh§¥"ŒÒ5=Sÿ¾4~kJ”ˆèp+º*—_ , eiff.´–wýÔ4„\†K9L1µ‡K h1È9ÌGl|-ÏcŸý&÷DOÍ™óØÙÔ3¢>BØ·©-È Ìkà„Ãp>î$DÈÙö¬ÝÕd•¶$­0¦æF¯À\èòìè %‘‘ªNShV›Œ‹ìþ(FÍn½9FŽžo»ý{ ¼±|€o_`…S¨Ÿ7Üjíꌃ^Ë}x)#¥ƒìHùƒ¬Fj„ÆÈuØ:mD’Hl“ÅìŠÝ<œnD)•“ËíIi7D€úÓúµØïØÿbˆ¤˜m’vIÆDîÞˆ‹·–)IeY†¹;p’C O®e¤œ"YŠyœ-ÑíT«Z­ÔïÂUcMÙ6cvå‡8ô†žÒ ˆ’ Z°0À>ñp2äbprp1ÇßYLy„‚PÖ!p)œšð ¬y”mé¿6¨Ÿ¡ŸÎ_´J„«–*}ñ™¾µ=kÈÀž¨«²Ç áqë,<1jr%åÑ>FX®Ÿ¼Ô º.^¯½}¿f„ ì×=ÁQ:^àn »§÷Áœ‚6ò~éW5ƒ–AËéöîS]§Z‡G@ÃHÉÝEH©ÉÁÔ"˜?Nê¿‚ÞUÐgžŠ:[ƒ>u馴ÈWæÄ~޹¦ þ{ã²4„N¡VíbK¶K–%ÀcDôS„šËóø†{AÖÖ±ôÎ4C®`ÍÛV¸è·>„ß¾B8—Ès J2=/Ã] ²ŒûšOcŽc(5qD—ÒÅÒ¬µ‡ð<\Ü'³´6r0¥[Ú×{Ä¿b.°Ñ><˜ÇbêhÒ)ëȲt£2?Ò†¸1ì‰Ó« ]rºZ•4IR½Ï£ WrDˆN [è ¾ðóI„^øD°=·HE* ÚÃY¥ «dïñ«í…žÌP5‘MªúøºÈºˆÒµŸ›=Rˆìž±óSá°A¼ã7øº›šÎÒ;ÉîïÆJ»’­k%/+O'Øø6~M€ah£ßçÁ½ÿ–À·‚µGXcaB^1;d‹ÓL™e ³tﱋýë£è¥Á][N“§·4ûé Ù¾t’¹B*“ÇJeB%P #3Öẗr› öBëîUP#Wk€F­ÌRâZ±6 ¬ÝlJ̆ !y«q˜W¯‚ÓáL΂3VÁe0ƒHõ¬ó‰–•=ACë‡Ö_¾½ Hn?WR\üñCCù÷ä÷÷êïT3Ú}¨1¯˜0Ô˜J+ †æü“9Àêœ#jF-f½¶š¬N7i Ô _#ÙˆÁfT¬ë$z —HöJñyŸT ŽG\–= Ò(„òÆžþ»ù a~râÆ…~Ð?üuýüÙCIÀ=òÛ€á9ÐXé"w~Žût.³øš<&è·â|‘}“•ÿ’Çd–Gý<:¦ µ”†ªâ’28\mÉoÅ;¬ÎM¢ŽêTýÏub¦2IôÔ7ÎÔ4²g:­ÎˆÿQmÓI¨'õ¹}ƒ•û–Ïÿù¿ Ϻ·èû<ÎZ.Ó#:öFƪœØÌùW4d¿d¿ž½Bê’ÒUeªF®“ë¶gˈX‘àhCe"™X™z$³ ì1íoÆëPº–qjº”çq…ãÒ½Võ ÿ±.^èðIšJÝI¾¨ Ó0./æ—/Ö{ŽÕ»‘‹Ð¶}–¬ªÝUÚÚäzq½xš+]™¶)QFÈdáê师VX¥hô–b³˜Qýñ:fÿê˜ërršNd0·³¨Ž(ª3•W+Œ¶Â3ÀÊ„‰Ð«zS-BPh [‚1#¨s¡}”Ã(Üwpì^ÜUWõ½gÍ×îbOc¿ùø"ñg_8½nÄ™»ï¶×¬hp\®1™L.R›2ÊAFùžãW0zJ}D/("a«}*÷Îy·kíØ\µ|æ£XÆ"¢øk“–àZõï*HúVêží¿ ]\:qqh?+">(-ÚQ©<œ`û¼Aó§V 5o—‡Zn=ÆF“.E QÁí~Õ ÊN2Ÿó½w‚¾†…›kT¼}Ê·h™}÷ùõ‘]dWD­ß,l¥&TÎ'ä|qB´ ¨¢ý3çãëéïž»}•Úo¢ 5=¶~u¦ØÚÎWÜǹ‘7¤ü²o#Ù¾¼Ec蹎,mÙ©h‘Õ‰êDÕ!Uƒz"~æ^|]<ÎnÿÑìÝUd¥ÖäN® 57j)æü…œ²…-DËê°»q aðžšz§¦S¾%o~Ù3Ty T^,¢PjFѾ[aQÔPV]WLµ–n¶2Ò{,3­,ו(‹åÀ(Ïç¯Ã˜“(œ•>[JÈC…Ñáì•-£]g×YT2f‰>^r¦Ð¹Cµá›aá°$ªxEÓŸAîxc³ÄìèÔÅS_‚èÝû>TÜ]ÃEWóÏdðgeve ´Moÿ–ˆ[ÉX|2ÑÆ Ö üDè{ý¤ßÐýB‘…+Ôªê@mU™®ñEV_%!ñ) QÐØÓä ¸Ç­S8 ‡¼³¬gÚí8ê—‰@EaÒÒÃØ²×zrΔMeMàãYÛzScþIûi°…ØõF1½”~ÒÉa:éó4<í³GyÔ è³«Ý‘ËÄåèùOF¿(õ%ó¹EeeJæ"qÅg˜ãa£¤QÇ­Þª2דò8÷½¿çÇ Éb7pñOpPúÞ~&‘Y›Y¼m•¿õKHÿ<°zz¾úêßÙÔóèôˆÅ&ž‘Èø@¿ŽÅ‰ÛIƒ˜ UÒ¡´(;ë]F/h´5ÇnÂù1 =™gmÈ>xôª¨1Ù”„¸·ê”üC ›ÖE-‡ÿî¸ë<‹;ÏzB½ÝÀæôtô¢ë3¹i“DB‹-p©{Àº“¾%’†èe¯çmØLlÞÀ£WÑoBú¥Àš LN׿gSº{Ý;ò ñqlúæ™{“Š DR -jùhïû}ÓG‰Ì%_¨U Þ¹Ì@­/¤°ô; ±Ž>É bßuÝ‹Î,–$ˆzº ;á«q‹­|`å›v¬†tïBŸ?ž»ÃúšÆ©X3µ3)hòÛœ¸Óæ4{Ãf¬·憶z¬oÖ6kñƺfJ;k=2\æ è‚(:hñö>¯ÍOÂpíÿ$Nò3[ý|ª(#HÏ(Úš ?ÈKú=²ŽJyü*–ÓXbPà Z¦:Y™‘‡„ññv ù˜¥¦¨œ†ÈE8÷*…c+ã’ùl½<µx÷âÝÝ…ï¼ Ó=û¢lD-¡Ÿc‘ÇÛô ¸FµS"Ä +Jd|$¹ÃBVÏ>‚ÔJÛ½¾ñz"h˜Tˆ¼µæ‰šj¨Üµ SÛ®’CNE»¯bÿN½ÑKvØûŽüþ:r†ºÃÜêkŸEÔ[ÿhÒ‡¦)®=ÝS }Z›Ødœtød/¶ÓÀÕªp¹´\s¬ãe!Œß.±kz@½Ó8rÆ›±þÓ}~7p÷ú;ûÛiÐÚ »Ö¢4ÕSíñÜm0± ÛeàiäLJUÉÓ mµ¨Ü†Ñ0¾û¡á–j WUDxC`wØuÍ×HyWš'È9âɰ•‡©})IÛXb±²¹!S+1RÆÐHØA’I:C18¢ ‹Iœ:¹ˆ+TˆÅýZ"•6ÚÔ¯uÊ€Cfæí‰¶§¡@­Äk«K5-LV­!,¿UlQºÂÝ» çd‰FO®ÙŸDLmã=‹‰z›ùˆÚGû’<{¹Öõõz\_¯l¬A‹¯‹ZËlÒ¹“}s#õ2]A}žüí£÷?:Cº^!]ÁÎh+³ãm.ÄF ýz‡Ø5f¥ Ê uÚ:\[[^ÊáÒbº8y~Õ"-Oà€{ᓼÿ0eiËÂù·æ·þ`¢—Èy`Í"@«º¨» £—a¼ NºÝëëX¬ü¢k[ä5À$mco†‰µØûMB£7*êUJRSk,$RÂ8­eve/иŒ#³ ¡È‘þ“d7èîï·ô£.×SÉ;¤ÀTÝÆþÍB¨½† 3A$åJAÓSÂÛ W» cŒˆ^Äéo(OãÊÓa HA¶#ÊQIŽG*r¸ìL釢?‡í™(;W#åiÞ±œƒ€úÙLü"Ä!LØVeUwµÛ0vm¡þýïS·o,#“!q• ï%×’;`ò—’ÍlÊÖ7Õ ÇÆŸÂúô¸“GÉ.z™žK xMs‹B¢ê&žŽI¹±ÑQ¨øJ­MêJ‡.|—¢Ê "ß$×ðFj®M®Š²®bd÷¾‹çó°¼óŒÃÌ€¹Sü‹m0 ®æÎý}uùÓÓ”<ÝÀ}×±ag881ȯ _%ÖÒ¥¼†V!RQ×;Þˆ±šþI¼Ç<ĆÈ}4óÞD|}ŠH}<œ ðZóÃ):įá5ðd€RzÒA½GkkÅÕÖ´ê35·³‹á”úmk‰¼ •7ñ••†¯O)“Ì"³(í” ÑYýaørœFp GÖ÷<÷Pû¤{0àv§‹ºÝ‹Q߉u-~¸è*G ï÷`_÷pžT м¨WÄë‘òó2Î9¬ŒStäè6@Ô¦~@áó­dæ³"ºL¨kt@ת6*…Üd•`¾Ò³¶ä<Þɬä¤ðp\à9)Bƒ¬Å¢åß/Öº/·ÐÚÀùJ¡XŒŠÅjRV≜ÆNG˜‹¼'€é ŸÒ†2‡ì½NÒi×kÜÿáy™Ÿµûg°ëþÑ1 øc¶›³ð¼l–;r§ÌoYܲxüú¥@Z#¸\°¯«ÏíB]½^k™š’°)·Z;yxâ Êl&Þ§±ÓÚf[κUzù®ÓûO>Qpàè¯O€Z"+Õå¶í¡ÝLõå&b²;ñò“wˆ sÏC+¨bÖ]@”Š«k±ªqèÆá98ñüƒŸÕ¥!—xòVŒbsj¥ E|I+D$2“UŽÉ­*»Ö ´½†©%8ùÃÔú£ ˆÌèÜg¿€Ú˯²&8€;q]z ¹³y£XÄ‹Îr}bý ·6Ùð|Õ ó鼤`ôIàV/g—¯;ØFÉ?TCa£_ÓÓzZ,R1\#9Z»%_!ãäψ/i¼eùt?ì¶8=hwwŸyMi«¡ Ö£pHû„ÁÂðvby•}=íeŸ…©=IYà±/æúºÆ@ºF°1ôkl €+:›a‰š#-Eɗȧdvb MSöÀ=&ÜjA­¯9œ>„Âjh@ëU÷È{ä.®»Ä*Ì&³SkÈQïEqU‡q³·¢]¸Ç”î‰K¹"U³ó’Ÿ3p(ü:Ѷº+{6“èHî'ºV÷Óæ©öª’5ôÈòXtÄ7ì ãTòcê'z·W\eVÊa^Ùâý(«h?‘#P»Œ¦Mzëån+lm³˜Mè¬ëêÚhª‡¢¢ášÂ/ò‹ÆŽßÚJì ofÿŽÌÌÛ\XÀl°˜ŠóÔ½_;ñÄm&%¦4©-Z+ÐZ 6•¨ÛlC;,ÎÀàôý/²?"Jë«ìæIàJ¥AU­Ýs»F ΡE⨠”/3ˆ r'q7ûsb+-+Á&½&—s¤‘š$R• Qµvtê0­Åàè‡/G•Câ>à7XëÚzE#µÏJN\îd…êPn(*‹#÷ñilp<öÕ2ñ{Â,ÈŽß¼ïv÷ºûñç[¤g¼ÖêGs—XWŠó«rQr 9BnO¬¥±Êb~Øa¶ÙqÔÖí5¥–F…Ê/ó=¡ÃÓ¯·W ²ë÷ÒÒ&æKâŸY¿åÂ!F ¨>õs ¹9’™èLþ…vu5@öC®EWÔåwú½®ðÀ´ùBlÍLu¯þ&JÞ†ÄZÖçÄögké Fá=𞫇⠔_âÿy´ˆÇ±x<°ô!ü!©0ŽÆ‡{ÝùŒB,+¹)gÝ,‘×°ûMx¯ûØÄ9ôÜø‹qdfÜ a¡s,šõè¯ÎÁBêZ›/a:Îh@ô†¶#¦7»lðBïüø:677þ®܀ȗʷŸ*<R¢ßZî¬Ä+ϾO¿ý^ࣿÂ\ºËœF§™¥ÞBä,SÊ®ÃØlYÕyø‚½úå^ 5!ƒþN‡3ušÚ;öv£¾ ëж©ð ñ©ª"´²¨¨ò ”@Ä÷"ŸÌÇß ÑÆo-wÖ³® ‰ÿÒÿ'Àµ·´ endstream endobj 44 0 obj << /Type /FontDescriptor /Ascent 695 /CapHeight 662 /Descent -216 /Flags 70 /FontBBox [-189 -216 986 913] /FontName /HDMHNM+TimesNewRomanPS-ItalicMT /ItalicAngle -15 /StemV 0 /XHeight 442 /CharSet (/i/t/S/u/I/d/k/v/m/w/l/n/y/period/b/o/z/c/p/O/T/e/q/P/A/space/r/f/a/h/s/g) /FontFile3 45 0 R >> endobj 45 0 obj << /Filter /FlateDecode /Length 5656 /Subtype /Type1C >> stream H‰t”iTSgÇo„{¹ãЈ¶ÑäÞ̽nmñŒ3í¸TD l…°JA)I!Ä„!$!d\ l\¾Ⱦ€+RTZ—©ÎÈ(­­ÛØqFßÀE¦±çÌÇ9çýŸ÷˳üŸóüÞ—Ù®€ ÆzïýþÞþ.!!_À—‹„±)Ÿñ¶ûHc“qþ!oc\-¸ýÚ¥uK\»ï¹vþ0Qykÿ{üøÿn{;°Ê8­«õÜuï®y›Ãù¿!ÍoÖC@†| @‹&Ùg0W­I‚VAÐFr† W´“¹£Ÿ=tm°º…6CNP ô’‘¼bûŠ{6ã¶{aø,fwÀî út¥óÊåßÖÙÇÚôaÞXäàêVŸXóéšsïž}oï{?±®­%<¹0´ÖªåR. -–Ú-K¹¶ÿ`-†pi·å®­a.q­ç9ØÊ’Ës¤"LT*¡äD:U§i›êʪ)’¢Êêš°&M­œ"(¹¤L„‹$¹œd‚‹E\8‰õæÜòC7Gž?™ÃOŽUD¨ØG¤¼+îDJI¦‘“Q¡­2aÆÂÊ’*¢¤ªºµ­ ma# ÚM÷‰î NÎQ ³ÒÒUhº(1ç0.EÔ °¥ÕZ?RX&#e¥™…j yT#f<Ù¡7/—àD„NzcaÑËï,máKm0“Nµ`㬠½²T{ÕžÎ7TbTÙˆéT —êæ¨Ic=ÇXW[Ýb@˨¶ÂÜÚc©Q%ÀçÚós«ÈªÜ39¥*´DU”•‰%j"ä^­~sI²KÆ“%s”r™"E¡MÈãýEirÒj1¨0¾(CÏaZ¾]àqá-,—Wß>þãÇî›hÔ*!½š^ƒyÝÛ÷íûÆýg£Ñ˜ÙyÉpà6ôÏ. ¸s`xgìD­ÛÀûØßåwãïqwB/èA{<÷P;pr”r!-jGÖˆgýî½ê(Í¥7VyÓèW_÷€ˆ !* Ì Äßwë¼E¼)™{‚v Ø0œ‰1ðÎùçWoOݾ:1}=;ýuå5üùÍDÏÑ·ëS\؉5ߟS…V+ÊÒ¥X’Ò_ü!AKßœI¢W½DŽDtP剿]P'RÖåUx¸4ÃÀÉ0äTš°¦Óæ YXúôžú*þâ1Õû|Ð;cüœ6]»=H¼uà2qÙsS+½_j}»ið:„U>=©Æç¦äñýd_\M˜7öi¦¿ FÇZ' ôÉòÀ£J)7¸Zº`æx2ËljiìÅ+MyšòNÊdf‡Õµwç÷â÷nWu\'¯wŒuN£ÓÕÖ¶—³.¤L ß[NOžúÝõ£¢þ졯0sÍWƒ}DïÀùšYüá¬8b‚4‡7úìÆR ’ âˆväß–0˜¤©HSjP23/WiNœÌ!óOÈJøÆß /D‹‰… 8mã*ðö$÷{%îÚŽVðZC‰ª/"g|—^ß¹-¥øå_Ä`žRÿ˜P"4ÚG¼ßþIÓÅ 2èBÊ­±¶“½E£„¡m—ŽÃݨ@ìb:« ©š­›hénîîn¡PjäjÙwøßº}9\ä"óS9 a¦<]fŠâ´á¸ø××ó9ÝG#¡üc)3jj°ÆÊoÛÁJÔ,î‚_#/j2jÉ–ÔŠ„(,V÷¹*œèF€ X‚—+môÌ\X„YGhD9šÖqÔÄ©9*(ýÜE¼}äÖý»¶ûÒ+Q«’i› ØþJ^gßÑŸ6ŠW¶™É›C÷îÍ$ͪ;œ„‰ŠÓ J"Û`Ò6ã}CÕ£äHçˆyxVPÇ> ˆ§£j¥*O‹ku§ôy¤®äXi9¦?Q|²”0=á »èßKàõ>,“¸ü F;ÓN4bŸ†þ°'ÌŠÏ4ÈHiƒºsû¡á…Øf`seîú´wdˆÀ»[²SMVÄ ¸p‹oWØd:eÀ[L¹*#Y–£ÏÎÄ”ª(én‚¾°Üï{õ2ágü‡GÍ—"¼ô×ûS¯Ð+¯Z_»/™‰%F>¬wÇÃ#³%QdTjH´¯ˆ\ðbÓÿäÁß¿¹ËªŸï¿qy »t¥~ ïëÌ´-‰Æ¨l“ds´#íâîw=ì„G|VÕåC‚µVƘE ÅàËÏ+8:RŒŠ##T¸wXu/ŸŒïMŸ¸Žý«ñåäKbhnrfzžž®Á;uÙyZS¬VbÚݱ\"_—£Vd)²4Ùy4O] Rar}¦!›P*skðÆÚòÚj²¾ùLG?6˜Ñu¤…h9bôÀ?Ø–ìïBºø²;x+¼Eääˆíhð0‡¡æ[â'øw·©îoÈÙžÙ+³s) læ‚õ×e%ØvÔŸ2⦪\µ,ÓY]däË´b"/+W®“l¥f‹ÛSëĨAœ\r?à–Âû¹iÿGúѶVtàä [°½UÝ1Ä¡îAé9+9TÏ$y÷ÂüËgÀ9žv`Ë}5|LX,«P Cµ¶ï®é%GûF'F® jØ¡¾ü8™ÍQ©óµxnî)}.™«/ÐcTiõ4žqm+égÁ0í·ÜÊ¢7ît;€'ÿÊŠ¬AÝ3†5C€ó ÍÏÎáÝ­Ùâz²N|&1£mÃèu›hg‚Yd9oñgÛÞgÐÁ1“ù<Ö“Ù.h&šažøV—” _x.× ¦Î4ŽwÜžôÌºËø%ÛpûZ]+Þ[gjñR/Ý]Ä1€Ü¼`"$B’;ܹ’ „‚!\ä& ¢¢Óz—a]]\ÛuêVwëvûJvöĺýr¾½gÞçyŸßÿÿ6™o?°MYÉûÝl/iâH¿Í{ŠÃ•pÝ<|~@ˆƒ[’’çIb%yGµ‡ñÔl÷ ‹` Š'.aކΦ^qçwž»”Œ‡3ô[s·O_û;´2Ê–¤‘;*Îegvö¼ÄÂÁ¶ªu|çü÷s·ÐòÑ‹| ×1¸¹ç›ÖHènäÜ™>Ôßv â.{ÞBkk´˜¾V£“­¼N©ÁdF…]TöèdøÚÌ.át™Û|X—¼“çþR¶=?œUÍ;Dâeåå,Ìã¤äoç¥ OHER‘D!Ò¡:Q~}®HFà^¹÷e"›Ü\±Q+ˆí«Ì®( ÊŠ¥¨´”§åS¢ÙhÐu†zƒk2š¬à°›Ì©·+m Y-o’âBqLJÈ«µRVn¹e@èUEðÙËÞ¡ËĽ sÏoÀ5ãßÄqx.{‘Ì€«i­Ÿ#ä{´˜Åðâßèº"Sz\Ä­äRM«B%Å\m~Œãê)%Jº«'±û¾ùñ907>žÃÇÂr%+¥NV&&¬á(³¹æ%N¿¥«ê¢•öŠr,›ËJ*¥IÛdë)cÚêH#N%}ÃXØ„A  {Úw°žWDth 4Ç!ôü·<ˆÁ×ÖÐŒ»[k”¡0Gs¹‚¼GÖ#p-í*dµžk?ý ®ž~àò\œ›œ  Ÿ×ìÆí¶:™0ëšÔJŒ¯ËWäò­¥Uˆp»:ƒU˜$.9¨v¹u¸×oq‰ +ÔŒ v÷·÷•¶18YlŸÂYCá¬û?Î&+Öd ¸Îób+Ò:kÆúÔ]b/ðŠÊm%xÊ~^j‘”ºžŒ!M?äQbÌD¢L¼÷æâÏÁ¶’ ¶w»6@ ¡Åý*ض¿ ¶UnÐ&©ü)ØVU¤ciÕ ÓH—Á‰·:jµVJÞŒ*V¥>*Þ Èß,e 2¦Ž-Ä*ÌâVª¢/õÏ¡ÖÐqytjfäFQ;#?Ãâð^¹š×êMÑZ¢®f1cæ.2ɧé”ìÃú8$^ô–±Çgpáí­zM3Ѭ6)å˜òdu½Ö’ q䟸™öBø[¸|–ô “›:ócEN¯:€w‡œ~"<éöã¢Ɖô‚Ü T%WÖªq…ÒÞ©"”~áB!\)z(ýB1öpŽái]›èíµõÙûìÃæ‰Fk˜±”LSs-è>YOÝ Î\g¨E ú†Z=¦Õ+UrÀÉÞ¶“\ñ.I[Ë€§(!ŸŒ¶º_›Á©vÊ ün½Æµ$êú*užh }?~Œˆvkr…X¥YÒ"²Ö‡NÛ;"ÄThföêW¼S ³€Å-CUÕŠZ®ù¹[VÌnîk¹à“¸7;É'i•²Ÿ-> [ s¿Ï`ÁÝ-z•ƒ°«LJ¦¯×Ô©€p+™ò2kh³07Ùrºw~ü¯W^Y˜<ñ£.ŸÏìÅ­–ZjLMZƒRЉ4yÒý€Üµô-×ÑFàûã>õï{pýC¸üñ8Õå Dh©C´®?)OªÀIš-Ù³™¼Ã¬U~Z‚ MUÔpË]m:Þ°¸(<]}݃£ƒ#]§[:‹= îá¢|j¸•2•^×Ô64ÕEK4[1Kó¨oPr‹4ú±aM·Ä<’ Ï̬«H@­}mеQ¢©¢­¦.Çx”èD¤ísët ©ƒ¢(ÑeT=)Ÿò˜ÉDòÁuÑ+È0öÅaŠè*’~»x‘>“öIp ¾e?m±¹kgzš¾F€m ìšaæÌþcüËÇ™'Ä×îÌO=E§žv>ûö˜?—6ÈãK÷èd|â–?nÀsO´ô–%½òñ«0þ>ŒÔ÷7Ÿâcý²bê ‹]GR0r‹|7‘Œ1pÙâJ ½nÜãªÕ¼’…Sè¸Õ€4þø†p«(«²*V,e©Sê5Ô’XB³P{,·±IFHM*³Î‚êlõvæ2õ8'Àmhë® ¨üºØ°®‡@â.µþŠ€ËáúK0¾‡Ý_f‚QV¶ï žÊ”qÓˆ4îþÔO>¼e òŸÙÌYʤwÃe“ßÜx€Þ¿qkðÞ¬øŸÀÎÎÄ’ÕûDû€(IÈ,Ëä”çr¸œ"~!e2……Z.þ‡tß›ø;œ¤ú{nq‰^ú?–Ë?¦‰3ŒãÓÙzÉf¶5)wîçܲÍÍ9·eÃ9¦‚Dt‚8~ɤ@ù]¤½®”öz´Å?Úr”Òß-´T,-hÇ‚ !€â LÅeq."™31Q·ä(Ë^Øòþý&ïû|Ÿçûý<ì&ù°$Táö–Xr”xQú>lÇÁØŽ°¡#ì‹åÛÞSœÇ`… Wý„ ޏƒcØü•{‹ EWH¾,¾&[.‘ãR¢š”kòµ‡5k…ƒ}‘SRe4É0Mš(3DY­vØ qe~]þ‡Ý]Êaß[9Ê;ɾpxϾCPîÉ\\€”‰þG¶>€l[~`ø‹ë:-þ>{éëQTù1¿h ÙöV}.¢Q1@¦QòÈowjH€§T©„ËUßJãQà8ÌÜæU£Ý1Ø9í¹êî¸þ×äýñ½a¿ße†šÌfƒi¦µ4fÔÔz¥^Ú\× VÀV«Ötyí]¬ý¢%<ûÜJ+j­'šq¤$om\ßß»ÅXˆÍfÞZ =Ik.âDÅDN,¿Á+“‰ëDˆRB[K°+nRë!Cm^ŠìO•äå`9§$é)°ÐTì,F¾ŒÉ„Ƀýénd–Ð ÓO×WˆPQ…@‘‰$Ÿl b…aéœîTÄMeïrBÜ.»×Ñ…Xœ:ªçǕCÈÂÏþ± lbìüÔ,®¬BÏ ¥Í}ú¸4(í$=éѵµÃ=–s>/Úî»` ##ßK½X ß}Øø1âN1“œBîZ–*·n"yGßMOÌd R+ÈÈ>pLvïÊ<ßO¦ áʱ»%\>² é߇'®M/–vðÓ‹óåõX„«äëÑþŸX`WË¥5RÿzéÁZÂ9¯qØÝÜ_˜N@ºQ@´x\»#[artarÖÁcqÇâr²‹qŠT8¢PLF™tf+쵎ûÐ?™yŽÿÛLöQ¹uÈe&1"Ô‰NciEÇ3¿êÆù—¯÷„lm¶&BÓ£5 ׂ€ß~ÂNs*¶+â2áRsU»•¶ùUÝÈÌ\ïÜ<6?û˜á1\&5“-!³ u¡®_s»X`åG½ÖŽvµljô~…—Ÿ_rZú€€ ü\Oë0}¶Å²þà‡(s`é‡ÝÉj‰\æÑ]>ƒéë$JœØð›ÖáX‰"00ƒÝ¾ksüÍDÍ?ºõã­ži×dî¦/à€ªSêE½¸Ø"BÄ2µœÀ‚ª‘Â"Àµ8Ú-qȰ—Õ4ÈPuU]9^¬f&ìa_’ã™Ç?ßE2_60µW”ÏkçëGˆaÙ0>Âo.Q›™»²k5¶±½ñªn!ZÉg˜8³‰½˜Än6vùô$ÐAÕ91/îäc¿°±x‚¸K»#I3«I )ƒ¡ñ™;î<ºõtŽÙ0±ØÛ3™»šzzáy°—§FÒZÞN)ê0¹¢¡V+ “mVZ•.pZ)ƒ¢•FYeÒLAšÀ¾¼‹} ØÖĈš_j×¹½Æ`‡Þ† t+q7æ’ØRÌÛÇW£øåù9)ÉYYß …HC6ètˆV§74‚ÔšìZ§¦Ec€hJeP Õ—`R©J|–™jí ;åAzÃöóCØP÷¹§@ý·™Xf ³ó9󌉙}¼ oº&Gá°* ó¡>iµµr] 9&'(¼ Æi™•@­„CéÑx4M“2j šXyV¥#Q —•eœØ“›(ÌŒÛþMœ ;oIÅW?Qß ê€<ˆ÷³ƒñü¨˜ß"¯ëîwwºœ.§»Õm„ –~ a.qW“V 8•ló0> endobj 5 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 555 500 500 1000 833 278 333 333 500 570 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 930 722 667 722 722 667 611 778 778 389 500 778 667 944 722 778 611 778 722 556 667 722 722 1000 722 722 667 333 278 333 581 500 333 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444 394 220 394 520 778 722 722 722 667 722 778 722 500 500 500 500 500 500 444 444 444 444 444 278 278 278 278 556 500 500 500 500 500 556 556 556 556 500 400 500 500 500 350 540 556 747 747 1000 333 333 549 1000 778 713 549 549 549 500 576 494 713 823 549 274 300 330 768 722 500 500 333 570 549 500 549 612 500 500 1000 250 722 722 778 1000 722 500 1000 500 500 333 333 549 494 500 722 167 500 333 333 556 556 500 250 333 500 1000 722 667 722 667 667 389 389 389 389 778 778 778 778 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 46 0 R /BaseFont /HDMHMJ+TimesNewRomanPS-BoldMT /FontDescriptor 42 0 R >> endobj 6 0 obj << /Type /Font /Subtype /Type1 /Name /F3 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 420 500 500 833 778 214 333 333 500 675 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 675 675 675 500 920 611 611 667 722 611 611 722 722 333 444 667 556 833 667 722 611 722 611 500 556 722 611 833 611 556 556 389 278 389 422 500 333 500 500 444 500 444 278 500 500 278 278 444 278 722 500 500 500 500 389 389 278 500 444 667 444 444 389 400 275 400 541 778 611 611 667 611 667 722 722 500 500 500 500 500 500 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 500 500 500 500 400 500 500 500 350 523 500 760 760 980 333 333 549 889 722 713 549 549 549 500 576 494 713 823 549 274 276 310 768 667 500 500 389 675 549 500 549 612 500 500 889 250 611 611 722 944 667 500 889 556 556 333 333 549 494 444 556 167 500 333 333 500 500 500 250 333 556 1000 611 611 611 611 611 333 333 333 333 722 722 778 722 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 46 0 R /BaseFont /HDMHNM+TimesNewRomanPS-ItalicMT /FontDescriptor 44 0 R >> endobj 7 0 obj << /Type /Font /Subtype /Type1 /Name /F5 /Encoding 47 0 R /BaseFont /Times-Roman >> endobj 22 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /Encoding 47 0 R /BaseFont /Courier >> endobj 23 0 obj << /Type /Font /Subtype /Type1 /Name /F9 /Encoding 47 0 R /BaseFont /Courier-Bold >> endobj 46 0 obj << /Type /Encoding /Differences [ 0/.null 9/nonmarkingreturn 13/nonmarkingreturn 128/Adieresis ] >> endobj 47 0 obj << /Type /Encoding /Differences [ 0/.notdef 8/.notdef/space 13/.notdef 29/.notdef 128/Adieresis 202/space ] >> endobj 1 0 obj << /Type /Page /Parent 9 0 R /Resources 3 0 R /Contents 2 0 R >> endobj 10 0 obj << /Type /Page /Parent 9 0 R /Resources 12 0 R /Contents 11 0 R >> endobj 13 0 obj << /Type /Page /Parent 9 0 R /Resources 15 0 R /Contents 14 0 R >> endobj 16 0 obj << /Type /Page /Parent 9 0 R /Resources 18 0 R /Contents 17 0 R >> endobj 19 0 obj << /Type /Page /Parent 9 0 R /Resources 21 0 R /Contents 20 0 R >> endobj 24 0 obj << /Type /Page /Parent 9 0 R /Resources 26 0 R /Contents 25 0 R >> endobj 27 0 obj << /Type /Page /Parent 9 0 R /Resources 29 0 R /Contents 28 0 R >> endobj 30 0 obj << /Type /Page /Parent 9 0 R /Resources 32 0 R /Contents 31 0 R >> endobj 33 0 obj << /Type /Page /Parent 9 0 R /Resources 35 0 R /Contents 34 0 R >> endobj 36 0 obj << /Type /Page /Parent 9 0 R /Resources 38 0 R /Contents 37 0 R >> endobj 9 0 obj << /Type /Pages /Kids [1 0 R 10 0 R 13 0 R 16 0 R 19 0 R 24 0 R 27 0 R 30 0 R 33 0 R 36 0 R] /Count 10 /MediaBox [0 0 595 842] >> endobj 48 0 obj << /Type /Catalog /Pages 9 0 R >> endobj 49 0 obj << /CreationDate (D:20011113180235) /Producer (Acrobat Distiller 3.02 for Power Macintosh) /Author (stephG4) /Creator (AppleWorks: LaserWriter 8 FU2-8.7.1) /Title (Callback adaptation) >> endobj xref 0 50 0000000000 65535 f 0000048145 00000 n 0000000016 00000 n 0000001820 00000 n 0000043970 00000 n 0000045177 00000 n 0000046394 00000 n 0000047606 00000 n 0000017725 00000 n 0000048972 00000 n 0000048225 00000 n 0000001944 00000 n 0000004141 00000 n 0000048308 00000 n 0000004256 00000 n 0000006251 00000 n 0000048391 00000 n 0000006366 00000 n 0000008600 00000 n 0000048474 00000 n 0000008715 00000 n 0000010527 00000 n 0000047705 00000 n 0000047801 00000 n 0000048557 00000 n 0000010664 00000 n 0000012021 00000 n 0000048640 00000 n 0000012148 00000 n 0000013531 00000 n 0000048723 00000 n 0000013658 00000 n 0000015110 00000 n 0000048806 00000 n 0000015237 00000 n 0000016595 00000 n 0000048889 00000 n 0000016722 00000 n 0000017487 00000 n 0000017602 00000 n 0000017796 00000 n 0000018332 00000 n 0000029012 00000 n 0000029518 00000 n 0000037913 00000 n 0000038223 00000 n 0000047902 00000 n 0000048018 00000 n 0000049117 00000 n 0000049167 00000 n trailer << /Size 50 /Root 48 0 R /Info 49 0 R /ID [<771b01795fd0dc9985670387ad003bc2><771b01795fd0dc9985670387ad003bc2>] >> startxref 49371 %%EOF portaudio-18.1.orig/pa_asio/readme_asio_sdk_patch.txt0000644000175000017500000000137607455606060023621 0ustar mikaelmikael00000000000000There is a bug in the ASIO SDK that causes the Macintosh version to often fail during initialization. Here is a patch that you can apply. In codefragments.cpp replace getFrontProcessDirectory function with the following one (GetFrontProcess replaced by GetCurrentProcess) bool CodeFragments::getFrontProcessDirectory(void *specs) { FSSpec *fss = (FSSpec *)specs; ProcessInfoRec pif; ProcessSerialNumber psn; memset(&psn,0,(long)sizeof(ProcessSerialNumber)); // if(GetFrontProcess(&psn) == noErr) // wrong !!! if(GetCurrentProcess(&psn) == noErr) // correct !!! { pif.processName = 0; pif.processAppSpec = fss; pif.processInfoLength = sizeof(ProcessInfoRec); if(GetProcessInformation(&psn, &pif) == noErr) return true; } return false; } portaudio-18.1.orig/pa_asio/Pa_ASIO.pdf0000644000175000017500000014313207423043454020430 0ustar mikaelmikael00000000000000%PDF-1.2 %âãÏÓ 1 0 obj << /Type /XObject /Subtype /Image /Name /Im1 /Width 243 /Height 270 /BitsPerComponent 8 /ColorSpace 2 0 R /Length 4603 /Filter /FlateDecode >> stream H‰ì— »º, À‡ˆ¤YYZv³ïÿ1ß ­£ˆæ/çüß=O‰€Û~2Ùø_ì Ëei7¦ö½cQ·¦’v°?ÇÝ‘çÏP÷ù Ôý~9ô0÷1ôp×)ô8·#ôh—´³%g³5W ³EG ³U7³e'5uk¬H­{TU¸Æ³¦}w*[ô¾”u*ØU1OâI yUÐÓøQÒú&] óD^0C{-_ôŒÈkYè©\`Ææ’ôd>æâfif“}‡»yCxrãç-Ð…£lCš¡\úß}SÌô4mÁïb2ï3¡®;µßì©y`‘šMrtpF¾ u9ÅíŠ5Æ¥™[Ã$:Cxa)À•TÛ Á“ÎH "ß„¸°{»bmÓZ1òŽ©=â2svM<šM¾ã@0Šûç³]±žœfnAæL}Ò2ÈpI @Æá<°½Ù3)©-*wv¼$-È/v¥Ëé‰d’oˆN!o ù$¥|È—ïÈUæÕ"ì…ÿn²Áe$‘ò†ÅÕÀŽNW¢{Qf3²‡¹Ç‡7'?cg8JA»TìÄq¹7Å  ¶áüD\ÅÕu¶‡ÐCòCaÀ/Õ‰èúÂ}ŒÖR`+ˆßIÊÍ“”iÃ6)^v™{šÁtH H8ØÚñ·°kÅPÿõ3C@Lÿ¡Ù‚Ùª¡9½°’4¸fÃJ“íŸæ4† &?¬…¹ŒûãÁ4¦´þ˜·|?î:i¬ wSõ:Ü ý¸:r£ÒÚ2K ‹ÌõY(ì Í[ÃpOL¥ßÌ-ÈÚ22ã ‹æNà‹Ú“ ·¨,3Ó?!?wBd-=L³Ìm õe&d!7“"ƒÚ_\b ›ù²“Ì·Ê0Arþ¢L‹l… ÷‰‘ Xdþšp«Ëì¸ 0/‰8¤OØó£Ù¥â¥[cþ®hþ Ìp’5ôZRnœ¢íÙ3HmÃ~—Ÿvu·LšYËQ¥D=ÚŽ+BéBç§—8MUŒWê±Ntrí«Š õtˆÎ•ìÏÙÆ«¿=Ÿ˜?KÕ‘ë3ú¬Y÷o˜U¯kB=Ú[tõ9v¶Ž^ÒÙd;6ëøVjúô½d)#/ˆ«y¬ÞÑÇn¹ôQ=ý• “A‘5œ´¤4³!÷Zf»vuä"{F£ðYæÒý2‘=#³ö%Ïú¾ZfÝÖ¼¶YfÍÔìɆkÈsέ-±‰,Šl‡™äËÍwÓ‹VP xÜüP+wednâQÌ_§7M¨f¨%«…s÷çO[*)ÿج¾óŽ$} ´ôL½È‚„‹-÷zuéÎ10u¢¯›-µÇÔÈ™âyD&®çqº“5³_·ÜaƦ»‰™3_]¢K’‚çpi4ûþöö‘Æ]zZælÃ9RŸÙ*ȳMùu„{úçóÖ>)sö”òà³§†ÜdÖî ¶gt+\FIØaôˆ¸†ÜÀ¬—†chŠ¥é˜i•ex9Á.q4dszÒ6¶ñ4Ujã57HÊQ®Sº LU~ÕpkµAlI‰=10—K3KF쨱&uèϽ5W×Ȭ&EÚ [Ь‰ýNž-ØSeM*Ôyê›kd.×Ùùåï#C¥<²îäZ™Ëòï![wqýÌÙꉱÁ„m…#ÅP‚Y7a[áH©Ÿ/þ dã¡11ˆ+6„Cí«PWAƒB¼§ Ä"„|4v‹Y¡ºÓU®CW«9ß Ÿ —C€LRÛ+^ŽGÆ‚| ÍÌwóQÁÕ%Ã’—¦r’—[¦c£BfÞ9àw&9Ï‘ïIt2rÌ9÷ðqvÇVŠ#¿E꽬¹Æ\EN*GpÇn…íI\FÆÿø™àÌ}?ŒqŸl*×"ŸâZ?7*äGr2 Ÿ™/ØVCÞSg)¥_ŒžëªÎ¬yÊÒ:ò…ÅñPE¾³;2 /FdVV¸ ÑŽÕ£cŽ §ä¨#ljzîZFÞ²=5+ ø$¬ YOOFdÁ˜Žì³ç7µ–)æ"‘Er °‰Û×N%)5²aiYá ¤^„˜‘QG–G¾S‘Dä"…ù¼œ|de…Ë‹8¿/zîÆœö]îS·dºƒ€ßÑø™‡'ñ]îªÅ‘_AœËêV µÚj{¶%Cf+ó‹‰xäñRÌÆÌŠ¥šá…˜[‘m2bif#ñȬ8ÆÌm0i>AŽ6d´²ò—EkÌM_ÏüÌÝê>Xq©9–æF®¼ãâ˪ç, vš-ϽÌ5bf õÑfÚ,ÏÌ\Þ›‹690Ò'ÓãK!3ÝpSÖã”Y¡þ²ç’Ú«n̓ýê oFä¾ÏÑ©ùó«é)}ߢ{ˆ¾§6ãýky‚UC»¯æ¡R[äoÆû¹öMWù÷Ñ;BL&¿ïì\‡`­W$åü‚ËžÆØà|‹Ý;¾â”û¸Sú1ÞÝF—“@G“>÷s'·â¼^ X8éÏ/ëÈž2;º‚g2z‚`R&8%2Š®E’qàG)å¹j§÷KnÃîq82,óá(“½rò衯8 Ã?yB—¤¼—udøNwDÞ{Ê+6`›m#|Qò2¾\–,ê>Âôón­£‹­µ06/!9™fàyªó~9ÜðB4.s5„Ì%މc´Ùá$Σw!]ÜÙéqÍW9¬³{° {¸ê‚òòU¾å« iod\åj`ãÝmca,^Ç€û?68’>á^<£O¢lfþÃÌè‘­|Ý¡“·#Â{'ôv{`„ÈwÎEY"‡OŽcÙÂì%”š Ù“a¸°c¡µÀ¶"zd‰€{BN v.{ŸIy/ë@c»„±g˜#à {÷1lðrÇ …WÌ-G\ìö¤jùã·L¾¾h…ýã%+kB`þ‰ýDÞ Å•.W¯ÈÅ9Â-Y¹î„+p£q)‹ŠøJ¾: BÄ9 õ£¦AÖ–yX ò¼ÌÚu‹|Á<Ʊ éw–”_øwQ²†”©22Θa•ï ‡û3øX`áOù’ëg/BÚ8ßåæýAg~K¶´“ãÏ?R¦Ü–Òf85ì ö¸'þJ[‹5*ž6IL;6þ”ï*;4ÀB’¸“G|Ìk UŠŠÇ²›‡Ë9¢,íí) Ó€ƒÿÛã®;pÐ?£¥DCb—œßÈä»Ëv˜‰i@„ˆ$ÑóÝD¶Í#2¹ä" TûF;MÂm²U®$²kÈAì’íùéU›ªDг;NçÝñLå˜AÄ¢]™"Â¥où°GÂTÞ¬™™›êNéV‘éÓ$¤3sœK»Y[´Ê~7fµ6d™™÷4sõÕ™ÙToÇ»07r{­dƒ¹çΔeäV‹Ý€`Ï×e3-Þöé8ù=kî¸î„ÜߕޡY ùóØ´Ù0Ó&Ε'¿ wãË“2[¹%Ms¢õé|ƒ_‚¸-3÷¡Eâ] ™U®?V”·ŒT3ùœ%o}ëÌ»-io2ª'ñ9‹üú>¢z­©o0 UÊyÏ5¬xå•>‹êÍ6¿uL+õsUû]²ý܇ײeó¦to=;ô”i‰ —^dÝäÖ¿}¹ókö§W©§‡…‘'±Þºª’ôU­Þý½°®©­n–KϬW HÙ¾ËQ¶Å•;B5ÒüäSRºð¢#V 7).q.O\ñL¨å?öËlAUÉPEQ|ÿÇ<é2²µ¸ ÎÉ…-Xò磡MwªÅ=x¢­T{¦!'Ä~‹™ø²Ãd[ùÇ fÄÇ †'Æ\‰v“'„ºad¢]]f1ýA?•0¶¿ä„ð™hK\C íÙX]3Œ6)ä¡Êyí™~hDXÁ/rJÈž Û$78VºšãÌGl Ødx CÌc™ØéB%´GíO¸£Œ‡ ÏÖÈTüy¤»RÈ¿o¨ç¸©ìÙPm ÔËžÚe™o ¨aIô„nä•Wb@Oí¼7|v+pPȧadµ¸(¯[ÉÕKlÕîñÚ‰MÉÙ¥§ðÓ­ßIìݶ©£w„ÜÚ45‘iÊŽ„ZòÝ熜li­ºÒôò™ÞÓjåc(ö3цX6uLòn››Fã¯2Tyì©YQÈ1'¥ìN2p¥6©H¶‡–ŽQß rÍÜÔÏXÜh}ûLuÅýXþ¿`À 1¬9 msW­ª{ŰÍåÆLFl‡Û@HýCG닸Þ_‚Œ‘±8_²h[B°M¾jk}rœŸ÷‹#¯ÇŠnD[=(¶›¶–“J;v³à‚G‰ì… :<±wmµo*¾X°Ê%r´Íˆ»â‰Í:jöe y‰wÙId¨*/À5Oì›n€UÙ G{ÝûexŽ 'uv —{€2ªuë ²g/Ç5Ú$ßîG gÂ{™ÛYyÿð]¨‡±Q÷Š"땟§Ô?Ç|zå¼÷²Ÿ ç~ìu6¸›ä;Óüt4w¸!7µ¨ë‡˜{ð¿iOÍiO…Šúaö{˪µ´Ñô×Kþ4ÿiy·¼ì×È –$¬€è²¥¥:±}zT·ìš¦ùå|Z¥WìL2Ó#>¡¡$ y­nY6ò˜ée¡Bîóþ:Ù¦…äóÑgóÄÎÏðAä7—ÓÚ¯&ºùfÅÅ•2yy–|'þFŽPEEZÂXÈšEôm§&¡nå"¯Ê¼,ó£äKOŒ?„L52Ys²°°kh\ô?ãZó†kÞ\©0Õq| ÂøTŠ[öMÉZ%Ö8ÑîÚ.άR¡™à–¼öTLÊìY]Ys«Ñ ;1l®£ö¢Ð}´YgÈÍuÔbw7‹_«^›þ’ŽlŒInzëã¹&¾™å(nÛÞt‰?†<`ëÈzænÑéÔ¬¢ù˜qRÄ#"ߘ'Å =ä‚‘Ñ1ØB\AÆ|~U@ÌbÞñaÁê>uÞ:3x¼•òc> stream H‰„VmSÛ8þùûn’`ÉoI?´…㆖^“™››ã>(¶œ¨µ¥Ô’ðë»+Ù!)3ÄÄÒêÙçyvWËÑÙ%Ëj4a"ü¥Ï$Š ›Á²E°]-¬í(šFËaYÐËñýÃèß“«¯çŸ>ÂÞ›fÛ9Ù§Ϊ¾J+E[làF¬¦púßòÏQ<ñ˜ò–F ȹH±N–²ØhUˆ>'1fÄ&ŒM¢ìtù ñÍz|3HX Œ3@e¨Œû@_Lë”^}žw¥2pþ匆óÅõmõÁ"ˆy,)˜G”ûhþ1b>ÜÂÝq–m7BK¸‘îÉGˆ¦ ¥Âö™¤3ÚwòÙÜËf…"·^”Ù p, iÔ˜çïk‚8­ZpvÉ{£ ñ>ïwä^“ó•u­(\X‡Å-Ì9ë1góór£,”¦è©”Ò­ZI ¶¨˜ ÜF¾ÐiBmé{’sö“(”vÆn@èþVº4v ×äã¶JÛàÂèEÆ’€ˆ±8r{£ „ÒYYŽaÕUjdÕ“QŠ­Ná©aù×¹p°îD+´“¥UƒaDY*ZеpR;”IÚ®vÖ#õ –¿y4i¸W ñíô˜úƒMãø< Eº/!\vÀKؼ/ðgÏÓæ˜ÅC%¼×%!>ˆáî$¾p­ ‘~­ÑªpÛáß»SP”ç¿”•Ò²ô m[³5Ȭv¸S*ŰöB ÒZO’ˆ1I_YUªP¤þQÚ를wŠðP08jBƒÝébÓ­žéx/T-VxX(¥ÛÅqùCéÃ8†öÉB näÇ•û¶gyoGÆã¾(9ï«ò9 a…Z­ZÑîBÉ!ó÷(¥»·ià_y³R¦søè=è÷­±v‚]ÁÞÁ>Ôƒi¿[bàc6Û¼MÏÊø¹çŒáFéîq ‹«ë1\¶R^,>ø£/äíb ¾Í5Rh»ÇL½µÿOK¬·77˜ÖRKòØ!˜l“åü°.¬Z£ñÆè9C@SVÞcˆúÀNE?i,|묣úl%}§ê¡¡ZÓµ…Ä…TG¤cžR—ç( ðôå¸Ä4šßP>R¬%y±GºÓøÂbHk*ç+q%݃”»È½¬Í–"þg܃PÿÓ “$ZÞ;|C;Áÿ_6ö7ݘdûÛE6 Ú,ÉžÝx|½@R|%Hl N÷×Ód#î%-_á„Ä2õëZUHú®¨å0ñ|´²U(á‘þÉPðIžmˆ¤”psÞˆíV–øÓîUdq—ÖˆŒ:ç> ¼p<¿«:]øñö êš‚+êC4¢ÑaüUÈ0Ö£yß… Þ”ÐÅiûT†ˆ(áQ'at‹âxéoÏW¹´÷wŒÃúæM~Þù—£t7IƒŽ<Ækb”@ž¤P4£³ë†Á3úkt±üµêy:T&"›eÃM3È5rD ê£CRAñA º0ÿèdí{~ñ 4ùž¾« Íbô]ÏLÚc›hsœòsÈgüå¤'ÿbÒ?®õlë endstream endobj 5 0 obj << /ProcSet [/PDF /Text /ImageC /ImageI] /Font << /F1 6 0 R /F2 7 0 R /F3 8 0 R /F5 9 0 R >> /XObject << /Im1 1 0 R >> /ExtGState << /GS1 10 0 R >> /ColorSpace << /CS1 2 0 R >> >> endobj 2 0 obj [/Indexed /DeviceRGB 31 12 0 R] endobj 12 0 obj << /Filter /ASCII85Decode /Length 124 >> stream s8W*!!!(HqdXct#lK[ZWb0":,AO&LG endstream endobj 14 0 obj << /Length 1977 /Filter /FlateDecode >> stream H‰„WÛrÛ8ýÿå­ƒ ‚yó8—õVfãéaª&[S´ÅÜ¥HEÅñ~ývãB°l%©"Å o§»O7~]_½ûÄ#ëÝÕ’Q‚ñ™WŠHIÖû+J¾_½û¼bäûñŠf”本7ø–ÓŠ¬Ÿ®ßx^OC¿'×ëÿ€6nµ‰ŒqÅAÝúžf ä_úz«·ö$ó'EÎÊé$åÌY`UŽþ\±'×ÿ^ÿcÖÎ2Á‹Y9x€Êïºflê¶ù_b!ÏòJå,p©œ…ãXš¼OÌð¬’ÅìgƵÅÍêî+ÚŠŒ,Y‘ñàYòŒ{KÌÇB« hÑ<<òB@¢äÅÈ¨àÆŒA,4À2®*9KäÖÀý õðB; Ñ¢¥W.‹ h)%Á\MhÝ$~=ívz8¾€MrÅ"Ø„ÏOÅ/ VÉ|.Áß ŠQ¡fçXá«L¨7ªŒ±@nÔÿ~꺦ûžÔ°â<´WS óK&ŠÀDÁ'ÌVc=¤%¦2%¡+"¬| ÐEÖ “íÐü¬ A6uÛ>Ô›ÿ’‡ú¨·¹ëÈø¨› 6ëÛ/¤îH}Ú6ý,ðÔ´-y°ô~Ž(Jšn«’~g~lûÓC«m`H›JGúÒá6‘¦ÈcÝîÈ·%ý@Ø·kòôØláësæC¿ÑGð•<<õáÐ6›zlú.CHhŸÀ5ˆìûãHšý¡ƺÉîÔmPL<Ö#ÙŸàÁÒ €ÑMÛµ1 gÀÃo»¾mû'D꽉Rd2ÎAîs .,£åLŠT–aE‘´ +Ң帗M ÔµTQ¤:E€0Uº°•iå é¨ôå\––ÆÞ[¡ý!)Ð<+Áažm†ûf7K8W¼a¿‰×ÀÉC*sÐjªV<À¼3@‰b%iHácGZˆ>4ÇT–g>ÛûZ•{Q)y¶…ºPJQŠ\Þß­—Áè{ 1 ƒ=­P;¶IÂy… ©Ëæùפ9FI;a£›%˾Ì8ì- ¹[Ø 8IÜ+% ’5]ŒÌ ˜ì¹ež#QʨH¤Ÿ ¾dm¥ÕÏ8ÃH9‚l¹•>Š2KÃ`8erùv%TW,¥çî’:¶›À›Ô‚Æ«ÁQCwæ0Fù÷ö¤á)_m¥p„icvëà™âHî[nÂ…õñÂõ`Í›†­ÊÌÚ÷4tg}75ÑBfý®²ªO¢ëÒ<”Ô|‘™7Œ±Æ{ÖV7CóàöÄÆ‘—yúŸ4ŒRócÎã [ãÕüiº•–óÀÅ|ݘ·X]ïM!y,*éò÷ñl{\/™`,ã‹»¸Õ¯—%,ð‹ù¬û`D8k–/>_/e¢­yŠÅÉýÖ ”3É2¹¸¹æ°/VöqÅWûN®9Ø-ý‰{b¢Ð‚YÐM¦“l©Lp·y3qãàÀ¸q9rµ’®c•cV¨.EçBg¹K(Ëýôq=‚ È/7£Š‚;Sþ뤇çúG³ÑwÝ®Ó"($CM Ìheë¼…íü¦Èsk\Zz —ÊÇrÛŸºÑZ´’¯ãö’»@7Ñ}> /ExtGState << /GS1 10 0 R >> >> endobj 19 0 obj << /Length 2177 /Filter /FlateDecode >> stream H‰¬WÛrÛÈýþÃ<Ò) ž+.û¶ki%µëMÄ<Å)E$¸°P²óõéž 0JŠ’J¹J&¥™ž¾œ>§û§ÝæÓÏadwØ\å‰à„Â?ûI IREv톒Çͧßß1ò8nhÂx‘“]µÙþVÞßMå0ÝMƒ.Û»€­ÂÚb<)ršƒ­Ý5\¡J(wåý8Ùk_ÎÓé<á5x‘Á‹œ¹ÓR‰‹Ó·;¼û<»8rÓ=Ö¶~¸˜Mxž+ï´0×~¼»ýbîàé+)žœ\‰¤HSáÎòÙ 0ߟÞ%Oc§úÓAÊõÙuˆôÂÚ;"äBö§7¤²ð~núQ¿#B&£Ê\\{Å)JùìÔu=žàÖOçÃAã ™al>{ó­^Uˆ'©”Üy“1‚ûÚº+'MÞôŸÓȼõv6s›¢A·ý“þ|ÝM×Cý¤{»ÞaÔvü/‹‚pÌS‹/Ra|ÄzB9Ÿ7[‘ˆ„‘/'ÝÕÝ#ù<êiÂO{ýTWšÔÝ¡ÚrªûξÀÜ "Q¾ÂÙ-0qÏ›¿m¿tä—²ª»©ÓGöÆÓ‘”ƒ&‡ºÑ#iú ’´‡gHIÆ“®ê²!‡¾ÙëTeÓÀŸ¾B)ÌmçßExo:jRžNM]/ɇ¿ïþhkè¡ÍXj}cL9ßì Ùõ¨c窲#ºë¦ùN4©Že÷/u{Âß|'zLPtÉF3õ¤ìöä0ô­qË1þØ¢,wIbia¹öœCw}«Éyª›zªÁâáÜU•ÍYùTÖMùÐh÷üÈÝõŸùÁ<%’4* µT÷•KE"Ð$¥*›±H]/5}¹!å .“Œæl9ͤ…ç6‚7!afÐÑÀ:|'ð½#õõS#éÊVwÜ &òÙå+4Î g\!éãäÃ/ •p ÞC‘ +€Àèl@ÚN0ÛP~…çÆ(ž4)tßrÅ6†ùH J¶dÐÓy€ÜcšÑaÒ€2¨ƒ«¿!ˆã2J>³:ƒLæ1@$eÒC‡Hwå]…S$"Ï—ÊHæÕêS{ÿç³¾_›þ¼…öŒÂ†É%“K ¹"õu:9-â2DʪңA¯é¥9¸á½EœõôŠCŒÒt¥V†Û²:‚*$1Ø ]×øÃž…Ò‚Í4ÄÉç¾;Ôçá|“y ™’6®x8ÂÞ±4AA#2õþ#©fûÐÑÐÊÕ±ïGlfSásû· Æ5*ß§þ ?Mÿwº?šÖÆscý/ƒ„K¢YÂ2rúlUc)÷ƒèrÝh[x4Z…Q£å¹­}dßw¦ëã¤òDI!–¦d¾)QážgaAz·º$¥•Cû¡‰9µÆ€¹‹}¶" ¡¨£€-‰ì€N©Å êÛŠck³Ž¨êAº@x»½É¾EÞh²•ñÚ3ºÂbñXÜ$¥-ìÀñ {‹)ÛŸųKï±^×5èðø2= gáŠ?u¥ƒJu+pÀŽn Ü÷©ëRÃÁ7ßê)h  ÇÃÔ?”²e>TÄŠÐñ¹›ÈÛu”¾C$w+„¡~ÜB,¢|B쵞_%Ô‘r‚UÐ( ¸0‚–Õ0u­×p6óíƒõ!|>íQ”/ûf5-”nOåq¬îAà~pK¹†Io­ iy)ºOµUØ’§r¨ÍÈ>ÁepÉn.vÈE7~ë‡éGY ê,a¬jE™W. æ]ÝÆÎÀÚ$äÅïJÑÉjxbPÃ<.nž:ÿs5×6%Ö=Ÿé׋kõO®Õ}çÆèy™ðÿª˜U_;Á¬dUyhìÂŽPp{½ô ç†]T—k±ÎÃù¹ÊÎ'wÏõtŒQ0Á…có0î¶KÒkªRY¤‹9z[^¨ŽXã‹=²H², õqnâ ÎuTùŽX¨ïŰ`¹Ëòô‚%) VÈ» ¼(HD°k·ðÌÍnóoŠGÔ endstream endobj 20 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 6 0 R /F2 7 0 R /F5 9 0 R /F7 16 0 R /F9 17 0 R >> /ExtGState << /GS1 10 0 R >> >> endobj 22 0 obj << /Length 2371 /Filter /FlateDecode >> stream H‰œWÛnÜFýýC?Ž ÍîæÕØ, oÖ ínâ Q°è!›š^ó2a“’œ¯ßª¾pHÎŒì,b ÒhX¬ªsêÔ©÷»›·(¡dWÝliHð?üÌ#’$d×Ü„äñæí?>Qò¨o )|ZàO4†§žo~ÝÜUƒìÉpDµjP¢VZ ªk‰äQßš¿Ü}ºÿH Q×{Q|&Ϫ®É^h…Ÿ|!eg¾SuuÝ=«ö‘tGÙ›BAª±®·åx¬å Ñ’¼{óÛîŸ71𠊃åá±ïʱ@3« æSr=ÙøbÌicß`ïV9{¾0˜žÿŒg'Ô¸'ã‹èÆWÅÉŒƒÓÔF.x‰…<ˆ³dö$÷EqÆÖCðÊûÀ‡yz‘ñœSs,Ó Nºh{š6ØälZ)KM £RnçD„ø%2~;m(,~LÞæµ&ÇÝwv8s?œ™kËî A™fÒÕˆ/d/AÝZHCÂëÐQ5ð‰<ʶ4BWÔÓ>áëȬÕ@˜á "z‰¨—yMŽ¢.êÓ¡6Àï…êÞšô'œ3À9;© uЉ3sÆÓ3Å#ÍŸìM_õØÈr‰>‹‚„BJṜ8òa±âLÿ’”ΘÇ"Oæ’+:Llç쳡¶<2Œ1—2;µðSÌõB£CúnöWégà»á þ`Ñ¿-en[2³-Y™u‰oôs'Ü<dœD”âhÙFYZõû(µ}e3 ;Í\ì4ång¬z{Ñ €6p/á×=ìXYÁvF©žS‹9ñ2%G֨䏧§s?ú™ßãU;zp¢M´|„>uÓB ’&ØFƒH’´Í$ø¼ëŽo ‚tÑ•ÐKGÈÒYW )(<>ýù àç] fT´D¾¸Ì†®«û-JJ/ªFqí£<Éâ<ÈóA.H6Û3è4–_Û ¤[3—›‰âd=BØ~,e¦ò‚OŠ=:±<ØCP! s©03Ùn;Ȭ_í;Òõ+‹t÷ó=Z(# x ÓhøØ®±žŒÞ~4ý\ÂÌWœ±^ô([³ßMÉA :@@~b¬íÁX “»•38æ 2ôºFnAê£,”¹?Pøf†8‚Ã-ÜŸ 5oÄk1@K¿`:8|ZÒ‚Ði-ú/Ázˆ®'Ô-hÕß`¡¿N~µ–ÁXî:ú¯ÖL˜à$xÆ®¹ß°ZŠâèFÎÞf•êáÝx¬àâ&«+7ĸ7÷#ÇmyªÁg ®&+ŸèéÎkäpèJPG(v}ÌÑéùÌL»Ü´‰ôXw{Q/µ5 Ò0]QÔ÷ºsÕ4JêáR§¾Ç¹]ýù³ýå"²Ð¹­{ÏÂÿ{-fÑÙä—M¥`:i–\3Äl2ÄñEÍuB¸fªj«?ËTPžŒF3¦ú›ÃOâ¦BÓ3¾ÒÅ)·0ûœ…[n=ɦ—ÙuÎ^£Å’³Ø_¼Q'ÒžZŒ‰­ºÌãÐQáü"™skìkõØ."0Ðá8›y5Ì«ŸæÃrðºåÙ‘ñ,¹Ä`o Á€Þ³õ'Ì/ÍÅ5àZÑÕò£,  hlA>]F¤ˆåÎp1ò~å8˵ã|ÕwQ/Ž”Fîº#ÆGVª8±I Ë1~ÊX 2<ƒ³‚÷¢øìܳaX±7ëvÓ£ñ§-Á^–òIÖݽïý€Ná‚÷:ó8òåXà sw€„ªñ§_ÿ-‡?ì3ú[pÖAÀ£2ƒ•KrÙØ>z´"§ 1¹_Þ«ž….Rh"¥,ô‘¸÷G<ò§ Ôã/Q?v=Ü) œB•jKo5¸îDjf_«ÎAmŽ£n;HôAUHNÃh\ý¨ ” ¿š{C“wÐ]Ì}qÌ6S«®•ÎùÿhÌóODôà˦EÜ{¹5ÐIQøãÊ;í¦ƒï£UÅ{£xöŒXž_·D¼XýâVñ#+lO¢WXŒ6y˜K´{ß aî6kŒ- ç†úEÅÌ6÷†Í¹(r]ü7Ä} ï°3ô1øXUZ«…)ØÌK:æ.â;jerUø1<ß@±cTn •–ç$Í,3OEXÎßw7ÿ`&uê endstream endobj 23 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 6 0 R /F2 7 0 R /F5 9 0 R >> /ExtGState << /GS1 10 0 R >> >> endobj 25 0 obj << /Length 2239 /Filter /FlateDecode >> stream H‰¤WksÛ6ýþø(ïZ ˜évÆi6©;MÜë[ÜñÐ$dq͇–¤¬º¿~ïŃ)ÙIÓ$3VDóâžsîãàÝúìÍFYoΖ, øŠ0"R’uu‡³7oyèΈ &ë ¾]ξ,ˆùs¾dQÑdqË#q./Èùïë_ 67±#ʃ€Cðõ{Œ@xˆ²Ø¥Û.»Ûwª½Þ÷»}ÿn¿Ù¨öC›Vêz³éT¾þï˜ “”³d5F  |Zq—Ð[²kº¢/šš5itX‚'{\çµä8 ¥ÌÆú6\ü.‘ŒE±‡kÛtý·â 4mÑo+Rt¨]Nú†dM˜•þ‹–ÑžãÉXí¡‡³Ås$õ¾º‡б6M«ƒlŠ¶ë Š|"†IòÁ„TNXdC¥IƒK‚¶ª&Ÿ~üLÈA‘\mŠZÍ8Lh¿ð¥W ~qœª F÷ë —gù1o8Å@e&ÇøkšÝ.>]|¾=§dzhDE,cïй.ŸÅz ¢<¥å^¡:øî2Œ) âp*„~oé>‹NÈ72ú¹K*ó˜ ¢ïk¥@JæEY¢žÒ¶HïKEnžâ¨2Eçö\cáœÊ±œ?‰ŽÄÿáuñaÐjøÚ_Õ3éÉ\{,^æå™à]ñÀ;"ü.½W‘7ÂØˆ6~QpIÃdµ_:ªÿ¢âÂåx²·<Ž^\Ðg·IÿHk=ø‹ú´ÖC"KQ‰˜,CTºI aT¶éÓ’üšöªÎž­ÚÃþ¤Ñtòºõ'zŽ/.7=¤£ëÏΚ¬UvÏÉaœ 1*Ëc®ÉA]?ªÞ$P¨nBÆŠF«$¥”nîJÎçn–Öä^ Óõ±nãh³€êÞ4`n›°ØF4ä¦un[ªt™Ñ);€'à „ÊœZº ¢˜J|êO;LY¼W;UçEý@,cy[<©¶…Ø„‰aõvQlHaµïH^´*ëËgœ’÷Ÿ. °êªb‚á™вD’4’õ?ÆCAVv0|›“û²É;JÖV¯‹äêÍõQ$ØãS‚g{†…£Ìi9†M0#ÏÜ/™ tõº\X.©aÍÄø-èÏ2u¤+þ„­œ§;ËkéÕÿ ÚE¿w„[T"Œ]ïpr™ãËÀÌP„¹ê²¶ØéÏ_i&îl ç¶V­žHº¼@ÍFUa›A=4mŸÖýpfçžÿ.÷yÑ`1i"fÅóVg47†f6ÀŒ}9±‚b2Šÿ³Wíó{õTdêªÞ4ÓÆqøù#ØaeβAÝ”Mšƒ3*Iú”¥žo:kר‚ ­œÊ@€ø†A\™Ž\Âq2ˆW#ªWùž=ÜGdƻÆ™hXÞdÚvÆSCoj,(‚‡ ^Ûªnט‡Å_hÕÿöе9(¬0FŽê¡Ñ%šÚ¿Ä,9]“8„•Ù3Ý<G“Η`ÖS\ùvÜÈá\vgŸeÛ´®UÙÙôaÖÅpa˜¤oúZß7¦`Ëù¶f°¹ad²À45ÙßݤXÍt)É.I0ÿ"å¦ZÀõX_d&  0™×POOŠ˜Ê"ŽS׈4U΀“4šö:w΂Yg1¶ hâkz‚ïâepÈ,´;㈘+ÜÆ~Óx4CñÊ'æÈù9b|Vœäš“?A/H>€´]n"ôÒ%ÅçÅeŽë°—MAAî¥JŸ€ç¿Ã’ó,’¯²t½?ɤ˗ãÈÒi2 Q'<É’à’MY’GFsFÓmÈy®–>[ðU8g ßO^žŒy»4‰çκ¼O³GSGsçMl¿ñÅ‹‹ù"ðý½p-(87$e.@Çr„0d¥·>¸\Z“–A˜¡÷Ϻ]-éf$ÙàšúÁÿ-¹ 2aS?8;Äv[÷”æ»Ôî̬ÉÕ…q¸ýDt2Jt¡=^Ãc*»¶É÷™¿ÌuDgüîñn渿Ó+×rlŽŸá|}ú¼¯ð³[s!XɹòzJ ·+6mS»ýˆF2òœ;76 4GÝ€›”ÜÀ$ó6«­d]ÿGáC…LÎ Æ–éõÆB!³èwupB{;Wõ…:6k* ]u^ñ„QöµÛ¡6hºv 4·©ˆ‹Ç]N`'X{æL¾#îòtª¯å+^ ö€IsçÔmŒCÉ»eÓ‡|~±Jlæè`+fky?ò˜0Ë`©¥UwŽ·_i ëÎÊ‚xj}ͲÌÊshÒÈjæâHˆA5“Ð8ôgÏ'–ßÇà<“ í Ï+ØN8T‚Ÿx]P ëjhsOÆÌHòkQf¤'µkº®@Ë ½mž´Kï¬ ´a"x@dœ¸°ž0Ý'¡?ª¾×öáT8»áê3áh~aÎ#1둾,Ö6ÜØ<ˆd£ ÷›¶ÝYÚa‡¤PÊ=”.éšr¯‡Ú¡Ù—98ÞC˲9Ì&¡#ö±¶aØ`¢3Læ²pëWnÜo›¦SµÓoox1Ýc2ÚnW™™×ýìÜîGac¸"éyXê¦ pÓ:à¯b2~ùbh“X–ÖÓm¼“ßð}ú¨NFs¿)j…þÈõNÕ7=4weç€ú#Íz¨9¸ ÏÖtúU§NZãèú芇ÖÉIxxå‚Ê/i=ZH¦‚]F_¹•.ƒèƒ\oçàIôBSòNe)°ào¿=xèQâ÷M üd‡ô‚·!d›º.l²‰éŒ„ð$!1 lŒqê5øïõÙÿäV8 endstream endobj 26 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 6 0 R /F2 7 0 R /F5 9 0 R >> /ExtGState << /GS1 10 0 R >> >> endobj 28 0 obj << /Length 1630 /Filter /FlateDecode >> stream H‰„W]wÚ8ýü‡yL÷ײã}£I?²gÓæÎö¡íƒ°E¬-±’JýÎH2Ò¦gO·Ë£;wîÜÞ¬F¯ß1`°ÚŒÆ,úþž¦˜Í`ÕŒbx½~¿dð`GqÇÉV}JÒV»Ñ—‹VÃZ@©•€]%Z= ÓJõ‹åÍ'Xw›0¤Â“¦ÿæ¸*¡­½ÒnöÀ[÷oÝm»6‚U%-l.„Å×-4ò»(a'Û ^}[ý5"¬b¿vÈâ< ‹³Œ]XÞlkðX©U¯VÿŽV¸CÓ4Ÿ²È¶ÚZ¹Æwdƒ×>‰F¨–.Fàâ{+í6í¢+¥¦ïx]ëŒiÞ€ÒjŒi S þ„PC¢”Ig¡LJÄvi@I?ɦÒ-ÔZ= eJ Ž"D±á¶…'Q´Ú€Þ Ã[ÌÎBÁ•Á” XÝনd‹G;#,|½¸A5,—oß½Ó;aî®`Q·Ã}}EY 1 8 $fè Ý ºhψ¶‘ òú]â¥Å¢ Œ“(éK5™„°“ÔGE)Üvµ¤0½^Bˆƒ:Ïb  º>“úEäòA©lkoPn ºfl"æþ–ÀæRÈe7Êk²3Æ•Ÿr#!8’ñ–-„é xªÃyl>O<0WÐ *›ðÑ•Æ2z `åÁÒÁØûlƒvŒ;ä`2ÍëC;‰'±À]€¾{"¬^éI2ñ€ÖòDu~?~¦þÃ&tñx½ã{KìÔ²A ¡ž÷wÿ˦kŽíò<øf½¦Ìõê ,]™°Zz»%¨Y]ÿc»ÌƒˆV¿®Z©QüÔN¥´D'm…‰µ;E9…š¤Q†.èoa©³» ¾ÖÎÑN áÁ ‰ˆ&žg‘«ÕYx<ÈžÅïs~v<‹\ºfâS5ø@ã,R°•îêpû8M£dÊæC²8„cqN6(%oë= ×YÝÇýI",òc³ô$ÓÚM"ddp¸o]vp•¶íðÒmÍ]+tª•µ{@ŒÍK}1ðÖcÙ}¶l1ºpØ•¬— Ëf'JÄ•ø$gj$¼¨àVà5/ z¢gó¼w´)|@ÖjJ Á¾tÞækUpSÚߨ[Ö‹)K‚½¹azr˜=/]yhõ¾PIVÜÏS4htlÙˆ0‰´ÂÓÀj§·BrPQþÌÙë9ŒÓÞÙz/ À¸ß÷‡ü¨<€SÇ, ;GâvŽ4ané8‘g°ˆ ®´*êŽÌ™5œ..)é¹9kÉ49yÓ’ˆõqF,înà˜ãš¾BaÜò‚V4 bù³T¥ÞY¨89£P~ñ±çMW×ûK €cÊ®Ž>ÌXÃXîxýšÓŒàÛm-‹0Í ‡wXYËv~Ïò³„V œÃ¼ÏbÁÂÆEÅ•µØsìá÷C!gLÈÌ7T)laäï:k“Š4-lXÛèY{N£Cç–77é ¾§$^^{Œhô“Ÿ6~ëê«rr áäêÑ-gwúÛÎ<·šÐ•¨·.g^>Éó錂ÏvÚ<†ÝSÃGY<žà9ˆ<ÎC+_ëòQ?ÙG,í5nn%ü#&Dn9ÆÅðWØ`Ù¡ë[áF ÑßSú²è',ëE?w>rq/ÐÚ„BM½(ô þ BÏèYFü'á<çù7X J'xöü %Œ7 ×øDë6\£wÔØüné}”¸/[!.:¸7ÒrÈrŒ‡ÿËO–zÓÂøÀàØ­Önº»±ïݹª¸Ùq#à}³þQ^Î\²`.I™¤,ô—7HTüÒ—6Á`ßà;% ÿ5M’£>þÄêÀ'42Ä×*¡÷îjÞb‰8¨_Kág^w¶š•~ˆ£í탖i£œÀ±¯Ür‡žw‹FR[…*:è—/Ÿ^X« é^Â’«SF'N”ï ÇÄm¡ŸóO“þ÷LtûåoÑþ´aÁ¶Ø.ÜwDÖN5Gñó’o˰܊¢Rò¿NXÏËûûÅí[¬îÖ{aý®€¿ùÛнT`Jg4:äé¹>j4Œ1ÄlÌØ8μÀ§Aà¹×w Š,£ý™~R^~K¤ÓoW£ÿ·`J endstream endobj 29 0 obj << /ProcSet [/PDF /Text ] /Font << /F1 6 0 R /F2 7 0 R /F5 9 0 R >> /ExtGState << /GS1 10 0 R >> >> endobj 30 0 obj << /Type /Halftone /HalftoneType 1 /HalftoneName (Default) /Frequency 60 /Angle 45 /SpotFunction /Round >> endobj 10 0 obj << /Type /ExtGState /SA false /OP false /HT /Default >> endobj 31 0 obj << /Type /FontDescriptor /Ascent 695 /CapHeight 662 /Descent -216 /Flags 6 /FontBBox [-167 -216 1009 913] /FontName /HAMKMH+TimesNewRomanPSMT /ItalicAngle 0 /StemV 0 /XHeight 447 /CharSet (/three/K/i/G/t/S/eacute/q/bracketleft/four/j/u/I/quotedblleft/U/d/bracketright/five/k/v/comma/greater/equal/less/underscore/six/m/L/hyphen/w/W/V/l/seven/n/M/y/period/x/at/H/b/o/N/z/B/eight/Y/slash/c/C/\ p/O/nine/bullet/T/zero/e/D/P/colon/parenleft/one/A/space/E/r/a/f/quoteright/two/parenright/h/s/R/g/F/quotedblright) /FontFile3 32 0 R >> endobj 32 0 obj << /Filter /FlateDecode /Length 10382 /Subtype /Type1C >> stream H‰d‘yTSgÆ¿¤¹¹„ˆèe¹7ÞË¢"K]†QED@ ˆ°ˆ‘¥² !„-*a\j§=(YTd";¸‚B"¨(ŒpÔѧµ:Ö¥~‘œ¦Ì_óžó;ïïyÞsžçáp8Û@ßÐàÐ@WqJF’⋤¼ðÌ ÙnQD¨ø÷ã mf…~œùBHX ñPŒ©ûÿûÍ7ÿÛf8äX@§¹0f^©ðóËß5–ÿÿ [Ø¥7Á:î“`,“‚â̶hÀ8gp†ZÀÀ„Ì`!Ø›7 ¸cÀ €uø°€¶@@)ä@°Õè,K@)˜åÄrÒ8õœ^n"·ÿ³ ž€·ŽwScüR|Þ‚àß<“¦ÞsìæÜ3‹7˜× Ts½ç·PZ¼œ—?ïå×óW̵`Š\G¾´Ún½ÈúºõCë÷ÖŸl^Ù¢,©Q:Š~·0ˆ±aβ‘v´]®}«ƒÌáߎÚE‹Íß\â¶dÀi¥ÓÈÒ¯œ½œ¿uqrÙîJ»>p[=½Sˆ+#ŸÊ„L—áŸr„¼Ób!ÚðI,äéø;Á°!}GÊ´©:Å@ö܉„jh)h] -5МÑ@³î·ºGÚ‡ú;Ozˆ‹8òðE¶H°ùF¢PÚI! j‘5cdñ_»Ü ø»è]щôn»&ë'Ã0YÈ#/D¶JŵO-'êi9"‘…lö!K92gäÈ,ÑI²NââG$ãÐcÚBÁ{èM¼‡>ý0 &PÐA…‘К1â ùnoôkn-é#d¸>özôÅ(B`@ÛÉ«C #zj¸ ?¥‹éJI¬‰§¿L/ÊÉf³E™iTJYVM>“ZSÜJWV–”V°U 'KÑGŽ>x”-Ý_¢ÞGIò¥IÑLR¬dW@h›ê½zÓhå©ai¨‚®3UÈÕ#ô‡«I¥²XžN¥—×)™Ü:º™>§)¯­cëêÊ5ÍÔ9µ&·Ž©SÊËÓét¹:WÉ ¤†? ±r¦H8-Áó EB¬[ËÀ`(#ÑçÏ~]­è¿èúÆØ±¾›{ —¸¹õÆ8þ@ÁœH¸y´aþã±LçH‡*wle½Å¡qˆGÄ"^ޱ eÚÒ–O  Ä>¶§ ië?¯çÛÏ×öÐ]­jåY¶+­YܰžhquâPq[Q\¦:šK”f v¦f³pϯ¢¨˜ýª}û Šó‹w þ3‘lø®ý6¡4ïxÞñ½UO«_}@ y©8zŠVHÇÓ¬" 2ò9*…J®Þ}ˆ8¸[úµ~å_èür Ü¹Ðì1Äû Zô'GG©×ÉO}Ç™1߈K;®J ÚÌnÚá¦Bs‰N~ãT÷ ]7Ñ­ª¹GO gŠu¬6âŒÿ* a1È #È mBE(•Hþx«°dc §ï‘;úlðgzD§”]b/Éê"(IQŒ"žQÄ'&IÒ%i’üȃDF ®íW+ûØ>e·¢I^“w:³:™¨—VDFR~òi$#‘ŠätfVÉ1«:’U‘P›P+¯P!Ž–¨heþþ½*Vµç@a>%?™Ýªd”­wŠ^Ð0ÚBÞvòY×;hJ=QŽËn3;†Bz=Z hñË÷?QCÊÁx3¶¦ÚÝ7[*bEÒhÿ¤­*ÁÇ Ãarš@\|Ö䓆ÆÑ4ô„ÓÆÐ|–´2d}\…Í®šÉÂ'!B¢Ê™8ïÐO…¶/'ĺM„vÓ™õžÔê ?‘ˆ‰v{Ó‘ÒSíR6­NY¹¯”8ºoOI!­0šØÃªö(, Rª3:3™¬Î[{ŸÐîø+{]s­íò¥Ë;´M·‰¦¡wïSP°ýW÷çŒã/Èî.Ú¤ùn±1¸ñBl¦/øøNˆí"ý|öìöd=2þ¾rÍÊÕþ.1ˆCD#®áÈœBáÃh9œæ0¡#2^ÒP9ƒÿ”Õ¿lÿù4Iy0ÅLxu-§]\Sƒ\Ù†çM:îvܽrûºqÎj5÷«¿/#:Ãð™ÀÙ9äñ¦3¥úéˆÌ£‡½²¦Þñ©Å9ÞqÛq\TV½óDK {y×-Å¡˜RP¥ÿbÛ/Õ7•‚Ó5d“ºmäJï`³mu‹®ìm0áÏ8 ÑZ òø†(!¶ëšMÑšÄ0Ä "Dy¢­”ÏÙM7ƒ¯ûo ICÓW­ú ö¾¾óo¯©)ù}©žIÒz#“ç?>u§CGth«µýÔƒ”{ACÌ­@÷sˆC#leZpœ²Á ;!n–0ÍÛFý!p_êç¿%ADÀí†`2µ9»µ (hÛßÞNik{.gº/Öèi½./á<ÛP³ÍŸ’¨cseŒR&Xë‡< Ðþ83@6&U”Ò ÌÎøðÎMN¤{Ób‡í¸œ™ÌÍ9÷~ßßù}~¿[÷ÿLáÈQ%8šZœñ% «Ù&ƒeõ±ú£Ú£àHKÇ‘.â§²TæxêWq-a 9´"8ÿDà³3 ôûkZ@xz–Vo¦è+l&D[Ë[–€S(P¤çd¹,W™M(2K*R©ÞµkÖh1š+ØeGÙíruÞXÀaB´8òèA«ž¡E$úZí¡˜Ñ -šžR“žÜ‚ “kmÜ‘¥×–íñ Þgs¶3±rCC¯åÑ»çvÜ$ˆÌz ­qh_ ?èzNv=¼û}è¹;Q?I¼y–¼{”ñ¿nß…HpK¦y¬s4p–ÀJ|.‡Š©ƒÅטràâð£$¸ÈZ~o>µcÞb‡ëQ$aºôG‚ªß%hsa¨LLò3b²÷2 ¢ÿƒ¡Tœš‘ÛeCü;\ˆ,^P/…Ù£Ý8òFö+‘‰f­Dœ@äHp·•Ö¸R¶–ùŒ} çmY³9ß}u0¿‰j“’T‰ªÒ*CÕÛÀ9,^fMiù½Ø@§Œ¹ÇU™¥û\ð)Û÷PT¡„,ˤ’| M ˆ0¾Q‹1åøOV,åÊÛ#$JóA^BÀAOå`ñéÇTrJ¦*(;X”å‡uC8õì®"y3Õ$«Í>y 4«”Wæ tt2;´)30Q2DAy› ¤§ÛhÀ ²Êc–{§¯HÞNµËš%õÂzamDõNÐÉ¡ž5¥dä¶ž.”¶Pµ un‰¨Ä_Fø˜ms+ –JÈ$Q¬4€‘KëB1A²ª2…ŸdÆ×*P 9Ô}§7Ã/ØÝíEŠzª^QUžQž^w$ˆÑÅÇ ¼²CDé ]ÄSè Z û~l,Í7ðp¢ò@( ò*yz‰šOy5q«cU@YJ0séÜ®=…æ{;®öAKÍNEš#7=Zù-&‘ƒË0WXA<}TVsŸºW3¢í´3ûîñKêSd{Í™ê>âÔY“&ë?«ÌcºQ^¥´LÊ$Ç£|p“-;*=2+BäáaÊÂecÃewÊýòޱ7 äu:œ—àÐY?€„¶“pémèEÀÅ/ã6=¤»ÝÏØ1F&Ð[̳áÚÍøœómñE•†TiÔ•u'@EóiU+qIg3û¬-”jgúüþö×?û<6ísêŸ|Þ`˜gÚÀv+x·ùsóæQ]ØtR$37~e{ì Í;½:Óè´Šªn¦ “ÍÛy´ ÛêkúŽóž-ØUú* Ùzª³jàÿ†ó¾kcÇ\ÆCƽ¸ZߺU¡¾Üs¡½£®½N«nP5”4ké ÿ4»­A©PSjE‰<Ï,ÈÈ‘<4-D¡ÈwÓ§Ñr…9µÓ×ýnp‹– ­Ggº?S‘̬èÀûÝ×E¼×`_6`ŠíH¨Ë8®Xv\^,“âÒ‚Ü9)ÏIUÆ|Ã2›[Ì­äj¹Zï· Ó?h¥ Œ…1,† Æ«p/'!.>— ¤¼­E+{Ì9èX‰”Ê9®8Q¨þ/×ÕÔÄÇo,ÙÝózÜ\5ìfv§­3¶êÍië õzm=EÅâ ¢ ¢ò~J‚¼ ! ࣠&,IHBò B /y%âûÅ¡¨Uœ2žgëÍ]ïªs×ß&¿»M¹ö¼Îì_;»Ÿýìïûù~?Ÿ/V£iè›Â=Ïѹæ‰VIk5j³S˜'ÎÝ%ì>oÆúêÔbeñûã„%dº`qjy{€1A9’¬°¬]Ùi¡lÆé÷ÀŒ†TÌñ“¬ žÎ*J­ˆ üã¬= Ù—¦è,¢Ê4µ“ó¸w)ú@2Ú¦#­z§úqÞî[ŽøÊü#¾ïÇ·<¹à8^m  ÕªJº “JEãþ¥? ©Ø@ÍcÕ¶ˆZ¾ˆJ¢Œ–Osz%.äqVqûÍ'ê5Tu—P#ÔTuå;’1ÿ–Wpbˆ¤Eœ8Gð_ÏÔû†ÿsŽTŠ|ÏÓÁòd›—qqõ (u Ž/t  3Þ3_Ðw†yAç¹päý]asq˜y~®D!$ ËÀúHØ"ß›fçÄ ¬¼›àcpI;Á&È8 pÈ…koíÜ×î†Ká2ÊS‘Ëý"#p3¬ÂaÎa¸>ürUø[à2¾¾føË-ÔZð³$ðà o„‚Èg³Áà~“¼þ›nUL?ãå6ôõžì!@èKëÌ,5ûGû3ðþ¸h&ñ ™xy÷@„3D¬‘ß¾úÿWIKÜÆ€pY T—þ ¶•â‘øtE— PTל¡ÐA±óx_#ƒ=+¸2×ÄJLW †¨!5]Ÿ€éd{cðßò·%°I !š¿(=öYS!uôl^s–c®~—8Yvîfi´:¹+Ù¼÷ò§Ï`Ãü ûæ¾ÚywXt;qŠLœŠé߮ŴÛßl…+ _í+Œé ÿq²ÿUÆ$zŠn=EÓ-§[mçé3VŠIYæ¿ñÇó‚®re·&%ýÄŸf ã\”+δ- ß³52–Œ\}rëëN׊k>æŒÊ‹läxnmI×*ˆJ¾T•AõnúXͦblmfÄf꓈Œ°Õx¬,Þ˜L’ì‡ÆÒÇÒ¾ˆØNöºsØXÚ—oÎSgcêl:;Ä'¦)‰‘ÅáÄ–JK4m9è(Í=6[ñ5–áK·#MÝ-Mc4-oV*gMÉMêfé HÛˆÕ[í'øå û½9jîžãÏ/qwõ„`œŒe&Û’m\ði¸î‹woÇ ¬BûîÖŽ Ãu3ÄÕË•y—¨‹¹C‡»ãº÷é¶ÊÖ³>šúëyœ(n%¼ÃéCš®¶lz[—¾W޵‡›o ̯E~Ô­wÙðj—yµ —³A ¼³@›.+¢S¥±X›[îpü_ÚÉ+4ñ«“È7‚•Õ+ùÑ$?:)!"K‹ø]ÙûDDŒÌH%ê3-‚>~_…K<‰§¯¸pæ)ú@:®Ò“½lO“öÅÈl¯æ³/ÛŽûL( §ákºÝ¤eƒ{Ûçû±ý‡Þ!ï[“ëõÈíºaº™î+þx8s½/UhÉ¡Ng‡›˜°ûޱ€®ÚÀ‘d '¥Í§šˆ‘:‹HS޵—Óåex~å¾¼H8»`„_{lœ¼™ªI+®oioW’ê6gëõs¬ßLd ÎÆžãz‘^¤­T•ÒÂöLc4Ó̃GCì“Ï ª5Ýî·õ„êuö¶ÑöìfÉy‹Çy¾ø]GOC­‘RÔËjéjŒ6 «ðܪ˜‚Hغ ‚rO1'¾êŠ7Iuj%©T™¤}„Íî3d &ÍÉF9¥¬WÕ©D²ÚÖš‘Н,PäXÖ…8Ø|S¼@@ç ûºÐ¥Çu-–¶Rm’Ú½Ýw*éïþ>m)ÒÊö]aÌ*¿7Ć€+®-Ža‚½;Ÿj/(ô¡«V¯“c2]§ÄÆZÍ»hàìÒu¶™êÔ”ºN.¢…]Õ\QŽç•&¥î"a»o#´1‘œ#×J‡ô¸Y®3¶‘ £™uÚ®@ˆ@ íõ j¬ÈRª¬TVtŠd0ßÍxïÇ–1kOAö¦D¸hDà9 æ™ãFÏùNs¨©³KgUbm=©š0Ú}ù¬Ô¯3ÿ„¹p‡¤ÁG¾(óo&ê!{ÿ>Ãã‚AžG?d¢xè_Ô‡H°×½\ÿP˜wh ƒŒGÉ-n7Šzˆé;ãÿ¸OM¡©©…aÖP'>)&ĵg%uTݹù Ö¨9åzŠƒèÓúË"3Y6T`IÓb¦øŠMÄ›áE‰1ÔîÄ‚¸=x¾¤HYA–+5u ‘ª””R)Õwã'/qÌ2£±ƒÔé­²âÂ@E¶™2g·E­Ã3Qø^ JÜžº=5éPáA¬4Gœ–‚oÕìq"Sœ“%7G‹ÒFé[/üeÛK§iŠIXñ˜›žÓf9JX„ŽQ¼¯µ·ÃBê,}]®.³ò¦ù_ ;Âwä$Á`šÇ9Ë=ˆÀN¤ÈâÐçÚ ¥¼¡®•¢k¥•ÍEXsÑÙO߯ý‘èÅ´©‚ eXÙ·ØMäåÀ“çøÉßÝàW TX1GÎE|àü5±rÍ.ø‹÷)ÏZôÅ«îím±·®äFMR“Q¦õð§8\^¸:>’Ü¿''šHO—ª2©LU–!ÛŠ1èÓa5š[ø¹Y›2c3ó±ƒñ»‹w¿ÙâœßGí›çÿ,Á¿5=qß"ÇnÃmÂi—꩎y~SZSª„/b|Yä Ìeà¬[4F|¢`,æ?tWÿWS÷žá~º¶ü°³´z¯»W[ukw6¿W:ÚYUŒØ"‚J I$_HÈÍ÷Ù1$7IFù*E‹Vê´ê°(Sk«uu[O×éì \8g7€Î¶§ÿÀ{ž÷yž÷yßwJÝØ¼Š]ÁKsV­ÃÖ­â3Ï1Kaæµ£ÌÏÇ×¢knü=÷r÷fûÅQlôâЃ ý¢´nAüÄ.g0ŽÒ±¦ÎX£Da+Ct'iÂL.Âck¶æŠ‹ôÏàɈiaæ×ÎRéû•Û^…™·¡2¶¶$"ÌK‹w2óÞĘyyÌ ÌË0³ kñØztý§÷òþt7ôc}þð±ó2ļKÇp6q;GYCJÒL/ }{î*:<8ÜúgäH»YÓuhZeþ¿àPž3LCï§í¤ Q&¿Š\æÐ±¢ûÜËèeîáe¿œ·&K\“ÏÄ3+afY7¯C×ÿ“OÇ ßÞ黌}2ÖûYÝWÅþ’DAOD¼L<YõÖÑq.¶õ†è»ô"0ñbÜÔ)ÚÌé88PaS) C”z HÅA¾3L½wðzpd Ä_˜X>ñ9g”1]‚èWœ_’aÔ®o x€§±Åu 6Y˜ßÐ$ ›… ¯ ˜¼›ñûj|>Ìës5øá.uXBíHnÚŒlHRïe—ëÞœ¤Û$YÿÇ•p ³e½eêˆkã*”PêÊT WÉËK%\zPS‡£uxPÓ©Næ íåBž²È$¾Çaa°èDšzž'¥9H/:þõ#ìê%ê¯cðÇšcGÑ‚®ì¦÷\yի̯œï8v;Ê*ÅNUÉ L¤Í}®­ò (Ùà„Z€þÃÁòA„޹:w »8Òqí øSÍù‚!”~>®Í{ÀQ…U9œ‡TV;ùàú ·½­pÚvpØ´d“×—¼!°Y¼F´- Kâ½½ N©Oe£¡ì~Áé}[Ry±€6Ò’þîžVʳª¬ùØÚ§^CÁ ŸÍmnsµÉû F©4;‡Ñ3E &—ÎXàîL-3M-¹'ŸibûRxúZTMâ5ev> )‚v‰¤+#gÕôEÕ\48ŠŸÌ£¿œÜÄÉ‹jSÕ&ð#m$Qm˜‡O‹ô¸X´Ò™âY”UätÍYÅ7ÇPÄ…¨¾ŽÓ!ÐÐI‘2ܫ⇰€È¾žB¡¢ý&”PÊ4F`Ô–g±•òŸLžú{“Ç…*úîCýí”o¡Š®õ3}*>{æ»2fª¥Wˆ+L¨UaÒêÌW[÷"aä*.OZE–E»®-¯–F{÷Ùè#w›8§ïFU§%½ö‰äÖîB²² òÝØ.yjfR¢þ‚l(/ :øÙÞ4¤¨Ðª/ õbµDn4çïårÉšêÎOrö4c¶210óÚjÉÁ¨›ö ê(]qÿ§ËâDÝþîópD }1þ·›ÈG”FÀw ûn<eTÏŠöI hfjðŠŸŠÕ Ìþh D¶³óúTuFÖ+d;æÖf!¯-ÛÆpct úø$ÄIÊßù>?ðÔ ëa„_½²ebnÑ1;i¹s#Ðw»Òwê/=w@÷ÿg·a½{ýïzfþIE6lRç'a‘˜åœ«¿ëd~ɼ3/•®àg éüô’ddíæ¡¯3°Œ•Ð ÷ݗ'ÑÀp[Õ©N7…\'añäD˜ãjn¬b·l½8„"jŒÕ8¨Â+;àéï ®oÕ¢VÙh$€¾Dl"ò‚ˆ²+.«p.šëkµý=çaºê„Ô­f §ú¬':ö}Ÿa÷²Gâj˜^" ¡wî¡£ïm V YZ1ûý‰w§íN´H1ÿc¾ZÚ:ïp¥Ä>g_P7Åœ“SmZ·H«ò¡šª6Õҵ˅¤Q“v- „$\ìÆÆ—ã ¾á»i€ñõðÝ`lÇ€!@p€,…¤feQ65M4­›¦­Y¤IÛt ¯Ñö:|™´`z¿?ïó{ßßïù=à»xåã=‚ðTÆ„õEà òÞñ©WÀ+xYþãO °¸zü£f6-ã¤*o›EñþÒ#ŒûùÕÝb!DkvžÂ– h‘Z¨SDeá®\ #Bh¸ÀÆ#GÉ£GšÁwÀQ ΃—¶om?nû¾|“M.‘‹©µ[÷¢ÕVîÁ³ëàJ²£V­Ì)Â{DåVX¸ØíÓ“z?T!Xøèþ‡: Ü[è%övü§õÙ-hS·äá^ƸC©g··ˆÍµ­ìoñùi«6Oæ´q%#C™nOû%¬ò."m—Ȥzh¸:È€ƒþ}m޾PHø+V¯qX‹k« ¸êœõWç̬7XQ£ªÃQUÈN¨w’‘ šT !8ÿ½)çÌ V>‹d?›ZÌL  Ëx‚85«&IÕdÊ’Àß¾±Š¥°IsŠŽ1Z¤ð·Þ> ¾{œäZ[`¯žÜ9IÙ ‹³u9m0™Õn'j¸æ¥ð7O+.5 •ᅢ]5e„D¦}óÚßšž5ÝoËJÐlר°ÅÝrBÞ-êmÆëÏÇ—ÈOnRÛº¿¢bðUŽ?ê úÂ8;Ö猑ڇ[Ö;ø—Û©[›äæJöŒ{/úàŸàÕߜʹLj'êÔ)kv˰éÉ$‘˜˜anâ÷né:Šd‘ÊÖ§Ž 9•zõðÁÛÙ)M³Q)mêhvÀ£¤L¨˜ûA¥‚Ô{Ù.‚íŠÒ=j˜ÌئðÅ…pzî\®”ømç›å­Ö„š4§—«ýQøë{JêŸ9ñ6s·%HMyu÷Grw`Ö:®CÇuþެF.]¼ÚIéP%¶ÉðŠIKIiÊt:ÎðH„,çúlcä˜íõPŸÞ-½†U^C~â©5ìå”pFŠvÏ,Wñ¥Ø<9»»öø(ødáÒÏ3ˆ‚viÿ7ƒü +¯‚ûHÍèîAÎsËh/k` ¬2Dq_í±µs|îËôØR4ŸˆÔ1„çú: VEH>>Ð$}>§×ŠºCv¦µËŒ"ˆ+1ÐY♲Žt‹ŽŒ² d#ž>1]yOįÙù;/,Ú&{Çõcúqq¤‰»¹¨æs‘òSNWyʃ·nìdÒÛ7f×}uÓ`^„Ì $]Œe¬³S;d½>® ƒörœçd‹Ã‹D$”÷-¢Ó•Ó"¤8v†l)CTn[x-¸Tù¸XNðÌ“®ds‡~"à`M•C"¤&]å•·êÒdZ7såÖ{Ü»À] ~¼»Ö¨ì©Ó™4vº¥¸Õ"ý¥ÊcdP#ã…±@¬°tà~È]ä0p‘7.ÖnÄ ³ÙF˜ô*§ÎÛÏ ˆpPâ£Ãt¸­ôÑÐÃ=©å¾Í»ó»ÅR.^—Oør8Ø!É1—¾-4&LG·6Õï|ÿÌ?Œ1˨#PGç,É0r!y_`Ü=W_© Bîy{¶úí,ô·1IXá×rO÷NÕž¯Óçé6ZS§¥5-îлý 2$”zÔx—®ƒ«ÖP5©ÝAEJE¨“Ys¿}'¾¸N®/-?(ü±ü­ÝWkÃóÁäˆ?cC¬—ñŽ»“ÕFX!‘þàuŽ8ÐaçÍŒÉr‹œ-•!@—[yê%K!…{Â!†`BqONWŽÃF€Ió—ØOÚ®X5©V«„¦ByÙu_óË»;k¼é=â^‘?X ÌåƒñÑpÄ‹z#óîû8·Æ¯üso…Gí”—çuòÿ_²+w¢üXð=ðœ—çsËÜsPñkžsçv¾46ÒçOb'çKDciƒÞÆ¿ØH”Jd©”ÜØÆ¾Pn4–ˆRãùäIüÄÊÆ&VÄÕ>øLpõ‚ú\=öáXSAH´Š=‹xa*O’‰8Õ¤eß·Ó9n6õ»L¤Ëh°ã6ǰßI:¼ýá6,¤òD27ŸÝ˜Bç7dgZ®^@˪AÁ• ê÷O`Ž^†ØÂëÅž|z*˜H‘©3‘Ã&,‰}l¿7«ØN£eÀÛíÃ~i÷õ³ãØœ¿›"¢™…뿞Eg7é³­»JþÓ]`q=¾µ­ë–©b†j¿Š‹$fZA*h³¬ ëþ¯,†GB¤› yp¯×eó’#Öa“kµP ¡‘\í<-D['‰Í¹ÅuÈ}X°°ÿìvbϳTkä NIÌ*šTÒfy[ ±5/°ÌàHb‡|¸×ã²{ªØÖÖK): Eg«ä‚bÿ>½5¿°·kùµÝ6ÁÆVæác¿ô‚z¤Þ.îUÊHMU!Ƥ~etŸz°C#cäpÐ7äÅ}>—ÕKz ¼£lR½’PR—…§ÚÐËÈ£‰O¯o 5»¾Cå þ#Àvj»¦ endstream endobj 33 0 obj << /Type /FontDescriptor /Ascent 662 /CapHeight 662 /Descent -216 /Flags 6 /FontBBox [-184 -226 1009 913] /FontName /HAMKNJ+TimesNewRomanPS-BoldMT /ItalicAngle 0 /StemV 0 /XHeight 457 /CharSet (/three/parenright/i/t/S/asterisk/G/equal/four/I/u/plus/d/greater/five/k/v/comma/underscore/six/m/L/w/hyphen/l/seven/n/y/x/period/X/M/H/b/o/z/B/bullet/N/slash/c/p/O/C/T/e/D/P/colon/q/one/A/space/r/f/a/E\ /Q/two/parenleft/h/s/R/g/F/less) /FontFile3 34 0 R >> endobj 34 0 obj << /Filter /FlateDecode /Length 8393 /Subtype /Type1C >> stream H‰”U{TSG¾@îÍ¥b è¼7Þ«P«®²KW[Ôc]ÐZ=®Ð" >1$!@ $!„ðPkåy)¯ð5‚@DL_€ÒºU[ëj¥]àØnm·–îºsÉ$ì†=gÝýgÿØ™óÍÌóý~¿™ó}3Çñðð wFFý>zך¸T…D-ÑîÉPÓß Ýš!GÅÍïc)ŸçBg_ÄçF¡t+²³ä|ðïÙ‡ øÕ¾ úåSü‘þóœÀÿ)öY†¬â¾†mB6{Fâ»ñ}H""Äe¾ˆÇ'n"â Þ\ÄC(Yê‰ãH(ŽlDÙŠ#»}5‚ls޼‚¬DN"?{{Fzš=mž?xa^B¯IN=ç&ºóÁ6bØ8ö„Ëá–âRoÊûÎK¹ üüâ3²ðW {x©¼IßR¿¥~S/×ú—øÿ°èö¢/B¤xØ·N- \r™ #ïSþ|Šo_º—Æéa&aÙÒeúå^Ë%ÁœàÛ!y!c!.ðŒ"nÌÕð!â¨áΩùœ)ÂLJsq|Î5ŒçÊâ9ÇA¹ã9pCŒ©$”߀q€7Ñîa#àC/ðz<>Ì:àBª}ÿ]Ñ“t໑BÁHA¸xÓíO{ÙoY/^üÌŽÛ¹ðxȇÐ nÀÝIØíÀF@ H%<ÄBØDϼàúëø~îÇÒ¡¤ÁðŽþu]Ðw£†Âý$LÖÃpô¦•¿–nI|'íð¾Co p¬¿øÀÓ7籿u4…ÕYín‹ŒBJ‘U¬Õ2Zíu&©¨Ïj˦5mg‹û¨3'+lLcóÉêïÇ 6¯h‰¾0#W¤i24yÙx^v©JI*kÔFc4±P]ufc25 ÔŒW7tVOµ4tšÎSÎ( :wO7ˆ«£…f®2wuQ棑i1Ö¶u‘¥­…M´Î”aEÆÌF}½¾^mÎ8‡—÷–·77Ÿh¤Þï6Ÿ8Cõ[ëLíL›ét»›TlÖémVm:%©…Œ,U­Ñé 3 ’ó*l•Œãé[ûqc_Ý9 Ù]dÉ6Ѧ쬺 J©*Tkª8SAªje&!mž–´m¥¢\’ܨ<­¯Çy›m,K°g&d3Y rjX5 tª4/à€ûˆ±]Sß“²ÇEƒô`Òóê (7-IMÕKIái—‚–wuçÙ(K›¡ÎÈTV**©ÊªãG«˜Ê²Š’B2NŸO§$ÄÞ’Š'rÚ3u}ìÁ¼*f²ŸÎ (b'€è_iPOÈÒôb)hYe´Üj˵Söþ¦³ç«µÉf'í¹ý²s´U&jPQ®LÆð\Ùx>*#œ±|G6 cl =BŒ7Ëã£)„óÌi–¢­CuÝTkKYQ#ÓXT_`Ðã}…8ŠtÅr_?_¢¦¨ruªT ÷ÍŒL\ý…úøšJ0È\˜b¶“k2W%¬¤^…«á>xâšÙ~îC–òدØ&âökxùŽnŠ˜K…9¨=Ñ×v1»®IºŠ xV[¥¡Ò³Š4n1hŠ” RØ’Ò§¤%W's—`éåŸf˜™Ÿ®LNfßK¡“FÞýè;[=—.Xì¸ÅÞpy˜|(¿=FFoé ¥~žÁDÄF‡„^îšÿò‡ÇÃO©[ÃZ‘±‰Zß‹#EE¢l1­g¥§ç(r´¿Óà)\à«xº÷öœwŒl!0 ü€úͺ s¹\(qÙÂÙ\ÂiuÒ\–f­(ïÞìzâ|çÉf ¼ V%o/1À;òæZèMÆjJD´Hòž6Þ­÷Êj-£¨M1Š,». ,Ê:¼6SiP¾8{±2ƒ”ÓÒ餛SÙÀ‹šùÞ40ÍL_üt|hÿh¢í«IìÈŠ'4ô{·ÂÜš+€ bÏb?ƒ:Ôå‹Ác®÷µ—ò93$ß Ù q7¤p9\K†´¬µ­£mënìü\€úì‘z’zx¿Õv—¹c»:ÖûGüüƒ–¯¿%Á¢Ôg;Ðv„÷¾J%&–f´eª‚t­yæÜÔÀ½{c7¿úbèGXx·pá[ïÃ0±;~ÔYE õ«u1ƒÛÍpÜMBÏÂm*)-Ueä*(…²¾]ÃÈ»Uãºi\7]òÍwä@ù]Ãw´i §®“â±M{ÐíÔu[í܈öaí7¬}ýFÜrãO À“ݘû+ ^Ãæµc!“ýÇ…2«M?ïÂF«õ¿\hu»PüÂ…'\Áÿ¿s7ó9 ð%ášÏf§ÁsÐܹGÎt×ñȹ˸îWj¶p<sa'8/Ö¼ÍÕÄì4|暆C!ã&± è×îl Ý\ï ¢9±6«¼ ¯,(/,$µ%úüb:O“\š@e&Ͼҋ +dõšVE§øSÁsg¾ãÇ Ì©›»#ï§-‘¥‰´Kñd6¡—ûVUbµ®—7çYúHKMoË = ‚PV…݇o¢ÎÓàĬôŸ¬—{TÙÇ}$™»-EÊ!œu&Á£hÙ.‹Ú-EÄE•—° ’„A" $!`ÂC´>@ˆ¼A^òZbñ±EA¬ZµÈbUt·»j‘ú¸nàt¢ÝžÖÚ=dzýc晹s¿¿Ïïw~¿ï…£˜mü„cÍx¬=†¯¸§{k/^Á/¥^#…ç¶tx6€† hN r ¦IçRgö®ª:£,­0¦æ…®ÁgXØêœPœÔ¤*Ó’3@FrxŽ7!2x`0.nÿê5v¥ãÞ$þXxgõ¹¹s©Y5ÁŸ6ÝmïîÆ)Ú‹ûäº&¥‹êJùBZ+µÂ¢`_Ü7#(QH&FEK;A²ÀCmOÐÍTLs¹½)í⦠ÐTêï…Î|' Ñ3ÏÁ»6âí…rJ^¡i8†ï;æùØämMJÅ æ±—ššoŽD½C©J¥ò1¬‘y¬'Â(„y.]ÆG0W š‡¸8š×„ÀšE Ùœ Ëø1Üm 8çq…nŒ;6záö(€`.nžkE@¸v•Ü‘XèX×»ZßrK:â&Ò`ŽÃyG «óÙ2Ò7x½t_©»G<û:fÃ(5º¾ß¾ ™ƒãtL“•ÁÜúÁàÁ‚ê›ò?×¶ ¶œïìéëîknM£eãqHÆÂyÞpé g;Œ!³~ÐõKd] ãsÑIN[SV:cÒKÓ àü`øïð Ì#7"[Eª“•ŠLÊvJ³£ˆ~Îv<Ö}îUé¹€.gп°Qh c´¶¡OWÚ’®…h.!‘åiåTz¾F›S ²‹öèÎãS'08wTÒÍ`63øðX3ÜÉkÙmÔ`JO¬.B~ԣʴѶ<”ÏhêjUË멊ô"ù¡$p@µ_ècÒÄß‘¥$ÕIéJ…¨c³Lšx¬BÎíÎq$È,`™«Øèj, gNÔö¼Ã J®Í(É.Ùe¹§ná´%6xF£h¥Z1õÁõAå^Ÿ6C°³kÁa ŒòNø ‘@÷@ŽyžÁÃ$ꙣn§nÈÏǵ…µ…ÕòµKA=Ÿ‡rÿ'¿wj5éa\~1ÓÈ‹ÓJ3+@fyî‰k8ýëãØõÁ‘ç©ó‘:Çbdt†UÑœÌ5r?Y„,Å?tCúÄ=Mƒh¿*yÑ0I6Lž¾sõ¸0ü—ÆIâå ÿõ?¼ä$²zz‡ÈßT­Á†ktúGÕŽqYÛˆ0‘a‹>쟓ŽYßsœ²À®è,(#µÕÅeZPRÓr¨èÒOou½ÎSÍæÉheL¤­ÞZSÛ̬9©Ÿú?åÖ‰NÄ̆@=÷¯ÿKòÙþu—~H'pcmbœ££"·…ì²ß ÆÉ±9ž‘ò•TbaZIf%ȬÜÝu 7¼x×ö_ê§Åï·=ÕÁ饨‘ŒOu§¿á±½¸Æ^щ· +†óñé¿a>{%{³ÈÌXubºB%OUÉÔ2õöé> ÑQzŽw¨öH<$õhf+Ø]º·cŸòÅè:ú”]Ë¡Ëy¬›ìõ¿•†ò, Kløû@KËM¾) cÇÈš±4þ|Ê’ÍtÓF“rÖ±§%»zWuF]R£¸QüáŒæž¶%^JJ¥›•« ¬ÅB#‹Ä”ø¨âìnø;6e73Ínšæ æ<\O®/­¬*ª*j+¼XôÆvk_j‹ÔÄ8ãÆQlz™aŒmL6;l㱪¹èç#Š£u}Èá%²&‘3œýVÀ\î†ïÃ5§& u/üºá0”]qÒtCî—Q\&ÚZ€Vyšþ ^×¹}¢N¯Öåà‹ååG|ýJÁ 0{2Æ>”ï$¡~J>a»²mäsjœ³ ºÂ4nª‡}NBËÁï¡1üeª˜ŽySlƒ%÷qõ­ç.ƒþK ·Çñçá÷{ü£#²Ñ¡M„qüý¦¿óŽÈ+J¢’+K5•@S¹ûÔMœ6Ãà'pvAÙ…Ú VÜWLˆ®­Õ«—à¶Éna!dH˜W¢3‘¡üýþdŠ¾Û½n…þPÆ} ­ÏB{¸‡‚7X’ÂCnWQDÈÏ àQÌò*$`€AM K’¹à|gè$éAüiùSàûÎcB¿ó¨¸î5€åHãse„sM—'µádȰtÚÕA«fK€š§Hn¯]=Z†¤8’E¢+Ðò3ább±Ëñ†,+’9Ÿ0dB»s/Hh1ô×ËÐŒ€ßy#óA“ñ`N3\z½q†M»ê9âý±‡ŽÈKâô@wè°Ǫ†šOu‚CÇîNàc‰×CÈïN×PíŠÌŠ1ý“÷¢¿¡žW”ü}‹‡X…ÁžûjdGp7ÕTçºwWùÉÂHY˜8.T¡™„?ýõ+Ž¹Í”“ii"52µìR«r„¾ZøŽ‡ DëZê·—KA¹ôŒ—kPSgÇGk8ïØ¦ÝmF|=ÇÎl•²êv×êj©Å"Š­ˆIˆI€0ÜÃIÈ=ˆSD.¹s“ÄÃ-7 x¡,E/µ ­‹¬ÖvµNwgêê¶Ûžà‰îF×;;ûa¿¿óÌóžyÿÿÓU.†ù5…>VÌÉ­ÏD—¯ άÁ×Ìì¡çWÐoa¼+˜dö'þ–Xd‰:}º¦>ü|õY"¤ÚPÄEéTzAäË{ø½/G¾£“à7•Ê¿†í™N»Áüz–IšØ.wq©òÞ†> pë|<㊰@dÜ1…Þ»]²yŸÙ|f¥“aSIªØ>–äXo‡€ªÌFz[RÝEx­[åë…KÐÀÂã“£·Ïæ*"à’•¡ÉiÑûË@‹Ç`ÕX5&E‡,qÌ+ˇ©LáB¯x…¤b1Ñ~ŒÞuE§ð©áñ˧¾‘;'þòwxŸ¸%¾†‰§þ~OB~^®#ÍX]üÎïð˜9ž‚ÄFãmìáÁz䓢¥Y®yƒÈÈÝu‚êP_]¡)Eùb³§ —zˆ>}4»[Æ¿†±ß WÆ>é¿€&3÷çÊé_± I¹NŒ~ȱžáûÂÉÊ[ ò–âë{ðÇîÙÁ1lÀåïîC¤†°ã¶FcE¯}«­È+Ro_S R&w"ºÌ½!8Y1žw;›·¡'M¤PÖ.¬Å·,/e0¿€LJaý1˸ñðý*zcúDø*~5òÉ¥á;åž>·¤¢B’Ób“ÏÇC†)ƒÆŽÛÕfEgh—ã¾ÿ,wò£Bª”Ý%ü.šµ½ŽŸ‹çæ–®%ëWý2?÷§M¬ÆÒ¦ÿZàîé!“3ˆCá³ó&Ão²úA«´Cn’ÕÝh¶´D¿€/ÆßFhôécöн{Šv£‡ëÚ-r\ÒS}ªñºýßDžûyÙ=ý ˆ“ôô[BÉšñeL/{ùÞq;2ù|#ƒ¨Û¡WZqO)1ó™ßž™™ž¤äøÅØ“¹Yö£_FZèM¬Áv¯ÅŽÙ-öN'j³Ô&¼SצV@u‹ªE…57´(õ°ÖXï”a2§_3ˆFúM®Üã²x)¬à÷b?×¾e~–.Îγ²K֥ð63©ËèÔ'¯#ûšËô¦#”M2 ÐÈ* ­¹Öü9ÿæI0y`¯g'Bel,ʤ¥=cŽé“öòmå€(ïÚC1`*¯…Z¯~m®óD —6ê¿ècbŸb¬å2Ðþ±užæ4|îßæ%Ô¼äˆúüÀï ÚF€·Eå¢ÇG|ØÄ”„/ã3È=ç°¹‰ðÍà}¼ïøüKø¡òAý*X*»Éƒ)ö»Þw£ù ~1Æ•p¹¼âTú3žkÏï„PNK•ZJ%|MEí#ƒãP ¿Ã¬ÀfܦsË8t&¿‚ÆÊG#rðjâóSׯ,"“#Ò*?Êí¥VSÛ`ê·²\6Ê×7Õ Y‡/>8†Å[éb'QÝÌ’V>m·[”j\¦ÍMCR‡òÏÖÚä> qBÐ}r™ Ñ;Ù*ÁXM ÜµÁU^ÒìÚ{êä~lÿIvvÅvP±]ú›-0Îgξ…¾ºøEù½Bø.a£ÎPpb PßBoÆW3å‚)¯ë½(Â8sMÉ×aò°—\¾†ú®">O ÝEƒ"€à¢Öôö+p’ k  =ÀÇ+jõêm:¢Ù’²|ÊsÜ|8i‡~§+R5¡ª&¡¦Òø´ÝiÒ©0+Ì;½3Ð^¾?Ÿ‰1Htßò'ï-Ô>é ô»ÓE ·ÙÜÖÚ…uj¿œò5cHÐOô{1¯Ï:'ñ!IÚ'ÕHéIï=¬„——sh k“?†Ö&óéOò˜ 1®j1ƒ®¹ GpU§E†ùŠOØŠ7ö ŽaEGÅÙûá,ïápäÌç}}àvq¤Ö} ¸Å–,Ôˆ¥RT*5ó’"o¸+WÌ nºƒzÄN¶÷:½H—½µÅ ïÝTE3vÿeì’ü‚? üQÛÕø†b†?ò§snlšß4Ÿ{ét e\.Ø×íq»PWoŸ%€LMɸa,\;™=ñIW’1¸+ÎfKÆšefé΂}G²d½}hÇPK®M¶C™çuIPk…¿z¢ÔMD7òŇ’ëg1—‘UUQW†hð Ž©-Í„Á ޶ÑY8~lüÕH~YGS.þð¿ #ÄÉçÕŠä@-=­#2E§E…©,Z»Þ ô½Æ©8ñrrÝó· ˆJëÚk/Cí¥ç9<ÀŸ¸$¿†\Úú"Xع™Ôºøºç”6Ñš$ñQ!“¼•h¸ÖKÓÙå³;À8õ~5jó·ô¨AÚ,—Â5²CµÛPê%*FýŠü†!XTM÷Ãn³ÓуZ­Ó2žÔWCA½wÈ=âàñÐVrq™Ëº´²y†è?zŠÀ_ÔõôÁÔÁjhÌØßbÃw5‰`Y3O^ŒR?¤Q¬ø*†4Ú<Ô÷t3j1÷™B)WCƒú¾æUÊÅwYÄ,Š•\EýŒ>/‰iG˜0Y ÚMx;S1ñé•HÛ¯tžöó†^'Û—w²fÒÉŽÄ>²{yã½*V%j˜áÅ ‘1ߨ/DLПPŸÒHZÝzB ­I£‚ …ùûPNÞ>2C>ØìjëÜÐj9cµÀ–v³©q?ËOöЭhÀý¿äBîµÍä6ê*ë÷Túþdz89øIZíWAi{§Ót6›õ ·mú!«É†v˜¡éÛ_±þJý’á©´ d°Ú Õ¶ Z]£a¥]cï¬Ø,sÔJÙdµü€õOr3cmœKfM&/G$M2¹Vhu]Lo6:úá3ͰÔ¼ÒKR[‹èiÞ¨áUÁ¥NÎHʉ(bÈí¹@lºýv‘üéNd±"ä C·Ýî^w?±R°yšym:‡ 8”ÝR1\)=P•‰R«¨1jk|5ƒ{OõÓÍN 6kŸi8U°+´~…WìgO¿F^_ÎbÕïa¤V˜oÈ»Lazý¦²ƒìP}ì×2j=’“ïJ|Æ8¿ úG!×¼+âò;ý}®ˆÀ´éBnNOZ—ÿÎ$®Cò.cmÒOn}²šÉf7Ü ï>0ÆFÙ±á_û X ‹Å ŸÀŸŽÇÐû``7²ë!û8¶öI÷úŒ5cþG€-þ£ endstream endobj 35 0 obj << /Type /FontDescriptor /Ascent 695 /CapHeight 662 /Descent -216 /Flags 70 /FontBBox [-189 -216 986 913] /FontName /HAMKOM+TimesNewRomanPS-ItalicMT /ItalicAngle -15 /StemV 0 /XHeight 442 /CharSet (/i/t/S/u/I/d/comma/m/w/W/l/n/M/x/period/y/b/o/z/c/p/O/T/e/q/P/A/space/r/f/a/h/s/g) /FontFile3 36 0 R >> endobj 36 0 obj << /Filter /FlateDecode /Length 6001 /Subtype /Type1C >> stream H‰tTkXéž3 ÁK£ÉL:ƒ«h×K˶vë£vE”Å”ÛbÀˆ ",B€„„{ÂÅ$C€Iä ‚`E@y¼vmeWÖÝZk×n«_„´ƒûôg¼Ï÷ý8ç=ç=ç{?äæ±X,Ÿ=;CƒÃC7DŠÄIÒ°$Å^‰8!ýÁ&¾,!M”¹ãgÃ=W8V:ÂxîßòÜCaÂíÑüçĉÿžîÀ{ Øä ö.­âqj—-äpÿ/!¤öô6B¿‚vB|( g XB(MóP¸²&˜TˆA‹!Ȃރ õù± Í,h  P¨´ßZÍ4­ÖB¹P7kkÐ%Óõ7®_»Âˆ òÀ=åyxzô,êùÙkÏÑÅ)‹{{x?\"\úáÒùeÕË÷.¿ñó^vÜ áÊVjçñ`h§ŽGCs:w§Œçö5{.’Gû;#ynÈ——ÏqZϞ휺zu ½r«éæv^e‘› ³\Z“gÈT ©gI°‚Š¢JQQªSóù:õ©RT«®P)1©2SšA¤ŠÓ£eT*ÇËçxŸ­PË$˜D'¥DÕ¤¶à–&}#ER”¾É‚YÔgA)¤z .‘ª™^vϹJœÊžÿÜùÌßWÀOJã&¥%äGS%sl¾H5ñdzuž‘›[§i0cFm}uQÝÐØÞÑαq|ڿ䣒% ®J\ ÏQ¢9’”âx\†¨’a[;à ?Óê³Él]žAI¡jCÕŠ+ºª†‰çp B§ÎÛØô Äö [‡ÐÑ{MذkìܪB¦ÕÔ–ê1J?`~D¥ýfÓ uÝØÌ56ml3 zªCÛ3%&D™ ÞY^Ú@6”ž)Ö)ÑjeeA–¢Þ¯"hÕüMéÖlAv·P‘Ÿ®ÊÕ$— Ž2¯3FhWæVq½æîÛ<8„­N)³–R.¥1図ég9Gº-[(—¢"ñÁ|>žñNœ€I ÔÆërÏpsÏ76cMúÓ=”ÙŸ€åÎY¸±wÌÍÒ²ùV±¯ŒŸ/ææ‹s 5Zq¸$šáP3SˆÎ K‘ÈD•E2,T f9Ý[7D­ýµé5ÔÐÂmh1Õ›uµÚþÊ{•¨•žqŸ·8ÓKçÃôsÄËþÚ.àÁ¿doˆó þý–·¬ £—  ÄôRz¶ËйƒèÜq-t:›ž•þ¾`Uß à‘€7\Àâ°eÐ6‚µØ__~D$>ŠºññôBàv꜆|eŸn m*_ö@`ó¶0Ú;ƒæDÑï öÐèv¿à€°ýbT^ޝõï¾C¸/ù8m`Õ8XO Å_¼šx8þpbdòQMà?¼ zŸ‘ßôÞ¾t½4iþò.öMʃLj±ÀÕí´îh_X xÉ®™¼^uŸWî#/&šöíÁþ˜* 'Dá±qጢp~Á.<6LGù“ÀÏf…½®¥±‡Ím­½x½¹LÝB>J¿ž×¥AK:{Ê{ñ'º¦È©®kCÝ“h÷d#Sv¬`4}„?X÷rÝË»’>TÒWtù*6lºzé"ÑÛÿ…i6¹„¶ò·aYÇR%È¿lûà$$çH¾¼Pª óÊrp¥údE1Y~2»:ÉiN2(´èiQŠ6§]ýD{ÉÝA)[7aáu‚ö(¢áHô>àÑ>O×wD¢TRÍ¡8,PEDÅò37ã›>²Üˆ #FÓ|uTôV"„vsœ€{/[=H˜Ëa[‘†é¦‘¶žs==ç(”˜Ðÿ ÿ3Bw:…’ Ù!ïtž"G…æI5B<ó)ž!µV8‰Jª6ÊÉl£ÚÔ‚µÖßë‹`šÛ ¿E^ÜPçž%Û²ê’c°„’ƒJ!уWà€uÈFÚ/¸p2mÿÃ\íâì‚­ÈÂõÎ?™56q­;,–ºVC»®û”ÞÊq¬E4É=åµ±k,¬ÎËÅ¥YJ ¡LGÇîvìœ÷áXÀq3ÀX­{\Q[uAg©1Ö µÆj³¾¯ròd Ãs…á¹W6 4+¸fEMz²ú¸ªsÔÎw?´gèþ^«¹™ÛÜ|µvêÝ_SÉ=Ö«þ)Xœ„I)'h§îd Ù?³?£‘ÂAyW†™kÊÕ$âAÁòýÝ[7Ó‹Pi´ë*lw½ ;‘8ÜÕ'ć®Õw “÷/?y2 ¹?§ ª$>“œ– ‰"ƒYs¿x¹±kè¾2-jâ|&JÌÌAU…Ê2 ®)9UUF–TÕÕ`U'OWèów@hßJÿV ûðÙæÌšCŒ^¿—^G#ŒqièwÛ÷íÂÅ™gZ²IY‹ªû ö¼å‡aàF ×[3S£hïÀeªïi+Ê2“^àÞÇNr×Z̧ x›¹Ti$õÅUEyX¡2F¶ GðŽ7?&¿ÆŸwnì¯ä÷7?ƒÞzÓþ@ØSéØAbà`xs.Œ.’Æ1Y‘±Á|mâÐÿÀßÎÅnží»;6„ݼÕ<Ž_ìε‘m)Ƙ0lµtM¬/ëƇ„É#ðýŸ4Xù$XÁxÄ ôÛOƒ£ìÿò\îAM]yßÙ%xgw–qv†5œËœ«Kkyø\wÖRßÚ•úˆ4XE !„$äM@;#'y@! H0„‡hP@±"c-2Ôõ5¶:u´[ÙnìÕÎÞX·ÿÜÿν÷wÎ÷óýžoJÚ‘lÆËÎ’gáŸdÚƒ,¢ X=v¼êœŸ‡çŽß˜Ɔ§¦ÚoàþÎZ™ƒhVêR >U{RëkU I¤F)«SbuŠSr9jÅ”ZZ4N¼³ÝÔn':¼fÿ-òA_Qºm¾fU#‰HblÝ”–€¥Å—ð>XïÞ5š 3FgxÏñ¹»ŽÀmbºoúÚôC®›µHEmFtá’FGƒ okÕ(,„QÙDý…¨^ æÁº°–Ÿ@þ@çõT¸xVÌÂ+Óá»·s&qo\»ŸŒ ´C+[¶´…¹¡Ê‹”t}ãÄ×WžÌ¿@‰äRºpŸ2‹8:U%»ºvö‡ˆPhì—l'=cë¸@‚©äŠz5®Ñ4h5„F{J«À} ¢±-ä‹4¹ÿç®h2ñ/Û¾/{+[Ñ7ПΡ˜§ˆ€>}2ýtÉx„‹g.ÎdD&¹,ŽL„ÔÑ,\^`D£ˆà㱉ØÐHÛèeÐ'îa{¡‡iýžÄe®%Ö0·n:‡1â8ïǃ®”‘úŠóGq(i­G%ª¼RöËÆs¨ã©YŽ<"o jä Ðvº³©"Üú£ó®#—£‰è;³_½‰ww¨ÄÔm@d”ƒ#U9ùY0?ë@nr£ü£êE/Zqù§Ù;XTöBÅë´î̋֠ÿnpü\/æ>° à6s½Æ@hëjU@S§TK JR/S±Vj–C¹9¬ —]o³V›Þî>I'Ç Ýeùælüð¡N‘Á9”›óiQ.‹Q°‰“Ê?.ˆB©@©'ÓqéÚIî|“œO®«X£*|R™UQÈ/.?Q"ÂDe—rý†F Qßx²Q š´:£ZÌ:‹X5f™ 6+$M"œ_U+’•Hx&C ùžyŸ¼Ö6x¸wev~Ň~ ¡„Ê@¿]ØCG+#[oÐÈ(» ,>Œæ8Ël¥FÌXšß”“ükLJćÛóÿ¾0™ƒŸÁÁÜ醢´’ìGÆå®•×Ň?Ëâˆd\ae…°q”.(¶²½lè- ñnVaÕ7ï*àß=2wÌsWýÁsXpØ92†Åýl?,îùØ·ÜMfž£ç˜8&¹ “›4Í`Òš,&è÷ŽvÜnCËtóÙ[ØÌÍÀ×O@Wm¼¢M‘ÞÓÈöÈDÒ-Ͱ+ÙÔ¦Uc¶ª?ʲ)#J»k.û®¹Ð,œ Mfñ  ‡ò•2k^&àײd‡ ÿ¾#½PÝÁÇ:*Í<ÅÎK)e)‰WQɺÑÙŸF÷ {‡@À𠧯¿{Ì…6çÍWÕXÒÇÒÒ£ –8h.ûéfÜÑZ+³©>|û$—’÷cÉ“4”9…òZÇÛ/zÎÇ|‹VŽ=°9¯Î^º4ìÁ,®6½7›êÕzB¯n¢r‡«.fCrÉë÷hüMŠt.¨Ð mXcs¨;ð6·Áê%¼6¿/8èîkï-³ÓY‡ óY\ g%…³úÿ8댠Iç±]„(ja#­uÒ86z¾pÍðL¥8c/'5…HI]EF‘$÷¢žÿæRn̤QH,‹XüµLTReBèhWy(48Þ–‰ö·e¢ÚíÂÊ_ÊDu5AZ^o¦vB7ìk´â­–:•‘r7­\ ªGªvBòϯÓib¦:Ÿ*ôU­Ô@-mÔ;û[ýÃĵó£ÃÓÅíô‚ƒ¬<çmª)q•ºA%œj­Çr¢œE&ùò õÈñÎL»Ú)3u;4JsØÒe Wä ¶AÒõóVš`»2‡*õÂ1·8UnÜÖÜ$Fý“Sßrºè,faû&¯‘ÖÉq察3³¾·å ˆžÇFt’ÏÓhÔ5ûûÅцBš¾ÏÕhÀ-¹…0Ëu2)МTÖË!#ÉxKCñ‘“('ˆ~ßr¶g.ôÏë¯?ºt9èÆl.—¾ 7ê¨cÖ©e" PæŠöBrÛëW4”9ŒÖ‡Pôè÷ЪÇèÏaž.ŸÕ^ ¢(Ãs}.;%‡§ÔŠ|áŽuä ½¿ÙÝGŒ®^Ÿü†""YW\N¡zpua"¨¡:Ÿ%&"™f¿a ¿Â+q‚š‡±ÃÜCìù4‰"b)yÅ,¦ˆ`P§ÿjñjôDÚ.ï|ÃZnÚjb5sÛ–ƒ ØÁøò„°Æ³m‚ ™3Ügø7Ï<ωï®Ì̾ÄF_v~ÿ/ðŒ;›6Éc¯ïE“Ë“7ì^çoé)%J{$¡)€`?Z~-‡Ôóéíÿ±\öAMœyo­‰;s^çî2öéí£g_¦wöZëŽ:=΢2Š ‚,B„H6!B²YBp¦$„òžBä%†5ÇQj9PÚØÂ½ŒõF©çÕNmÿXâBï¼›ý{g÷÷öý~¾ÀÄ(U‰fXé-:‰s/—p¿8ÈíDVº-ùÝ–5vÅÝÞúémé4¸Ž‘6æœí‡gÈ|eCŠJSb8ÙJ£h[µ•-ó¥–v j:ôv¦cºZ]nÜÛqÌÏÙ®hCŸ>¤4GúÍ1À¾ÍŸ‡ìØ=sìëìkøŠj¾äCâÃ’óáÓ û %= ÏJOd§íÿ3K ¹Ÿç±¢:ˆÑAsw:¯„{ˆPøª3>þƒJ<c¥Ö·±aþ<;Ç+ã#7Ò¿´d¿ž›^(.ŸªyWM_"Éäo¬òÈ#t®¯éT4åÓ`)üœŽÏÞ\X«ìæ¤W”j›0…œ4hŸzãÿ”À‰û;¯m¡îï×ïñØ·ø¾›M aþPÀáŽn…&¯§Õ ÂÝv_::Û}N(”?n¸©S±ú¡ª!.X$D…$¿ØÂk¼·Í Æõdú•î,Çî™Í„²Ò¢¼¬Ì‚‚‹‰3ÑÍf3h1·YZѪ·8š=->S§É‚ÙƒEê•4©„*•AQ‡«í…@ÌÏÁPÂÓ?'W–¿Ekö*{ˆ}‘Ýó»ó1»s黸gXü3ÿÜž0ÄÔa"¬ªwÕ IµZ¨¥²'mjE¸(¯>h šœ¦v3fm±˜šqýeƒ™&R]^•wnß…t‰(u÷™TqañºAh|dü„‰cÚ89ʧ¡2Ó¿Lb‚~`4Ðç÷ù}®€³8‡Ûæ{¿™±y‰W“„;î¡3-ç«/P2-¥ÕPM fj(¾œ¸q~2#y‰×»ùãû9ï…'?[ÿà¿ Áþ°‘ endstream endobj 6 0 obj << /Type /Font /Subtype /Type1 /Name /F1 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 408 500 500 833 778 180 333 333 500 564 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722 556 722 667 556 611 722 722 944 722 722 611 333 278 333 469 500 333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444 480 200 480 541 778 722 722 667 611 722 722 722 444 444 444 444 444 444 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 500 500 500 500 400 500 500 500 350 453 500 760 760 980 333 333 549 889 722 713 549 549 549 500 576 494 713 823 549 274 276 310 768 667 500 444 333 564 549 500 549 612 500 500 1000 250 722 722 722 889 722 500 1000 444 444 333 333 549 494 500 722 167 500 333 333 556 556 500 250 333 444 1000 722 611 722 611 611 333 333 333 333 722 722 778 722 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 37 0 R /BaseFont /HAMKMH+TimesNewRomanPSMT /FontDescriptor 31 0 R >> endobj 7 0 obj << /Type /Font /Subtype /Type1 /Name /F2 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 555 500 500 1000 833 278 333 333 500 570 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 930 722 667 722 722 667 611 778 778 389 500 778 667 944 722 778 611 778 722 556 667 722 722 1000 722 722 667 333 278 333 581 500 333 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444 394 220 394 520 778 722 722 722 667 722 778 722 500 500 500 500 500 500 444 444 444 444 444 278 278 278 278 556 500 500 500 500 500 556 556 556 556 500 400 500 500 500 350 540 556 747 747 1000 333 333 549 1000 778 713 549 549 549 500 576 494 713 823 549 274 300 330 768 722 500 500 333 570 549 500 549 612 500 500 1000 250 722 722 778 1000 722 500 1000 500 500 333 333 549 494 500 722 167 500 333 333 556 556 500 250 333 500 1000 722 667 722 667 667 389 389 389 389 778 778 778 778 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 37 0 R /BaseFont /HAMKNJ+TimesNewRomanPS-BoldMT /FontDescriptor 33 0 R >> endobj 8 0 obj << /Type /Font /Subtype /Type1 /Name /F3 /FirstChar 1 /LastChar 255 /Widths [778 778 778 778 778 778 778 0 250 778 778 778 250 778 778 778 778 778 778 778 778 778 778 778 778 778 778 778 0 778 778 250 333 420 500 500 833 778 214 333 333 500 675 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 675 675 675 500 920 611 611 667 722 611 611 722 722 333 444 667 556 833 667 722 611 722 611 500 556 722 611 833 611 556 556 389 278 389 422 500 333 500 500 444 500 444 278 500 500 278 278 444 278 722 500 500 500 500 389 389 278 500 444 667 444 444 389 400 275 400 541 778 611 611 667 611 667 722 722 500 500 500 500 500 500 444 444 444 444 444 278 278 278 278 500 500 500 500 500 500 500 500 500 500 500 400 500 500 500 350 523 500 760 760 980 333 333 549 889 722 713 549 549 549 500 576 494 713 823 549 274 276 310 768 667 500 500 389 675 549 500 549 612 500 500 889 250 611 611 722 944 667 500 889 556 556 333 333 549 494 444 556 167 500 333 333 500 500 500 250 333 556 1000 611 611 611 611 611 333 333 333 333 722 722 778 722 722 722 722 278 333 333 333 333 333 333 333 333 333 333 ] /Encoding 37 0 R /BaseFont /HAMKOM+TimesNewRomanPS-ItalicMT /FontDescriptor 35 0 R >> endobj 9 0 obj << /Type /Font /Subtype /Type1 /Name /F5 /Encoding 38 0 R /BaseFont /Times-Roman >> endobj 16 0 obj << /Type /Font /Subtype /Type1 /Name /F7 /Encoding 38 0 R /BaseFont /Helvetica-Bold >> endobj 17 0 obj << /Type /Font /Subtype /Type1 /Name /F9 /Encoding 38 0 R /BaseFont /Helvetica >> endobj 37 0 obj << /Type /Encoding /Differences [ 0/.null 9/nonmarkingreturn 13/nonmarkingreturn 128/Adieresis ] >> endobj 38 0 obj << /Type /Encoding /Differences [ 0/.notdef 8/.notdef/space 13/.notdef 29/.notdef 128/Adieresis 202/space ] >> endobj 3 0 obj << /Type /Page /Parent 11 0 R /Resources 5 0 R /Contents 4 0 R /Rotate -180 >> endobj 13 0 obj << /Type /Page /Parent 11 0 R /Resources 15 0 R /Contents 14 0 R /Rotate -180 >> endobj 18 0 obj << /Type /Page /Parent 11 0 R /Resources 20 0 R /Contents 19 0 R /Rotate -180 >> endobj 21 0 obj << /Type /Page /Parent 11 0 R /Resources 23 0 R /Contents 22 0 R /Rotate -180 >> endobj 24 0 obj << /Type /Page /Parent 11 0 R /Resources 26 0 R /Contents 25 0 R /Rotate -180 >> endobj 27 0 obj << /Type /Page /Parent 11 0 R /Resources 29 0 R /Contents 28 0 R /Rotate -180 >> endobj 11 0 obj << /Type /Pages /Kids [3 0 R 13 0 R 18 0 R 21 0 R 24 0 R 27 0 R] /Count 6 /MediaBox [0 0 595 842] >> endobj 39 0 obj << /Type /Catalog /Pages 11 0 R >> endobj 40 0 obj << /CreationDate (D:20011113175920) /Producer (Acrobat Distiller 3.02 for Power Macintosh) /Author (stephG4) /Creator (AppleWorks: LaserWriter 8 FU2-8.7.1) /Title (Pa_ASIO1) >> endobj xref 0 41 0000000000 65535 f 0000000016 00000 n 0000006474 00000 n 0000048862 00000 n 0000004795 00000 n 0000006279 00000 n 0000044683 00000 n 0000045890 00000 n 0000047107 00000 n 0000048319 00000 n 0000018231 00000 n 0000049441 00000 n 0000006521 00000 n 0000048956 00000 n 0000006720 00000 n 0000008771 00000 n 0000048418 00000 n 0000048521 00000 n 0000049053 00000 n 0000008909 00000 n 0000011160 00000 n 0000049150 00000 n 0000011298 00000 n 0000013743 00000 n 0000049247 00000 n 0000013859 00000 n 0000016172 00000 n 0000049344 00000 n 0000016288 00000 n 0000017992 00000 n 0000018108 00000 n 0000018303 00000 n 0000018848 00000 n 0000029322 00000 n 0000029789 00000 n 0000038273 00000 n 0000038591 00000 n 0000048619 00000 n 0000048735 00000 n 0000049558 00000 n 0000049609 00000 n trailer << /Size 41 /Root 39 0 R /Info 40 0 R /ID [<22d1064700ff024bdc4ec712f949bc29><22d1064700ff024bdc4ec712f949bc29>] >> startxref 49802 %%EOF portaudio-18.1.orig/pa_unix_oss/0000755000175000000620000000000007700016422017317 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_unix_oss/Makefile0000644000175000017500000000126407553764164021151 0ustar mikaelmikael00000000000000# Make PortAudio for Linux # # by Phil Burk # # To compile a test program, make a target with a .app suffix. # For example to compile "../pa_tests/pa_devs.c", enter: # gmake pa_devs.app # # To compile and execute a test program, make a target with a .run suffix. # For example to build and run "../pa_tests/pa_devs.c", enter: # gmake pa_devs.run VPATH = ../pa_common ../pa_tests CFLAGS = -g -Wall -I../pa_common CC = gcc PAOBJS = pa_lib.o pa_unix_oss.o pa_unix.o PAINC = portaudio.h pa_unix.h PALIBS = -lm -lpthread all: patest_sine.run %.app: %.o $(PAOBJS) $(PAINC) Makefile gcc $(CFLAGS) $*.o $(PAOBJS) $(PALIBS) -o $@ %.run: %.app ./$*.app clean: -rm *.app -rm *.o portaudio-18.1.orig/pa_unix_oss/pa_unix_solaris.c0000644000175000017500000003161107631074006023035 0ustar mikaelmikael00000000000000/* * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * Linux OSS Implementation by douglas repetto and Phil Burk * * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* Modification history: 20020621: Initial cut at Solaris modifications jointly by Sam Bayer and Augustus Saunders. 20030206 - Martin Rohrbach - various mods for Solaris */ #define __solaris_native__ #include "pa_unix.h" /* SAM 6/2/02: Docs say we should include sys/audio.h, but that doesn't exist pre Solaris 2.8. These headers work fine. */ #include #include /********************************************************************* * Try to open the named device. * If it opens, try to set various rates and formats and fill in * the device info structure. */ PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ) { int result = paHostError; int tempDevHandle; int numChannels, maxNumChannels; int numSampleRates; int sampleRate; int numRatesToTry; int ratesToTry[9] = {96000, 48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}; int i; audio_info_t solaris_info; audio_device_t device_info; /* douglas: we have to do this querying in a slightly different order. apparently some sound cards will give you different info based on their settins. e.g. a card might give you stereo at 22kHz but only mono at 44kHz. the correct order for OSS is: format, channels, sample rate */ /* to check a device for it's capabilities, it's probably better to use the equivalent "-ctl"-descriptor - MR */ char devname[strlen(deviceName) + 4]; if ( (tempDevHandle = open(strcat(strcpy(devname, deviceName), "ctl"), O_WRONLY|O_NONBLOCK)) == -1 ) { DBUG(("Pa_QueryDevice: could not open %s\n", deviceName )); return paHostError; } /* Ask OSS what formats are supported by the hardware. */ pad->pad_Info.nativeSampleFormats = 0; AUDIO_INITINFO(&solaris_info); /* SAM 12/31/01: Sparc native does mulaw, alaw and PCM. I think PCM is signed. */ for (i = 8; i <= 32; i += 8) { solaris_info.play.precision = i; solaris_info.play.encoding = AUDIO_ENCODING_LINEAR; /* If there are no errors, add the format. */ if (ioctl(tempDevHandle, AUDIO_SETINFO, &solaris_info) > -1) { switch (i) { case 8: pad->pad_Info.nativeSampleFormats |= paInt8; break; case 16: pad->pad_Info.nativeSampleFormats |= paInt16; break; case 24: pad->pad_Info.nativeSampleFormats |= paInt24; break; case 32: pad->pad_Info.nativeSampleFormats |= paInt32; break; } } } maxNumChannels = 0; for( numChannels = 1; numChannels <= 16; numChannels++ ) { int temp = numChannels; DBUG(("Pa_QueryDevice: use SNDCTL_DSP_CHANNELS, numChannels = %d\n", numChannels )) AUDIO_INITINFO(&solaris_info); solaris_info.play.channels = temp; if (ioctl(tempDevHandle, AUDIO_SETINFO, &solaris_info) < 0) { /* ioctl() failed so bail out if we already have stereo */ if( numChannels > 2 ) break; } else { /* ioctl() worked but bail out if it does not support numChannels. * We don't want to leave gaps in the numChannels supported. */ if( (numChannels > 2) && (temp != numChannels) ) break; DBUG(("Pa_QueryDevice: temp = %d\n", temp )) if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */ } } pad->pad_Info.maxOutputChannels = maxNumChannels; DBUG(("Pa_QueryDevice: maxNumChannels = %d\n", maxNumChannels)) /* FIXME - for now, assume maxInputChannels = maxOutputChannels. * Eventually do separate queries for O_WRONLY and O_RDONLY */ pad->pad_Info.maxInputChannels = pad->pad_Info.maxOutputChannels; DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) /* Determine available sample rates by trying each one and seeing result. */ numSampleRates = 0; AUDIO_INITINFO(&solaris_info); numRatesToTry = sizeof(ratesToTry)/sizeof(int); for (i = 0; i < numRatesToTry; i++) { sampleRate = ratesToTry[i]; solaris_info.play.sample_rate = sampleRate; /* AS: We opened for Write, so set play */ if (ioctl(tempDevHandle, AUDIO_SETINFO, &solaris_info) >= 0 ) /* PLB20010817 */ { if (sampleRate == ratesToTry[i]) { DBUG(("Pa_QueryDevice: got sample rate: %d\n", sampleRate)) pad->pad_SampleRates[numSampleRates] = (float)ratesToTry[i]; numSampleRates++; } } } DBUG(("Pa_QueryDevice: final numSampleRates = %d\n", numSampleRates)) if (numSampleRates==0) /* HP20010922 */ { ERR_RPT(("Pa_QueryDevice: no supported sample rate (or SNDCTL_DSP_SPEED ioctl call failed).\n" )); goto error; } pad->pad_Info.numSampleRates = numSampleRates; pad->pad_Info.sampleRates = pad->pad_SampleRates; /* query for the device name instead of using the filesystem-device - MR */ if (ioctl(tempDevHandle, AUDIO_GETDEV, &device_info) == -1) { pad->pad_Info.name = deviceName; } else { char *pt = (char *)PaHost_AllocateFastMemory(strlen(device_info.name)); strcpy(pt, device_info.name); pad->pad_Info.name = pt; } result = paNoError; error: /* We MUST close the handle here or we won't be able to reopen it later!!! */ close(tempDevHandle); return result; } /*******************************************************************************************/ PaError Pa_SetupInputDeviceFormat( int devHandle, int numChannels, int sampleRate ) { audio_info_t solaris_info; AUDIO_INITINFO(&solaris_info); /* Sam Bayer/Bryan George 1/10/02: Various folks have reported that on Solaris Ultra II, the not-right thing happens on read unless you make sure the audio device is flushed. The folks who wrote the Robust Audio Tool say: + XXX driver issue - on Ultra II's if you don't drain * the device before reading commences then the device * reads in blocks of 500ms irrespective of the * blocksize set. After a minute or so it flips into the * correct mode, but obviously this is too late to be + * useful for most apps. grrr. */ /* AS: And the Solaris man audio pages say you should flush before changing formats anyway. So there you go. */ if (Pa_FlushStream(devHandle) != paNoError) return paHostError; solaris_info.record.encoding = AUDIO_ENCODING_LINEAR; solaris_info.record.sample_rate = sampleRate; solaris_info.record.precision = 16; solaris_info.record.channels = numChannels; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_SetupDeviceFormat: could not set audio info\n" )); return paHostError; } return paNoError; } PaError Pa_SetupOutputDeviceFormat( int devHandle, int numChannels, int sampleRate ) { audio_info_t solaris_info; AUDIO_INITINFO(&solaris_info); /* Sam Bayer/Bryan George 1/10/02: Various folks have reported that on Solaris Ultra II, the not-right thing happens on read unless you make sure the audio device is flushed. The folks who wrote the Robust Audio Tool say: + XXX driver issue - on Ultra II's if you don't drain * the device before reading commences then the device * reads in blocks of 500ms irrespective of the * blocksize set. After a minute or so it flips into the * correct mode, but obviously this is too late to be + * useful for most apps. grrr. */ /* AS: And the Solaris man audio pages say you should flush before changing formats anyway. So there you go. */ if (Pa_FlushStream(devHandle) != paNoError) return paHostError; solaris_info.play.encoding = AUDIO_ENCODING_LINEAR; solaris_info.play.sample_rate = sampleRate; solaris_info.play.precision = 16; solaris_info.play.channels = numChannels; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_SetupDeviceFormat: could not set audio info\n" )); return paHostError; } return paNoError; } PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate ) { PaError result = paNoError; result = Pa_SetupOutputDeviceFormat(devHandle, numChannels, sampleRate); if (result != paNoError) return result; return Pa_SetupInputDeviceFormat(devHandle, numChannels, sampleRate); } /******************************************************************************************* ** Set number of fragments and size of fragments to achieve desired latency. */ static PaError Pa_Unpause(int devHandle); static PaError Pa_PauseAndFlush(int devHandle); void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, int channelsPerFrame ) { int bufferSize; audio_info_t solaris_info; /* Increase size of buffers and reduce number of buffers to reduce latency inside driver. */ while( numBuffers > 8 ) { numBuffers = (numBuffers + 1) >> 1; framesPerBuffer = framesPerBuffer << 1; } /* calculate size of buffers in bytes */ bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME - other sizes? */ DBUG(("Pa_SetLatency: numBuffers = %d, framesPerBuffer = %d\n", numBuffers, framesPerBuffer)); /* SAM 6/6/02: Documentation says to pause and flush before changing buffer size. */ if (Pa_PauseAndFlush(devHandle) != paNoError) { ERR_RPT(("Pa_SetLatency: could not pause audio\n" )); return; } AUDIO_INITINFO(&solaris_info); /* AS: Doesn't look like solaris has multiple buffers, so I'm being conservative and making one buffer. Might not be what we want... */ solaris_info.play.buffer_size = solaris_info.record.buffer_size = bufferSize; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_SetLatency: could not set audio info\n" )); } Pa_Unpause(devHandle); } /***********************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *past = (internalPortAudioStream *) stream; PaHostSoundControl *pahsc; audio_info_t solaris_info; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; ioctl(pahsc->pahsc_OutputHandle, AUDIO_GETINFO, &solaris_info); return solaris_info.play.samples; } void Pa_UpdateStreamTime(PaHostSoundControl *pahsc) { /* AS: Don't need to do anytying for this under Solaris.*/ } static PaError Pa_PauseAndFlush(int devHandle) { audio_info_t solaris_info; AUDIO_INITINFO(&solaris_info); solaris_info.play.pause = solaris_info.record.pause = 1; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_FlushStream failed.\n")); return paHostError; } if (ioctl(devHandle, I_FLUSH, FLUSHRW) == -1) { ERR_RPT(("Pa_FlushStream failed.\n")); /* Unpause! */ AUDIO_INITINFO(&solaris_info); solaris_info.play.pause = solaris_info.record.pause = 0; ioctl(devHandle, AUDIO_SETINFO, &solaris_info); return paHostError; } return paNoError; } static PaError Pa_Unpause(int devHandle) { audio_info_t solaris_info; AUDIO_INITINFO(&solaris_info); solaris_info.play.pause = solaris_info.record.pause = 0; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_FlushStream failed.\n")); return paHostError; } return paNoError; } PaError Pa_FlushStream(int devHandle) { PaError res = Pa_PauseAndFlush(devHandle); if (res == paNoError) return Pa_Unpause(devHandle); else return res; } portaudio-18.1.orig/pa_unix_oss/pa_unix_oss.c0000644000175000017500000003246107700014616022167 0ustar mikaelmikael00000000000000/* * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * Linux OSS Implementation by douglas repetto and Phil Burk * * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* Modification history: 20020621: pa_unix_oss.c split into pa_unix.c, pa_unix.h, pa_unix_oss.c by Augustus Saunders. See pa_unix.c for previous history. Pa_FlushStream added by Augustus Saunders for Solaris compatibility. PLB20021018 - Fill device info table with actual sample rates instead of wished for rates. - Allow stream to open if sample rate within 10% of desired rate. 20030630 - Thomas Richter - eliminated unused variable warnings. */ #include "pa_unix.h" #ifdef __linux__ #include #else #include /* JH20010905 */ #endif #ifndef AFMT_S16_NE #define AFMT_S16_NE Get_AFMT_S16_NE() /********************************************************************* * Some versions of OSS do not define AFMT_S16_NE. So check CPU. * PowerPC is Big Endian. X86 is Little Endian. */ int Get_AFMT_S16_NE( void ) { long testData = 1; char *ptr = (char *) &testData; int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */ return isLittle ? AFMT_S16_LE : AFMT_S16_BE; } #endif /* AFMT_S16_NE */ /********************************************************************* * Try to open the named device. * If it opens, try to set various rates and formats and fill in * the device info structure. */ PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ) { int result = paHostError; int tempDevHandle; int numChannels, maxNumChannels; int format; int numSampleRates; int sampleRate; int numRatesToTry; int lastRate; int ratesToTry[9] = {96000, 48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}; int i; /* douglas: we have to do this querying in a slightly different order. apparently some sound cards will give you different info based on their settings. e.g. a card might give you stereo at 22kHz but only mono at 44kHz. the correct order for OSS is: format, channels, sample rate */ if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 ) { DBUG(("Pa_QueryDevice: could not open %s\n", deviceName )); return paHostError; } /* Ask OSS what formats are supported by the hardware. */ pad->pad_Info.nativeSampleFormats = 0; if (ioctl(tempDevHandle, SNDCTL_DSP_GETFMTS, &format) == -1) { ERR_RPT(("Pa_QueryDevice: could not get format info\n" )); goto error; } if( format & AFMT_U8 ) pad->pad_Info.nativeSampleFormats |= paUInt8; if( format & AFMT_S16_NE ) pad->pad_Info.nativeSampleFormats |= paInt16; /* Negotiate for the maximum number of channels for this device. PLB20010927 * Consider up to 16 as the upper number of channels. * Variable numChannels should contain the actual upper limit after the call. * Thanks to John Lazzaro and Heiko Purnhagen for suggestions. */ maxNumChannels = 0; for( numChannels = 1; numChannels <= 16; numChannels++ ) { int temp = numChannels; DBUG(("Pa_QueryDevice: use SNDCTL_DSP_CHANNELS, numChannels = %d\n", numChannels )) if(ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) { /* ioctl() failed so bail out if we already have stereo */ if( numChannels > 2 ) break; } else { /* ioctl() worked but bail out if it does not support numChannels. * We don't want to leave gaps in the numChannels supported. */ if( (numChannels > 2) && (temp != numChannels) ) break; DBUG(("Pa_QueryDevice: temp = %d\n", temp )) if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */ } } /* The above negotiation may fail for an old driver so try this older technique. */ if( maxNumChannels < 1 ) { int stereo = 1; if(ioctl(tempDevHandle, SNDCTL_DSP_STEREO, &stereo) < 0) { maxNumChannels = 1; } else { maxNumChannels = (stereo) ? 2 : 1; } DBUG(("Pa_QueryDevice: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", maxNumChannels )) } pad->pad_Info.maxOutputChannels = maxNumChannels; DBUG(("Pa_QueryDevice: maxNumChannels = %d\n", maxNumChannels)) /* During channel negotiation, the last ioctl() may have failed. This can * also cause sample rate negotiation to fail. Hence the following, to return * to a supported number of channels. SG20011005 */ { int temp = maxNumChannels; if( temp > 2 ) temp = 2; /* use most reasonable default value */ ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp); } /* FIXME - for now, assume maxInputChannels = maxOutputChannels. * Eventually do separate queries for O_WRONLY and O_RDONLY */ pad->pad_Info.maxInputChannels = pad->pad_Info.maxOutputChannels; DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) /* Determine available sample rates by trying each one and seeing result. * OSS often supports funky rates such as 44188 instead of 44100! */ numSampleRates = 0; lastRate = 0; numRatesToTry = sizeof(ratesToTry)/sizeof(int); for (i = 0; i < numRatesToTry; i++) { sampleRate = ratesToTry[i]; if (ioctl(tempDevHandle, SNDCTL_DSP_SPEED, &sampleRate) >= 0 ) /* PLB20010817 */ { /* Use whatever rate OSS tells us. PLB20021018 */ if (sampleRate != lastRate) { DBUG(("Pa_QueryDevice: adding sample rate: %d\n", sampleRate)) pad->pad_SampleRates[numSampleRates] = (float)sampleRate; numSampleRates++; lastRate = sampleRate; } else { DBUG(("Pa_QueryDevice: dang - got sample rate %d again!\n", sampleRate)) } } } DBUG(("Pa_QueryDevice: final numSampleRates = %d\n", numSampleRates)) if (numSampleRates==0) /* HP20010922 */ { /* Desparate attempt to keep running even though no good rates found! */ ERR_RPT(("Pa_QueryDevice: no supported sample rate (or SNDCTL_DSP_SPEED ioctl call failed). Force 44100 Hz\n" )); pad->pad_SampleRates[numSampleRates++] = 44100; } pad->pad_Info.numSampleRates = numSampleRates; pad->pad_Info.sampleRates = pad->pad_SampleRates; /* use pointer to embedded array */ pad->pad_Info.name = deviceName; result = paNoError; error: /* We MUST close the handle here or we won't be able to reopen it later!!! */ close(tempDevHandle); return result; } /*******************************************************************************************/ PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate ) { PaError result = paNoError; int tmp; /* Set format, channels, and rate in this order to keep OSS happy. */ /* Set data format. FIXME - handle more native formats. */ tmp = AFMT_S16_NE; if( ioctl(devHandle,SNDCTL_DSP_SETFMT,&tmp) == -1) { ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_SETFMT\n" )); return paHostError; } if( tmp != AFMT_S16_NE ) { ERR_RPT(("Pa_SetupDeviceFormat: HW does not support AFMT_S16_NE\n" )); return paHostError; } /* Set number of channels. */ tmp = numChannels; if (ioctl(devHandle, SNDCTL_DSP_CHANNELS, &numChannels) == -1) { ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_CHANNELS\n" )); return paHostError; } if( tmp != numChannels) { ERR_RPT(("Pa_SetupDeviceFormat: HW does not support %d channels\n", numChannels )); return paHostError; } /* Set playing frequency. */ tmp = sampleRate; if( ioctl(devHandle,SNDCTL_DSP_SPEED,&tmp) == -1) { ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_SPEED\n" )); return paHostError; } else if( tmp != sampleRate ) { int percentError = abs( (100 * (sampleRate - tmp)) / sampleRate ); PRINT(("Pa_SetupDeviceFormat: warning - requested sample rate = %d Hz - closest = %d\n", sampleRate, tmp )); /* Allow sample rate within 10% off of requested rate. PLB20021018 * Sometimes OSS uses a funky rate like 44188 instead of 44100. */ if( percentError > 10 ) { ERR_RPT(("Pa_SetupDeviceFormat: HW does not support %d Hz sample rate\n",sampleRate )); return paHostError; } } return result; } PaError Pa_SetupOutputDeviceFormat( int devHandle, int numChannels, int sampleRate ) { return Pa_SetupDeviceFormat(devHandle, numChannels, sampleRate); } PaError Pa_SetupInputDeviceFormat( int devHandle, int numChannels, int sampleRate ) { return Pa_SetupDeviceFormat(devHandle, numChannels, sampleRate); } /******************************************************************************************* ** Set number of fragments and size of fragments to achieve desired latency. */ static int CalcHigherLogTwo( int n ) { int log2 = 0; while( (1< 8 ) { numBuffers = (numBuffers + 1) >> 1; framesPerBuffer = framesPerBuffer << 1; } /* calculate size of buffers in bytes */ bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME - other sizes? */ /* Calculate next largest power of two */ powerOfTwo = CalcHigherLogTwo( bufferSize ); DBUG(("Pa_SetLatency: numBuffers = %d, framesPerBuffer = %d, powerOfTwo = %d\n", numBuffers, framesPerBuffer, powerOfTwo )); /* Encode info into a single int */ tmp=(numBuffers<<16) + powerOfTwo; if(ioctl(devHandle,SNDCTL_DSP_SETFRAGMENT,&tmp) == -1) { ERR_RPT(("Pa_SetLatency: could not SNDCTL_DSP_SETFRAGMENT\n" )); /* Don't return an error. Best to just continue and hope for the best. */ ERR_RPT(("Pa_SetLatency: numBuffers = %d, framesPerBuffer = %d, powerOfTwo = %d\n", numBuffers, framesPerBuffer, powerOfTwo )); } } /***********************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { internalPortAudioStream *past = (internalPortAudioStream *) stream; PaHostSoundControl *pahsc; count_info info; int delta; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc->pahsc_NativeOutputBuffer ) { ioctl(pahsc->pahsc_OutputHandle, SNDCTL_DSP_GETOPTR, &info); delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF; return (pahsc->pahsc_LastStreamBytes + delta) / (past->past_NumOutputChannels * sizeof(short)); } else { ioctl(pahsc->pahsc_InputHandle, SNDCTL_DSP_GETIPTR, &info); delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF; return (pahsc->pahsc_LastStreamBytes + delta) / (past->past_NumInputChannels * sizeof(short)); } } void Pa_UpdateStreamTime(PaHostSoundControl *pahsc) { count_info info; int delta; /* Update current stream time (using a double so that we don't wrap around like info.bytes does) */ if( pahsc->pahsc_NativeOutputBuffer ) { ioctl(pahsc->pahsc_OutputHandle, SNDCTL_DSP_GETOPTR, &info); } else { ioctl(pahsc->pahsc_InputHandle, SNDCTL_DSP_GETIPTR, &info); } delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF; pahsc->pahsc_LastStreamBytes += delta; pahsc->pahsc_LastPosPtr = info.bytes; } PaError Pa_FlushStream(int devHandle) { /* AS: This doesn't do anything under OSS; it was added for Solaris.*/ devHandle = devHandle; /* unused */ return paNoError; } portaudio-18.1.orig/pa_unix_oss/Makefile_freebsd0000644000175000017500000000171107423043534022623 0ustar mikaelmikael00000000000000# Make PortAudio for FreeBSD LIBS = -lm -pthread CDEFINES = -I../pa_common CFLAGS = -g PASRC = ../pa_common/pa_lib.c pa_freebsd.c PAINC = ../pa_common/portaudio.h # Tests that work. #TESTC = $(PASRC) ../pa_tests/patest_sine.c TESTC = $(PASRC) ../pa_tests/patest_sine_time.c #TESTC = $(PASRC) ../pa_tests/patest_stop.c #TESTC = $(PASRC) ../pa_tests/patest_sync.c #TESTC = $(PASRC) ../pa_tests/patest_pink.c #TESTC = $(PASRC) ../pa_tests/patest_leftright.c #TESTC = $(PASRC) ../pa_tests/patest_clip.c #TESTC = $(PASRC) ../pa_tests/patest_dither.c #TESTC = $(PASRC) ../pa_tests/pa_devs.c #TESTC = $(PASRC) ../pa_tests/patest_many.c #TESTC = $(PASRC) ../pa_tests/patest_record.c #TESTC = $(PASRC) ../pa_tests/patest_wire.c #TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Tests that do not yet work. TESTH = $(PAINC) all: patest patest: $(TESTC) $(TESTH) Makefile gcc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest run: patest ./patest portaudio-18.1.orig/pa_unix_oss/pa_unix.c0000644000175000017500000011421307700014616021277 0ustar mikaelmikael00000000000000/* * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * Linux OSS Implementation by douglas repetto and Phil Burk * * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* Modification History 1/2001 - Phil Burk - initial hack for Linux 2/2001 - Douglas Repetto - many improvements, initial query support 4/2/2001 - Phil - stop/abort thread control, separate in/out native buffers 5/28/2001 - Phil - use pthread_create() instead of clone(). Thanks Stephen Brandon! use pthread_join() after thread shutdown. 5/29/2001 - Phil - query for multiple devices, multiple formats, input mode and input+output mode working, Pa_GetCPULoad() implemented. PLB20010817 - Phil & Janos Haber - don't halt if test of sample rate fails. SB20010904 - Stephen Brandon - mods needed for GNUSTEP and SndKit JH20010905 - Janos Haber - FreeBSD mods 2001-09-22 - Heiko - (i.e. Heiko Purnhagen ;-) added 24k and 16k to ratesToTry[] fixed Pa_GetInternalDevice() changed DEVICE_NAME_BASE from /dev/audio to /dev/dsp handled SNDCTL_DSP_SPEED in Pq_QueryDevice() more graceful fixed Pa_StreamTime() for paqa_errs.c fixed numCannel=2 oddity and error handling in Pa_SetupDeviceFormat() grep also for HP20010922 ... PLB20010924 - Phil - merged Heiko's changes removed sNumDevices and potential related bugs, use getenv("PA_MIN_LATENCY_MSEC") to set desired latency, simplify CPU Load calculation by comparing real-time to framesPerBuffer, always close device when querying even if error occurs, PLB20010927 - Phil - Improved negotiation for numChannels. SG20011005 - Stewart Greenhill - set numChannels back to reasonable value after query. DH20010115 - David Herring - fixed uninitialized handle. DM20020218 - Dominic Mazzoni - Try to open in nonblocking mode first, in case the device is already open. New implementation of Pa_StreamTime that uses SNDCTL_DSP_GETOPTR but uses our own counter to avoid wraparound. PLB20020222 - Phil Burk - Added WatchDog proc if audio running at high priority. Check error return from read() and write(). Check CPU endianness instead of assuming Little Endian. 20020621 - pa_unix_oss.c split into pa_unix.c, pa_unix.h, pa_unix_oss.c by Augustus Saunders. Return values from usleep() ignored by Sam Bayer because not cross-platform compatible (at least until we get configure going). Pa_SetupDeviceFormat split into input and output sides to reflect capabilities of Solaris. 20030206 - Martin Rohrbach - various mods for Solaris 20030410 - Bjorn Dittmer-Roche - fixed numerous problems associated with pthread_t 20030630 - Thomas Richter - eliminated unused variable warnings. TODO O- put semaphore lock around shared data? O- handle native formats better O- handle stereo-only device better ??? O- what if input and output of a device capabilities differ (e.g. es1371) ??? */ #include "pa_unix.h" typedef void *(*pthread_function_t)(void *); /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ static internalPortAudioDevice *sDeviceList = NULL; static int sDefaultInputDeviceID = paNoDevice; static int sDefaultOutputDeviceID = paNoDevice; static int sPaHostError = 0; /********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ static void Pa_StartUsageCalculation( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; /* Query system timer for usage analysis and to prevent overuse of CPU. */ gettimeofday( &pahsc->pahsc_EntryTime, NULL ); } static long SubtractTime_AminusB( struct timeval *timeA, struct timeval *timeB ) { long secs = timeA->tv_sec - timeB->tv_sec; long usecs = secs * 1000000; usecs += (timeA->tv_usec - timeB->tv_usec); return usecs; } /****************************************************************************** ** Measure fractional CPU load based on real-time it took to calculate ** buffers worth of output. */ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { struct timeval currentTime; long usecsElapsed; double newUsage; #define LOWPASS_COEFFICIENT_0 (0.95) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; if( gettimeofday( ¤tTime, NULL ) == 0 ) { usecsElapsed = SubtractTime_AminusB( ¤tTime, &pahsc->pahsc_EntryTime ); /* Use inverse because it is faster than the divide. */ newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerBuffer; past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + (LOWPASS_COEFFICIENT_1 * newUsage); } } /****************************************** END CPU UTILIZATION *******/ /********************************************************************* * Determines the number of available devices by trying to open * each "/dev/dsp#" or "/dsp/audio#" in order until it fails. * Add each working device to a singly linked list of devices. */ PaError Pa_QueryDevices( void ) { internalPortAudioDevice *pad, *lastPad; int go = 1; int numDevices = 0; PaError testResult; PaError result = paNoError; char *envdev; sDefaultInputDeviceID = paNoDevice; sDefaultOutputDeviceID = paNoDevice; lastPad = NULL; while( go ) { /* Allocate structure to hold device info. */ pad = (internalPortAudioDevice *) PaHost_AllocateFastMemory( sizeof(internalPortAudioDevice) ); if( pad == NULL ) return paInsufficientMemory; memset( pad, 0, sizeof(internalPortAudioDevice) ); /* Build name for device. */ if( numDevices == 0 ) { sprintf( pad->pad_DeviceName, DEVICE_NAME_BASE); } else { sprintf( pad->pad_DeviceName, DEVICE_NAME_BASE "%d", numDevices ); } DBUG(("Try device %s\n", pad->pad_DeviceName )); testResult = Pa_QueryDevice( pad->pad_DeviceName, pad ); DBUG(("Pa_QueryDevice returned %d\n", testResult )); if( testResult != paNoError ) { if( lastPad == NULL ) { result = testResult; /* No good devices! */ } go = 0; PaHost_FreeFastMemory( pad, sizeof(internalPortAudioDevice) ); } else { numDevices += 1; /* Add to linked list of devices. */ if( lastPad ) { lastPad->pad_Next = pad; } else { sDeviceList = pad; /* First element in linked list. */ } lastPad = pad; } } /* I'm sitting at a SunRay1 and I neither have /dev/audio# nor /dev/dsp#. Instead, the correct audio device is stored in the environment variable AUDIODEV and/or UTAUDIODEV, so check these devices as well if we haven't checked them yet above - MR */ DBUG(("Checking for AUDIODEV and UTAUDIODEV\n")); envdev = getenv("AUDIODEV"); if (envdev != NULL && !strstr(envdev, DEVICE_NAME_BASE)) { result = paNoError; /* Allocate structure to hold device info. */ pad = (internalPortAudioDevice *) PaHost_AllocateFastMemory( sizeof(internalPortAudioDevice) ); if( pad == NULL ) return paInsufficientMemory; memset( pad, 0, sizeof(internalPortAudioDevice) ); /* Build name for device. */ strcpy(pad->pad_DeviceName, envdev); DBUG(("Try device %s\n", pad->pad_DeviceName )); testResult = Pa_QueryDevice( pad->pad_DeviceName, pad ); DBUG(("Pa_QueryDevice returned %d\n", testResult )); if( testResult != paNoError ) { if( lastPad == NULL ) { result = testResult; /* No good devices! */ } PaHost_FreeFastMemory( pad, sizeof(internalPortAudioDevice) ); } else { numDevices += 1; /* Add to linked list of devices. */ if( lastPad ) { lastPad->pad_Next = pad; } else { sDeviceList = pad; /* First element in linked list. */ } lastPad = pad; } } envdev = getenv("UTAUDIODEV"); if (envdev != NULL && !strstr(envdev, DEVICE_NAME_BASE) && getenv("AUDIODEV") != NULL && strcmp(envdev, getenv("AUDIODEV"))) { result = paNoError; /* Allocate structure to hold device info. */ pad = (internalPortAudioDevice *) PaHost_AllocateFastMemory( sizeof(internalPortAudioDevice) ); if( pad == NULL ) return paInsufficientMemory; memset( pad, 0, sizeof(internalPortAudioDevice) ); /* Build name for device. */ strcpy(pad->pad_DeviceName, envdev); DBUG(("Try device %s\n", pad->pad_DeviceName )); testResult = Pa_QueryDevice( pad->pad_DeviceName, pad ); DBUG(("Pa_QueryDevice returned %d\n", testResult )); if( testResult != paNoError ) { if( lastPad == NULL ) { result = testResult; /* No good devices! */ } PaHost_FreeFastMemory( pad, sizeof(internalPortAudioDevice) ); } else { numDevices += 1; /* Add to linked list of devices. */ if( lastPad ) { lastPad->pad_Next = pad; } else { sDeviceList = pad; /* First element in linked list. */ } lastPad = pad; } } return result; } /*************************************************************************/ int Pa_CountDevices() { int numDevices = 0; internalPortAudioDevice *pad; if( sDeviceList == NULL ) Pa_Initialize(); /* Count devices in list. */ pad = sDeviceList; while( pad != NULL ) { pad = pad->pad_Next; numDevices++; } return numDevices; } /*************************************************************************/ internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ) { internalPortAudioDevice *pad; if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; pad = sDeviceList; while( id > 0 ) { pad = pad->pad_Next; id--; } return pad; } /*************************************************************************/ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { internalPortAudioDevice *pad; if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; pad = Pa_GetInternalDevice( id ); return &pad->pad_Info ; } static PaError Pa_MaybeQueryDevices( void ) { if( sDeviceList == NULL ) { return Pa_QueryDevices(); } return 0; } PaDeviceID Pa_GetDefaultInputDeviceID( void ) { /* return paNoDevice; */ return 0; } PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { return 0; } /********************************************************************** ** Make sure that we have queried the device capabilities. */ PaError PaHost_Init( void ) { return Pa_MaybeQueryDevices(); } /******************************************************************************************* * The ol' Canary in a Coal Mine trick. * Just update the time periodically. * Runs at low priority so if audio thread runs wild, this thread will get starved * and the watchdog will detect it. */ #define SCHEDULER_POLICY SCHED_RR #define WATCHDOG_MAX_SECONDS (3) #define WATCHDOG_INTERVAL_USEC (1000000) static int PaHost_CanaryProc( PaHostSoundControl *pahsc ) { int result = 0; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif while( pahsc->pahsc_CanaryRun) { usleep( WATCHDOG_INTERVAL_USEC ); gettimeofday( &pahsc->pahsc_CanaryTime, NULL ); } DBUG(("PaHost_CanaryProc: exiting.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return result; } /******************************************************************************************* * Monitor audio thread and lower its it if it hogs the CPU. * To prevent getting killed, the audio thread must update a * variable with a timer value. * If the value is not recent enough, then the * thread will get killed. */ static PaError PaHost_WatchDogProc( PaHostSoundControl *pahsc ) { struct sched_param schp = { 0 }; int maxPri; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif /* Run at a priority level above audio thread so we can still run if it hangs. */ /* Rise more than 1 because of rumored off-by-one scheduler bugs. */ schp.sched_priority = pahsc->pahsc_AudioPriority + 4; maxPri = sched_get_priority_max(SCHEDULER_POLICY); if( schp.sched_priority > maxPri ) schp.sched_priority = maxPri; if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) { ERR_RPT(("PaHost_WatchDogProc: cannot set watch dog priority!\n")); goto killAudio; } /* Compare watchdog time with audio and canary thread times. */ /* Sleep for a while or until thread cancelled. */ while( pahsc->pahsc_WatchDogRun ) { int delta; struct timeval currentTime; usleep( WATCHDOG_INTERVAL_USEC ); gettimeofday( ¤tTime, NULL ); /* If audio thread is not advancing, then it must be hung so kill it. */ delta = currentTime.tv_sec - pahsc->pahsc_EntryTime.tv_sec; DBUG(("PaHost_WatchDogProc: audio delta = %d\n", delta )); if( delta > WATCHDOG_MAX_SECONDS ) { goto killAudio; } /* If canary died, then lower audio priority and halt canary. */ delta = currentTime.tv_sec - pahsc->pahsc_CanaryTime.tv_sec; if( delta > WATCHDOG_MAX_SECONDS ) { ERR_RPT(("PaHost_WatchDogProc: canary died!\n")); goto lowerAudio; } } DBUG(("PaHost_WatchDogProc: exiting.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return 0; lowerAudio: { struct sched_param schat = { 0 }; if( sched_setscheduler(pahsc->pahsc_AudioThreadPID, SCHED_OTHER, &schat) != 0) { ERR_RPT(("PaHost_WatchDogProc: failed to lower audio priority. errno = %d\n", errno )); /* Fall through into killing audio thread. */ } else { ERR_RPT(("PaHost_WatchDogProc: lowered audio priority to prevent hogging of CPU.\n")); goto cleanup; } } killAudio: ERR_RPT(("PaHost_WatchDogProc: killing hung audio thread!\n")); pthread_kill( pahsc->pahsc_AudioThread, SIGKILL ); cleanup: pahsc->pahsc_CanaryRun = 0; DBUG(("PaHost_WatchDogProc: cancel Canary\n")); pthread_cancel( pahsc->pahsc_CanaryThread ); DBUG(("PaHost_WatchDogProc: join Canary\n")); pthread_join( pahsc->pahsc_CanaryThread, NULL ); DBUG(("PaHost_WatchDogProc: forget Canary\n")); pahsc->pahsc_IsCanaryThreadValid = 0; #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return 0; } /*******************************************************************************************/ static void PaHost_StopWatchDog( PaHostSoundControl *pahsc ) { /* Cancel WatchDog thread if there is one. */ if( pahsc->pahsc_IsWatchDogThreadValid ) { pahsc->pahsc_WatchDogRun = 0; DBUG(("PaHost_StopWatchDog: cancel WatchDog\n")); pthread_cancel( pahsc->pahsc_WatchDogThread ); pthread_join( pahsc->pahsc_WatchDogThread, NULL ); pahsc->pahsc_IsWatchDogThreadValid = 0; } /* Cancel Canary thread if there is one. */ if( pahsc->pahsc_IsCanaryThreadValid ) { pahsc->pahsc_CanaryRun = 0; DBUG(("PaHost_StopWatchDog: cancel Canary\n")); pthread_cancel( pahsc->pahsc_CanaryThread ); DBUG(("PaHost_StopWatchDog: join Canary\n")); pthread_join( pahsc->pahsc_CanaryThread, NULL ); pahsc->pahsc_IsCanaryThreadValid = 0; } } /*******************************************************************************************/ static PaError PaHost_StartWatchDog( PaHostSoundControl *pahsc ) { int hres; PaError result = 0; /* The watch dog watches for these timer updates */ gettimeofday( &pahsc->pahsc_EntryTime, NULL ); gettimeofday( &pahsc->pahsc_CanaryTime, NULL ); /* Launch a canary thread to detect priority abuse. */ pahsc->pahsc_CanaryRun = 1; hres = pthread_create(&(pahsc->pahsc_CanaryThread), NULL /*pthread_attr_t * attr*/, (pthread_function_t)PaHost_CanaryProc, pahsc); if( hres != 0 ) { pahsc->pahsc_IsCanaryThreadValid = 0; result = paHostError; sPaHostError = hres; goto error; } pahsc->pahsc_IsCanaryThreadValid = 1; /* Launch a watchdog thread to prevent runaway audio thread. */ pahsc->pahsc_WatchDogRun = 1; hres = pthread_create(&(pahsc->pahsc_WatchDogThread), NULL /*pthread_attr_t * attr*/, (pthread_function_t)PaHost_WatchDogProc, pahsc); if( hres != 0 ) { pahsc->pahsc_IsWatchDogThreadValid = 0; result = paHostError; sPaHostError = hres; goto error; } pahsc->pahsc_IsWatchDogThreadValid = 1; return result; error: PaHost_StopWatchDog( pahsc ); return result; } /******************************************************************************************* * Bump priority of audio thread if running with superuser priveledges. * if priority bumped then launch a watchdog. */ static PaError PaHost_BoostPriority( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; PaError result = paNoError; struct sched_param schp = { 0 }; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; pahsc->pahsc_AudioThreadPID = getpid(); DBUG(("PaHost_BoostPriority: audio PID = %d\n", pahsc->pahsc_AudioThreadPID )); /* Choose a priority in the middle of the range. */ pahsc->pahsc_AudioPriority = (sched_get_priority_max(SCHEDULER_POLICY) - sched_get_priority_min(SCHEDULER_POLICY)) / 2; schp.sched_priority = pahsc->pahsc_AudioPriority; if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) { DBUG(("PortAudio: only superuser can use real-time priority.\n")); } else { DBUG(("PortAudio: audio callback priority set to level %d!\n", schp.sched_priority)); /* We are running at high priority so we should have a watchdog in case audio goes wild. */ result = PaHost_StartWatchDog( pahsc ); } return result; } /*******************************************************************************************/ static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) { PaError result; PaHostSoundControl *pahsc; ssize_t bytes_read, bytes_written; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif result = PaHost_BoostPriority( past ); if( result < 0 ) goto error; past->past_IsActive = 1; DBUG(("entering thread.\n")); while( (past->past_StopNow == 0) && (past->past_StopSoon == 0) ) { /* Read data from device */ if(pahsc->pahsc_NativeInputBuffer) { unsigned int totalread = 0; DBUG(("Pa_AudioThreadProc: attempt to read %d bytes\n", pahsc->pahsc_BytesPerInputBuffer)); do { bytes_read = read(pahsc->pahsc_InputHandle, (char *)pahsc->pahsc_NativeInputBuffer + totalread, pahsc->pahsc_BytesPerInputBuffer - totalread); if (bytes_read < 0) { ERR_RPT(("PortAudio: read interrupted!\n")); break; } totalread += bytes_read; } while( totalread < pahsc->pahsc_BytesPerInputBuffer); } /* Convert 16 bit native data to user data and call user routine. */ DBUG(("converting...\n")); Pa_StartUsageCalculation( past ); result = Pa_CallConvertInt16( past, pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer ); Pa_EndUsageCalculation( past ); if( result != 0) { DBUG(("hmm, Pa_CallConvertInt16() says: %d. i'm bailing.\n", result)); break; } /* Write data to device. */ if( pahsc->pahsc_NativeOutputBuffer ) { unsigned int totalwritten = 0; do { bytes_written = write(pahsc->pahsc_OutputHandle, (void *)pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); if( bytes_written < 0 ) { ERR_RPT(("PortAudio: write interrupted!")); break; } totalwritten += bytes_written; } while( totalwritten < pahsc->pahsc_BytesPerOutputBuffer); } Pa_UpdateStreamTime(pahsc); } DBUG(("Pa_AudioThreadProc: left audio loop.\n")); past->past_IsActive = 0; PaHost_StopWatchDog( pahsc ); error: DBUG(("leaving audio thread.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return result; } /************************************************************************* ** Determine minimum number of buffers required for this host based ** on minimum latency. Latency can be optionally set by user by setting ** an environment variable. For example, to set latency to 200 msec, put: ** ** set PA_MIN_LATENCY_MSEC=200 ** ** in the cshrc file. */ #define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond ) { int minBuffers; int minLatencyMsec = MIN_LATENCY_MSEC; char *minLatencyText = getenv(PA_LATENCY_ENV_NAME); if( minLatencyText != NULL ) { PRINT(("PA_MIN_LATENCY_MSEC = %s\n", minLatencyText )); minLatencyMsec = atoi( minLatencyText ); if( minLatencyMsec < 1 ) minLatencyMsec = 1; else if( minLatencyMsec > 5000 ) minLatencyMsec = 5000; } minBuffers = (int) ((minLatencyMsec * framesPerSecond) / ( 1000.0 * framesPerBuffer )); if( minBuffers < 2 ) minBuffers = 2; return minBuffers; } /*******************************************************************/ PaError PaHost_OpenStream( internalPortAudioStream *past ) { PaError result = paNoError; PaHostSoundControl *pahsc; unsigned int minNumBuffers; internalPortAudioDevice *pad; DBUG(("PaHost_OpenStream() called.\n" )); /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl)); if( pahsc == NULL ) { result = paInsufficientMemory; goto error; } memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; /* No device currently opened. */ pahsc->pahsc_InputHandle = BAD_DEVICE_ID; pahsc->pahsc_IsAudioThreadValid = 0; pahsc->pahsc_IsWatchDogThreadValid = 0; /* Allocate native buffers. */ pahsc->pahsc_BytesPerInputBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels * sizeof(short); if( past->past_NumInputChannels > 0) { pahsc->pahsc_NativeInputBuffer = (short *) malloc(pahsc->pahsc_BytesPerInputBuffer); if( pahsc->pahsc_NativeInputBuffer == NULL ) { result = paInsufficientMemory; goto error; } } pahsc->pahsc_BytesPerOutputBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels * sizeof(short); if( past->past_NumOutputChannels > 0) { pahsc->pahsc_NativeOutputBuffer = (short *) malloc(pahsc->pahsc_BytesPerOutputBuffer); if( pahsc->pahsc_NativeOutputBuffer == NULL ) { result = paInsufficientMemory; goto error; } } /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */ minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; pahsc->pahsc_InverseMicrosPerBuffer = past->past_SampleRate / (1000000.0 * past->past_FramesPerUserBuffer); DBUG(("past_SampleRate = %g\n", past->past_SampleRate )); DBUG(("past_FramesPerUserBuffer = %d\n", past->past_FramesPerUserBuffer )); DBUG(("pahsc_InverseMicrosPerBuffer = %g\n", pahsc->pahsc_InverseMicrosPerBuffer )); /* ------------------------- OPEN DEVICE -----------------------*/ /* just output */ if (past->past_OutputDeviceID == past->past_InputDeviceID) { if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0) ) { pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_RDWR\n", pad->pad_DeviceName )); /* dmazzoni: test it first in nonblocking mode to make sure the device is not busy */ pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDWR|O_NONBLOCK); if(pahsc->pahsc_InputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName )); result = paHostError; goto error; } close(pahsc->pahsc_InputHandle); pahsc->pahsc_OutputHandle = pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDWR); if(pahsc->pahsc_InputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName )); result = paHostError; goto error; } Pa_SetLatency( pahsc->pahsc_OutputHandle, past->past_NumUserBuffers, past->past_FramesPerUserBuffer, past->past_NumOutputChannels ); result = Pa_SetupDeviceFormat( pahsc->pahsc_OutputHandle, past->past_NumOutputChannels, (int)past->past_SampleRate ); } } else { if (past->past_NumOutputChannels > 0) { pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_WRONLY\n", pad->pad_DeviceName )); /* dmazzoni: test it first in nonblocking mode to make sure the device is not busy */ pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY|O_NONBLOCK); if(pahsc->pahsc_OutputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_WRONLY\n", pad->pad_DeviceName )); result = paHostError; goto error; } close(pahsc->pahsc_OutputHandle); pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY); if(pahsc->pahsc_OutputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_WRONLY\n", pad->pad_DeviceName )); result = paHostError; goto error; } Pa_SetLatency( pahsc->pahsc_OutputHandle, past->past_NumUserBuffers, past->past_FramesPerUserBuffer, past->past_NumOutputChannels ); result = Pa_SetupOutputDeviceFormat( pahsc->pahsc_OutputHandle, past->past_NumOutputChannels, (int)past->past_SampleRate ); } if (past->past_NumInputChannels > 0) { pad = Pa_GetInternalDevice( past->past_InputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_RDONLY\n", pad->pad_DeviceName )); /* dmazzoni: test it first in nonblocking mode to make sure the device is not busy */ pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY|O_NONBLOCK); if(pahsc->pahsc_InputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDONLY\n", pad->pad_DeviceName )); result = paHostError; goto error; } close(pahsc->pahsc_InputHandle); pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY); if(pahsc->pahsc_InputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDONLY\n", pad->pad_DeviceName )); result = paHostError; goto error; } Pa_SetLatency( pahsc->pahsc_InputHandle, /* DH20010115 - was OutputHandle! */ past->past_NumUserBuffers, past->past_FramesPerUserBuffer, past->past_NumInputChannels ); result = Pa_SetupInputDeviceFormat( pahsc->pahsc_InputHandle, past->past_NumInputChannels, (int)past->past_SampleRate ); } } DBUG(("PaHost_OpenStream: SUCCESS - result = %d\n", result )); return result; error: ERR_RPT(("PaHost_OpenStream: ERROR - result = %d\n", result )); PaHost_CloseStream( past ); return result; } /*************************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { past = past; /* unused */ return paNoError; } /*************************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *past ) { past = past; /* unused */ return paNoError; } /*************************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; PaError result = paNoError; int hres; pahsc = (PaHostSoundControl *) past->past_DeviceData; past->past_StopSoon = 0; past->past_StopNow = 0; past->past_IsActive = 1; /* Use pthread_create() instead of __clone() because: * - pthread_create also works for other UNIX systems like Solaris, * - the Java HotSpot VM crashes in pthread_setcanceltype() when using __clone() */ hres = pthread_create(&(pahsc->pahsc_AudioThread), NULL /*pthread_attr_t * attr*/, (pthread_function_t)Pa_AudioThreadProc, past); if( hres != 0 ) { result = paHostError; sPaHostError = hres; pahsc->pahsc_IsAudioThreadValid = 0; goto error; } pahsc->pahsc_IsAudioThreadValid = 1; error: return result; } /*************************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { int hres; PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; /* Tell background thread to stop generating more data and to let current data play out. */ past->past_StopSoon = 1; /* If aborting, tell background thread to stop NOW! */ if( abort ) past->past_StopNow = 1; /* Join thread to recover memory resources. */ if( pahsc->pahsc_IsAudioThreadValid ) { /* This check is needed for GNUSTEP - SB20010904 */ if ( !pthread_equal( pahsc->pahsc_AudioThread, pthread_self() ) ) { hres = pthread_join( pahsc->pahsc_AudioThread, NULL ); } else { DBUG(("Play thread was stopped from itself - can't do pthread_join()\n")); hres = 0; } if( hres != 0 ) { result = paHostError; sPaHostError = hres; } pahsc->pahsc_IsAudioThreadValid = 0; } past->past_IsActive = 0; return result; } /*************************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { past = past; /* unused */ abort = abort; /* unused */ return paNoError; } /*************************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { past = past; /* unused */ abort = abort; /* unused */ return paNoError; } /*******************************************************************/ PaError PaHost_CloseStream( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; if( pahsc->pahsc_OutputHandle != BAD_DEVICE_ID ) { int err = 0; DBUG(("PaHost_CloseStream: attempt to close output device handle = %d\n", pahsc->pahsc_OutputHandle )); Pa_FlushStream(pahsc->pahsc_OutputHandle); err = close(pahsc->pahsc_OutputHandle); if( err < 0 ) { ERR_RPT(("PaHost_CloseStream: warning, closing output device failed.\n")); } } if( (pahsc->pahsc_InputHandle != BAD_DEVICE_ID) && (pahsc->pahsc_InputHandle != pahsc->pahsc_OutputHandle) ) { int err = 0; DBUG(("PaHost_CloseStream: attempt to close input device handle = %d\n", pahsc->pahsc_InputHandle )); Pa_FlushStream(pahsc->pahsc_InputHandle); err = close(pahsc->pahsc_InputHandle); if( err < 0 ) { ERR_RPT(("PaHost_CloseStream: warning, closing input device failed.\n")); } } pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; pahsc->pahsc_InputHandle = BAD_DEVICE_ID; if( pahsc->pahsc_NativeInputBuffer ) { free( pahsc->pahsc_NativeInputBuffer ); pahsc->pahsc_NativeInputBuffer = NULL; } if( pahsc->pahsc_NativeOutputBuffer ) { free( pahsc->pahsc_NativeOutputBuffer ); pahsc->pahsc_NativeOutputBuffer = NULL; } free( pahsc ); past->past_DeviceData = NULL; return paNoError; } /*************************************************************************/ PaError PaHost_Term( void ) { /* Free all of the linked devices. */ internalPortAudioDevice *pad, *nextPad; pad = sDeviceList; while( pad != NULL ) { nextPad = pad->pad_Next; DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName )); PaHost_FreeFastMemory( pad, sizeof(internalPortAudioDevice) ); pad = nextPad; } sDeviceList = NULL; return 0; } /************************************************************************* * Sleep for the requested number of milliseconds. */ void Pa_Sleep( long msec ) { #if 0 struct timeval timeout; timeout.tv_sec = msec / 1000; timeout.tv_usec = (msec % 1000) * 1000; select( 0, NULL, NULL, NULL, &timeout ); #else long usecs = msec * 1000; usleep( usecs ); #endif } /************************************************************************* * Allocate memory that can be accessed in real-time. * This may need to be held in physical memory so that it is not * paged to virtual memory. * This call MUST be balanced with a call to PaHost_FreeFastMemory(). */ void *PaHost_AllocateFastMemory( long numBytes ) { void *addr = malloc( numBytes ); /* FIXME - do we need physical, wired, non-virtual memory? */ if( addr != NULL ) memset( addr, 0, numBytes ); return addr; } /************************************************************************* * Free memory that could be accessed in real-time. * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). */ void PaHost_FreeFastMemory( void *addr, long numBytes ) { numBytes = numBytes; /* unused */ if( addr != NULL ) free( addr ); } /***********************************************************************/ PaError PaHost_StreamActive( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; return (PaError) (past->past_IsActive != 0); } /***********************************************************************/ long Pa_GetHostError( void ) { return (long) sPaHostError; } portaudio-18.1.orig/pa_unix_oss/pa_unix.h0000644000175000017500000001333407645326412021316 0ustar mikaelmikael00000000000000/* * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * Linux OSS Implementation by douglas repetto and Phil Burk * * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ /* Modification history: 20020621: pa_unix_oss.c split into pa_unix.c, pa_unix.h, pa_unix_oss.c by Augustus Saunders. See pa_unix.c for previous history. */ /* PROPOSED - should we add this to "portaudio.h". Problem with Pa_QueryDevice() not having same driver name os Pa_OpenStream(). A PaDriverInfo structure can be passed to the underlying device on the Pa_OpenStream() call. The contents and interpretation of the structure is determined by the PA implementation. */ typedef struct PaDriverInfo /* PROPOSED */ { /* Size of structure. Allows driver to extend the structure without breaking existing applications. */ int size; /* Can be used to request a specific device name. */ const char *name; unsigned long data; } PaDriverInfo; #include #include //#include #include #include #include #include #include #include #include #include #include #include #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" #define PRINT(x) { printf x; fflush(stdout); } #define ERR_RPT(x) PRINT(x) #define DBUG(x) /* PRINT(x) */ #define DBUGX(x) /* PRINT(x) */ #define BAD_DEVICE_ID (-1) #define MIN_LATENCY_MSEC (100) #define MIN_TIMEOUT_MSEC (100) #define MAX_TIMEOUT_MSEC (1000) /************************************************* Definitions ********/ #ifdef __linux__ #define DEVICE_NAME_BASE "/dev/dsp" #else #define DEVICE_NAME_BASE "/dev/audio" #endif #define MAX_CHARS_DEVNAME (32) #define MAX_SAMPLE_RATES (10) typedef struct internalPortAudioDevice { struct internalPortAudioDevice *pad_Next; /* Singly linked list. */ double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ char pad_DeviceName[MAX_CHARS_DEVNAME]; PaDeviceInfo pad_Info; } internalPortAudioDevice; /* Define structure to contain all OSS and Linux specific data. */ typedef struct PaHostSoundControl { int pahsc_OutputHandle; int pahsc_InputHandle; int pahsc_AudioPriority; /* priority of background audio thread */ pthread_t pahsc_AudioThread; /* background audio thread */ int pahsc_IsAudioThreadValid; /* Is pahsc_AudioThread valid?*/ pid_t pahsc_AudioThreadPID; /* background audio thread */ pthread_t pahsc_WatchDogThread; /* highest priority thread that protects system */ int pahsc_IsWatchDogThreadValid; /* Is pahsc_WatchDogThread valid?*/ int pahsc_WatchDogRun; /* Ask WatchDog to stop. */ pthread_t pahsc_CanaryThread; /* low priority thread that detects abuse by audio */ int pahsc_IsCanaryThreadValid; /* Is pahsc_CanaryThread valid?*/ struct timeval pahsc_CanaryTime; int pahsc_CanaryRun; /* Ask Canary to stop. */ short *pahsc_NativeInputBuffer; short *pahsc_NativeOutputBuffer; unsigned int pahsc_BytesPerInputBuffer; /* native buffer size in bytes */ unsigned int pahsc_BytesPerOutputBuffer; /* native buffer size in bytes */ /* For measuring CPU utilization. */ struct timeval pahsc_EntryTime; double pahsc_InverseMicrosPerBuffer; /* 1/Microseconds of real-time audio per user buffer. */ /* For calculating stream time */ int pahsc_LastPosPtr; double pahsc_LastStreamBytes; } PaHostSoundControl; /************************************************* Prototypes **********/ internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id ); PaError Pa_QueryDevices( void ); PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ); PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate ); PaError Pa_SetupInputDeviceFormat( int devHandle, int numChannels, int sampleRate ); PaError Pa_SetupOutputDeviceFormat( int devHandle, int numChannels, int sampleRate ); void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, int channelsPerFrame ); void Pa_UpdateStreamTime(PaHostSoundControl *pahsc); int Pa_FlushStream(int devHandle); portaudio-18.1.orig/pa_unix_oss/recplay.c0000644000175000017500000000436507423043534021304 0ustar mikaelmikael00000000000000/* * recplay.c * Phil Burk * Minimal record and playback test. * */ #include #include #include #ifndef __STDC__ /* #include */ #endif /* __STDC__ */ #include #ifdef __STDC__ #include #else /* __STDC__ */ #include #endif /* __STDC__ */ #include #define NUM_BYTES (64*1024) #define BLOCK_SIZE (4*1024) #define AUDIO "/dev/dsp" char buffer[NUM_BYTES]; int audioDev = 0; main (int argc, char *argv[]) { int numLeft; char *ptr; int num; int samplesize; /********** RECORD ********************/ /* Open audio device. */ audioDev = open (AUDIO, O_RDONLY, 0); if (audioDev == -1) { perror (AUDIO); exit (-1); } /* Set to 16 bit samples. */ samplesize = 16; ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); if (samplesize != 16) { perror("Unable to set the sample size."); exit(-1); } /* Record in blocks */ printf("Begin recording.\n"); numLeft = NUM_BYTES; ptr = buffer; while( numLeft >= BLOCK_SIZE ) { if ( (num = read (audioDev, ptr, BLOCK_SIZE)) < 0 ) { perror (AUDIO); exit (-1); } else { printf("Read %d bytes\n", num); ptr += num; numLeft -= num; } } close( audioDev ); /********** PLAYBACK ********************/ /* Open audio device for writing. */ audioDev = open (AUDIO, O_WRONLY, 0); if (audioDev == -1) { perror (AUDIO); exit (-1); } /* Set to 16 bit samples. */ samplesize = 16; ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); if (samplesize != 16) { perror("Unable to set the sample size."); exit(-1); } /* Play in blocks */ printf("Begin playing.\n"); numLeft = NUM_BYTES; ptr = buffer; while( numLeft >= BLOCK_SIZE ) { if ( (num = write (audioDev, ptr, BLOCK_SIZE)) < 0 ) { perror (AUDIO); exit (-1); } else { printf("Wrote %d bytes\n", num); ptr += num; numLeft -= num; } } close( audioDev ); } portaudio-18.1.orig/pa_unix_oss/low_latency_tip.txt0000644000175000017500000000604707423043534023435 0ustar mikaelmikael00000000000000From: "Benno Senoner" To: Subject: Re: [music-dsp] coding realtime guitar efx on a "pc" Date: Saturday, June 30, 2001 8:19 AM Andrè, you are solving your problem the wrong way: you need to use a single threaded solution which does this: - set the audio I/O parameters to fragnum=4 fragsize=128 bytes (=32samples) if you use stereo or fragsize=64 bytes (=32 samples) if you use mono. (do not forget to activate fulltuplex with using the _TRIGGER_ stuff) (you need to frist deactivate audio and then start the trigger after the DAC is prefilled (see below)) This will give you a total input to output latency of 4x32 samples = 128 samples which at 44.1kHz correspond to 2.9msec latency. now set your process to SCHED_FIFO (see man sched_setscheduler) after the initialization your code should do more than less this: - write() 4 x 32 samples to the audio fd in order to prefill the DAC. Without this you will get dropouts. while(1) { read() 32 samples from ADC perform_dsp_stuff() on the 32 samples write() 32 samples to DAC } If you use a low latency kernel and pay attention to all the stuff above, then you will get rock solid 3msec latencies (plus eventual converter latencies but these are in the 1-2msec range AFAIK). Using multiple threads , pipes etc, only complicates your life and often makes it impossible to achieve these low latences. Realtime/audio programming is not an easy task , this is why people often fail to get the desired results even if their hardware is low-latency capable. The problem is that the final latency depends on the hardware you use, the application and the operating system. cheers, Benno. http://www.linuxaudiodev.org The Home of Linux Audio Development On Sat, 30 Jun 2001, you wrote: > On 2001-06-29 21:38 +0200, Benno Senoner wrote: > > > OSS/Free refuses to use a low # of frags ? > > > > That's a myth. > > I hope it is. :-) > > The fact is that ioctl(SNDCTL_DSP_SETFRAGMENT) succeeds with > values as low a 0x10007 (one 128-B fragment) but the latency is > still high enough to be clearly noticeable, which suggests that > it's *way* above 2/3 ms. This is on an otherwise idle machine > equipped with a SB PCI 128. > > But maybe it's me who's doing something wrong. I've been careful > to flush stdio buffers or use unbuffered I/O (write(2)) but I > may have let something else through. > > For example, since the signal processing and the I/O are done by > two different vanilla processes communicating via pipes, it may > be a scheduling granularity problem (E.G. the kernel giving the > I/O process a time slice every 20 ms). > > -- > André Majorel > http://www.teaser.fr/~amajorel/ > > dupswapdrop -- the music-dsp mailing list and website: subscription info, > FAQ, source code archive, list archive, book reviews, dsp links > http://shoko.calarts.edu/musicdsp/ -- dupswapdrop -- the music-dsp mailing list and website: subscription info, FAQ, source code archive, list archive, book reviews, dsp links http://shoko.calarts.edu/musicdsp/ portaudio-18.1.orig/Makefile.linux0000644000175000000620000000302007506124332017565 0ustar mikaelstaff00000000000000# Make PortAudio for Linux # Updated 2001/08/25 Bill Eldridge bill@rfa.org # Updated 2001/10/16, philburk@softsynth.com, s/unix_oss/unix_oss/ # Updated 2002/04/30 Bill Eldridge bill@rfa.org # Made the libinstall and tests compile a bit cleaner # A pretty bare makefile, that figures out all the test files # and compiles them against the library in the pa_unix_oss directory. # Do "make all" and then when happy, "make libinstall" # (if not happy, "make clean") # The ldconfig stuff in libinstall is the wrong way to do it - # someone tell me the right way, please LIBS = -lm -lpthread CDEFINES = -I../pa_common CFLAGS = -g LIBINST = /usr/local/lib TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) TESTO:= $(wildcard pa_tests/pa*.o pa_tests/debug*.o) LIBFILES:= ./pa_common/pa_lib.c ./pa_unix_oss/pa_unix_oss.c ./pa_unix_oss/pa_unix.c #all: sharedlib libinstall tests all: sharedlib libinstall testo testq .c.o: -gcc $(CFLAGS) -c -I./pa_common $< -o $*.o .o: -gcc $*.o -o $* -Lpa_unix_oss -lportaudio $(LIBS) #.c.o: # -gcc -c -I./pa_common $< -o $*.o # -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio sharedlib: $(LIBFILES:.c=.o) gcc -shared -o ./pa_unix_oss/libportaudio.so ./pa_common/pa_lib.o ./pa_unix_oss/pa_unix_oss.o ./pa_unix_oss/pa_unix.o libinstall: ./pa_unix_oss/libportaudio.so @cp -f ./pa_unix_oss/libportaudio.so $(LIBINST) @/sbin/ldconfig testo: $(TESTS:.c=.o) testq: $(TESTO:.o=) clean: -@rm -f $(TESTS:.c=.o) -@rm -f $(TESTS:.c=) -@rm -f $(LIBFILES:.c=.o) -@rm -f ./pa_unix_oss/libportaudio.so portaudio-18.1.orig/Makefile.mingw0000644000175000000620000000401707434671430017564 0ustar mikaelstaff00000000000000 # Makefile for PortAudio on mingw (http://mingw.sourceforge.net) # Contributed by Bill Eldridge, bill@rfa.org, Radio Free Asia # Copyright 2002/02/20, GPL # Uses a common mingw32 cross-compiler that defaults # to everything in /usr/local/cross-tools # First edit your path with # export PATH=/usr/local/cross-tools/bin:$PATH # Usage: make -f Makefile.mingw all # or make -f Makefile.mingw sharedlib # make -f Makefile.mingw tests # # Then copy executables & portaudio.dll to your Windows machine # # To make work with pa_win_ds, you'll have to substitue # all the pa_win_wmme files with pa_win_ds files, no biggie. CC= i586-mingw32msvc-gcc DLLTOOL= i586-mingw32msvc-dlltool DLLWRAP= i586-mingw32msvc-dllwrap ARCH= pa_win_wmme TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c) .c.o: -$(CC) -c -I./pa_common $< -o $*.o -$(CC) $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm all: sharedlib tests sharedlib: ./pa_common/pa_lib.c $(CC) -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o $(CC) -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o $(CC) -shared -mthreads -o portaudio.dll pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm $(DLLWRAP) --export-all --output-def=libportaudio.def --output-lib=libportaudio.a --dllname=portaudio.dll --drivername=i586-mingw32msvc-gcc pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm $(CC) -shared -Wl,--enable-auto-image-base -o portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm tests: $(TESTS:.c=.o) sine: $(CC) -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o $(CC) pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm clean: -rm ./pa_tests/*.exe -rm ./pa_tests/*.o nothing: $(CC) pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm portaudio-18.1.orig/pa_mac_core/0000755000175000000620000000000007700016420017216 5ustar mikaelstaff00000000000000portaudio-18.1.orig/pa_mac_core/notes.txt0000644000175000017500000000177207553745440021303 0ustar mikaelmikael00000000000000Notes on Core Audio Implementation of PortAudio by Phil Burk and Darren Gibbs Document last updated October 18, 2002 WHAT WORKS Output with very low latency, <10 msec. Half duplex input or output. Full duplex The paFLoat32, paInt16, paInt8, paUInt8 sample formats. Pa_GetCPULoad() Pa_StreamTime() KNOWN BUGS OR LIMITATIONS The iMic supports multiple sample rates. But there is a bug when changing sample rates: Run patest_record.c at rate A - it works. Then run patest_record.c at rate B - it FAIL! Then run patest_record.c again at rate B - it works! DEVICE MAPPING CoreAudio devices can support both input and output. But the sample rates supported may be different. So we have map one or two PortAudio device to each CoreAudio device depending on whether it supports input, output or both. When we query devices, we first get a list of CoreAudio devices. Then we scan the list and add a PortAudio device for each CoreAudio device that supports input. Then we make a scan for output devices. portaudio-18.1.orig/pa_mac_core/pa_mac_core.c0000644000175000017500000024167507647243452022016 0ustar mikaelmikael00000000000000/* * $Id: pa_mac_core.c,v 1.8.4.12 2003/04/16 19:06:01 philburk Exp $ * pa_mac_core.c * Implementation of PortAudio for Mac OS X Core Audio * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Authors: Ross Bencina and Phil Burk * Copyright (c) 1999-2002 Ross Bencina and Phil Burk * * Theory of Operation * * This code uses the HAL (Hardware Access Layer) of the Apple CoreAudio library. * This is the layer closes to the hardware. * The HAL layer only supports the native HW supported sample rates. * So if the chip only supports 44100 Hz, then the HAL only supports 44100. * To provide other rates we use the handy Apple AudioConverter which provides * sample rate conversion, mono-to-stereo conversion, and buffer size adaptation. * * There are four modes of operation: * PA_MODE_OUTPUT_ONLY, * PA_MODE_INPUT_ONLY, * PA_MODE_IO_ONE_DEVICE, * PA_MODE_IO_TWO_DEVICES * * The processing pipeline for PA_MODE_IO_ONE_DEVICE is in one thread: * * PaOSX_CoreAudioIOCallback() input buffers -> RingBuffer -> input.AudioConverter -> * PortAudio callback -> output.AudioConverter -> PaOSX_CoreAudioIOCallback() output buffers * * For two separate devices, we have to use two separate callbacks. * We pass data between them using a RingBuffer FIFO. * The processing pipeline for PA_MODE_IO_TWO_DEVICES is split into two threads: * * PaOSX_CoreAudioInputCallback() input buffers -> RingBuffer * * RingBuffer -> input.AudioConverter -> * PortAudio callback -> output.AudioConverter -> PaOSX_CoreAudioIOCallback() output buffers * * License * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * 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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * CHANGE HISTORY: 3.29.2001 - Phil Burk - First pass... converted from Window MME code with help from Darren. 3.30.2001 - Darren Gibbs - Added more support for dynamically querying device info. 12.7.2001 - Gord Peters - Tweaks to compile on PA V17 and OS X 10.1 2.7.2002 - Darren and Phil - fixed isInput so GetProperty works better, fixed device queries for numChannels and sampleRates, one CoreAudio device now maps to separate input and output PaDevices, audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices). 2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7 3.19.2002 - Phil Burk - Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file. Return error if opened in mono mode cuz not supported. [Supported 10.12.2002] Add support for Pa_GetCPULoad(); Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!) Check for invalid sample rates and return an error. Check for getenv("PA_MIN_LATENCY_MSEC") to set latency externally. Better error checking for invalid channel counts and invalid devices. 3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers. 3.31.2002 - Phil Burk - Use getrusage() instead of gettimeofday() for CPU Load calculation. 10.12.2002 - Phil Burk - Use AudioConverter to allow wide range of sample rates, and mono. Use FIFO (from pablio/rinbuffer.h) so that we can pull data through converter. Added PaOSX_FixVolumeScalar() to make iMic audible. 10.17.2002 - Phil Burk - Support full duplex between two different devices. Name internal functions PaOSX_* Dumped useless PA_MIN_LATENCY_MSEC environment variable. Use kAudioDevicePropertyStreamFormatMatch to determine max channels. 02.03.2003 - Phil Burk - always use AudioConverters so that we can adapt when format changes. Synchronize with device when format changes. 02.13.2003 - Phil Burk - scan for maxChannels because FormatMatch won't tell us. 03.05.2003 - Phil Burk and Dominic Mazzoni - interleave and deinterleave multiple CoreAudio buffers. Needed for MOTU828 and some other N>2 channel devices. See code related to "streamInterleavingBuffer". 03.06.2003 - Phil Burk and Ryan Francesconi - fixed numChannels query for MOTU828. Handle fact that MOTU828 gives you 8 channels even when you ask for 2! 04.06.2003 - Phil Burk - Combine Dominic Mazzoni's technique of using Configuration to query maxChannels with old technique of scanning for mormat. Increase channel scan by 1 to handle mono USB microphones. Do not merge or split channels in AudioConverter to handle 2+2 channels of Quattro which has a format of 2 channels. 04.07.2003 - Phil Burk - use AudioGetCurrentHostTime instead of getrusage() which can lock threads. 04.10.2003 - Phil Burk - fixed pointer bug with input deinterleaving loop. Detect and ignore NULL inputData and outputData in CodeAudio callback. Overlap creation and deletion of AudioConverters to prevent thread death when device rate changes. 04.16.2003 - Phil Burk - Fixed input channel scrambling when numChannels != 2^N. Caused by alignment error when filling RingBuffer with 2^N zero bytes. */ #include #include #include #include #include #include #include #include #include #include "portaudio.h" #include "pa_host.h" #include "pa_trace.h" #include "ringbuffer.h" /************************************************* Configuration ********/ #define PA_ENABLE_LOAD_MEASUREMENT (1) /************************************************* Constants ********/ #define SET_DEVICE_BUFFER_SIZE (1) /* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ #define PA_TRACE_RUN (0) #define PA_TRACE_START_STOP (0) #define PA_MIN_LATENCY_MSEC (20) /* FIXME */ #define MIN_TIMEOUT_MSEC (3000) #define PRINT(x) { printf x; fflush(stdout); } #define PRINT_ERR( msg, err ) PRINT(( msg ": error = 0x%0lX = '%s'\n", (err), ErrorToString(err)) ) #define DBUG(x) /* PRINT(x) */ #define DBUGBACK(x) /* if( sMaxBackgroundErrorMessages-- > 0 ) PRINT(x) */ #define DBUGX(x) // define value of isInput passed to CoreAudio routines #define IS_INPUT (true) #define IS_OUTPUT (false) typedef enum PaDeviceMode { PA_MODE_OUTPUT_ONLY, PA_MODE_INPUT_ONLY, PA_MODE_IO_ONE_DEVICE, PA_MODE_IO_TWO_DEVICES } PaDeviceMode; #define PA_USING_OUTPUT (pahsc->mode != PA_MODE_INPUT_ONLY) #define PA_USING_INPUT (pahsc->mode != PA_MODE_OUTPUT_ONLY) /************************************************************** * Information needed by PortAudio specific to a CoreAudio device. */ typedef struct PaHostInOut_s { AudioDeviceID audioDeviceID; /* CoreAudio specific ID */ int bytesPerUserNativeBuffer; /* User buffer size in native host format. Depends on numChannels. */ AudioConverterRef converter; void *converterBuffer; int numChannels; /** Used for interleaving or de-interleaving multiple streams for devices like MOTU828. */ int streamInterleavingBufferLen; /**< size in bytes */ Float32 *streamInterleavingBuffer; } PaHostInOut; /************************************************************** * Structure for internal host specific stream data. * This is allocated on a per stream basis. */ typedef struct PaHostSoundControl { PaHostInOut input; PaHostInOut output; AudioDeviceID primaryDeviceID; PaDeviceMode mode; RingBuffer ringBuffer; char *ringBufferData; Boolean formatListenerCalled; /* For measuring CPU utilization. */ UInt64 entryTime; double inverseHostTicksPerBuffer; /* 1/Ticks of real-time audio per user buffer. */ } PaHostSoundControl; /************************************************************** * Structure for internal extended device info query. * There will be one or two PortAudio devices for each Core Audio device: * one input and or one output. */ typedef struct PaHostDeviceInfo { PaDeviceInfo paInfo; AudioDeviceID audioDeviceID; } PaHostDeviceInfo; /************************************************* Shared Data ********/ /* FIXME - put Mutex around this shared data. */ static int sNumPaDevices = 0; /* Total number of PaDeviceInfos */ static int sNumInputDevices = 0; /* Total number of input PaDeviceInfos */ static int sNumOutputDevices = 0; static int sNumCoreDevices = 0; static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs static PaHostDeviceInfo *sDeviceInfos = NULL; static int sDefaultInputDeviceID = paNoDevice; static int sDefaultOutputDeviceID = paNoDevice; static int sSavedHostError = 0; static const double supportedSampleRateRange[] = { 8000.0, 96000.0 }; /* FIXME - go to double HW rate. */ static const char sMapperSuffixInput[] = " - Input"; static const char sMapperSuffixOutput[] = " - Output"; /* Debug support. */ //static int sMaxBackgroundErrorMessages = 100; //static int sCoverageCounter = 1; // used to check code coverage during validation /* We index the input devices first, then the output devices. */ #define LOWEST_INPUT_DEVID (0) #define HIGHEST_INPUT_DEVID (sNumInputDevices - 1) #define LOWEST_OUTPUT_DEVID (sNumInputDevices) #define HIGHEST_OUTPUT_DEVID (sNumPaDevices - 1) /************************************************* Macros ********/ /************************************************* Prototypes **********/ static PaError PaOSX_QueryDevices( void ); static int PaOSX_ScanDevices( Boolean isInput ); static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput ); static PaDeviceID PaOSX_QueryDefaultInputDevice( void ); static PaDeviceID PaOSX_QueryDefaultOutputDevice( void ); static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past ); static OSStatus PAOSX_DevicePropertyListener (AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void* inClientData); /**********************************************************************/ /* OS X errors are 4 character ID that can be printed. * Note that uses a static pad so result must be printed immediately. */ static OSStatus statusText[2] = { 0, 0 }; static const char *ErrorToString( OSStatus err ) { const char *str; switch (err) { case kAudioHardwareUnspecifiedError: str = "kAudioHardwareUnspecifiedError"; break; case kAudioHardwareNotRunningError: str = "kAudioHardwareNotRunningError"; break; case kAudioHardwareUnknownPropertyError: str = "kAudioHardwareUnknownPropertyError"; break; case kAudioDeviceUnsupportedFormatError: str = "kAudioDeviceUnsupportedFormatError"; break; case kAudioHardwareBadPropertySizeError: str = "kAudioHardwareBadPropertySizeError"; break; case kAudioHardwareIllegalOperationError: str = "kAudioHardwareIllegalOperationError"; break; default: statusText[0] = err; str = (const char *)statusText; break; } return str; } /**********************************************************************/ static unsigned long RoundUpToNextPowerOf2( unsigned long n ) { long numBits = 0; if( ((n-1) & n) == 0) return n; /* Already Power of two. */ while( n > 0 ) { n= n>>1; numBits++; } return (1<past_DeviceData; if( pahsc == NULL ) return; /* Query user CPU timer for usage analysis and to prevent overuse of CPU. */ pahsc->entryTime = AudioGetCurrentHostTime(); } /****************************************************************************** ** Measure fractional CPU load based on real-time it took to calculate ** buffers worth of output. */ static void Pa_EndUsageCalculation( internalPortAudioStream *past ) { UInt64 exitTime; UInt64 ticksElapsed; double newUsage; #define LOWPASS_COEFFICIENT_0 (0.95) #define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return; exitTime = AudioGetCurrentHostTime(); ticksElapsed = exitTime - pahsc->entryTime; /* Use inverse because it is faster than the divide. */ newUsage = ticksElapsed * pahsc->inverseHostTicksPerBuffer; /* Low pass filter result. */ past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + (LOWPASS_COEFFICIENT_1 * newUsage); } /****************************************** END CPU UTILIZATION *******/ /************************************************************************/ static PaDeviceID PaOSX_QueryDefaultInputDevice( void ) { OSStatus err = noErr; UInt32 count; int i; AudioDeviceID tempDeviceID = kAudioDeviceUnknown; PaDeviceID defaultDeviceID = paNoDevice; // get the default output device for the HAL // it is required to pass the size of the data to be returned count = sizeof(tempDeviceID); err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &tempDeviceID); if (err != noErr) goto error; // scan input devices to see which one matches this device defaultDeviceID = paNoDevice; for( i=LOWEST_INPUT_DEVID; i<=HIGHEST_INPUT_DEVID; i++ ) { DBUG(("PaOSX_QueryDefaultInputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID )); if( sDeviceInfos[i].audioDeviceID == tempDeviceID ) { defaultDeviceID = i; break; } } error: return defaultDeviceID; } /************************************************************************/ static PaDeviceID PaOSX_QueryDefaultOutputDevice( void ) { OSStatus err = noErr; UInt32 count; int i; AudioDeviceID tempDeviceID = kAudioDeviceUnknown; PaDeviceID defaultDeviceID = paNoDevice; // get the default output device for the HAL // it is required to pass the size of the data to be returned count = sizeof(tempDeviceID); err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &tempDeviceID); if (err != noErr) goto error; // scan output devices to see which one matches this device defaultDeviceID = paNoDevice; for( i=LOWEST_OUTPUT_DEVID; i<=HIGHEST_OUTPUT_DEVID; i++ ) { DBUG(("PaOSX_QueryDefaultOutputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID )); if( sDeviceInfos[i].audioDeviceID == tempDeviceID ) { defaultDeviceID = i; break; } } error: return defaultDeviceID; } /******************************************************************/ static PaError PaOSX_QueryDevices( void ) { OSStatus err = noErr; UInt32 outSize; Boolean outWritable; int numBytes; // find out how many Core Audio devices there are, if any outSize = sizeof(outWritable); err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &outSize, &outWritable); if (err != noErr) { PRINT_ERR("Couldn't get info about list of audio devices", err); sSavedHostError = err; return paHostError; } // calculate the number of device available sNumCoreDevices = outSize / sizeof(AudioDeviceID); // Bail if there aren't any devices if (sNumCoreDevices < 1) { PRINT(("No Devices Available")); return paHostError; } // make space for the devices we are about to get sCoreDeviceIDs = (AudioDeviceID *)malloc(outSize); // get an array of AudioDeviceIDs err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sCoreDeviceIDs); if (err != noErr) { PRINT_ERR("Couldn't get list of audio device IDs", err); sSavedHostError = err; return paHostError; } // Allocate structures to hold device info pointers. // There will be a maximum of two Pa devices per Core Audio device, input and/or output. numBytes = sNumCoreDevices * 2 * sizeof(PaHostDeviceInfo); sDeviceInfos = (PaHostDeviceInfo *) PaHost_AllocateFastMemory( numBytes ); if( sDeviceInfos == NULL ) return paInsufficientMemory; // Scan all the Core Audio devices to see which support input and allocate a // PaHostDeviceInfo structure for each one. DBUG(("PaOSX_QueryDevices: scan for input ======================\n")); PaOSX_ScanDevices( IS_INPUT ); sNumInputDevices = sNumPaDevices; // Now scan all the output devices. DBUG(("PaOSX_QueryDevices: scan for output ======================\n")); PaOSX_ScanDevices( IS_OUTPUT ); sNumOutputDevices = sNumPaDevices - sNumInputDevices; // Figure out which of the devices that we scanned is the default device. sDefaultInputDeviceID = PaOSX_QueryDefaultInputDevice(); sDefaultOutputDeviceID = PaOSX_QueryDefaultOutputDevice(); return paNoError; } /*************************************************************************/ /* Query a device for its sample rate. * @return positive rate or 0.0 on error. */ static Float64 PaOSX_GetDeviceSampleRate( AudioDeviceID deviceID, Boolean isInput ) { OSStatus err = noErr; AudioStreamBasicDescription formatDesc; UInt32 dataSize; dataSize = sizeof(formatDesc); err = AudioDeviceGetProperty( deviceID, 0, isInput, kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc); if( err != noErr ) return 0.0; else return formatDesc.mSampleRate; } /*************************************************************************/ /* Allocate a string containing the device name. */ static char *PaOSX_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput ) { OSStatus err = noErr; UInt32 outSize; Boolean outWritable; char *deviceName = nil; // query size of name err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, &outWritable); if (err == noErr) { deviceName = (char*)malloc( outSize + 1); if( deviceName ) { err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, deviceName); if (err != noErr) PRINT_ERR("Couldn't get audio device name", err); } } return deviceName; } /************************************************************************* ** Scan all of the Core Audio devices to see which support selected ** input or output mode. ** Changes sNumDevices, and fills in sDeviceInfos. */ static int PaOSX_ScanDevices( Boolean isInput ) { int coreDeviceIndex; int result; PaHostDeviceInfo *hostDeviceInfo; int numAdded = 0; for( coreDeviceIndex=0; coreDeviceIndex 0 ) { sNumPaDevices += 1; // bump global counter if we got one numAdded += 1; } else if( result < 0 ) return result; } return numAdded; } /************************************************************************* ** Determine the maximum number of channels based on the configuration. ** @return maxChannels or negative error. */ static int PaOSX_GetMaxChannels_Config( AudioDeviceID devID, Boolean isInput ) { OSStatus err; UInt32 outSize; Boolean outWritable; AudioBufferList *list; int numChannels; int i; // Determine maximum number of channels supported. // dmazzoni: new method outSize = 0; err = AudioDeviceGetPropertyInfo(devID, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable); if ( err != noErr ) { PRINT_ERR("PaOSX_GetMaxChannels_Config: Could not get stream configuration info", err); sSavedHostError = err; return paHostError; } list = (AudioBufferList *)PaHost_AllocateFastMemory( outSize ); err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, list); if ( err != noErr ) { PRINT_ERR("PaOSX_GetMaxChannels_Config: Could not get stream configuration", err); sSavedHostError = err; return paHostError; } numChannels = 0; for( i=0; imNumberBuffers; i++ ) { int bufChannels = list->mBuffers[i].mNumberChannels; DBUG(("PaOSX_GetMaxChannels_Config: buffer %d has %d channels.\n", i, bufChannels )); numChannels += bufChannels; } PaHost_FreeFastMemory( list, outSize ); return numChannels; } /************************************************************************* ** Determine the maximum number of channels a device will support based on scanning the format. ** @return maxChannels or negative error. */ static int PaOSX_GetMaxChannels_Format( AudioDeviceID devID, Boolean isInput ) { OSStatus err; UInt32 outSize; AudioStreamBasicDescription formatDesc; int maxChannels; int numChannels; Boolean gotMax; // Scan to find highest matching format. // Unfortunately some devices won't just return maxChannels for the match. // For example, some 8 channel devices return 2 when given 256 as input. gotMax = false; maxChannels = 0; numChannels = 0; while( !gotMax ) { memset( &formatDesc, 0, sizeof(formatDesc)); numChannels = numChannels + 1; DBUG(("PaOSX_GetMaxChannels: try numChannels = %d = %d + 1\n", numChannels, numChannels )); formatDesc.mChannelsPerFrame = numChannels; outSize = sizeof(formatDesc); err = AudioDeviceGetProperty( devID, 0, isInput, kAudioDevicePropertyStreamFormatMatch, &outSize, &formatDesc); DBUG(("PaOSX_GetMaxChannels: err 0x%0x, formatDesc.mChannelsPerFrame= %d\n", err, formatDesc.mChannelsPerFrame )); if( err != noErr ) { if (numChannels > (maxChannels + 4)) // Try several possibilities above current max { gotMax = true; } } else { // This value worked so we have a new candidate for maxChannels. if (formatDesc.mChannelsPerFrame > numChannels) { maxChannels = formatDesc.mChannelsPerFrame; } else if(formatDesc.mChannelsPerFrame < numChannels) { if (numChannels > (maxChannels + 4)) // Try several possibilities above current max { gotMax = true; } } else { maxChannels = numChannels; } } } return maxChannels; } /************************************************************************* ** Determine the maximum number of channels a device will support. ** It is not clear at this point which the better technique so ** we do both and use the biggest result. ** ** @return maxChannels or negative error. */ static int PaOSX_GetMaxChannels( AudioDeviceID devID, Boolean isInput ) { int maxChannelsFormat; int maxChannelsConfig; maxChannelsFormat = PaOSX_GetMaxChannels_Format( devID, isInput ); maxChannelsConfig = PaOSX_GetMaxChannels_Config( devID, isInput ); return (maxChannelsFormat > maxChannelsConfig) ? maxChannelsFormat : maxChannelsConfig; } /************************************************************************* ** Try to fill in the device info for this device. ** Return 1 if a good device that PA can use. ** Return 0 if not appropriate ** or return negative error. ** */ static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput ) { OSStatus err; UInt32 outSize; AudioStreamBasicDescription formatDesc; AudioDeviceID devID; PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo; int maxChannels; deviceInfo->structVersion = 1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->sampleRates = supportedSampleRateRange; // because we use sample rate converter to get continuous rates deviceInfo->numSampleRates = -1; devID = sCoreDeviceIDs[ coreDeviceIndex ]; hostDeviceInfo->audioDeviceID = devID; DBUG(("PaOSX_QueryDeviceInfo: coreDeviceIndex = %d, devID = %d, isInput = %d\n", coreDeviceIndex, (int) devID, isInput )); // Get data format info from the device. outSize = sizeof(formatDesc); err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc); // This just may not be an appropriate device for input or output so leave quietly. if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error; DBUG(("PaOSX_QueryDeviceInfo: mFormatID = 0x%x\n", (unsigned int) formatDesc.mFormatID)); DBUG(("PaOSX_QueryDeviceInfo: mFormatFlags = 0x%x\n",(unsigned int) formatDesc.mFormatFlags)); // Right now the Core Audio headers only define one formatID: LinearPCM // Apparently LinearPCM must be Float32 for now. if( (formatDesc.mFormatID == kAudioFormatLinearPCM) && ((formatDesc.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) ) { deviceInfo->nativeSampleFormats = paFloat32; } else { PRINT(("PaOSX_QueryDeviceInfo: ERROR - not LinearPCM & Float32!!!\n")); return paSampleFormatNotSupported; } maxChannels = PaOSX_GetMaxChannels( devID, isInput ); if( maxChannels <= 0 ) goto error; if( isInput ) { deviceInfo->maxInputChannels = maxChannels; } else { deviceInfo->maxOutputChannels = maxChannels; } // Get the device name deviceInfo->name = PaOSX_DeviceNameFromID( devID, isInput ); DBUG(("PaOSX_QueryDeviceInfo: name = %s\n", deviceInfo->name )); return 1; error: return 0; } /**********************************************************************/ static PaError PaOSX_MaybeQueryDevices( void ) { if( sNumPaDevices == 0 ) { return PaOSX_QueryDevices(); } return 0; } static char zeroPad[256] = { 0 }; /********************************************************************** ** This is the proc that supplies the data to the AudioConverterFillBuffer call. ** We can pass back arbitrarily sized blocks so if the FIFO region is split ** just pass back the first half. */ static OSStatus PaOSX_InputConverterCallbackProc (AudioConverterRef inAudioConverter, UInt32* outDataSize, void** outData, void* inUserData) { internalPortAudioStream *past = (internalPortAudioStream *) inUserData; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; void *dataPtr1; long size1; void *dataPtr2; long size2; /* Pass contiguous region from FIFO directly to converter. */ RingBuffer_GetReadRegions( &pahsc->ringBuffer, *outDataSize, &dataPtr1, &size1, &dataPtr2, &size2 ); if( size1 > 0 ) { *outData = dataPtr1; *outDataSize = size1; RingBuffer_AdvanceReadIndex( &pahsc->ringBuffer, size1 ); DBUGX(("PaOSX_InputConverterCallbackProc: read %ld bytes from FIFO.\n", size1 )); } else { DBUGBACK(("PaOSX_InputConverterCallbackProc: got no data!\n")); *outData = zeroPad; /* Give it zero data to keep it happy. */ *outDataSize = sizeof(zeroPad); } return noErr; } /***************************************************************************** ** Get audio input, if any, from passed in buffer, or from converter or from FIFO, ** then run PA callback and output data. */ static OSStatus PaOSX_LoadAndProcess( internalPortAudioStream *past, void *inputBuffer, void *outputBuffer ) { OSStatus err = noErr; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( past->past_StopSoon ) { if( outputBuffer ) { /* Clear remainder of audio buffer if we are waiting for stop. */ AddTraceMessage("PaOSX_LoadAndProcess: zero rest of wave buffer ", i ); memset( outputBuffer, 0, pahsc->output.bytesPerUserNativeBuffer ); } } else { /* Do we need data from the converted input? */ if( PA_USING_INPUT ) { UInt32 size = pahsc->input.bytesPerUserNativeBuffer; err = AudioConverterFillBuffer( pahsc->input.converter, PaOSX_InputConverterCallbackProc, past, &size, pahsc->input.converterBuffer); if( err != noErr ) return err; inputBuffer = pahsc->input.converterBuffer; } /* Measure CPU load. */ #if PA_ENABLE_LOAD_MEASUREMENT Pa_StartUsageCalculation( past ); #endif /* Fill part of audio converter buffer by converting input to user format, * calling user callback, then converting output to native format. */ if( PaConvert_Process( past, inputBuffer, outputBuffer )) { past->past_StopSoon = 1; } #if PA_ENABLE_LOAD_MEASUREMENT Pa_EndUsageCalculation( past ); #endif } return err; } /***************************************************************************** ** This is the proc that supplies the data to the AudioConverterFillBuffer call */ static OSStatus PaOSX_OutputConverterCallbackProc (AudioConverterRef inAudioConverter, UInt32* outDataSize, void** outData, void* inUserData) { internalPortAudioStream *past = (internalPortAudioStream *) inUserData; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; *outData = pahsc->output.converterBuffer; *outDataSize = pahsc->output.bytesPerUserNativeBuffer; return PaOSX_LoadAndProcess ( past, pahsc->input.converterBuffer, pahsc->output.converterBuffer ); } /********************************************************************** ** If data available, write it to the Ring Buffer so we can ** pull it from the other side. */ static OSStatus PaOSX_WriteInputRingBuffer( internalPortAudioStream *past, const AudioBufferList* inInputData ) { int numBytes = 0; int currentInterleavedChannelIndex; int numFramesInInputBuffer; int numInterleavedChannels; int numChannelsRemaining; int i; long writeRoom; char *inputNativeBufferfPtr = NULL; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; /* Do we need to deinterleave the buffers first? */ if( past->past_NumInputChannels != inInputData->mBuffers[0].mNumberChannels ) { numFramesInInputBuffer = inInputData->mBuffers[0].mDataByteSize / (sizeof(float) * inInputData->mBuffers[0].mNumberChannels); numBytes = numFramesInInputBuffer * sizeof(float) * past->past_NumInputChannels; /* Allocate temporary buffer if needed. */ if ( (pahsc->input.streamInterleavingBuffer != NULL) && (pahsc->input.streamInterleavingBufferLen < numBytes) ) { PaHost_FreeFastMemory( pahsc->input.streamInterleavingBuffer, pahsc->input.streamInterleavingBufferLen ); pahsc->input.streamInterleavingBuffer = NULL; } if ( pahsc->input.streamInterleavingBuffer == NULL ) { pahsc->input.streamInterleavingBufferLen = numBytes; pahsc->input.streamInterleavingBuffer = (float *)PaHost_AllocateFastMemory( pahsc->input.streamInterleavingBufferLen ); } /* Perform interleaving by writing to temp buffer. */ currentInterleavedChannelIndex = 0; numInterleavedChannels = past->past_NumInputChannels; numChannelsRemaining = numInterleavedChannels; for( i=0; imNumberBuffers; i++ ) { int j; int numBufChannels = inInputData->mBuffers[i].mNumberChannels; /* Don't use more than we need or more than we have. */ int numChannelsUsedInThisBuffer = (numChannelsRemaining < numBufChannels ) ? numChannelsRemaining : numBufChannels; for( j=0; jinput.streamInterleavingBuffer[ currentInterleavedChannelIndex ]; float *src = &((float *)inInputData->mBuffers[i].mData)[ j ]; /* Move one channel from CoreAudio buffer to interleaved buffer. */ for( k=0; kinput.streamInterleavingBuffer; } else { inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData; numBytes = inInputData->mBuffers[0].mDataByteSize; } writeRoom = RingBuffer_GetWriteAvailable( &pahsc->ringBuffer ); if( numBytes <= writeRoom ) { RingBuffer_Write( &pahsc->ringBuffer, inputNativeBufferfPtr, numBytes ); DBUGBACK(("PaOSX_WriteInputRingBuffer: wrote %ld bytes to FIFO.\n", numBytes)); } // FIXME else drop samples on floor, remember overflow??? return noErr; } /********************************************************************** ** Use any available input buffers by writing to RingBuffer. ** Process input if PA_MODE_INPUT_ONLY. */ static OSStatus PaOSX_HandleInput( internalPortAudioStream *past, const AudioBufferList* inInputData ) { OSStatus err = noErr; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( inInputData == NULL ) { DBUG(("PaOSX_HandleInput: inInputData == NULL\n")); return noErr; } if( inInputData->mNumberBuffers > 0 ) { /* Write to FIFO here if we are only using this callback. */ if( (pahsc->mode == PA_MODE_INPUT_ONLY) || (pahsc->mode == PA_MODE_IO_ONE_DEVICE) ) { err = PaOSX_WriteInputRingBuffer( past, inInputData ); if( err != noErr ) goto error; } } if( pahsc->mode == PA_MODE_INPUT_ONLY ) { /* Generate user buffers as long as we have a half full input FIFO. */ long halfSize = pahsc->ringBuffer.bufferSize / 2; while( (RingBuffer_GetReadAvailable( &pahsc->ringBuffer ) >= halfSize) && (past->past_StopSoon == 0) ) { err = PaOSX_LoadAndProcess ( past, NULL, NULL ); if( err != noErr ) goto error; } } error: return err; } /********************************************************************** ** Fill any available output buffers. */ static OSStatus PaOSX_HandleOutput( internalPortAudioStream *past, AudioBufferList* outOutputData ) { OSStatus err = noErr; void *outputNativeBufferfPtr = NULL; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; UInt32 numBytes = 0; int numChannelsRemaining; Boolean deinterleavingNeeded; int numFramesInOutputBuffer; if( outOutputData == NULL ) { DBUG(("PaOSX_HandleOutput: outOutputData == NULL\n")); return noErr; } deinterleavingNeeded = past->past_NumOutputChannels != outOutputData->mBuffers[0].mNumberChannels; numFramesInOutputBuffer = outOutputData->mBuffers[0].mDataByteSize / (sizeof(float) * outOutputData->mBuffers[0].mNumberChannels); if( pahsc->mode != PA_MODE_INPUT_ONLY ) { /* If we are using output, then we need an empty output buffer. */ if( outOutputData->mNumberBuffers > 0 ) { /* If we have multiple CoreAudio buffers, then we will need to deinterleave after conversion. */ if( deinterleavingNeeded ) { numBytes = numFramesInOutputBuffer * sizeof(float) * past->past_NumOutputChannels; /* Free old buffer if we are allocating new one. */ if ( (pahsc->output.streamInterleavingBuffer != NULL) && (pahsc->output.streamInterleavingBufferLen < numBytes) ) { PaHost_FreeFastMemory( pahsc->output.streamInterleavingBuffer, pahsc->output.streamInterleavingBufferLen ); pahsc->output.streamInterleavingBuffer = NULL; } /* Allocate interleaving buffer if needed. */ if ( pahsc->output.streamInterleavingBuffer == NULL ) { pahsc->output.streamInterleavingBufferLen = numBytes; pahsc->output.streamInterleavingBuffer = (float *)PaHost_AllocateFastMemory( pahsc->output.streamInterleavingBufferLen ); } outputNativeBufferfPtr = (void*)pahsc->output.streamInterleavingBuffer; } else { numBytes = outOutputData->mBuffers[0].mDataByteSize; outputNativeBufferfPtr = (void*)outOutputData->mBuffers[0].mData; } /* Pull data from PA user through converter. */ err = AudioConverterFillBuffer( pahsc->output.converter, PaOSX_OutputConverterCallbackProc, past, &numBytes, outputNativeBufferfPtr); if( err != noErr ) { PRINT_ERR("PaOSX_HandleOutput: AudioConverterFillBuffer failed", err); goto error; } /* Deinterleave data from PortAudio and write to multiple CoreAudio buffers. */ if( deinterleavingNeeded ) { int numInterleavedChannels = past->past_NumOutputChannels; int i, currentInterleavedChannelIndex = 0; numChannelsRemaining = numInterleavedChannels; for( i=0; imNumberBuffers; i++ ) { int numBufChannels = outOutputData->mBuffers[i].mNumberChannels; int j; /* Don't use more than we need or more than we have. */ int numChannelsUsedInThisBuffer = (numChannelsRemaining < numBufChannels ) ? numChannelsRemaining : numBufChannels; for( j=0; jmBuffers[i].mData)[ j ]; float *src = &pahsc->output.streamInterleavingBuffer[ currentInterleavedChannelIndex ]; /* Move one channel from interleaved buffer to CoreAudio buffer. */ for( k=0; kpast_DeviceData; /* If there is a FIFO for input then write to it. */ if( (pahsc->ringBufferData != NULL) && (inInputData != NULL) ) { err = PaOSX_WriteInputRingBuffer( past, inInputData ); if( err != noErr ) goto error; } error: return err; } /****************************************************************** * This is the primary callback for CoreAudio. * It can handle input and/or output for a single device. * It takes input from CoreAudio, converts it and passes it to the * PortAudio user callback. Then takes the PA results and passes it * back to CoreAudio. */ static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* contextPtr) { OSStatus err = noErr; internalPortAudioStream *past; PaHostSoundControl *pahsc; past = (internalPortAudioStream *) contextPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; /* Has someone asked us to abort by calling Pa_AbortStream()? */ if( past->past_StopNow ) { past->past_IsActive = 0; /* Will cause thread to return. */ } /* Has someone asked us to stop by calling Pa_StopStream() * OR has a user callback returned '1' to indicate finished. */ else if( past->past_StopSoon ) { // FIXME - Pretend all done. Should wait for audio to play out but CoreAudio latency very low. past->past_IsActive = 0; /* Will cause thread to return. */ } else { /* use time stamp from CoreAudio if valid */ if( inOutputTime->mFlags & kAudioTimeStampSampleTimeValid) { past->past_FrameCount = inOutputTime->mSampleTime; } else if( inInputTime->mFlags & kAudioTimeStampSampleTimeValid) { past->past_FrameCount = inInputTime->mSampleTime; } past->past_NumCallbacks += 1; /* Process full input buffer. */ err = PaOSX_HandleInput( past, inInputData ); if( err != 0 ) goto error; /* Fill up empty output buffers. */ err = PaOSX_HandleOutput( past, outOutputData ); if( err != 0 ) goto error; } if( err != 0 ) DBUG(("PaOSX_CoreAudioIOCallback: returns %ld.\n", err )); error: return err; } /*******************************************************************/ /** Attempt to set device sample rate. * This is not critical because we use an AudioConverter but we may * get better fidelity if we can avoid resampling. * * Only set format once because some devices take time to settle. * Return flag indicating whether format changed so we know whether to wait * for DevicePropertyListener to get called. * * @return negative error, zero if no change, or one if changed successfully. */ static PaError PaOSX_SetFormat( AudioDeviceID devID, Boolean isInput, double desiredRate, int desiredNumChannels ) { AudioStreamBasicDescription formatDesc; PaError result = 0; OSStatus err; UInt32 dataSize; Float64 originalRate; int originalChannels; /* Get current device format. This is critical because if we pass * zeros for unspecified fields then the iMic device gets switched to a 16 bit * integer format!!! I don't know if this is a Mac bug or not. But it only * started happening when I upgraded from OS X V10.1 to V10.2 (Jaguar). */ dataSize = sizeof(formatDesc); err = AudioDeviceGetProperty( devID, 0, isInput, kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc); if( err != noErr ) { PRINT_ERR("PaOSX_SetFormat: Could not get format.", err); sSavedHostError = err; return paHostError; } originalRate = formatDesc.mSampleRate; originalChannels = formatDesc.mChannelsPerFrame; // Is it already set to the correct format? if( (originalRate != desiredRate) || (originalChannels != desiredNumChannels) ) { DBUG(("PaOSX_SetFormat: try to change sample rate to %f.\n", desiredRate )); DBUG(("PaOSX_SetFormat: try to set number of channels to %d\n", desiredNumChannels)); formatDesc.mSampleRate = desiredRate; formatDesc.mChannelsPerFrame = desiredNumChannels; formatDesc.mBytesPerFrame = formatDesc.mChannelsPerFrame * sizeof(float); formatDesc.mBytesPerPacket = formatDesc.mBytesPerFrame * formatDesc.mFramesPerPacket; err = AudioDeviceSetProperty( devID, 0, 0, isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); if (err != noErr) { /* Could not set to desired rate so query for closest match. */ dataSize = sizeof(formatDesc); err = AudioDeviceGetProperty( devID, 0, isInput, kAudioDevicePropertyStreamFormatMatch, &dataSize, &formatDesc); DBUG(("PaOSX_SetFormat: closest rate is %f.\n", formatDesc.mSampleRate )); DBUG(("PaOSX_SetFormat: closest numChannels is %d.\n", (int)formatDesc.mChannelsPerFrame )); // Set to closest if different from original. if( (err == noErr) && ((originalRate != formatDesc.mSampleRate) || (originalChannels != formatDesc.mChannelsPerFrame)) ) { err = AudioDeviceSetProperty( devID, 0, 0, isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); if( err == noErr ) result = 1; } } else result = 1; } return result; } /******************************************************************* * Check volume level of device. If below threshold, then set to newLevel. * Using volume instead of decibels because decibel range varies by device. */ static void PaOSX_FixVolumeScalars( AudioDeviceID devID, Boolean isInput, int numChannels, double threshold, double newLevel ) { OSStatus err = noErr; UInt32 dataSize; int iChannel; /* The master channel is 0. Left and right are channels 1 and 2. */ /* Fix volume. */ for( iChannel = 0; iChannel<=numChannels; iChannel++ ) { Float32 fdata32; dataSize = sizeof( fdata32 ); err = AudioDeviceGetProperty( devID, iChannel, isInput, kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 ); if( err == noErr ) { DBUG(("kAudioDevicePropertyVolumeScalar for channel %d = %f\n", iChannel, fdata32)); if( fdata32 <= (Float32) threshold ) { dataSize = sizeof( fdata32 ); fdata32 = (Float32) newLevel; err = AudioDeviceSetProperty( devID, 0, iChannel, isInput, kAudioDevicePropertyVolumeScalar, dataSize, &fdata32 ); if( err != noErr ) { PRINT(("Warning: audio volume is very low and could not be turned up.\n")); } else { PRINT(("Volume for audio channel %d was <= %4.2f so set to %4.2f by PortAudio!\n", iChannel, threshold, newLevel )); } } } } /* Unmute if muted. */ for( iChannel = 0; iChannel<=numChannels; iChannel++ ) { UInt32 uidata32; dataSize = sizeof( uidata32 ); err = AudioDeviceGetProperty( devID, iChannel, isInput, kAudioDevicePropertyMute, &dataSize, &uidata32 ); if( err == noErr ) { DBUG(("mute for channel %d = %ld\n", iChannel, uidata32)); if( uidata32 == 1 ) // muted? { dataSize = sizeof( uidata32 ); uidata32 = 0; // unmute err = AudioDeviceSetProperty( devID, 0, iChannel, isInput, kAudioDevicePropertyMute, dataSize, &uidata32 ); if( err != noErr ) { PRINT(("Warning: audio is muted and could not be unmuted!\n")); } else { PRINT(("Audio channel %d was unmuted by PortAudio!\n", iChannel )); } } } } } #if 0 static void PaOSX_DumpDeviceInfo( AudioDeviceID devID, Boolean isInput ) { OSStatus err = noErr; UInt32 dataSize; UInt32 uidata32; Float32 fdata32; AudioValueRange audioRange; dataSize = sizeof( uidata32 ); err = AudioDeviceGetProperty( devID, 0, isInput, kAudioDevicePropertyLatency, &dataSize, &uidata32 ); if( err != noErr ) { PRINT_ERR("Error reading kAudioDevicePropertyLatency", err); return; } PRINT(("kAudioDevicePropertyLatency = %d\n", (int)uidata32 )); dataSize = sizeof( fdata32 ); err = AudioDeviceGetProperty( devID, 1, isInput, kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 ); if( err != noErr ) { PRINT_ERR("Error reading kAudioDevicePropertyVolumeScalar", err); return; } PRINT(("kAudioDevicePropertyVolumeScalar = %f\n", fdata32 )); dataSize = sizeof( uidata32 ); err = AudioDeviceGetProperty( devID, 0, isInput, kAudioDevicePropertyBufferSize, &dataSize, &uidata32 ); if( err != noErr ) { PRINT_ERR("Error reading buffer size", err); return; } PRINT(("kAudioDevicePropertyBufferSize = %d bytes\n", (int)uidata32 )); dataSize = sizeof( audioRange ); err = AudioDeviceGetProperty( devID, 0, isInput, kAudioDevicePropertyBufferSizeRange, &dataSize, &audioRange ); if( err != noErr ) { PRINT_ERR("Error reading buffer size range", err); return; } PRINT(("kAudioDevicePropertyBufferSizeRange = %g to %g bytes\n", audioRange.mMinimum, audioRange.mMaximum )); dataSize = sizeof( uidata32 ); err = AudioDeviceGetProperty( devID, 0, isInput, kAudioDevicePropertyBufferFrameSize, &dataSize, &uidata32 ); if( err != noErr ) { PRINT_ERR("Error reading buffer size", err); return; } PRINT(("kAudioDevicePropertyBufferFrameSize = %d frames\n", (int)uidata32 )); dataSize = sizeof( audioRange ); err = AudioDeviceGetProperty( devID, 0, isInput, kAudioDevicePropertyBufferFrameSizeRange, &dataSize, &audioRange ); if( err != noErr ) { PRINT_ERR("Error reading buffer size range", err); return; } PRINT(("kAudioDevicePropertyBufferFrameSizeRange = %g to %g frames\n", audioRange.mMinimum, audioRange.mMaximum )); return; } #endif /*******************************************************************/ static OSStatus PAOSX_DevicePropertyListener (AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void* inClientData) { PaHostSoundControl *pahsc; internalPortAudioStream *past; UInt32 dataSize; OSStatus err = noErr; AudioStreamBasicDescription userStreamFormat, hardwareStreamFormat; PaHostInOut *hostInOut; AudioStreamBasicDescription *destFormatPtr, *srcFormatPtr; past = (internalPortAudioStream *) inClientData; pahsc = (PaHostSoundControl *) past->past_DeviceData; DBUG(("PAOSX_DevicePropertyListener: called with propertyID = 0x%0X\n", (unsigned int) inPropertyID )); if(inPropertyID == kAudioDevicePropertyStreamFormat) { /* Get target device format */ dataSize = sizeof(hardwareStreamFormat); err = AudioDeviceGetProperty(inDevice, 0, isInput, kAudioDevicePropertyStreamFormat, &dataSize, &hardwareStreamFormat); if( err != noErr ) { PRINT_ERR("PAOSX_DevicePropertyListener: Could not get device format", err); sSavedHostError = err; goto error; } DBUG(("PAOSX_DevicePropertyListener: HW mChannelsPerFrame = %d\n", (int)hardwareStreamFormat.mChannelsPerFrame )); /* Set source user format. */ userStreamFormat = hardwareStreamFormat; userStreamFormat.mSampleRate = past->past_SampleRate; // sample rate of the user synthesis code userStreamFormat.mChannelsPerFrame = (isInput) ? past->past_NumInputChannels : past->past_NumOutputChannels; // the number of channels in each frame DBUG(("PAOSX_DevicePropertyListener: User mChannelsPerFrame = %d\n", (int)userStreamFormat.mChannelsPerFrame )); userStreamFormat.mBytesPerFrame = userStreamFormat.mChannelsPerFrame * sizeof(float); userStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerFrame * userStreamFormat.mFramesPerPacket; /* Don't use AudioConverter for merging or splitting channels. */ hardwareStreamFormat.mChannelsPerFrame = userStreamFormat.mChannelsPerFrame; hardwareStreamFormat.mBytesPerFrame = userStreamFormat.mBytesPerFrame; hardwareStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerPacket; if( isInput ) { hostInOut = &pahsc->input; srcFormatPtr = &hardwareStreamFormat; destFormatPtr = &userStreamFormat; } else { hostInOut = &pahsc->output; srcFormatPtr = &userStreamFormat; destFormatPtr = &hardwareStreamFormat; } DBUG(("PAOSX_DevicePropertyListener: source rate = %f\n", srcFormatPtr->mSampleRate )); DBUG(("PAOSX_DevicePropertyListener: dest rate = %f\n", destFormatPtr->mSampleRate )); // Don't delete old converter until we create new one so we don't pull // the rug out from under other audio threads. AudioConverterRef oldConverter = hostInOut->converter; // Make converter to change sample rate. err = AudioConverterNew ( srcFormatPtr, destFormatPtr, &hostInOut->converter ); if( err != noErr ) { PRINT_ERR("Could not create format converter", err); sSavedHostError = err; goto error; } if( oldConverter != NULL ) { verify_noerr( AudioConverterDispose( oldConverter ) ); } } error: pahsc->formatListenerCalled = true; return err; } /* Allocate FIFO between Device callback and Converter callback so that device can push data * and converter can pull data. */ static PaError PaOSX_CreateInputRingBuffer( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; OSStatus err = noErr; UInt32 dataSize; double sampleRateRatio; long numBytes; UInt32 framesPerHostBuffer; UInt32 bytesForDevice; UInt32 bytesForUser; UInt32 bytesPerFrame; AudioStreamBasicDescription formatDesc; dataSize = sizeof(formatDesc); err = AudioDeviceGetProperty( pahsc->input.audioDeviceID, 0, IS_INPUT, kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc); if( err != noErr ) { PRINT_ERR("PaOSX_CreateInputRingBuffer: Could not get input format.\n", err); sSavedHostError = err; return paHostError; } // If device is delivering audio faster than being consumed then buffer must be bigger. sampleRateRatio = formatDesc.mSampleRate / past->past_SampleRate; // Get size of CoreAudio IO buffers. dataSize = sizeof(framesPerHostBuffer); err = AudioDeviceGetProperty( pahsc->input.audioDeviceID, 0, IS_INPUT, kAudioDevicePropertyBufferFrameSize, &dataSize, &framesPerHostBuffer); if( err != noErr ) { PRINT_ERR("PaOSX_CreateInputRingBuffer: Could not get input buffer size.\n", err); sSavedHostError = err; return paHostError; } bytesPerFrame = past->past_NumInputChannels * sizeof(Float32); bytesForDevice = framesPerHostBuffer * bytesPerFrame * 2; bytesForUser = past->past_FramesPerUserBuffer * bytesPerFrame * 3 * sampleRateRatio; // Ring buffer should be large enough to consume audio input from device, // and to deliver a complete user buffer. numBytes = (bytesForDevice > bytesForUser) ? bytesForDevice : bytesForUser; numBytes = RoundUpToNextPowerOf2( numBytes ); DBUG(("PaOSX_CreateInputRingBuffer: FIFO numBytes = %ld\n", numBytes)); pahsc->ringBufferData = PaHost_AllocateFastMemory( numBytes ); if( pahsc->ringBufferData == NULL ) { return paInsufficientMemory; } RingBuffer_Init( &pahsc->ringBuffer, numBytes, pahsc->ringBufferData ); // Make it look almost full at beginning. We must advance by an integral number of frames // so that the channels don't get scrambled when numChannels is not a power of 2. { int numZeroFrames = numBytes / bytesPerFrame; int numZeroBytes = numZeroFrames * bytesPerFrame; RingBuffer_AdvanceWriteIndex( &pahsc->ringBuffer, numZeroBytes ); } return paNoError; } /****************************************************************** * Try to set the I/O bufferSize of the device. * Scale the size by the ratio of the sample rates so that the converter will have * enough data to operate on. */ static OSStatus PaOSX_SetDeviceBufferSize( AudioDeviceID devID, Boolean isInput, int framesPerUserBuffer, Float64 sampleRateRatio ) { UInt32 dataSize; UInt32 ioBufferSize; int scaler; scaler = (int) sampleRateRatio; if( sampleRateRatio > (Float64) scaler ) scaler += 1; DBUG(("PaOSX_SetDeviceBufferSize: buffer size scaler = %d\n", scaler )); ioBufferSize = framesPerUserBuffer * scaler; // Limit buffer size to reasonable value. if( ioBufferSize < 128 ) ioBufferSize = 128; dataSize = sizeof(ioBufferSize); return AudioDeviceSetProperty( devID, 0, 0, isInput, kAudioDevicePropertyBufferFrameSize, dataSize, &ioBufferSize); } /*******************************************************************/ static PaError PaOSX_OpenCommonDevice( internalPortAudioStream *past, PaHostInOut *inOut, Boolean isInput ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; PaError result = paNoError; OSStatus err = noErr; Float64 deviceRate; PaOSX_FixVolumeScalars( inOut->audioDeviceID, isInput, inOut->numChannels, 0.1, 0.9 ); // The HW device format changes are asynchronous. // So we don't know when or if the PAOSX_DevicePropertyListener() will // get called. To be safe, call the listener now to forcibly create the converter. if( inOut->converter == NULL ) { err = PAOSX_DevicePropertyListener (inOut->audioDeviceID, 0, isInput, kAudioDevicePropertyStreamFormat, past); if (err != kAudioHardwareNoError) { PRINT_ERR("PaOSX_OpenCommonDevice: PAOSX_DevicePropertyListener failed.\n", err); sSavedHostError = err; return paHostError; } } // Add listener for when format changed by other apps. DBUG(("PaOSX_OpenCommonDevice: call AudioDeviceAddPropertyListener()\n" )); err = AudioDeviceAddPropertyListener( inOut->audioDeviceID, 0, isInput, kAudioDevicePropertyStreamFormat, (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener, past ); if (err != noErr) { return -1; // FIXME } // Only change format if current HW format is different. // Don't bother to check result because we are going to use an AudioConverter anyway. pahsc->formatListenerCalled = false; result = PaOSX_SetFormat( inOut->audioDeviceID, isInput, past->past_SampleRate, inOut->numChannels ); // Synchronize with device because format changes put some devices into unusable mode. if( result > 0 ) { const int sleepDurMsec = 50; int spinCount = MIN_TIMEOUT_MSEC / sleepDurMsec; while( !pahsc->formatListenerCalled && (spinCount > 0) ) { Pa_Sleep( sleepDurMsec ); // FIXME - use a semaphore or signal spinCount--; } if( !pahsc->formatListenerCalled ) { PRINT(("PaOSX_OpenCommonDevice: timed out waiting for device format to settle.\n")); } result = 0; } #if SET_DEVICE_BUFFER_SIZE // Try to set the I/O bufferSize of the device. { Float64 ratio; deviceRate = PaOSX_GetDeviceSampleRate( inOut->audioDeviceID, isInput ); if( deviceRate <= 0.0 ) deviceRate = past->past_SampleRate; ratio = deviceRate / past->past_SampleRate ; err = PaOSX_SetDeviceBufferSize( inOut->audioDeviceID, isInput, past->past_FramesPerUserBuffer, ratio ); if( err != noErr ) { DBUG(("PaOSX_OpenCommonDevice: Could not set I/O buffer size.\n")); } } #endif /* Allocate an input buffer because we need it between the user callback and the converter. */ inOut->converterBuffer = PaHost_AllocateFastMemory( inOut->bytesPerUserNativeBuffer ); if( inOut->converterBuffer == NULL ) { return paInsufficientMemory; } return result; } /*******************************************************************/ static PaError PaOSX_OpenInputDevice( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; const PaHostDeviceInfo *hostDeviceInfo; PaError result = paNoError; DBUG(("PaOSX_OpenInputDevice: -------------\n")); if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) || (past->past_InputDeviceID > HIGHEST_INPUT_DEVID) ) { return paInvalidDeviceId; } hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID]; if( past->past_NumInputChannels > hostDeviceInfo->paInfo.maxInputChannels ) { return paInvalidChannelCount; /* Too many channels! */ } pahsc->input.numChannels = past->past_NumInputChannels; // setup PA conversion procedure result = PaConvert_SetupInput( past, paFloat32 ); result = PaOSX_OpenCommonDevice( past, &pahsc->input, IS_INPUT ); if( result != paNoError ) goto error; // Allocate a ring buffer so we can push in data from device, and pull through AudioConverter. result = PaOSX_CreateInputRingBuffer( past ); if( result != paNoError ) goto error; error: return result; } /*******************************************************************/ static PaError PaOSX_OpenOutputDevice( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; const PaHostDeviceInfo *hostDeviceInfo; PaError result = paNoError; DBUG(("PaOSX_OpenOutputDevice: -------------\n")); pahsc = (PaHostSoundControl *) past->past_DeviceData; // Validate DeviceID DBUG(("PaOSX_OpenOutputDevice: deviceID = 0x%x\n", past->past_OutputDeviceID)); if( (past->past_OutputDeviceID < LOWEST_OUTPUT_DEVID) || (past->past_OutputDeviceID > HIGHEST_OUTPUT_DEVID) ) { return paInvalidDeviceId; } hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID]; // Validate number of channels. if( past->past_NumOutputChannels > hostDeviceInfo->paInfo.maxOutputChannels ) { return paInvalidChannelCount; /* Too many channels! */ } pahsc->output.numChannels = past->past_NumOutputChannels; // setup conversion procedure result = PaConvert_SetupOutput( past, paFloat32 ); if( result != paNoError ) goto error; result = PaOSX_OpenCommonDevice( past, &pahsc->output, IS_OUTPUT ); if( result != paNoError ) goto error; error: return result; } /******************************************************************* * Determine how many User Buffers we can put into our CoreAudio stream buffer. * Uses: * past->past_FramesPerUserBuffer, etc. * Sets: * past->past_NumUserBuffers * pahsc->input.bytesPerUserNativeBuffer * pahsc->output.bytesPerUserNativeBuffer */ static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past ) { PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData; // Determine number of user buffers based strictly on minimum reasonable buffer size. // We ignore the Pa_OpenStream numBuffer parameter because CoreAudio has a big // mix buffer and handles latency automatically. past->past_NumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); // calculate buffer sizes in bytes pahsc->input.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer * Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels; pahsc->output.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer * Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels; DBUG(("PaOSX_CalcNumHostBuffers: past_NumUserBuffers = %ld\n", past->past_NumUserBuffers )); DBUG(("PaOSX_CalcNumHostBuffers: input.bytesPerUserNativeBuffer = %d\n", pahsc->input.bytesPerUserNativeBuffer )); DBUG(("PaOSX_CalcNumHostBuffers: output.bytesPerUserNativeBuffer = %d\n", pahsc->output.bytesPerUserNativeBuffer )); } /*****************************************************************************/ /************** Internal Host API ********************************************/ /*****************************************************************************/ PaError PaHost_OpenStream( internalPortAudioStream *past ) { PaError result = paNoError; PaHostSoundControl *pahsc; Boolean useInput; Boolean useOutput; assert( past->past_Magic == PA_MAGIC ); /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl)); if( pahsc == NULL ) { result = paInsufficientMemory; goto error; } memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; pahsc->primaryDeviceID = kAudioDeviceUnknown; pahsc->input.audioDeviceID = kAudioDeviceUnknown; pahsc->output.audioDeviceID = kAudioDeviceUnknown; PaOSX_CalcHostBufferSize( past ); useOutput = (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0); useInput = (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0); // Set device IDs and determine IO Device mode. if( useOutput ) { pahsc->output.audioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; pahsc->primaryDeviceID = pahsc->output.audioDeviceID; if( useInput ) { pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; pahsc->mode = ( pahsc->input.audioDeviceID != pahsc->primaryDeviceID ) ? PA_MODE_IO_TWO_DEVICES : PA_MODE_IO_ONE_DEVICE; } else { pahsc->mode = PA_MODE_OUTPUT_ONLY; } } else { /* Just input, not output. */ pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; pahsc->primaryDeviceID = pahsc->input.audioDeviceID; pahsc->mode = PA_MODE_INPUT_ONLY; } DBUG(("outputDeviceID = %ld\n", pahsc->output.audioDeviceID )); DBUG(("inputDeviceID = %ld\n", pahsc->input.audioDeviceID )); DBUG(("primaryDeviceID = %ld\n", pahsc->primaryDeviceID )); /* ------------------ OUTPUT */ if( useOutput ) { result = PaOSX_OpenOutputDevice( past ); if( result < 0 ) goto error; } /* ------------------ INPUT */ if( useInput ) { result = PaOSX_OpenInputDevice( past ); if( result < 0 ) goto error; } #if PA_ENABLE_LOAD_MEASUREMENT pahsc->inverseHostTicksPerBuffer = past->past_SampleRate / (AudioGetHostClockFrequency() * past->past_FramesPerUserBuffer); DBUG(("inverseHostTicksPerBuffer based on buffer size of %d frames.\n", past->past_FramesPerUserBuffer )); #else PRINT(("WARNING - Pa_GetCPULoad() mesaurement disabled in pa_mac_core.c.\n")); #endif return result; error: PaHost_CloseStream( past ); return result; } /*************************************************************************/ PaError PaHost_StartOutput( internalPortAudioStream *past ) { return 0; } /*************************************************************************/ PaError PaHost_StartInput( internalPortAudioStream *past ) { return 0; } /*************************************************************************/ PaError PaHost_StartEngine( internalPortAudioStream *past ) { OSStatus err = noErr; PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; past->past_StopSoon = 0; past->past_StopNow = 0; past->past_IsActive = 1; /* If full duplex and using two separate devices then start input device. */ if( pahsc->mode == PA_MODE_IO_TWO_DEVICES ) { // Associate an IO proc with the device and pass a pointer to the audio data context err = AudioDeviceAddIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback, past); if (err != noErr) { PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc secondary failed", err ); goto error; } // start playing sound through the device err = AudioDeviceStart(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback); if (err != noErr) { PRINT_ERR("PaHost_StartEngine: AudioDeviceStart secondary failed", err ); PRINT(("The program may succeed if you run it again!\n")); goto error; } } // Associate an IO proc with the device and pass a pointer to the audio data context err = AudioDeviceAddIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback, past); if (err != noErr) { PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc primary failed", err ); goto error; } // start playing sound through the device err = AudioDeviceStart(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback); if (err != noErr) { PRINT_ERR("PaHost_StartEngine: AudioDeviceStart primary failed", err ); PRINT(("The program may succeed if you run it again!\n")); goto error; } return result; error: sSavedHostError = err; return paHostError; } /*************************************************************************/ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) { OSStatus err = noErr; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; (void) abort; /* Tell background thread to stop generating more data and to let current data play out. */ past->past_StopSoon = 1; /* If aborting, tell background thread to stop NOW! */ if( abort ) past->past_StopNow = 1; past->past_IsActive = 0; #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); #endif // FIXME - we should ask proc to stop instead of stopping abruptly err = AudioDeviceStop(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback); if (err != noErr) { goto error; } err = AudioDeviceRemoveIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback); if (err != noErr) goto error; /* If full duplex and using two separate devices then stop second input device. */ if( pahsc->mode == PA_MODE_IO_TWO_DEVICES ) { err = AudioDeviceStop(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback); if (err != noErr) goto error; err = AudioDeviceRemoveIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback); if (err != noErr) goto error; } return paNoError; error: sSavedHostError = err; return paHostError; } /*************************************************************************/ PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) { return paNoError; } /*************************************************************************/ PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) { return paNoError; } /*******************************************************************/ PaError PaHost_CloseStream( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; //PaOSX_DumpDeviceInfo( sDeviceInfos[past->past_OutputDeviceID].audioDeviceID, IS_OUTPUT ); #if PA_TRACE_START_STOP AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); #endif // Stop Listener callbacks ASAP before dismantling stream. if( PA_USING_INPUT ) { AudioDeviceRemovePropertyListener( pahsc->input.audioDeviceID, 0, IS_INPUT, kAudioDevicePropertyStreamFormat, (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener ); } if( PA_USING_OUTPUT ) { AudioDeviceRemovePropertyListener( pahsc->output.audioDeviceID, 0, IS_OUTPUT, kAudioDevicePropertyStreamFormat, (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener ); } if( pahsc->output.converterBuffer != NULL ) { PaHost_FreeFastMemory( pahsc->output.converterBuffer, pahsc->output.bytesPerUserNativeBuffer ); } if( pahsc->input.converterBuffer != NULL ) { PaHost_FreeFastMemory( pahsc->input.converterBuffer, pahsc->input.bytesPerUserNativeBuffer ); } if( pahsc->ringBufferData != NULL ) { PaHost_FreeFastMemory( pahsc->ringBufferData, pahsc->ringBuffer.bufferSize ); } if( pahsc->output.converter != NULL ) { verify_noerr(AudioConverterDispose (pahsc->output.converter)); } if( pahsc->input.converter != NULL ) { verify_noerr(AudioConverterDispose (pahsc->input.converter)); } if ( pahsc->input.streamInterleavingBuffer != NULL ) { PaHost_FreeFastMemory( pahsc->input.streamInterleavingBuffer, pahsc->input.streamInterleavingBufferLen ); } if ( pahsc->output.streamInterleavingBuffer != NULL ) { PaHost_FreeFastMemory( pahsc->output.streamInterleavingBuffer, pahsc->output.streamInterleavingBufferLen ); } free( pahsc ); past->past_DeviceData = NULL; return paNoError; } /********************************************************************** ** Initialize Host dependant part of API. */ PaError PaHost_Init( void ) { return PaOSX_MaybeQueryDevices(); } /************************************************************************* ** Cleanup device info. */ PaError PaHost_Term( void ) { int i; if( sDeviceInfos != NULL ) { for( i=0; ipast_DeviceData; if( pahsc == NULL ) return paInternalError; return (PaError) past->past_IsActive; } /*****************************************************************************/ /************** External User API ********************************************/ /*****************************************************************************/ /********************************************************************** ** Query devices and use result. */ PaDeviceID Pa_GetDefaultInputDeviceID( void ) { PaError result = PaOSX_MaybeQueryDevices(); if( result < 0 ) return result; return sDefaultInputDeviceID; } PaDeviceID Pa_GetDefaultOutputDeviceID( void ) { PaError result = PaOSX_MaybeQueryDevices(); if( result < 0 ) return result; return sDefaultOutputDeviceID; } /************************************************************************* ** Determine minimum number of buffers required for this host based ** on minimum latency. Because CoreAudio manages latency, this just selects ** a reasonably small number of buffers. */ int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond ) { int minBuffers; double denominator; int minLatencyMsec = PA_MIN_LATENCY_MSEC; denominator = 1000.0 * framesPerBuffer; minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator ); if( minBuffers < 1 ) minBuffers = 1; return minBuffers; } /*************************************************************************/ void Pa_Sleep( long msec ) { usleep( msec * 1000 ); } /*************************************************************************/ PaTimestamp Pa_StreamTime( PortAudioStream *stream ) { AudioTimeStamp timeStamp; PaTimestamp streamTime; PaHostSoundControl *pahsc; internalPortAudioStream *past = (internalPortAudioStream *) stream; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; AudioDeviceGetCurrentTime(pahsc->primaryDeviceID, &timeStamp); streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ? timeStamp.mSampleTime : past->past_FrameCount; return streamTime; } /************************************************************************************/ long Pa_GetHostError() { return sSavedHostError; } /*************************************************************************/ int Pa_CountDevices() { if( sNumPaDevices <= 0 ) Pa_Initialize(); return sNumPaDevices; } /************************************************************************* ** PaDeviceInfo structures have already been created ** so just return the pointer. ** */ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) { if( id < 0 || id >= sNumPaDevices ) return NULL; return &sDeviceInfos[id].paInfo; }