| cannam@162 | 1 /** @file patest1.c | 
| cannam@162 | 2 	@ingroup test_src | 
| cannam@162 | 3 	@brief Ring modulate the audio input with a sine wave for 20 seconds. | 
| cannam@162 | 4 	@author Ross Bencina <rossb@audiomulch.com> | 
| cannam@162 | 5 */ | 
| cannam@162 | 6 /* | 
| cannam@162 | 7  * $Id$ | 
| cannam@162 | 8  * | 
| cannam@162 | 9  * This program uses the PortAudio Portable Audio Library. | 
| cannam@162 | 10  * For more information see: http://www.portaudio.com | 
| cannam@162 | 11  * Copyright (c) 1999-2000 Ross Bencina and Phil Burk | 
| cannam@162 | 12  * | 
| cannam@162 | 13  * Permission is hereby granted, free of charge, to any person obtaining | 
| cannam@162 | 14  * a copy of this software and associated documentation files | 
| cannam@162 | 15  * (the "Software"), to deal in the Software without restriction, | 
| cannam@162 | 16  * including without limitation the rights to use, copy, modify, merge, | 
| cannam@162 | 17  * publish, distribute, sublicense, and/or sell copies of the Software, | 
| cannam@162 | 18  * and to permit persons to whom the Software is furnished to do so, | 
| cannam@162 | 19  * subject to the following conditions: | 
| cannam@162 | 20  * | 
| cannam@162 | 21  * The above copyright notice and this permission notice shall be | 
| cannam@162 | 22  * included in all copies or substantial portions of the Software. | 
| cannam@162 | 23  * | 
| cannam@162 | 24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 
| cannam@162 | 25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | 
| cannam@162 | 26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | 
| cannam@162 | 27  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | 
| cannam@162 | 28  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | 
| cannam@162 | 29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | 
| cannam@162 | 30  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 
| cannam@162 | 31  */ | 
| cannam@162 | 32 | 
| cannam@162 | 33 /* | 
| cannam@162 | 34  * The text above constitutes the entire PortAudio license; however, | 
| cannam@162 | 35  * the PortAudio community also makes the following non-binding requests: | 
| cannam@162 | 36  * | 
| cannam@162 | 37  * Any person wishing to distribute modifications to the Software is | 
| cannam@162 | 38  * requested to send the modifications to the original developer so that | 
| cannam@162 | 39  * they can be incorporated into the canonical version. It is also | 
| cannam@162 | 40  * requested that these non-binding requests be included along with the | 
| cannam@162 | 41  * license above. | 
| cannam@162 | 42  */ | 
| cannam@162 | 43 | 
| cannam@162 | 44 #include <stdio.h> | 
| cannam@162 | 45 #include <math.h> | 
| cannam@162 | 46 #include "portaudio.h" | 
| cannam@162 | 47 | 
| cannam@162 | 48 #ifndef M_PI | 
| cannam@162 | 49 #define M_PI (3.14159265) | 
| cannam@162 | 50 #endif | 
| cannam@162 | 51 | 
| cannam@162 | 52 #define SAMPLE_RATE (44100) | 
| cannam@162 | 53 | 
| cannam@162 | 54 typedef struct | 
| cannam@162 | 55 { | 
| cannam@162 | 56     float sine[100]; | 
| cannam@162 | 57     int phase; | 
| cannam@162 | 58     int sampsToGo; | 
| cannam@162 | 59 } | 
| cannam@162 | 60 patest1data; | 
| cannam@162 | 61 | 
| cannam@162 | 62 static int patest1Callback( const void *inputBuffer, void *outputBuffer, | 
| cannam@162 | 63                             unsigned long framesPerBuffer, | 
| cannam@162 | 64                             const PaStreamCallbackTimeInfo* timeInfo, | 
| cannam@162 | 65                             PaStreamCallbackFlags statusFlags, | 
| cannam@162 | 66                             void *userData ) | 
| cannam@162 | 67 { | 
| cannam@162 | 68     patest1data *data = (patest1data*)userData; | 
| cannam@162 | 69     float *in = (float*)inputBuffer; | 
| cannam@162 | 70     float *out = (float*)outputBuffer; | 
| cannam@162 | 71     int framesToCalc = framesPerBuffer; | 
| cannam@162 | 72     unsigned long i = 0; | 
| cannam@162 | 73     int finished; | 
| cannam@162 | 74 | 
| cannam@162 | 75     if( data->sampsToGo < framesPerBuffer ) | 
| cannam@162 | 76     { | 
| cannam@162 | 77         framesToCalc = data->sampsToGo; | 
| cannam@162 | 78         finished = paComplete; | 
| cannam@162 | 79     } | 
| cannam@162 | 80     else | 
| cannam@162 | 81     { | 
| cannam@162 | 82         finished = paContinue; | 
| cannam@162 | 83     } | 
| cannam@162 | 84 | 
| cannam@162 | 85     for( ; i<framesToCalc; i++ ) | 
| cannam@162 | 86     { | 
| cannam@162 | 87         *out++ = *in++ * data->sine[data->phase];  /* left */ | 
| cannam@162 | 88         *out++ = *in++ * data->sine[data->phase++];  /* right */ | 
| cannam@162 | 89         if( data->phase >= 100 ) | 
| cannam@162 | 90             data->phase = 0; | 
| cannam@162 | 91     } | 
| cannam@162 | 92 | 
| cannam@162 | 93     data->sampsToGo -= framesToCalc; | 
| cannam@162 | 94 | 
| cannam@162 | 95     /* zero remainder of final buffer if not already done */ | 
| cannam@162 | 96     for( ; i<framesPerBuffer; i++ ) | 
| cannam@162 | 97     { | 
| cannam@162 | 98         *out++ = 0; /* left */ | 
| cannam@162 | 99         *out++ = 0; /* right */ | 
| cannam@162 | 100     } | 
| cannam@162 | 101 | 
| cannam@162 | 102     return finished; | 
| cannam@162 | 103 } | 
| cannam@162 | 104 | 
| cannam@162 | 105 int main(int argc, char* argv[]); | 
| cannam@162 | 106 int main(int argc, char* argv[]) | 
| cannam@162 | 107 { | 
| cannam@162 | 108     PaStream                *stream; | 
| cannam@162 | 109     PaError                 err; | 
| cannam@162 | 110     patest1data             data; | 
| cannam@162 | 111     int                     i; | 
| cannam@162 | 112     PaStreamParameters      inputParameters, outputParameters; | 
| cannam@162 | 113     const PaHostErrorInfo*  herr; | 
| cannam@162 | 114 | 
| cannam@162 | 115     printf("patest1.c\n"); fflush(stdout); | 
| cannam@162 | 116     printf("Ring modulate input for 20 seconds.\n"); fflush(stdout); | 
| cannam@162 | 117 | 
| cannam@162 | 118     /* initialise sinusoidal wavetable */ | 
| cannam@162 | 119     for( i=0; i<100; i++ ) | 
| cannam@162 | 120         data.sine[i] = sin( ((double)i/100.) * M_PI * 2. ); | 
| cannam@162 | 121     data.phase = 0; | 
| cannam@162 | 122     data.sampsToGo = SAMPLE_RATE * 20;        /* 20 seconds. */ | 
| cannam@162 | 123 | 
| cannam@162 | 124     /* initialise portaudio subsytem */ | 
| cannam@162 | 125     err = Pa_Initialize(); | 
| cannam@162 | 126 | 
| cannam@162 | 127     inputParameters.device = Pa_GetDefaultInputDevice();    /* default input device */ | 
| cannam@162 | 128     if (inputParameters.device == paNoDevice) { | 
| cannam@162 | 129       fprintf(stderr,"Error: No input default device.\n"); | 
| cannam@162 | 130       goto done; | 
| cannam@162 | 131     } | 
| cannam@162 | 132     inputParameters.channelCount = 2;                       /* stereo input */ | 
| cannam@162 | 133     inputParameters.sampleFormat = paFloat32;               /* 32 bit floating point input */ | 
| cannam@162 | 134     inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency; | 
| cannam@162 | 135     inputParameters.hostApiSpecificStreamInfo = NULL; | 
| cannam@162 | 136 | 
| cannam@162 | 137     outputParameters.device = Pa_GetDefaultOutputDevice();  /* default output device */ | 
| cannam@162 | 138     if (outputParameters.device == paNoDevice) { | 
| cannam@162 | 139       fprintf(stderr,"Error: No default output device.\n"); | 
| cannam@162 | 140       goto done; | 
| cannam@162 | 141     } | 
| cannam@162 | 142     outputParameters.channelCount = 2;                      /* stereo output */ | 
| cannam@162 | 143     outputParameters.sampleFormat = paFloat32;              /* 32 bit floating point output */ | 
| cannam@162 | 144     outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; | 
| cannam@162 | 145     outputParameters.hostApiSpecificStreamInfo = NULL; | 
| cannam@162 | 146 | 
| cannam@162 | 147     err = Pa_OpenStream( | 
| cannam@162 | 148                         &stream, | 
| cannam@162 | 149                         &inputParameters, | 
| cannam@162 | 150                         &outputParameters, | 
| cannam@162 | 151                         (double)SAMPLE_RATE, /* Samplerate in Hertz. */ | 
| cannam@162 | 152                         512,                 /* Small buffers */ | 
| cannam@162 | 153                         paClipOff,           /* We won't output out of range samples so don't bother clipping them. */ | 
| cannam@162 | 154                         patest1Callback, | 
| cannam@162 | 155                         &data ); | 
| cannam@162 | 156     if( err != paNoError ) goto done; | 
| cannam@162 | 157 | 
| cannam@162 | 158     err = Pa_StartStream( stream ); | 
| cannam@162 | 159     if( err != paNoError ) goto done; | 
| cannam@162 | 160 | 
| cannam@162 | 161     printf( "Press any key to end.\n" ); fflush(stdout); | 
| cannam@162 | 162 | 
| cannam@162 | 163     getc( stdin ); /* wait for input before exiting */ | 
| cannam@162 | 164 | 
| cannam@162 | 165     err = Pa_AbortStream( stream ); | 
| cannam@162 | 166     if( err != paNoError ) goto done; | 
| cannam@162 | 167 | 
| cannam@162 | 168     printf( "Waiting for stream to complete...\n" ); | 
| cannam@162 | 169 | 
| cannam@162 | 170     /* sleep until playback has finished */ | 
| cannam@162 | 171     while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) Pa_Sleep(1000); | 
| cannam@162 | 172     if( err < 0 ) goto done; | 
| cannam@162 | 173 | 
| cannam@162 | 174     err = Pa_CloseStream( stream ); | 
| cannam@162 | 175     if( err != paNoError ) goto done; | 
| cannam@162 | 176 | 
| cannam@162 | 177 done: | 
| cannam@162 | 178     Pa_Terminate(); | 
| cannam@162 | 179 | 
| cannam@162 | 180     if( err != paNoError ) | 
| cannam@162 | 181     { | 
| cannam@162 | 182         fprintf( stderr, "An error occured while using portaudio\n" ); | 
| cannam@162 | 183         if( err == paUnanticipatedHostError ) | 
| cannam@162 | 184         { | 
| cannam@162 | 185             fprintf( stderr, " unanticipated host error.\n"); | 
| cannam@162 | 186             herr = Pa_GetLastHostErrorInfo(); | 
| cannam@162 | 187             if (herr) | 
| cannam@162 | 188             { | 
| cannam@162 | 189                 fprintf( stderr, " Error number: %ld\n", herr->errorCode ); | 
| cannam@162 | 190                 if (herr->errorText) | 
| cannam@162 | 191                     fprintf( stderr, " Error text: %s\n", herr->errorText ); | 
| cannam@162 | 192             } | 
| cannam@162 | 193             else | 
| cannam@162 | 194                 fprintf( stderr, " Pa_GetLastHostErrorInfo() failed!\n" ); | 
| cannam@162 | 195         } | 
| cannam@162 | 196         else | 
| cannam@162 | 197         { | 
| cannam@162 | 198             fprintf( stderr, " Error number: %d\n", err ); | 
| cannam@162 | 199             fprintf( stderr, " Error text: %s\n", Pa_GetErrorText( err ) ); | 
| cannam@162 | 200         } | 
| cannam@162 | 201 | 
| cannam@162 | 202         err = 1;          /* Always return 0 or 1, but no other return codes. */ | 
| cannam@162 | 203     } | 
| cannam@162 | 204 | 
| cannam@162 | 205     printf( "bye\n" ); | 
| cannam@162 | 206 | 
| cannam@162 | 207     return err; | 
| cannam@162 | 208 } |