From 90fb73a91936ede98ccedda073929397ddf842b1 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 2 Aug 2012 20:43:30 +0200 Subject: New portaudio approach. --- src/Makefile.am | 6 +- src/audio.cc | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/audio.h | 1 + src/audioin.cc | 17 +++- src/audioout.cc | 7 +- src/crosscomposer.cc | 18 +++-- 6 files changed, 251 insertions(+), 12 deletions(-) create mode 100644 src/audio.cc create mode 100644 src/audio.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index db3a5b5..a57457a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,16 +2,18 @@ SUBDIRS = bin_PROGRAMS = crosscomposer -crosscomposer_LDADD = $(ALSA_LIBS) $(AO_LIBS) -crosscomposer_CXXFLAGS = $(ALSA_CFLAGS) $(AO_CFLAGS) +crosscomposer_LDADD = $(PA_LIBS) $(ALSA_LIBS) $(AO_LIBS) +crosscomposer_CXXFLAGS = $(PA_CFLAGS) $(ALSA_CFLAGS) $(AO_CFLAGS) crosscomposer_SOURCES = \ crosscomposer.cc \ + audio.cc \ audioin.cc \ audioout.cc \ socket.cc EXTRA_DIST = \ + audio.h \ audioin.h \ audioout.h \ socket.h diff --git a/src/audio.cc b/src/audio.cc new file mode 100644 index 0000000..ffe65c2 --- /dev/null +++ b/src/audio.cc @@ -0,0 +1,214 @@ +/* + * $Id: patest_read_record.c 757 2004-02-13 07:48:10Z rossbencina $ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * 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. + * + * 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. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * 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. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include + +/* #define SAMPLE_RATE (17932) // Test failure to open with this value. */ +#define SAMPLE_RATE (44100) +#define FRAMES_PER_BUFFER (32) +#define NUM_CHANNELS (1) +#define NUM_SECONDS (15) +/* #define DITHER_FLAG (paDitherOff) */ +#define DITHER_FLAG (0) + +/* @todo Underflow and overflow is disabled until we fix priming of blocking write. */ +#define CHECK_OVERFLOW (0) +#define CHECK_UNDERFLOW (0) + + +/* Select sample format. */ +#if 1 +#define PA_SAMPLE_TYPE paFloat32 +#define SAMPLE_SIZE (4) +#define SAMPLE_SILENCE (0.0f) +#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) +#define PRINTF_S_FORMAT "%.8f" +#elif 0 +#define PA_SAMPLE_TYPE paInt16 +#define SAMPLE_SIZE (2) +#define SAMPLE_SILENCE (0) +#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) +#define PRINTF_S_FORMAT "%d" +#elif 0 +#define PA_SAMPLE_TYPE paInt24 +#define SAMPLE_SIZE (3) +#define SAMPLE_SILENCE (0) +#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) +#define PRINTF_S_FORMAT "%d" +#elif 0 +#define PA_SAMPLE_TYPE paInt8 +#define SAMPLE_SIZE (1) +#define SAMPLE_SILENCE (0) +#define CLEAR(a) memset( (a), 0, FRAMES_PER_BUFFER * NUM_CHANNELS * SAMPLE_SIZE ) +#define PRINTF_S_FORMAT "%d" +#else +#define PA_SAMPLE_TYPE paUInt8 +#define SAMPLE_SIZE (1) +#define SAMPLE_SILENCE (128) +#define CLEAR( a ) { \ + int i; \ + for( i=0; idefaultLowInputLatency ); + printf( "Input HL: %g s\n", Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ); + inputParameters.channelCount = NUM_CHANNELS; + inputParameters.sampleFormat = PA_SAMPLE_TYPE; + inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultHighInputLatency ; + inputParameters.hostApiSpecificStreamInfo = NULL; + + outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ + printf( "Output device # %d.\n", outputParameters.device ); + printf( "Output LL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency ); + printf( "Output HL: %g s\n", Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency ); + outputParameters.channelCount = NUM_CHANNELS; + outputParameters.sampleFormat = PA_SAMPLE_TYPE; + outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultHighOutputLatency; + outputParameters.hostApiSpecificStreamInfo = NULL; + + /* -- setup -- */ + + err = Pa_OpenStream( + &stream, + &inputParameters, + &outputParameters, + SAMPLE_RATE, + FRAMES_PER_BUFFER, + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + NULL, /* no callback, use blocking API */ + NULL ); /* no callback, so no callback userData */ + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Wire on. Will run %d seconds.\n", NUM_SECONDS); fflush(stdout); + + for( i=0; i<(NUM_SECONDS*SAMPLE_RATE)/FRAMES_PER_BUFFER; ++i ) + { + err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err && CHECK_OVERFLOW ) goto xrun; + err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err && CHECK_UNDERFLOW ) goto xrun; + } + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + CLEAR( sampleBlock ); +/* + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + printf("Wire on. Interrupt to stop.\n"); fflush(stdout); + + while( 1 ) + { + err = Pa_WriteStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + err = Pa_ReadStream( stream, sampleBlock, FRAMES_PER_BUFFER ); + if( err ) goto xrun; + } + err = Pa_StopStream( stream ); + if( err != paNoError ) goto error; + + Pa_CloseStream( stream ); +*/ + free( sampleBlock ); + + Pa_Terminate(); + return 0; + +xrun: + if( stream ) { + Pa_AbortStream( stream ); + Pa_CloseStream( stream ); + } + free( sampleBlock ); + Pa_Terminate(); + if( err & paInputOverflow ) + fprintf( stderr, "Input Overflow.\n" ); + if( err & paOutputUnderflow ) + fprintf( stderr, "Output Underflow.\n" ); + return -2; + +error: + if( stream ) { + Pa_AbortStream( stream ); + Pa_CloseStream( stream ); + } + free( sampleBlock ); + 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; +} + + diff --git a/src/audio.h b/src/audio.h new file mode 100644 index 0000000..bf2370c --- /dev/null +++ b/src/audio.h @@ -0,0 +1 @@ +int pamain(); diff --git a/src/audioin.cc b/src/audioin.cc index 3792ae2..b15666f 100644 --- a/src/audioin.cc +++ b/src/audioin.cc @@ -29,6 +29,7 @@ AudioIn::AudioIn(std::string device, std::string mixer_interface, unsigned int srate, int ch) { + /* frames = 940; elem = NULL; @@ -78,6 +79,7 @@ AudioIn::AudioIn(std::string device, std::string mixer_interface, if (rc < 0) throw UnableToSetHWParams(); mixhnd = NULL; + */ /* // // Set up mixer @@ -138,8 +140,20 @@ AudioIn::~AudioIn() if(mixhnd) snd_mixer_close(mixhnd); } +#define TEST +#ifdef TEST +#include +#endif/*TEST*/ size_t AudioIn::read(sample_t *buf, size_t size) { +#ifdef TEST + static unsigned int x = 0; + for(size_t i = 0; i < size; i++) { + buf[i] = sin((float)x / 50.0); + x++; + } + return size; +#else int rc; if(size < frames * channels) { @@ -157,8 +171,9 @@ size_t AudioIn::read(sample_t *buf, size_t size) } else if (rc != (int)frames) { throw ShortRead(); } - + printf("rc: %d\n", rc); return rc * channels; +#endif/*TEST*/ } int AudioIn::set_level(unsigned int channel, float level) diff --git a/src/audioout.cc b/src/audioout.cc index 0495a2c..b0ab3d7 100644 --- a/src/audioout.cc +++ b/src/audioout.cc @@ -29,8 +29,6 @@ #define T(x, msg) if(x < 0) { printf("%s failed: %s\n", msg, snd_strerror(x)); fflush(stdout); } -#define BUFSZ 40960 - AudioOut::AudioOut(std::string device, unsigned int srate, int channels) { handle = NULL; @@ -83,5 +81,8 @@ AudioOut::~AudioOut() void AudioOut::write(sample_t *samples, size_t size) { // Write the interleaved buffer to the soundcard - snd_pcm_writei(handle, samples, size); + size_t sz = 0; + while(size > sz) { + sz += snd_pcm_writei(handle, samples + sz, size - sz); + } } diff --git a/src/crosscomposer.cc b/src/crosscomposer.cc index 010aa92..169fd4c 100644 --- a/src/crosscomposer.cc +++ b/src/crosscomposer.cc @@ -32,13 +32,19 @@ #include "audioin.h" #include "audioout.h" +#include "audio.h" + #define NUM_SAMPLES 940 int main(int argc, char *argv[]) { - sample_t samples[940]; + sample_t samples[NUM_SAMPLES]; Socket s; s.open("127.0.0.1", 10000); + int loop = 100; + + return pamain(); + switch(fork()) { case 0: @@ -46,11 +52,11 @@ int main(int argc, char *argv[]) AudioIn in("default", "Capture", 44100, 1); s.setSend(0); - int i = 50; - while(i--) { + while(loop--) { int sz = in.read(samples, NUM_SAMPLES); for(size_t i = 0; i < NUM_SAMPLES; i++) { - samples[i] = ((sample_t)rand() / (float)RAND_MAX) * 10; + //samples[i] = ((sample_t)rand() / (float)RAND_MAX) * 10; + //samples[i] *= 30; } s.sendTo(samples, sz * sizeof(sample_t)); printf("s"); fflush(stdout); @@ -64,10 +70,10 @@ int main(int argc, char *argv[]) s.setRecv(); AudioOut out("default", 44100, 1); - int i = 50; - while(i--) { + while(loop--) { int sz = s.recvFrom(samples, sizeof(samples)); out.write(samples, sz / sizeof(sample_t)); + sz = sz; printf("r%f", samples[0]); fflush(stdout); } printf("R!\n"); -- cgit v1.2.3