Mercurial > hg > sv-dependency-builds
comparison src/portaudio/pablio/pablio.c @ 89:8a15ff55d9af
Add bzip2, zlib, liblo, portaudio sources
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Wed, 20 Mar 2013 13:59:52 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
88:fe7c3a0b0259 | 89:8a15ff55d9af |
---|---|
1 /* | |
2 * $Id: pablio.c 1151 2006-11-29 02:11:16Z leland_lucius $ | |
3 * pablio.c | |
4 * Portable Audio Blocking Input/Output utility. | |
5 * | |
6 * Author: Phil Burk, http://www.softsynth.com | |
7 * | |
8 * This program uses the PortAudio Portable Audio Library. | |
9 * For more information see: http://www.portaudio.com | |
10 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk | |
11 * | |
12 * Permission is hereby granted, free of charge, to any person obtaining | |
13 * a copy of this software and associated documentation files | |
14 * (the "Software"), to deal in the Software without restriction, | |
15 * including without limitation the rights to use, copy, modify, merge, | |
16 * publish, distribute, sublicense, and/or sell copies of the Software, | |
17 * and to permit persons to whom the Software is furnished to do so, | |
18 * subject to the following conditions: | |
19 * | |
20 * The above copyright notice and this permission notice shall be | |
21 * included in all copies or substantial portions of the Software. | |
22 * | |
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
26 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR | |
27 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
28 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
29 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
30 */ | |
31 | |
32 /* | |
33 * The text above constitutes the entire PortAudio license; however, | |
34 * the PortAudio community also makes the following non-binding requests: | |
35 * | |
36 * Any person wishing to distribute modifications to the Software is | |
37 * requested to send the modifications to the original developer so that | |
38 * they can be incorporated into the canonical version. It is also | |
39 * requested that these non-binding requests be included along with the | |
40 * license above. | |
41 */ | |
42 | |
43 #include <stdio.h> | |
44 #include <stdlib.h> | |
45 #include <math.h> | |
46 #include "portaudio.h" | |
47 #include "pa_ringbuffer.h" | |
48 #include "pablio.h" | |
49 #include <string.h> | |
50 | |
51 /************************************************************************/ | |
52 /******** Constants *****************************************************/ | |
53 /************************************************************************/ | |
54 | |
55 #define FRAMES_PER_BUFFER (256) | |
56 | |
57 /************************************************************************/ | |
58 /******** Prototypes ****************************************************/ | |
59 /************************************************************************/ | |
60 | |
61 static int blockingIOCallback( void *inputBuffer, void *outputBuffer, | |
62 unsigned long framesPerBuffer, | |
63 PaTimestamp outTime, void *userData ); | |
64 static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame ); | |
65 static PaError PABLIO_TermFIFO( RingBuffer *rbuf ); | |
66 | |
67 /************************************************************************/ | |
68 /******** Functions *****************************************************/ | |
69 /************************************************************************/ | |
70 | |
71 /* Called from PortAudio. | |
72 * Read and write data only if there is room in FIFOs. | |
73 */ | |
74 static int blockingIOCallback( void *inputBuffer, void *outputBuffer, | |
75 unsigned long framesPerBuffer, | |
76 PaTimestamp outTime, void *userData ) | |
77 { | |
78 PABLIO_Stream *data = (PABLIO_Stream*)userData; | |
79 long numBytes = data->bytesPerFrame * framesPerBuffer; | |
80 (void) outTime; | |
81 | |
82 /* This may get called with NULL inputBuffer during initial setup. */ | |
83 if( inputBuffer != NULL ) | |
84 { | |
85 PaUtil_WriteRingBuffer( &data->inFIFO, inputBuffer, numBytes ); | |
86 } | |
87 if( outputBuffer != NULL ) | |
88 { | |
89 int i; | |
90 int numRead = PaUtil_ReadRingBuffer( &data->outFIFO, outputBuffer, numBytes ); | |
91 /* Zero out remainder of buffer if we run out of data. */ | |
92 for( i=numRead; i<numBytes; i++ ) | |
93 { | |
94 ((char *)outputBuffer)[i] = 0; | |
95 } | |
96 } | |
97 | |
98 return 0; | |
99 } | |
100 | |
101 /* Allocate buffer. */ | |
102 static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame ) | |
103 { | |
104 long numBytes = numFrames * bytesPerFrame; | |
105 char *buffer = (char *) malloc( numBytes ); | |
106 if( buffer == NULL ) return paInsufficientMemory; | |
107 memset( buffer, 0, numBytes ); | |
108 return (PaError) PaUtil_InitializeRingBuffer( rbuf, numBytes, buffer ); | |
109 } | |
110 | |
111 /* Free buffer. */ | |
112 static PaError PABLIO_TermFIFO( RingBuffer *rbuf ) | |
113 { | |
114 if( rbuf->buffer ) free( rbuf->buffer ); | |
115 rbuf->buffer = NULL; | |
116 return paNoError; | |
117 } | |
118 | |
119 /************************************************************ | |
120 * Write data to ring buffer. | |
121 * Will not return until all the data has been written. | |
122 */ | |
123 long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) | |
124 { | |
125 long bytesWritten; | |
126 char *p = (char *) data; | |
127 long numBytes = aStream->bytesPerFrame * numFrames; | |
128 while( numBytes > 0) | |
129 { | |
130 bytesWritten = PaUtil_WriteRingBuffer( &aStream->outFIFO, p, numBytes ); | |
131 numBytes -= bytesWritten; | |
132 p += bytesWritten; | |
133 if( numBytes > 0) Pa_Sleep(10); | |
134 } | |
135 return numFrames; | |
136 } | |
137 | |
138 /************************************************************ | |
139 * Read data from ring buffer. | |
140 * Will not return until all the data has been read. | |
141 */ | |
142 long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) | |
143 { | |
144 long bytesRead; | |
145 char *p = (char *) data; | |
146 long numBytes = aStream->bytesPerFrame * numFrames; | |
147 while( numBytes > 0) | |
148 { | |
149 bytesRead = PaUtil_ReadRingBuffer( &aStream->inFIFO, p, numBytes ); | |
150 numBytes -= bytesRead; | |
151 p += bytesRead; | |
152 if( numBytes > 0) Pa_Sleep(10); | |
153 } | |
154 return numFrames; | |
155 } | |
156 | |
157 /************************************************************ | |
158 * Return the number of frames that could be written to the stream without | |
159 * having to wait. | |
160 */ | |
161 long GetAudioStreamWriteable( PABLIO_Stream *aStream ) | |
162 { | |
163 int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); | |
164 return bytesEmpty / aStream->bytesPerFrame; | |
165 } | |
166 | |
167 /************************************************************ | |
168 * Return the number of frames that are available to be read from the | |
169 * stream without having to wait. | |
170 */ | |
171 long GetAudioStreamReadable( PABLIO_Stream *aStream ) | |
172 { | |
173 int bytesFull = PaUtil_GetRingBufferReadAvailable( &aStream->inFIFO ); | |
174 return bytesFull / aStream->bytesPerFrame; | |
175 } | |
176 | |
177 /************************************************************/ | |
178 static unsigned long RoundUpToNextPowerOf2( unsigned long n ) | |
179 { | |
180 long numBits = 0; | |
181 if( ((n-1) & n) == 0) return n; /* Already Power of two. */ | |
182 while( n > 0 ) | |
183 { | |
184 n= n>>1; | |
185 numBits++; | |
186 } | |
187 return (1<<numBits); | |
188 } | |
189 | |
190 /************************************************************ | |
191 * Opens a PortAudio stream with default characteristics. | |
192 * Allocates PABLIO_Stream structure. | |
193 * | |
194 * flags parameter can be an ORed combination of: | |
195 * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, | |
196 * and either PABLIO_MONO or PABLIO_STEREO | |
197 */ | |
198 PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate, | |
199 PaSampleFormat format, long flags ) | |
200 { | |
201 long bytesPerSample; | |
202 long doRead = 0; | |
203 long doWrite = 0; | |
204 PaError err; | |
205 PABLIO_Stream *aStream; | |
206 long minNumBuffers; | |
207 long numFrames; | |
208 | |
209 /* Allocate PABLIO_Stream structure for caller. */ | |
210 aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) ); | |
211 if( aStream == NULL ) return paInsufficientMemory; | |
212 memset( aStream, 0, sizeof(PABLIO_Stream) ); | |
213 | |
214 /* Determine size of a sample. */ | |
215 bytesPerSample = Pa_GetSampleSize( format ); | |
216 if( bytesPerSample < 0 ) | |
217 { | |
218 err = (PaError) bytesPerSample; | |
219 goto error; | |
220 } | |
221 aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2; | |
222 aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame; | |
223 | |
224 /* Initialize PortAudio */ | |
225 err = Pa_Initialize(); | |
226 if( err != paNoError ) goto error; | |
227 | |
228 /* Warning: numFrames must be larger than amount of data processed per interrupt | |
229 * inside PA to prevent glitches. Just to be safe, adjust size upwards. | |
230 */ | |
231 minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); | |
232 numFrames = minNumBuffers * FRAMES_PER_BUFFER; | |
233 numFrames = RoundUpToNextPowerOf2( numFrames ); | |
234 | |
235 /* Initialize Ring Buffers */ | |
236 doRead = ((flags & PABLIO_READ) != 0); | |
237 doWrite = ((flags & PABLIO_WRITE) != 0); | |
238 if(doRead) | |
239 { | |
240 err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame ); | |
241 if( err != paNoError ) goto error; | |
242 } | |
243 if(doWrite) | |
244 { | |
245 long numBytes; | |
246 err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame ); | |
247 if( err != paNoError ) goto error; | |
248 /* Make Write FIFO appear full initially. */ | |
249 numBytes = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); | |
250 PaUtil_AdvanceRingBufferWriteIndex( &aStream->outFIFO, numBytes ); | |
251 } | |
252 | |
253 /* Open a PortAudio stream that we will use to communicate with the underlying | |
254 * audio drivers. */ | |
255 err = Pa_OpenStream( | |
256 &aStream->stream, | |
257 (doRead ? Pa_GetDefaultInputDeviceID() : paNoDevice), | |
258 (doRead ? aStream->samplesPerFrame : 0 ), | |
259 format, | |
260 NULL, | |
261 (doWrite ? Pa_GetDefaultOutputDeviceID() : paNoDevice), | |
262 (doWrite ? aStream->samplesPerFrame : 0 ), | |
263 format, | |
264 NULL, | |
265 sampleRate, | |
266 FRAMES_PER_BUFFER, | |
267 minNumBuffers, | |
268 paClipOff, /* we won't output out of range samples so don't bother clipping them */ | |
269 blockingIOCallback, | |
270 aStream ); | |
271 if( err != paNoError ) goto error; | |
272 | |
273 err = Pa_StartStream( aStream->stream ); | |
274 if( err != paNoError ) goto error; | |
275 | |
276 *rwblPtr = aStream; | |
277 return paNoError; | |
278 | |
279 error: | |
280 CloseAudioStream( aStream ); | |
281 *rwblPtr = NULL; | |
282 return err; | |
283 } | |
284 | |
285 /************************************************************/ | |
286 PaError CloseAudioStream( PABLIO_Stream *aStream ) | |
287 { | |
288 PaError err; | |
289 int bytesEmpty; | |
290 int byteSize = aStream->outFIFO.bufferSize; | |
291 | |
292 /* If we are writing data, make sure we play everything written. */ | |
293 if( byteSize > 0 ) | |
294 { | |
295 bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); | |
296 while( bytesEmpty < byteSize ) | |
297 { | |
298 Pa_Sleep( 10 ); | |
299 bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO ); | |
300 } | |
301 } | |
302 | |
303 err = Pa_StopStream( aStream->stream ); | |
304 if( err != paNoError ) goto error; | |
305 err = Pa_CloseStream( aStream->stream ); | |
306 if( err != paNoError ) goto error; | |
307 Pa_Terminate(); | |
308 | |
309 error: | |
310 PABLIO_TermFIFO( &aStream->inFIFO ); | |
311 PABLIO_TermFIFO( &aStream->outFIFO ); | |
312 free( aStream ); | |
313 return err; | |
314 } |