PortAudio 2.0
|
00001 00007 /* 00008 * $Id: paex_sine.c 1752 2011-09-08 03:21:55Z philburk $ 00009 * 00010 * This program uses the PortAudio Portable Audio Library. 00011 * For more information see: http://www.portaudio.com/ 00012 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 00013 * 00014 * Permission is hereby granted, free of charge, to any person obtaining 00015 * a copy of this software and associated documentation files 00016 * (the "Software"), to deal in the Software without restriction, 00017 * including without limitation the rights to use, copy, modify, merge, 00018 * publish, distribute, sublicense, and/or sell copies of the Software, 00019 * and to permit persons to whom the Software is furnished to do so, 00020 * subject to the following conditions: 00021 * 00022 * The above copyright notice and this permission notice shall be 00023 * included in all copies or substantial portions of the Software. 00024 * 00025 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00026 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00027 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00028 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 00029 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 00030 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00031 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00032 */ 00033 00034 /* 00035 * The text above constitutes the entire PortAudio license; however, 00036 * the PortAudio community also makes the following non-binding requests: 00037 * 00038 * Any person wishing to distribute modifications to the Software is 00039 * requested to send the modifications to the original developer so that 00040 * they can be incorporated into the canonical version. It is also 00041 * requested that these non-binding requests be included along with the 00042 * license above. 00043 */ 00044 #include <stdio.h> 00045 #include <math.h> 00046 #include "portaudio.h" 00047 00048 #define NUM_SECONDS (5) 00049 #define SAMPLE_RATE (44100) 00050 #define FRAMES_PER_BUFFER (64) 00051 00052 #ifndef M_PI 00053 #define M_PI (3.14159265) 00054 #endif 00055 00056 #define TABLE_SIZE (200) 00057 00058 class Sine 00059 { 00060 public: 00061 Sine() : stream(0), left_phase(0), right_phase(0) 00062 { 00063 /* initialise sinusoidal wavetable */ 00064 for( int i=0; i<TABLE_SIZE; i++ ) 00065 { 00066 sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); 00067 } 00068 00069 sprintf( message, "No Message" ); 00070 } 00071 00072 bool open(PaDeviceIndex index) 00073 { 00074 PaStreamParameters outputParameters; 00075 00076 outputParameters.device = index; 00077 if (outputParameters.device == paNoDevice) { 00078 return false; 00079 } 00080 00081 outputParameters.channelCount = 2; /* stereo output */ 00082 outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ 00083 outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; 00084 outputParameters.hostApiSpecificStreamInfo = NULL; 00085 00086 PaError err = Pa_OpenStream( 00087 &stream, 00088 NULL, /* no input */ 00089 &outputParameters, 00090 SAMPLE_RATE, 00091 FRAMES_PER_BUFFER, 00092 paClipOff, /* we won't output out of range samples so don't bother clipping them */ 00093 &Sine::paCallback, 00094 this /* Using 'this' for userData so we can cast to Sine* in paCallback method */ 00095 ); 00096 00097 if (err != paNoError) 00098 { 00099 /* Failed to open stream to device !!! */ 00100 return false; 00101 } 00102 00103 err = Pa_SetStreamFinishedCallback( stream, &Sine::paStreamFinished ); 00104 00105 if (err != paNoError) 00106 { 00107 Pa_CloseStream( stream ); 00108 stream = 0; 00109 00110 return false; 00111 } 00112 00113 return true; 00114 } 00115 00116 bool close() 00117 { 00118 if (stream == 0) 00119 return false; 00120 00121 PaError err = Pa_CloseStream( stream ); 00122 stream = 0; 00123 00124 return (err == paNoError); 00125 } 00126 00127 00128 bool start() 00129 { 00130 if (stream == 0) 00131 return false; 00132 00133 PaError err = Pa_StartStream( stream ); 00134 00135 return (err == paNoError); 00136 } 00137 00138 bool stop() 00139 { 00140 if (stream == 0) 00141 return false; 00142 00143 PaError err = Pa_StopStream( stream ); 00144 00145 return (err == paNoError); 00146 } 00147 00148 private: 00149 /* The instance callback, where we have access to every method/variable in object of class Sine */ 00150 int paCallbackMethod(const void *inputBuffer, void *outputBuffer, 00151 unsigned long framesPerBuffer, 00152 const PaStreamCallbackTimeInfo* timeInfo, 00153 PaStreamCallbackFlags statusFlags) 00154 { 00155 float *out = (float*)outputBuffer; 00156 unsigned long i; 00157 00158 (void) timeInfo; /* Prevent unused variable warnings. */ 00159 (void) statusFlags; 00160 (void) inputBuffer; 00161 00162 for( i=0; i<framesPerBuffer; i++ ) 00163 { 00164 *out++ = sine[left_phase]; /* left */ 00165 *out++ = sine[right_phase]; /* right */ 00166 left_phase += 1; 00167 if( left_phase >= TABLE_SIZE ) left_phase -= TABLE_SIZE; 00168 right_phase += 3; /* higher pitch so we can distinguish left and right. */ 00169 if( right_phase >= TABLE_SIZE ) right_phase -= TABLE_SIZE; 00170 } 00171 00172 return paContinue; 00173 00174 } 00175 00176 /* This routine will be called by the PortAudio engine when audio is needed. 00177 ** It may called at interrupt level on some machines so don't do anything 00178 ** that could mess up the system like calling malloc() or free(). 00179 */ 00180 static int paCallback( const void *inputBuffer, void *outputBuffer, 00181 unsigned long framesPerBuffer, 00182 const PaStreamCallbackTimeInfo* timeInfo, 00183 PaStreamCallbackFlags statusFlags, 00184 void *userData ) 00185 { 00186 /* Here we cast userData to Sine* type so we can call the instance method paCallbackMethod, we can do that since 00187 we called Pa_OpenStream with 'this' for userData */ 00188 return ((Sine*)userData)->paCallbackMethod(inputBuffer, outputBuffer, 00189 framesPerBuffer, 00190 timeInfo, 00191 statusFlags); 00192 } 00193 00194 00195 void paStreamFinishedMethod() 00196 { 00197 printf( "Stream Completed: %s\n", message ); 00198 } 00199 00200 /* 00201 * This routine is called by portaudio when playback is done. 00202 */ 00203 static void paStreamFinished(void* userData) 00204 { 00205 return ((Sine*)userData)->paStreamFinishedMethod(); 00206 } 00207 00208 PaStream *stream; 00209 float sine[TABLE_SIZE]; 00210 int left_phase; 00211 int right_phase; 00212 char message[20]; 00213 }; 00214 00215 00216 /*******************************************************************/ 00217 int main(void); 00218 int main(void) 00219 { 00220 PaError err; 00221 Sine sine; 00222 00223 printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); 00224 00225 err = Pa_Initialize(); 00226 if( err != paNoError ) goto error; 00227 00228 if (sine.open(Pa_GetDefaultOutputDevice())) 00229 { 00230 if (sine.start()) 00231 { 00232 printf("Play for %d seconds.\n", NUM_SECONDS ); 00233 Pa_Sleep( NUM_SECONDS * 1000 ); 00234 00235 sine.stop(); 00236 } 00237 00238 sine.close(); 00239 } 00240 00241 Pa_Terminate(); 00242 printf("Test finished.\n"); 00243 00244 return err; 00245 00246 error: 00247 Pa_Terminate(); 00248 fprintf( stderr, "An error occured while using the portaudio stream\n" ); 00249 fprintf( stderr, "Error number: %d\n", err ); 00250 fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); 00251 return err; 00252 }