| Chris@39 | 1 /** @file | 
| Chris@39 | 2 	@ingroup test_src | 
| Chris@39 | 3 	@brief Hear the latency caused by big buffers. | 
| Chris@39 | 4 	Play a sine wave and change frequency based on letter input. | 
| Chris@39 | 5 	@author Phil Burk <philburk@softsynth.com>, and Darren Gibbs | 
| Chris@39 | 6 */ | 
| Chris@39 | 7 /* | 
| Chris@39 | 8  * $Id: patest_latency.c 1368 2008-03-01 00:38:27Z rossb $ | 
| Chris@39 | 9  * | 
| Chris@39 | 10  * This program uses the PortAudio Portable Audio Library. | 
| Chris@39 | 11  * For more information see: http://www.portaudio.com | 
| Chris@39 | 12  * Copyright (c) 1999-2000 Ross Bencina and Phil Burk | 
| Chris@39 | 13  * | 
| Chris@39 | 14  * Permission is hereby granted, free of charge, to any person obtaining | 
| Chris@39 | 15  * a copy of this software and associated documentation files | 
| Chris@39 | 16  * (the "Software"), to deal in the Software without restriction, | 
| Chris@39 | 17  * including without limitation the rights to use, copy, modify, merge, | 
| Chris@39 | 18  * publish, distribute, sublicense, and/or sell copies of the Software, | 
| Chris@39 | 19  * and to permit persons to whom the Software is furnished to do so, | 
| Chris@39 | 20  * subject to the following conditions: | 
| Chris@39 | 21  * | 
| Chris@39 | 22  * The above copyright notice and this permission notice shall be | 
| Chris@39 | 23  * included in all copies or substantial portions of the Software. | 
| Chris@39 | 24  * | 
| Chris@39 | 25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 
| Chris@39 | 26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 
| Chris@39 | 27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | 
| Chris@39 | 28  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | 
| Chris@39 | 29  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | 
| Chris@39 | 30  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | 
| Chris@39 | 31  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 
| Chris@39 | 32  */ | 
| Chris@39 | 33 | 
| Chris@39 | 34 /* | 
| Chris@39 | 35  * The text above constitutes the entire PortAudio license; however, | 
| Chris@39 | 36  * the PortAudio community also makes the following non-binding requests: | 
| Chris@39 | 37  * | 
| Chris@39 | 38  * Any person wishing to distribute modifications to the Software is | 
| Chris@39 | 39  * requested to send the modifications to the original developer so that | 
| Chris@39 | 40  * they can be incorporated into the canonical version. It is also | 
| Chris@39 | 41  * requested that these non-binding requests be included along with the | 
| Chris@39 | 42  * license above. | 
| Chris@39 | 43  */ | 
| Chris@39 | 44 | 
| Chris@39 | 45 #include <stdio.h> | 
| Chris@39 | 46 #include <math.h> | 
| Chris@39 | 47 #include "portaudio.h" | 
| Chris@39 | 48 | 
| Chris@39 | 49 #define OUTPUT_DEVICE       (Pa_GetDefaultOutputDevice()) | 
| Chris@39 | 50 #define SAMPLE_RATE         (44100) | 
| Chris@39 | 51 #define FRAMES_PER_BUFFER   (64) | 
| Chris@39 | 52 | 
| Chris@39 | 53 #define MIN_FREQ            (100.0f) | 
| Chris@39 | 54 #define CalcPhaseIncrement(freq)  ((freq)/SAMPLE_RATE) | 
| Chris@39 | 55 #ifndef M_PI | 
| Chris@39 | 56 #define M_PI  (3.14159265) | 
| Chris@39 | 57 #endif | 
| Chris@39 | 58 #define TABLE_SIZE   (400) | 
| Chris@39 | 59 | 
| Chris@39 | 60 typedef struct | 
| Chris@39 | 61 { | 
| Chris@39 | 62     float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */ | 
| Chris@39 | 63     float phase_increment; | 
| Chris@39 | 64     float left_phase; | 
| Chris@39 | 65     float right_phase; | 
| Chris@39 | 66 } | 
| Chris@39 | 67 paTestData; | 
| Chris@39 | 68 | 
| Chris@39 | 69 float LookupSine( paTestData *data, float phase ); | 
| Chris@39 | 70 /* Convert phase between and 1.0 to sine value | 
| Chris@39 | 71  * using linear interpolation. | 
| Chris@39 | 72  */ | 
| Chris@39 | 73 float LookupSine( paTestData *data, float phase ) | 
| Chris@39 | 74 { | 
| Chris@39 | 75     float fIndex = phase*TABLE_SIZE; | 
| Chris@39 | 76     int   index = (int) fIndex; | 
| Chris@39 | 77     float fract = fIndex - index; | 
| Chris@39 | 78     float lo = data->sine[index]; | 
| Chris@39 | 79     float hi = data->sine[index+1]; | 
| Chris@39 | 80     float val = lo + fract*(hi-lo); | 
| Chris@39 | 81     return val; | 
| Chris@39 | 82 } | 
| Chris@39 | 83 | 
| Chris@39 | 84 /* This routine will be called by the PortAudio engine when audio is needed. | 
| Chris@39 | 85 ** It may called at interrupt level on some machines so don't do anything | 
| Chris@39 | 86 ** that could mess up the system like calling malloc() or free(). | 
| Chris@39 | 87 */ | 
| Chris@39 | 88 static int patestCallback( const void *inputBuffer, void *outputBuffer, | 
| Chris@39 | 89                            unsigned long framesPerBuffer, | 
| Chris@39 | 90                            const PaStreamCallbackTimeInfo* timeInfo, | 
| Chris@39 | 91                            PaStreamCallbackFlags statusFlags, | 
| Chris@39 | 92                            void *userData ) | 
| Chris@39 | 93 { | 
| Chris@39 | 94     paTestData *data = (paTestData*)userData; | 
| Chris@39 | 95     float *out = (float*)outputBuffer; | 
| Chris@39 | 96     int i; | 
| Chris@39 | 97 | 
| Chris@39 | 98     (void) inputBuffer; /* Prevent unused variable warning. */ | 
| Chris@39 | 99 | 
| Chris@39 | 100     for( i=0; i<framesPerBuffer; i++ ) | 
| Chris@39 | 101     { | 
| Chris@39 | 102         *out++ = LookupSine(data, data->left_phase);  /* left */ | 
| Chris@39 | 103         *out++ = LookupSine(data, data->right_phase);  /* right */ | 
| Chris@39 | 104         data->left_phase += data->phase_increment; | 
| Chris@39 | 105         if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f; | 
| Chris@39 | 106         data->right_phase += (data->phase_increment * 1.5f); /* fifth above */ | 
| Chris@39 | 107         if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f; | 
| Chris@39 | 108     } | 
| Chris@39 | 109     return 0; | 
| Chris@39 | 110 } | 
| Chris@39 | 111 | 
| Chris@39 | 112 /*******************************************************************/ | 
| Chris@39 | 113 int main(void); | 
| Chris@39 | 114 int main(void) | 
| Chris@39 | 115 { | 
| Chris@39 | 116     PaStream *stream; | 
| Chris@39 | 117     PaStreamParameters outputParameters; | 
| Chris@39 | 118     PaError err; | 
| Chris@39 | 119     paTestData data; | 
| Chris@39 | 120     int i; | 
| Chris@39 | 121     int done = 0; | 
| Chris@39 | 122 | 
| Chris@39 | 123     printf("PortAudio Test: enter letter then hit ENTER.\n" ); | 
| Chris@39 | 124     /* initialise sinusoidal wavetable */ | 
| Chris@39 | 125     for( i=0; i<TABLE_SIZE; i++ ) | 
| Chris@39 | 126     { | 
| Chris@39 | 127         data.sine[i] = 0.90f * (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); | 
| Chris@39 | 128     } | 
| Chris@39 | 129     data.sine[TABLE_SIZE] = data.sine[0]; /* set guard point. */ | 
| Chris@39 | 130     data.left_phase = data.right_phase = 0.0; | 
| Chris@39 | 131     data.phase_increment = CalcPhaseIncrement(MIN_FREQ); | 
| Chris@39 | 132 | 
| Chris@39 | 133     err = Pa_Initialize(); | 
| Chris@39 | 134     if( err != paNoError ) goto error; | 
| Chris@39 | 135     printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE ); | 
| Chris@39 | 136 | 
| Chris@39 | 137     outputParameters.device = OUTPUT_DEVICE; | 
| Chris@39 | 138     if (outputParameters.device == paNoDevice) { | 
| Chris@39 | 139       fprintf(stderr,"Error: No default output device.\n"); | 
| Chris@39 | 140       goto error; | 
| Chris@39 | 141     } | 
| Chris@39 | 142     outputParameters.channelCount = 2;         /* stereo output */ | 
| Chris@39 | 143     outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ | 
| Chris@39 | 144     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; | 
| Chris@39 | 145     outputParameters.hostApiSpecificStreamInfo = NULL; | 
| Chris@39 | 146 | 
| Chris@39 | 147     printf("Requested output latency = %.4f seconds.\n", outputParameters.suggestedLatency ); | 
| Chris@39 | 148     printf("%d frames per buffer.\n.", FRAMES_PER_BUFFER ); | 
| Chris@39 | 149 | 
| Chris@39 | 150     err = Pa_OpenStream( | 
| Chris@39 | 151               &stream, | 
| Chris@39 | 152               NULL, /* no input */ | 
| Chris@39 | 153               &outputParameters, | 
| Chris@39 | 154               SAMPLE_RATE, | 
| Chris@39 | 155               FRAMES_PER_BUFFER, | 
| Chris@39 | 156               paClipOff|paDitherOff,      /* we won't output out of range samples so don't bother clipping them */ | 
| Chris@39 | 157               patestCallback, | 
| Chris@39 | 158               &data ); | 
| Chris@39 | 159     if( err != paNoError ) goto error; | 
| Chris@39 | 160 | 
| Chris@39 | 161     err = Pa_StartStream( stream ); | 
| Chris@39 | 162     if( err != paNoError ) goto error; | 
| Chris@39 | 163     printf("Play ASCII keyboard. Hit 'q' to stop. (Use RETURN key on Mac)\n"); | 
| Chris@39 | 164     fflush(stdout); | 
| Chris@39 | 165     while ( !done ) | 
| Chris@39 | 166     { | 
| Chris@39 | 167         float  freq; | 
| Chris@39 | 168         int index; | 
| Chris@39 | 169         char c; | 
| Chris@39 | 170         do | 
| Chris@39 | 171         { | 
| Chris@39 | 172             c = getchar(); | 
| Chris@39 | 173         } | 
| Chris@39 | 174         while( c < ' '); /* Strip white space and control chars. */ | 
| Chris@39 | 175 | 
| Chris@39 | 176         if( c == 'q' ) done = 1; | 
| Chris@39 | 177         index = c % 26; | 
| Chris@39 | 178         freq = MIN_FREQ + (index * 40.0); | 
| Chris@39 | 179         data.phase_increment = CalcPhaseIncrement(freq); | 
| Chris@39 | 180     } | 
| Chris@39 | 181     printf("Call Pa_StopStream()\n"); | 
| Chris@39 | 182     err = Pa_StopStream( stream ); | 
| Chris@39 | 183     if( err != paNoError ) goto error; | 
| Chris@39 | 184     Pa_Terminate(); | 
| Chris@39 | 185     printf("Test finished.\n"); | 
| Chris@39 | 186     return err; | 
| Chris@39 | 187 error: | 
| Chris@39 | 188     Pa_Terminate(); | 
| Chris@39 | 189     fprintf( stderr, "An error occured while using the portaudio stream\n" ); | 
| Chris@39 | 190     fprintf( stderr, "Error number: %d\n", err ); | 
| Chris@39 | 191     fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); | 
| Chris@39 | 192     return err; | 
| Chris@39 | 193 } |