Update of /cvsroot/pure-data/pd/portaudio/pablio In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12467
Added Files: Tag: devel_0_38 README.txt pablio.c pablio.def pablio.h ringbuffer.c ringbuffer.h test_rw.c test_rw_echo.c test_w_saw.c test_w_saw8.c Log Message: checking in pablio
--- NEW FILE: ringbuffer.c --- /* * $Id: ringbuffer.c,v 1.2.2.2 2005/06/28 16:37:42 timblech Exp $ * ringbuffer.c * Ring Buffer utility.. * * Author: Phil Burk, http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "ringbuffer.h" #include <string.h>
/*************************************************************************** * Initialize FIFO. * numBytes must be power of 2, returns -1 if not. */ long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr ) { if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */ rbuf->bufferSize = numBytes; rbuf->buffer = (char *)dataPtr; RingBuffer_Flush( rbuf ); rbuf->bigMask = (numBytes*2)-1; rbuf->smallMask = (numBytes)-1; return 0; } /*************************************************************************** ** Return number of bytes available for reading. */ long RingBuffer_GetReadAvailable( RingBuffer *rbuf ) { return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); } /*************************************************************************** ** Return number of bytes available for writing. */ long RingBuffer_GetWriteAvailable( RingBuffer *rbuf ) { return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf)); }
/*************************************************************************** ** Clear buffer. Should only be called when buffer is NOT being read. */ void RingBuffer_Flush( RingBuffer *rbuf ) { rbuf->writeIndex = rbuf->readIndex = 0; }
/*************************************************************************** ** Get address of region(s) to which we can write data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ) { long index; long available = RingBuffer_GetWriteAvailable( rbuf ); if( numBytes > available ) numBytes = available; /* Check to see if write is not contiguous. */ index = rbuf->writeIndex & rbuf->smallMask; if( (index + numBytes) > rbuf->bufferSize ) { /* Write data in two blocks that wrap the buffer. */ long firstHalf = rbuf->bufferSize - index; *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = firstHalf; *dataPtr2 = &rbuf->buffer[0]; *sizePtr2 = numBytes - firstHalf; } else { *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = numBytes; *dataPtr2 = NULL; *sizePtr2 = 0; } return numBytes; }
/*************************************************************************** */ long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes ) { return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask; }
/*************************************************************************** ** Get address of region(s) from which we can read data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ) { long index; long available = RingBuffer_GetReadAvailable( rbuf ); if( numBytes > available ) numBytes = available; /* Check to see if read is not contiguous. */ index = rbuf->readIndex & rbuf->smallMask; if( (index + numBytes) > rbuf->bufferSize ) { /* Write data in two blocks that wrap the buffer. */ long firstHalf = rbuf->bufferSize - index; *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = firstHalf; *dataPtr2 = &rbuf->buffer[0]; *sizePtr2 = numBytes - firstHalf; } else { *dataPtr1 = &rbuf->buffer[index]; *sizePtr1 = numBytes; *dataPtr2 = NULL; *sizePtr2 = 0; } return numBytes; } /*************************************************************************** */ long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes ) { return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask; }
/*************************************************************************** ** Return bytes written. */ long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes ) { long size1, size2, numWritten; void *data1, *data2; numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); if( size2 > 0 ) {
memcpy( data1, data, size1 ); data = ((char *)data) + size1; memcpy( data2, data, size2 ); } else { memcpy( data1, data, size1 ); } RingBuffer_AdvanceWriteIndex( rbuf, numWritten ); return numWritten; }
/*************************************************************************** ** Return bytes read. */ long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes ) { long size1, size2, numRead; void *data1, *data2; numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); if( size2 > 0 ) { memcpy( data, data1, size1 ); data = ((char *)data) + size1; memcpy( data, data2, size2 ); } else { memcpy( data, data1, size1 ); } RingBuffer_AdvanceReadIndex( rbuf, numRead ); return numRead; }
--- NEW FILE: pablio.h --- #ifndef _PABLIO_H #define _PABLIO_H
#ifdef __cplusplus extern "C" { #endif /* __cplusplus */
/* * $Id: pablio.h,v 1.2.2.2 2005/06/28 16:37:42 timblech Exp $ * PABLIO.h * Portable Audio Blocking read/write utility. * * Author: Phil Burk, http://www.softsynth.com/portaudio/ * * Include file for PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "portaudio.h" #include "ringbuffer.h" #include <string.h>
typedef struct { RingBuffer inFIFO; RingBuffer outFIFO; PortAudioStream *stream; int bytesPerFrame; int samplesPerFrame; } PABLIO_Stream;
/* Values for flags for OpenAudioStream(). */ #define PABLIO_READ (1<<0) #define PABLIO_WRITE (1<<1) #define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE) #define PABLIO_MONO (1<<2) #define PABLIO_STEREO (1<<3)
/************************************************************ * Write data to ring buffer. * Will not return until all the data has been written. */ long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
/************************************************************ * Read data from ring buffer. * Will not return until all the data has been read. */ long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
/************************************************************ * Return the number of frames that could be written to the stream without * having to wait. */ long GetAudioStreamWriteable( PABLIO_Stream *aStream );
/************************************************************ * Return the number of frames that are available to be read from the * stream without having to wait. */ long GetAudioStreamReadable( PABLIO_Stream *aStream );
/************************************************************ * Opens a PortAudio stream with default characteristics. * Allocates PABLIO_Stream structure. * * flags parameter can be an ORed combination of: * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, * and either PABLIO_MONO or PABLIO_STEREO */ PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate, PaSampleFormat format, long flags );
PaError CloseAudioStream( PABLIO_Stream *aStream );
#ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _PABLIO_H */
--- NEW FILE: test_w_saw.c --- /* * $Id: test_w_saw.c,v 1.2.2.2 2005/06/28 16:37:42 timblech Exp $ * test_w_saw.c * Generate stereo sawtooth waveforms. * * Author: Phil Burk, http://www.softsynth.com * * This program uses PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */
#include <stdio.h> #include <stdlib.h> #include <math.h> #include "pablio.h" #include <string.h>
#define SAMPLE_RATE (44100) #define NUM_SECONDS (6) #define SAMPLES_PER_FRAME (2)
#define FREQUENCY (220.0f) #define PHASE_INCREMENT (2.0f * FREQUENCY / SAMPLE_RATE) #define FRAMES_PER_BLOCK (100)
float samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME]; float phases[SAMPLES_PER_FRAME];
/*******************************************************************/ int main(void); int main(void) { int i,j; PaError err; PABLIO_Stream *aOutStream;
printf("Generate sawtooth waves using PABLIO.\n"); fflush(stdout);
/* Open simplified blocking I/O layer on top of PortAudio. */ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paFloat32, (PABLIO_WRITE | PABLIO_STEREO) ); if( err != paNoError ) goto error;
/* Initialize oscillator phases. */ phases[0] = 0.0; phases[1] = 0.0;
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) { /* Generate sawtooth waveforms in a block for efficiency. */ for( j=0; j<FRAMES_PER_BLOCK; j++ ) { /* Generate a sawtooth wave by incrementing a variable. */ phases[0] += PHASE_INCREMENT; /* The signal range is -1.0 to +1.0 so wrap around if we go over. */ if( phases[0] > 1.0f ) phases[0] -= 2.0f; samples[j][0] = phases[0];
/* On the second channel, generate a sawtooth wave a fifth higher. */ phases[1] += PHASE_INCREMENT * (3.0f / 2.0f); if( phases[1] > 1.0f ) phases[1] -= 2.0f; samples[j][1] = phases[1]; }
/* Write samples to output. */ WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK ); }
CloseAudioStream( aOutStream );
printf("Sawtooth sound test complete.\n" ); fflush(stdout); return 0;
error: fprintf( stderr, "An error occured while using PABLIO\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; }
--- NEW FILE: test_rw.c --- /* * $Id: test_rw.c,v 1.2.2.2 2005/06/28 16:37:42 timblech Exp $ * test_rw.c * Read input from one stream and write it to another. * * Author: Phil Burk, http://www.softsynth.com/portaudio/ * * This program uses PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */
#include <stdio.h> #include <stdlib.h> #include "pablio.h"
/* ** Note that many of the older ISA sound cards on PCs do NOT support ** full duplex audio (simultaneous record and playback). ** And some only support full duplex at lower sample rates. */ #define SAMPLE_RATE (44100) #define NUM_SECONDS (5) #define SAMPLES_PER_FRAME (2) #define FRAMES_PER_BLOCK (64)
/* Select whether we will use floats or shorts. */ #if 1 #define SAMPLE_TYPE paFloat32 typedef float SAMPLE; #else #define SAMPLE_TYPE paInt16 typedef short SAMPLE; #endif
/*******************************************************************/ int main(void); int main(void) { int i; SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK]; PaError err; PABLIO_Stream *aStream;
printf("Full duplex sound test using PortAudio and RingBuffers\n"); fflush(stdout);
/* Open simplified blocking I/O layer on top of PortAudio. */ err = OpenAudioStream( &aStream, SAMPLE_RATE, SAMPLE_TYPE, (PABLIO_READ_WRITE | PABLIO_STEREO) ); if( err != paNoError ) goto error;
/* Process samples in the foreground. */ for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) { /* Read one block of data into sample array from audio input. */ ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK ); /* Write that same block of data to output. */ WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK ); }
CloseAudioStream( aStream );
printf("Full duplex sound test complete.\n" ); fflush(stdout); return 0;
error: Pa_Terminate(); fprintf( stderr, "An error occured while using the portaudio stream\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; }
--- NEW FILE: README.txt --- README for PABLIO Portable Audio Blocking I/O Library Author: Phil Burk
PABLIO is a simplified interface to PortAudio that provide read/write style blocking I/O.
Please see the .DOC file for documentation.
/* * More information on PortAudio at: http://www.portaudio.com * Copyright (c) 1999-2000 Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */
--- NEW FILE: ringbuffer.h --- #ifndef _RINGBUFFER_H #define _RINGBUFFER_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */
/* * $Id: ringbuffer.h,v 1.2.2.2 2005/06/28 16:37:42 timblech Exp $ * ringbuffer.h * Ring Buffer utility.. * * Author: Phil Burk, http://www.softsynth.com * * This program is distributed with the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "ringbuffer.h" #include <string.h>
typedef struct { long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */ long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */ long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */ long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */ long smallMask; /* Used for fitting indices to buffer. */ char *buffer; } RingBuffer; /* * Initialize Ring Buffer. * numBytes must be power of 2, returns -1 if not. */ long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
/* Clear buffer. Should only be called when buffer is NOT being read. */ void RingBuffer_Flush( RingBuffer *rbuf );
/* Return number of bytes available for writing. */ long RingBuffer_GetWriteAvailable( RingBuffer *rbuf ); /* Return number of bytes available for read. */ long RingBuffer_GetReadAvailable( RingBuffer *rbuf ); /* Return bytes written. */ long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes ); /* Return bytes read. */ long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
/* Get address of region(s) to which we can write data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 ); long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
/* Get address of region(s) from which we can read data. ** If the region is contiguous, size2 will be zero. ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2 );
long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
#ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _RINGBUFFER_H */
--- NEW FILE: test_w_saw8.c --- /* * $Id: test_w_saw8.c,v 1.2.2.2 2005/06/28 16:37:42 timblech Exp $ * test_w_saw8.c * Generate stereo 8 bit sawtooth waveforms. * * Author: Phil Burk, http://www.softsynth.com * * This program uses PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */
#include <stdio.h> #include <stdlib.h> #include <math.h> #include "pablio.h" #include <string.h>
#define SAMPLE_RATE (22050) #define NUM_SECONDS (6) #define SAMPLES_PER_FRAME (2)
#define FRAMES_PER_BLOCK (100)
unsigned char samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME]; unsigned char phases[SAMPLES_PER_FRAME];
/*******************************************************************/ int main(void); int main(void) { int i,j; PaError err; PABLIO_Stream *aOutStream;
printf("Generate unsigned 8 bit sawtooth waves using PABLIO.\n"); fflush(stdout);
/* Open simplified blocking I/O layer on top of PortAudio. */ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paUInt8, (PABLIO_WRITE | PABLIO_STEREO) ); if( err != paNoError ) goto error;
/* Initialize oscillator phases to "ground" level for paUInt8. */ phases[0] = 128; phases[1] = 128;
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK ) { /* Generate sawtooth waveforms in a block for efficiency. */ for( j=0; j<FRAMES_PER_BLOCK; j++ ) { /* Generate a sawtooth wave by incrementing a variable. */ phases[0] += 1; /* We don't have to do anything special to wrap when using paUint8 because * 8 bit arithmetic automatically wraps. */ samples[j][0] = phases[0];
/* On the second channel, generate a higher sawtooth wave. */ phases[1] += 3; samples[j][1] = phases[1]; }
/* Write samples to output. */ WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK ); }
CloseAudioStream( aOutStream );
printf("Sawtooth sound test complete.\n" ); fflush(stdout); return 0;
error: fprintf( stderr, "An error occured while using PABLIO\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; }
--- NEW FILE: pablio.c --- /* * $Id: pablio.c,v 1.2.2.2 2005/06/28 16:37:42 timblech Exp $ * pablio.c * Portable Audio Blocking Input/Output utility. * * Author: Phil Burk, http://www.softsynth.com * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include <stdio.h> #include <stdlib.h> #include <math.h> #include "portaudio.h" #include "ringbuffer.h" #include "pablio.h" #include <string.h>
/************************************************************************/ /******** Constants *****************************************************/ /************************************************************************/
#define FRAMES_PER_BUFFER (256)
/************************************************************************/ /******** Prototypes ****************************************************/ /************************************************************************/
static int blockingIOCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ); static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame ); static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
/************************************************************************/ /******** Functions *****************************************************/ /************************************************************************/
/* Called from PortAudio. * Read and write data only if there is room in FIFOs. */ static int blockingIOCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *userData ) { PABLIO_Stream *data = (PABLIO_Stream*)userData; long numBytes = data->bytesPerFrame * framesPerBuffer; (void) outTime;
/* This may get called with NULL inputBuffer during initial setup. */ if( inputBuffer != NULL ) { RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes ); } if( outputBuffer != NULL ) { int i; int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes ); /* Zero out remainder of buffer if we run out of data. */ for( i=numRead; i<numBytes; i++ ) { ((char *)outputBuffer)[i] = 0; } }
return 0; }
/* Allocate buffer. */ static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame ) { long numBytes = numFrames * bytesPerFrame; char *buffer = (char *) malloc( numBytes ); if( buffer == NULL ) return paInsufficientMemory; memset( buffer, 0, numBytes ); return (PaError) RingBuffer_Init( rbuf, numBytes, buffer ); }
/* Free buffer. */ static PaError PABLIO_TermFIFO( RingBuffer *rbuf ) { if( rbuf->buffer ) free( rbuf->buffer ); rbuf->buffer = NULL; return paNoError; }
/************************************************************ * Write data to ring buffer. * Will not return until all the data has been written. */ long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) { long bytesWritten; char *p = (char *) data; long numBytes = aStream->bytesPerFrame * numFrames; while( numBytes > 0) { bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes ); numBytes -= bytesWritten; p += bytesWritten; if( numBytes > 0) Pa_Sleep(10); } return numFrames; }
/************************************************************ * Read data from ring buffer. * Will not return until all the data has been read. */ long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) { long bytesRead; char *p = (char *) data; long numBytes = aStream->bytesPerFrame * numFrames; while( numBytes > 0) { bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes ); numBytes -= bytesRead; p += bytesRead; if( numBytes > 0) Pa_Sleep(10); } return numFrames; }
/************************************************************ * Return the number of frames that could be written to the stream without * having to wait. */ long GetAudioStreamWriteable( PABLIO_Stream *aStream ) { int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); return bytesEmpty / aStream->bytesPerFrame; }
/************************************************************ * Return the number of frames that are available to be read from the * stream without having to wait. */ long GetAudioStreamReadable( PABLIO_Stream *aStream ) { int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO ); return bytesFull / aStream->bytesPerFrame; }
/************************************************************/ static unsigned long RoundUpToNextPowerOf2( unsigned long n ) { long numBits = 0; if( ((n-1) & n) == 0) return n; /* Already Power of two. */ while( n > 0 ) { n= n>>1; numBits++; } return (1<<numBits); }
/************************************************************ * Opens a PortAudio stream with default characteristics. * Allocates PABLIO_Stream structure. * * flags parameter can be an ORed combination of: * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, * and either PABLIO_MONO or PABLIO_STEREO */ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate, PaSampleFormat format, long flags ) { long bytesPerSample; long doRead = 0; long doWrite = 0; PaError err; PABLIO_Stream *aStream; long minNumBuffers; long numFrames;
/* Allocate PABLIO_Stream structure for caller. */ aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) ); if( aStream == NULL ) return paInsufficientMemory; memset( aStream, 0, sizeof(PABLIO_Stream) );
/* Determine size of a sample. */ bytesPerSample = Pa_GetSampleSize( format ); if( bytesPerSample < 0 ) { err = (PaError) bytesPerSample; goto error; } aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2; aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
/* Initialize PortAudio */ err = Pa_Initialize(); if( err != paNoError ) goto error;
/* Warning: numFrames must be larger than amount of data processed per interrupt * inside PA to prevent glitches. Just to be safe, adjust size upwards. */ minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate ); numFrames = minNumBuffers * FRAMES_PER_BUFFER; numFrames = RoundUpToNextPowerOf2( numFrames );
/* Initialize Ring Buffers */ doRead = ((flags & PABLIO_READ) != 0); doWrite = ((flags & PABLIO_WRITE) != 0); if(doRead) { err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame ); if( err != paNoError ) goto error; } if(doWrite) { long numBytes; err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame ); if( err != paNoError ) goto error; /* Make Write FIFO appear full initially. */ numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes ); }
/* Open a PortAudio stream that we will use to communicate with the underlying * audio drivers. */ err = Pa_OpenStream( &aStream->stream, (doRead ? Pa_GetDefaultInputDeviceID() : paNoDevice), (doRead ? aStream->samplesPerFrame : 0 ), format, NULL, (doWrite ? Pa_GetDefaultOutputDeviceID() : paNoDevice), (doWrite ? aStream->samplesPerFrame : 0 ), format, NULL, sampleRate, FRAMES_PER_BUFFER, minNumBuffers, paClipOff, /* we won't output out of range samples so don't bother clipping them */ blockingIOCallback, aStream ); if( err != paNoError ) goto error;
err = Pa_StartStream( aStream->stream ); if( err != paNoError ) goto error;
*rwblPtr = aStream; return paNoError;
error: CloseAudioStream( aStream ); *rwblPtr = NULL; return err; }
/************************************************************/ PaError CloseAudioStream( PABLIO_Stream *aStream ) { PaError err; int bytesEmpty; int byteSize = aStream->outFIFO.bufferSize;
/* If we are writing data, make sure we play everything written. */ if( byteSize > 0 ) { bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); while( bytesEmpty < byteSize ) { Pa_Sleep( 10 ); bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO ); } }
err = Pa_StopStream( aStream->stream ); if( err != paNoError ) goto error; err = Pa_CloseStream( aStream->stream ); if( err != paNoError ) goto error; Pa_Terminate();
error: PABLIO_TermFIFO( &aStream->inFIFO ); PABLIO_TermFIFO( &aStream->outFIFO ); free( aStream ); return err; }
--- NEW FILE: pablio.def --- LIBRARY PABLIO DESCRIPTION 'PABLIO Portable Audio Blocking I/O'
EXPORTS ; Explicit exports can go here Pa_Initialize @1 Pa_Terminate @2 Pa_GetHostError @3 Pa_GetErrorText @4 Pa_CountDevices @5 Pa_GetDefaultInputDeviceID @6 Pa_GetDefaultOutputDeviceID @7 Pa_GetDeviceInfo @8 Pa_OpenStream @9 Pa_OpenDefaultStream @10 Pa_CloseStream @11 Pa_StartStream @12 Pa_StopStream @13 Pa_StreamActive @14 Pa_StreamTime @15 Pa_GetCPULoad @16 Pa_GetMinNumBuffers @17 Pa_Sleep @18
OpenAudioStream @19 CloseAudioStream @20 WriteAudioStream @21 ReadAudioStream @22
Pa_GetSampleSize @23
;123456789012345678901234567890123456 ;000000000111111111122222222223333333
--- NEW FILE: test_rw_echo.c --- /* * $Id: test_rw_echo.c,v 1.2.2.2 2005/06/28 16:37:42 timblech Exp $ * test_rw_echo.c * Echo delayed input to output. * * Author: Phil Burk, http://www.softsynth.com/portaudio/ * * This program uses PABLIO, the Portable Audio Blocking I/O Library. * PABLIO is built on top of PortAudio, the Portable Audio Library. * * Note that if you need low latency, you should not use PABLIO. * Use the PA_OpenStream callback technique which is lower level * than PABLIO. * * For more information see: http://www.audiomulch.com/portaudio/ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * Any person wishing to distribute modifications to the Software is * requested to send the modifications to the original developer so that * they can be incorporated into the canonical version. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */
#include <stdio.h> #include <stdlib.h> #include <math.h> #include "pablio.h" #include <string.h>
/* ** Note that many of the older ISA sound cards on PCs do NOT support ** full duplex audio (simultaneous record and playback). ** And some only support full duplex at lower sample rates. */ #define SAMPLE_RATE (22050) #define NUM_SECONDS (20) #define SAMPLES_PER_FRAME (2)
/* Select whether we will use floats or shorts. */ #if 1 #define SAMPLE_TYPE paFloat32 typedef float SAMPLE; #else #define SAMPLE_TYPE paInt16 typedef short SAMPLE; #endif
#define NUM_ECHO_FRAMES (2*SAMPLE_RATE) SAMPLE samples[NUM_ECHO_FRAMES][SAMPLES_PER_FRAME] = {0.0};
/*******************************************************************/ int main(void); int main(void) { int i; PaError err; PABLIO_Stream *aInStream; PABLIO_Stream *aOutStream; int index;
printf("Full duplex sound test using PABLIO\n"); fflush(stdout);
/* Open simplified blocking I/O layer on top of PortAudio. */ /* Open input first so it can start to fill buffers. */ err = OpenAudioStream( &aInStream, SAMPLE_RATE, SAMPLE_TYPE, (PABLIO_READ | PABLIO_STEREO) ); if( err != paNoError ) goto error; /* printf("opened input\n"); fflush(stdout); /**/
err = OpenAudioStream( &aOutStream, SAMPLE_RATE, SAMPLE_TYPE, (PABLIO_WRITE | PABLIO_STEREO) ); if( err != paNoError ) goto error; /* printf("opened output\n"); fflush(stdout); /**/
/* Process samples in the foreground. */ index = 0; for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ ) { /* Write old frame of data to output. */ /* samples[index][1] = (i&256) * (1.0f/256.0f); /* sawtooth */ WriteAudioStream( aOutStream, &samples[index][0], 1 );
/* Read one frame of data into sample array for later output. */ ReadAudioStream( aInStream, &samples[index][0], 1 ); index += 1; if( index >= NUM_ECHO_FRAMES ) index = 0;
if( (i & 0xFFFF) == 0 ) printf("i = %d\n", i ); fflush(stdout); /**/ }
CloseAudioStream( aOutStream ); CloseAudioStream( aInStream );
printf("R/W echo sound test complete.\n" ); fflush(stdout); return 0;
error: fprintf( stderr, "An error occured while using PortAudio\n" ); fprintf( stderr, "Error number: %d\n", err ); fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); return -1; }