43 | */ | 44 | */ |
44 | | 45 | |
45 | #include <stdio.h> | 46 | #include <stdio.h> |
46 | #include <math.h> | 47 | #include <math.h> |
47 | #include "portaudio.h" | 48 | #include "portaudio.h" |
48 | | 49 | |
49 | #define NUM_SECONDS (5) | 50 | #define NUM_SECONDS (5) |
50 | #define SAMPLE_RATE (44100) | 51 | #define SAMPLE_RATE (44100) |
51 | #define FRAMES_PER_BUFFER (64) | 52 | #define FRAMES_PER_BUFFER (64) |
52 | | 53 | |
53 | #ifndef M_PI | 54 | #ifndef M_PI |
54 | #define M_PI (3.14159265) | 55 | #define M_PI (3.14159265) |
55 | #endif | 56 | #endif |
56 | | 57 | |
57 | #define TABLE_SIZE (200) | 58 | #define TABLE_SIZE (200) |
58 | typedef struct | 59 | typedef struct |
59 | { | 60 | { |
60 | PaStream *stream; | 61 | PaStream *stream; |
61 | PaTime start; | 62 | PaTime start; |
62 | float sine[TABLE_SIZE]; | 63 | float sine[TABLE_SIZE]; |
63 | int left_phase; | 64 | int left_phase; |
64 | int right_phase; | 65 | int right_phase; |
65 | } | 66 | } |
66 | paTestData; | 67 | paTestData; |
67 | | 68 | |
68 | /* This routine will be called by the PortAudio engine when audio is needed. | 69 | /* This routine will be called by the PortAudio engine when audio is needed. |
69 | ** It may called at interrupt level on some machines so don't do anything | 70 | ** It may called at interrupt level on some machines so don't do anything |
70 | ** that could mess up the system like calling malloc() or free(). | 71 | ** that could mess up the system like calling malloc() or free(). |
71 | */ | 72 | */ |
72 | static int patestCallback( const void *inputBuffer, void *outputBuffer, | 73 | static int patestCallback( const void *inputBuffer, void *outputBuffer, |
73 | unsigned long framesPerBuffer, | 74 | unsigned long framesPerBuffer, |
74 | const PaStreamCallbackTimeInfo* timeInfo, | 75 | const PaStreamCallbackTimeInfo* timeInfo, |
75 | PaStreamCallbackFlags statusFlags, | 76 | PaStreamCallbackFlags statusFlags, |
76 | void *userData ) | 77 | void *userData ) |
77 | { | 78 | { |
78 | paTestData *data = (paTestData*)userData; | 79 | paTestData *data = (paTestData*)userData; |
79 | float *out = (float*)outputBuffer; | 80 | float *out = (float*)outputBuffer; |
80 | unsigned long i; | 81 | unsigned long i; |
81 | | 82 | |
82 | (void) timeInfo; /* Prevent unused variable warnings. */ | 83 | (void) timeInfo; /* Prevent unused variable warnings. */ |
83 | (void) statusFlags; | 84 | (void) statusFlags; |
84 | (void) inputBuffer; | 85 | (void) inputBuffer; |
85 | | 86 | |
86 | printf( "Timing info given to callback: Adc: %g, Current: %g, Dac: %g\n", | 87 | printf( "Timing info given to callback: Adc: %g, Current: %g, Dac: %g\n", |
87 | timeInfo->inputBufferAdcTime, | 88 | timeInfo->inputBufferAdcTime, |
88 | timeInfo->currentTime, | 89 | timeInfo->currentTime, |
89 | timeInfo->outputBufferDacTime ); | 90 | timeInfo->outputBufferDacTime ); |
90 | | 91 | |
91 | printf( "getStreamTime() returns: %g\n", Pa_GetStreamTime(data->stream)-data->start ); | 92 | printf( "getStreamTime() returns: %g\n", Pa_GetStreamTime(data->stream)-data->start ); |
92 | | 93 | |
93 | for( i=0; i<framesPerBuffer; i++ ) | 94 | for( i=0; i<framesPerBuffer; i++ ) |
94 | { | 95 | { |
95 | *out++ = data->sine[data->left_phase]; /* left */ | 96 | *out++ = data->sine[data->left_phase]; /* left */ |
96 | *out++ = data->sine[data->right_phase]; /* right */ | 97 | *out++ = data->sine[data->right_phase]; /* right */ |
97 | data->left_phase += 1; | 98 | data->left_phase += 1; |
98 | if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; | 99 | if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; |
99 | data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ | 100 | data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ |
100 | if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; | 101 | if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE; |
101 | } | 102 | } |
102 | | 103 | |
103 | return paContinue; | 104 | return paContinue; |
104 | } | 105 | } |
105 | | 106 | |
106 | /*******************************************************************/ | 107 | /*******************************************************************/ |
107 | int main(void); | 108 | int main(void); |
108 | int main(void) | 109 | int main(void) |
109 | { | 110 | { |
110 | PaStreamParameters outputParameters; | 111 | PaStreamParameters outputParameters; |
111 | PaStream *stream; | 112 | PaStream *stream; |
112 | PaError err; | 113 | PaError err; |
113 | paTestData data; | 114 | paTestData data; |
114 | int i; | 115 | int i; |
115 | | 116 | |
116 | | 117 | |
117 | printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); | 118 | printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER); |
118 | | 119 | |
119 | /* initialise sinusoidal wavetable */ | 120 | /* initialise sinusoidal wavetable */ |
120 | for( i=0; i<TABLE_SIZE; i++ ) | 121 | for( i=0; i<TABLE_SIZE; i++ ) |
121 | { | 122 | { |
122 | data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); | 123 | data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ); |
123 | } | 124 | } |
124 | data.left_phase = data.right_phase = 0; | 125 | data.left_phase = data.right_phase = 0; |
125 | | 126 | |
126 | err = Pa_Initialize(); | 127 | err = Pa_Initialize(); |
127 | if( err != paNoError ) goto error; | 128 | if( err != paNoError ) goto error; |
128 | | 129 | |
129 | outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ | 130 | outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ |
130 | outputParameters.channelCount = 2; /* stereo output */ | 131 | outputParameters.channelCount = 2; /* stereo output */ |
131 | outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ | 132 | outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */ |
132 | outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; | 133 | outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; |
133 | outputParameters.hostApiSpecificStreamInfo = NULL; | 134 | outputParameters.hostApiSpecificStreamInfo = NULL; |
134 | | 135 | |
135 | err = Pa_OpenStream( | 136 | err = Pa_OpenStream( |
136 | &stream, | 137 | &stream, |
137 | NULL, /* no input */ | 138 | NULL, /* no input */ |
138 | &outputParameters, | 139 | &outputParameters, |
139 | SAMPLE_RATE, | 140 | SAMPLE_RATE, |
140 | FRAMES_PER_BUFFER, | 141 | FRAMES_PER_BUFFER, |
141 | paClipOff, /* we won't output out of range samples so don't bother clipping them */ | 142 | paClipOff, /* we won't output out of range samples so don't bother clipping them */ |
142 | patestCallback, | 143 | patestCallback, |
143 | &data ); | 144 | &data ); |
144 | data.stream = stream; | 145 | data.stream = stream; |
145 | data.start = Pa_GetStreamTime(stream); | 146 | data.start = Pa_GetStreamTime(stream); |
146 | if( err != paNoError ) goto error; | 147 | if( err != paNoError ) goto error; |
147 | | 148 | |
148 | err = Pa_StartStream( stream ); | 149 | err = Pa_StartStream( stream ); |
149 | data.start = Pa_GetStreamTime(stream); | 150 | data.start = Pa_GetStreamTime(stream); |
150 | if( err != paNoError ) goto error; | 151 | if( err != paNoError ) goto error; |
151 | | 152 | |
152 | printf("Play for %d seconds.\n", NUM_SECONDS ); | 153 | printf("Play for %d seconds.\n", NUM_SECONDS ); |
153 | Pa_Sleep( NUM_SECONDS * 1000 ); | 154 | Pa_Sleep( NUM_SECONDS * 1000 ); |
154 | | 155 | |
155 | err = Pa_StopStream( stream ); | 156 | err = Pa_StopStream( stream ); |
156 | if( err != paNoError ) goto error; | 157 | if( err != paNoError ) goto error; |
157 | | 158 | |
158 | err = Pa_CloseStream( stream ); | 159 | err = Pa_CloseStream( stream ); |
159 | if( err != paNoError ) goto error; | 160 | if( err != paNoError ) goto error; |
160 | | 161 | |
161 | Pa_Terminate(); | 162 | Pa_Terminate(); |
162 | printf("Test finished.\n"); | 163 | printf("Test finished.\n"); |
163 | printf("The tone should have been heard for about 5 seconds and all the timing info above should report that about 5 seconds elapsed (except Adc, which
is undefined since there was no input device opened).\n"); | 164 | printf("The tone should have been heard for about 5 seconds and all the timing info above should report that about 5 seconds elapsed (except Adc, which
is undefined since there was no input device opened).\n"); |
164 | | 165 | |
165 | return err; | 166 | return err; |
166 | error: | 167 | error: |
167 | Pa_Terminate(); | 168 | Pa_Terminate(); |
168 | fprintf( stderr, "An error occured while using the portaudio stream\n" ); | 169 | fprintf( stderr, "An error occured while using the portaudio stream\n" ); |
169 | fprintf( stderr, "Error number: %d\n", err ); | 170 | fprintf( stderr, "Error number: %d\n", err ); |
170 | fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); | 171 | fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); |
171 | return err; | 172 | return err; |
172 | } | 173 | } |