From 1cce154d1d446cf8d2cb7e856563bcf10b350248 Mon Sep 17 00:00:00 2001 From: c vw Date: Fri, 8 Nov 2019 17:35:34 +0100 Subject: [PATCH] Modified to John's new audio interface --- portaudio.c | 181 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 104 insertions(+), 77 deletions(-) diff --git a/portaudio.c b/portaudio.c index cae5b1d..c46f451 100644 --- a/portaudio.c +++ b/portaudio.c @@ -8,6 +8,11 @@ // If PortAudio is NOT used, this file is empty, and audio.c // is used instead. // +// It seems that a PortAudio device can only be opened once, +// therefore there is no need to support stereo output. +// (cw_)audio_write therefore put the sum of left and right +// channel to a (mono) output stream +// #include @@ -23,29 +28,23 @@ #include "new_protocol.h" #include "old_protocol.h" -#ifdef RADIOBERRY -#include "radioberry.h" -#endif #include "radio.h" #include "receiver.h" #include "mode.h" #include "portaudio.h" -#include "math.h" // for sintab, two-tone generator +#include "audio.h" static PaStream *record_handle=NULL; -#define MAXDEVICES 12 - -const char *input_devices[MAXDEVICES]; -const char *output_devices[MAXDEVICES]; +int n_input_devices; +AUDIO_DEVICE input_devices[MAX_AUDIO_DEVICES]; +int n_output_devices; +AUDIO_DEVICE output_devices[MAX_AUDIO_DEVICES]; int n_input_devices=0; int n_output_devices=0; -static int in_device_no[MAXDEVICES]; -static int out_device_no[MAXDEVICES]; - -static unsigned char *mic_buffer=NULL; +static float *mic_buffer=NULL; static int mic_buffer_size; static int audio_buffer_size=256; @@ -84,9 +83,16 @@ void audio_get_cards() inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ inputParameters.hostApiSpecificStreamInfo = NULL; if (Pa_IsFormatSupported(&inputParameters, NULL, 48000.0) == paFormatIsSupported) { - if (n_input_devices < MAXDEVICES) { - input_devices[n_input_devices]=deviceInfo->name; - in_device_no[n_input_devices++] =i; + if (n_input_devices < MAX_AUDIO_DEVICES) { + // + // probably not necessary with portaudio, but to be on the safe side, + // we copy the device name to local storage. This is referenced both + // by the name and description element. + // + input_devices[n_input_devices].name=input_devices[n_input_devices].description=g_new0(char,strlen(deviceInfo->name)+1); + strcpy(input_devices[n_input_devices].name, deviceInfo->name); + input_devices[n_input_devices].index=i; + n_input_devices++; } fprintf(stderr,"PORTAUDIO INPUT DEVICE, No=%d, Name=%s\n", i, deviceInfo->name); } @@ -97,9 +103,11 @@ void audio_get_cards() outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */ outputParameters.hostApiSpecificStreamInfo = NULL; if (Pa_IsFormatSupported(NULL, &outputParameters, 48000.0) == paFormatIsSupported) { - if (n_output_devices < MAXDEVICES) { - output_devices[n_output_devices]=deviceInfo->name; - out_device_no[n_output_devices++] =i; + if (n_output_devices < MAX_AUDIO_DEVICES) { + output_devices[n_output_devices].name=output_devices[n_output_devices].description=g_new0(char,strlen(deviceInfo->name)+1); + strcpy(output_devices[n_output_devices].name, deviceInfo->name); + output_devices[n_output_devices].index=i; + n_output_devices++; } fprintf(stderr,"PORTAUDIO OUTPUT DEVICE, No=%d, Name=%s\n", i, deviceInfo->name); } @@ -122,35 +130,53 @@ int audio_open_input() PaStreamParameters inputParameters, outputParameters; long framesPerBuffer; int i; + int padev; - fprintf(stderr,"audio_open_input: %d\n",transmitter->input_device); - if(transmitter->input_device<0 || transmitter->input_device>=n_input_devices) { - transmitter->input_device=0; + if(transmitter->microphone_name==NULL) { + transmitter->local_microphone=0; + return -1; + } + // + // Look up device name and determine device ID + // + padev=-1; + for (i=0; imicrophone_name, input_devices[i].name)) { + padev=input_devices[i].index; + break; + } + } + fprintf(stderr,"audio_open_input: name=%s PADEV=%d\n",transmitter->microphone_name,padev); + // + // Should not occur, but possibly device name not found + // + if (padev < 0) { return -1; } switch(protocol) { case ORIGINAL_PROTOCOL: +#ifdef SOAPYSDR + case SOAPYSDR_PROTOCOL: +#endif framesPerBuffer = 720; break; case NEW_PROTOCOL: framesPerBuffer = 64; break; -#ifdef RADIOBERRY - case RADIOBERRY_PROTOCOL: - framesPerBuffer = 1024; - break; -#endif default: + framesPerBuffer = 720; // we should never come here break; } + mic_buffer_size=framesPerBuffer; + fprintf(stderr,"audio_open_input: mic_buffer_size=%d\n",mic_buffer_size); bzero( &inputParameters, sizeof( inputParameters ) ); //not necessary if you are filling in all the fields - inputParameters.channelCount = 1; - inputParameters.device = in_device_no[transmitter->input_device]; + inputParameters.channelCount = 1; // MONO + inputParameters.device = padev; inputParameters.hostApiSpecificStreamInfo = NULL; inputParameters.sampleFormat = paFloat32; - inputParameters.suggestedLatency = Pa_GetDeviceInfo(in_device_no[transmitter->input_device])->defaultLowInputLatency ; + inputParameters.suggestedLatency = Pa_GetDeviceInfo(padev)->defaultLowInputLatency ; inputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field err = Pa_OpenStream(&record_handle, &inputParameters, NULL, 48000.0, framesPerBuffer, paNoFlag, pa_mic_cb, NULL); @@ -164,8 +190,7 @@ int audio_open_input() fprintf(stderr, "PORTAUDIO ERROR: AOI start stream:%s\n",Pa_GetErrorText(err)); return -1; } - mic_buffer=(unsigned char *)malloc(2*framesPerBuffer); - mic_buffer_size=framesPerBuffer; + mic_buffer=g_new0(float,mic_buffer_size); return 0; } @@ -177,43 +202,32 @@ int pa_mic_cb(const void *inputBuffer, void *outputBuffer, unsigned long framesP PaStreamCallbackFlags statusFlags, void *userdata) { - const float *in = (float *)inputBuffer; + float *in = (float *)inputBuffer; int i; - short isample; - unsigned char *p; -// -// Convert input buffer in paFloat32 into a sequence of 16-bit -// values in the mic buffer. -// if (mic_buffer == NULL) return paAbort; - p=mic_buffer; +// +// if something does not look good, fill mic_buffer with silence +// if (in == NULL || framesPerBuffer != mic_buffer_size) { - for (i=0; i> 8)& 0xFF; - } + memcpy(mic_buffer, in, sizeof(float)*mic_buffer_size); } // // Call routine to send mic buffer // switch(protocol) { case ORIGINAL_PROTOCOL: - old_protocol_process_local_mic(mic_buffer,1); + old_protocol_process_local_mic(mic_buffer); break; case NEW_PROTOCOL: - new_protocol_process_local_mic(mic_buffer,1); + new_protocol_process_local_mic(mic_buffer); break; -#ifdef RADIOBERRY - case RADIOBERRY_PROTOCOL: - radioberry_protocol_process_local_mic(mic_buffer,1); +#ifdef SOAPYSDR + case SOAPYSDR_PROTOCOL: + soapy_protocol_process_local_mic(mic_buffer); break; #endif default: @@ -232,13 +246,32 @@ int audio_open_output(RECEIVER *rx) PaError err; PaStreamParameters outputParameters; long framesPerBuffer=(long) audio_buffer_size; + int padev; + int i; - int padev = out_device_no[rx->audio_device]; - fprintf(stderr,"audio_open_output: %d PADEV=%d\n",rx->audio_device,padev); - if(rx->audio_device<0 || rx->audio_device>=n_output_devices) { - rx->audio_device=-1; + if(rx->audio_name==NULL) { + rx->local_audio=0; + return -1; + } + // + // Look up device name and determine device ID + // + padev=-1; + for (i=0; iaudio_name, output_devices[i].name)) { + padev=output_devices[i].index; + break; + } + } + fprintf(stderr,"audio_open_output: name=%s PADEV=%d\n",rx->audio_name,padev); + // + // Should not occur, but possibly device name not found + // + if (padev < 0) { return -1; } + + bzero( &outputParameters, sizeof( outputParameters ) ); //not necessary if you are filling in all the fields outputParameters.channelCount = 1; // Always MONO outputParameters.device = padev; @@ -247,13 +280,13 @@ int audio_open_output(RECEIVER *rx) outputParameters.suggestedLatency = Pa_GetDeviceInfo(padev)->defaultLowOutputLatency ; outputParameters.hostApiSpecificStreamInfo = NULL; //See you specific host's API docs for info on using this field - // Try using AudioWrite without a call-back function + // Do not use call-back function, just stream it rx->playback_buffer=malloc(audio_buffer_size*sizeof(float)); rx->playback_offset=0; err = Pa_OpenStream(&(rx->playback_handle), NULL, &outputParameters, 48000.0, framesPerBuffer, paNoFlag, NULL, NULL); if (err != paNoError) { - fprintf(stderr,"PORTAUDIO ERROR: AOO open stream: %s\n",Pa_GetErrorText(err)); + fprintf(stderr,"PORTAUDIO ERROR: out open stream: %s\n",Pa_GetErrorText(err)); rx->playback_handle = NULL; if (rx->playback_buffer) free(rx->playback_buffer); rx->playback_buffer = NULL; @@ -262,7 +295,7 @@ int audio_open_output(RECEIVER *rx) err = Pa_StartStream(rx->playback_handle); if (err != paNoError) { - fprintf(stderr,"PORTAUDIO ERROR: AOO start stream:%s\n",Pa_GetErrorText(err)); + fprintf(stderr,"PORTAUDIO ERROR: out start stream:%s\n",Pa_GetErrorText(err)); rx->playback_handle=NULL; if (rx->playback_buffer) free(rx->playback_buffer); rx->playback_buffer = NULL; @@ -284,16 +317,16 @@ void audio_close_input() { PaError err; - fprintf(stderr,"AudioCloseInput: %d\n", transmitter->input_device); + fprintf(stderr,"AudioCloseInput: %s\n", transmitter->microphone_name); if(record_handle!=NULL) { err = Pa_StopStream(record_handle); if (err != paNoError) { - fprintf(stderr,"PORTAUDIO ERROR: ACI stop stream: %s\n",Pa_GetErrorText(err)); + fprintf(stderr,"PORTAUDIO ERROR: in stop stream: %s\n",Pa_GetErrorText(err)); } err = Pa_CloseStream(record_handle); if (err != paNoError) { - fprintf(stderr,"PORTAUDIO ERROR: ACI close stream: %s\n",Pa_GetErrorText(err)); + fprintf(stderr,"PORTAUDIO ERROR: in close stream: %s\n",Pa_GetErrorText(err)); } record_handle=NULL; } @@ -311,7 +344,7 @@ void audio_close_input() void audio_close_output(RECEIVER *rx) { PaError err; - fprintf(stderr,"AudioCloseOutput: %d\n", rx->audio_device); + fprintf(stderr,"AudioCloseOutput: %s\n", rx->audio_name); // free the buffer first, this then indicates to audio_write to do nothing if(rx->playback_buffer!=NULL) { @@ -322,11 +355,11 @@ void audio_close_output(RECEIVER *rx) { if(rx->playback_handle!=NULL) { err = Pa_StopStream(rx->playback_handle); if (err != paNoError) { - fprintf(stderr,"PORTAUDIO ERROR: ACO stop stream: %s\n",Pa_GetErrorText(err)); + fprintf(stderr,"PORTAUDIO ERROR: out stop stream: %s\n",Pa_GetErrorText(err)); } err = Pa_CloseStream(rx->playback_handle); if (err != paNoError) { - fprintf(stderr,"PORTAUDIO ERROR: ACO close stream: %s\n",Pa_GetErrorText(err)); + fprintf(stderr,"PORTAUDIO ERROR: out close stream: %s\n",Pa_GetErrorText(err)); } rx->playback_handle=NULL; } @@ -339,7 +372,7 @@ void audio_close_output(RECEIVER *rx) { // we have to store the data such that the PA callback function // can access it. // -int audio_write (RECEIVER *rx, short r, short l) +int audio_write (RECEIVER *rx, short l, short r) { PaError err; int mode=transmitter->mode; @@ -356,12 +389,9 @@ int audio_write (RECEIVER *rx, short r, short l) if (rx->playback_handle != NULL && rx->playback_buffer != NULL) { rx->playback_buffer[rx->playback_offset++] = (r + l) *0.000015259; // 65536 --> 1.0 if (rx->playback_offset == audio_buffer_size) { - rx->playback_offset=0; err=Pa_WriteStream(rx->playback_handle, (void *) rx->playback_buffer, (unsigned long) audio_buffer_size); - //if (err != paNoError) { - // fprintf(stderr,"PORTAUDIO ERROR: write stream dev=%d: %s\n",out_device_no[rx->audio_device],Pa_GetErrorText(err)); - // return -1; - // } + rx->playback_offset=0; + // do not check on errors, there will be underflows every now and then } } return 0; @@ -374,12 +404,9 @@ int cw_audio_write(double sample) { if (rx->playback_handle != NULL && rx->playback_buffer != NULL) { rx->playback_buffer[rx->playback_offset++] = sample; if (rx->playback_offset == audio_buffer_size) { - rx->playback_offset=0; err=Pa_WriteStream(rx->playback_handle, (void *) rx->playback_buffer, (unsigned long) audio_buffer_size); - //if (err != paNoError) { - // fprintf(stderr,"PORTAUDIO ERROR: write stream dev=%d: %s\n",out_device_no[rx->audio_device],Pa_GetErrorText(err)); - // return -1; - // } + // do not check on errors, there will be underflows every now and then + rx->playback_offset=0; } } return 0; -- 2.45.2