dsd-fme/src/dsd_audio.c

896 lines
27 KiB
C

/*
* Copyright (C) 2010 DSD Author
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "dsd.h"
pa_sample_spec ss;
pa_sample_spec tt;
pa_sample_spec zz;
pa_sample_spec cc;
pa_sample_spec ff; //float
void closePulseOutput (dsd_opts * opts)
{
pa_simple_free (opts->pulse_digi_dev_out);
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1) //EDACS analog calls and/or monitoring source analog audio
pa_simple_free (opts->pulse_raw_dev_out);
}
void closePulseInput (dsd_opts * opts)
{
pa_simple_free (opts->pulse_digi_dev_in);
}
void openPulseOutput(dsd_opts * opts)
{
ss.format = PA_SAMPLE_S16NE;
ss.channels = opts->pulse_raw_out_channels;
ss.rate = opts->pulse_raw_rate_out;
tt.format = PA_SAMPLE_S16NE;
tt.channels = opts->pulse_digi_out_channels;
tt.rate = opts->pulse_digi_rate_out;
ff.format = PA_SAMPLE_FLOAT32NE;
ff.channels = opts->pulse_digi_out_channels;
ff.rate = opts->pulse_digi_rate_out;
//reconfigured to open when using edacs or raw analog monitor so we can have a analog audio out that runs at 48k1 and not 8k1 float/short
if (opts->frame_provoice == 1 || opts->monitor_input_audio == 1)
opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD-FME3", PA_STREAM_PLAYBACK, NULL, "Analog", &ss, 0, NULL, NULL);
pa_channel_map* fl = 0; //NULL and 0 are same in this context
pa_channel_map* ss = 0; //NULL and 0 are same in this context
if (opts->floating_point == 0)
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &tt, ss, NULL, NULL);
if (opts->floating_point == 1)
opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD-FME", PA_STREAM_PLAYBACK, NULL, opts->output_name, &ff, fl, NULL, NULL);
}
void openPulseInput(dsd_opts * opts)
{
cc.format = PA_SAMPLE_S16NE;
cc.channels = opts->pulse_digi_in_channels;
cc.rate = opts->pulse_digi_rate_in; //48000
opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD-FME", PA_STREAM_RECORD, NULL, opts->output_name, &cc, NULL, NULL, NULL);
}
void openOSSOutput (dsd_opts * opts)
{
int fmt;
int speed = 48000;
if (opts->audio_in_type == 5) //if((strncmp(opts->audio_in_dev, "/dev/dsp", 8) == 0)) or 'split' == 0
{
if((strncmp(opts->audio_out_dev, "/dev/dsp", 8) == 0))
{
fprintf (stderr, "OSS Output %s.\n", opts->audio_out_dev);
opts->audio_out_fd = open (opts->audio_out_dev, O_RDWR);
if (opts->audio_out_fd == -1)
{
fprintf (stderr, "Error, couldn't open #1 %s\n", opts->audio_out_dev);
opts->audio_out = 0;
exit(1);
}
fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
{
fprintf (stderr, "ioctl reset error \n");
}
fmt = speed;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
{
fprintf (stderr, "ioctl speed error \n");
}
fmt = 0; //this seems okay to be 1 or 0, not sure what the difference really is (works in stereo on 0)
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
{
fprintf (stderr, "ioctl stereo error \n");
}
fmt = AFMT_S16_LE;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
{
fprintf (stderr, "ioctl setfmt error \n");
}
opts->audio_out_type = 5; //5 for 1 channel - 48k OSS 16-bit short output (matching with input)
opts->pulse_digi_rate_out = 48000; //this is used to force to upsample and also allow source audio monitor conditional check
opts->pulse_digi_out_channels = 1; //this is used to allow source audio monitor conditional check
opts->audio_gain = 0;
}
}
if (opts->audio_in_type != 5) //split == 1
{
if((strncmp(opts->audio_out_dev, "/dev/dsp", 8) == 0))
{
fprintf (stderr, "OSS Output %s.\n", opts->audio_out_dev);
opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY);
if (opts->audio_out_fd == -1)
{
fprintf (stderr, "Error, couldn't open %s\n", opts->audio_out_dev);
opts->audio_out = 0;
exit(1);
}
//Setup the device. Note that it's important to set the sample format, number of channels and sample rate exactly in this order. Some devices depend on the order.
fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
{
fprintf (stderr, "ioctl reset error \n");
}
fmt = AFMT_S16_LE; //Sample Format
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
{
fprintf (stderr, "ioctl setfmt error \n");
}
fmt = opts->pulse_digi_out_channels; //number of channels //was 2
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_CHANNELS, &fmt) < 0)
{
fprintf (stderr, "ioctl channel error \n");
}
//if using split with OSS output, and using EDACS w/ Analog, we have to use 48k
if (opts->frame_provoice == 1)
opts->pulse_digi_rate_out = 48000;
speed = opts->pulse_digi_rate_out; //since we have split input/output, we want to mirror pulse rate out
fmt = speed; //output rate
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
{
fprintf (stderr, "ioctl speed error \n");
}
if (opts->pulse_digi_out_channels == 2)
fmt = 1;
else fmt = 0;
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
{
fprintf (stderr, "ioctl stereo error \n");
}
//TODO: Multiple output returns based on 8k/1, 8k/2, or maybe 48k/1? (2,3,5)??
if (opts->pulse_digi_out_channels == 2)
opts->audio_out_type = 2; //2 for 2 channel 8k OSS 16-bit short output
else if (opts->frame_m17 == 1)
opts->audio_out_type = 2;
else opts->audio_out_type = 5;
//debug
fprintf (stderr, "Using OSS Output with %dk/%d channel configuration.\n", opts->pulse_digi_rate_out, opts->pulse_digi_out_channels);
}
}
}
void
processAudio (dsd_opts * opts, dsd_state * state)
{
int i, n;
float aout_abs, max, gainfactor, gaindelta, maxbuf;
if (opts->audio_gain == (float) 0)
{
// detect max level
max = 0;
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
aout_abs = fabsf (*state->audio_out_temp_buf_p);
if (aout_abs > max)
{
max = aout_abs;
}
state->audio_out_temp_buf_p++;
}
*state->aout_max_buf_p = max;
state->aout_max_buf_p++;
state->aout_max_buf_idx++;
if (state->aout_max_buf_idx > 24)
{
state->aout_max_buf_idx = 0;
state->aout_max_buf_p = state->aout_max_buf;
}
// lookup max history
for (i = 0; i < 25; i++)
{
maxbuf = state->aout_max_buf[i];
if (maxbuf > max)
{
max = maxbuf;
}
}
// determine optimal gain level
if (max > (float) 0)
{
gainfactor = ((float) 30000 / max);
}
else
{
gainfactor = (float) 50;
}
if (gainfactor < state->aout_gain)
{
state->aout_gain = gainfactor;
gaindelta = (float) 0;
}
else
{
if (gainfactor > (float) 50)
{
gainfactor = (float) 50;
}
gaindelta = gainfactor - state->aout_gain;
if (gaindelta > ((float) 0.05 * state->aout_gain))
{
gaindelta = ((float) 0.05 * state->aout_gain);
}
}
gaindelta /= (float) 160;
}
else
{
gaindelta = (float) 0;
}
if(opts->audio_gain >= 0)
{
// adjust output gain
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
*state->audio_out_temp_buf_p = (state->aout_gain + ((float) n * gaindelta)) * (*state->audio_out_temp_buf_p);
state->audio_out_temp_buf_p++;
}
state->aout_gain += ((float) 160 * gaindelta);
}
// copy audio data to output buffer and upsample if necessary
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
//we only want to upsample when using sample rates greater than 8k for output
if (opts->pulse_digi_rate_out > 8000)
{
for (n = 0; n < 160; n++)
{
upsample (state, *state->audio_out_temp_buf_p);
state->audio_out_temp_buf_p++;
state->audio_out_float_buf_p += 6;
state->audio_out_idx += 6;
state->audio_out_idx2 += 6;
}
state->audio_out_float_buf_p -= (960 + opts->playoffset);
// copy to output (short) buffer
for (n = 0; n < 960; n++)
{
if (*state->audio_out_float_buf_p > 32767.0F)
{
*state->audio_out_float_buf_p = 32767.0F;
}
else if (*state->audio_out_float_buf_p < -32768.0F)
{
*state->audio_out_float_buf_p = -32768.0F;
}
*state->audio_out_buf_p = (short) *state->audio_out_float_buf_p;
//tap the pointer here and store the short upsample buffer samples
state->s_lu[n] = (short) *state->audio_out_float_buf_p;
state->audio_out_buf_p++;
state->audio_out_float_buf_p++;
}
state->audio_out_float_buf_p += opts->playoffset;
}
else
{
for (n = 0; n < 160; n++)
{
if (*state->audio_out_temp_buf_p > 32767.0F)
{
*state->audio_out_temp_buf_p = 32767.0F;
}
else if (*state->audio_out_temp_buf_p < -32768.0F)
{
*state->audio_out_temp_buf_p = -32768.0F;
}
*state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p;
//tap the pointer here and store the short buffer samples
state->s_l[n] = (short) *state->audio_out_temp_buf_p;
//debug
// fprintf (stderr, " %d", state->s_l[n]);
state->audio_out_buf_p++;
state->audio_out_temp_buf_p++;
state->audio_out_idx++;
state->audio_out_idx2++;
}
}
}
void
processAudioR (dsd_opts * opts, dsd_state * state)
{
int i, n;
float aout_abs, max, gainfactor, gaindelta, maxbuf;
if (opts->audio_gainR == (float) 0)
{
// detect max level
max = 0;
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
for (n = 0; n < 160; n++)
{
aout_abs = fabsf (*state->audio_out_temp_buf_pR);
if (aout_abs > max)
{
max = aout_abs;
}
state->audio_out_temp_buf_pR++;
}
*state->aout_max_buf_pR = max;
state->aout_max_buf_pR++;
state->aout_max_buf_idxR++;
if (state->aout_max_buf_idxR > 24)
{
state->aout_max_buf_idxR = 0;
state->aout_max_buf_pR = state->aout_max_bufR;
}
// lookup max history
for (i = 0; i < 25; i++)
{
maxbuf = state->aout_max_bufR[i];
if (maxbuf > max)
{
max = maxbuf;
}
}
// determine optimal gain level
if (max > (float) 0)
{
gainfactor = ((float) 30000 / max);
}
else
{
gainfactor = (float) 50;
}
if (gainfactor < state->aout_gainR)
{
state->aout_gainR = gainfactor;
gaindelta = (float) 0;
}
else
{
if (gainfactor > (float) 50)
{
gainfactor = (float) 50;
}
gaindelta = gainfactor - state->aout_gainR;
if (gaindelta > ((float) 0.05 * state->aout_gainR))
{
gaindelta = ((float) 0.05 * state->aout_gainR);
}
}
gaindelta /= (float) 160;
}
else
{
gaindelta = (float) 0;
}
if(opts->audio_gainR >= 0)
{
// adjust output gain
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
for (n = 0; n < 160; n++)
{
*state->audio_out_temp_buf_pR = (state->aout_gainR + ((float) n * gaindelta)) * (*state->audio_out_temp_buf_pR);
state->audio_out_temp_buf_pR++;
}
state->aout_gainR += ((float) 160 * gaindelta);
}
// copy audio data to output buffer and upsample if necessary
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
//we only want to upsample when using sample rates greater than 8k for output,
if (opts->pulse_digi_rate_out > 8000)
{
for (n = 0; n < 160; n++)
{
upsample (state, *state->audio_out_temp_buf_pR);
state->audio_out_temp_buf_pR++;
state->audio_out_float_buf_pR += 6;
state->audio_out_idxR += 6;
state->audio_out_idx2R += 6;
}
state->audio_out_float_buf_pR -= (960 + opts->playoffsetR);
// copy to output (short) buffer
for (n = 0; n < 960; n++)
{
if (*state->audio_out_float_buf_pR > 32767.0F)
{
*state->audio_out_float_buf_pR = 32767.0F;
}
else if (*state->audio_out_float_buf_pR < -32768.0F)
{
*state->audio_out_float_buf_pR = -32768.0F;
}
*state->audio_out_buf_pR = (short) *state->audio_out_float_buf_pR;
//tap the pointer here and store the short upsample buffer samples
state->s_ru[n] = (short) *state->audio_out_float_buf_pR;
state->audio_out_buf_pR++;
state->audio_out_float_buf_pR++;
}
state->audio_out_float_buf_pR += opts->playoffsetR;
}
else
{
for (n = 0; n < 160; n++)
{
if (*state->audio_out_temp_buf_pR > 32767.0F)
{
*state->audio_out_temp_buf_pR = 32767.0F;
}
else if (*state->audio_out_temp_buf_pR < -32768.0F)
{
*state->audio_out_temp_buf_pR = -32768.0F;
}
*state->audio_out_buf_pR = (short) *state->audio_out_temp_buf_pR;
//tap the pointer here and store the short buffer samples
state->s_r[n] = (short) *state->audio_out_temp_buf_pR;
state->audio_out_buf_pR++;
state->audio_out_temp_buf_pR++;
state->audio_out_idxR++;
state->audio_out_idx2R++;
}
}
}
void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state)
{
int n;
short aout_buf[160];
short *aout_buf_p;
aout_buf_p = aout_buf;
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
for (n = 0; n < 160; n++)
{
if (*state->audio_out_temp_buf_p > (float) 32767)
{
*state->audio_out_temp_buf_p = (float) 32767;
}
else if (*state->audio_out_temp_buf_p < (float) -32768)
{
*state->audio_out_temp_buf_p = (float) -32768;
}
*aout_buf_p = (short) *state->audio_out_temp_buf_p;
aout_buf_p++;
state->audio_out_temp_buf_p++;
}
sf_write_short(opts->wav_out_f, aout_buf, 160);
}
void writeSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
{
int n;
short aout_buf[160];
short *aout_buf_p;
aout_buf_p = aout_buf;
state->audio_out_temp_buf_pR = state->audio_out_temp_bufR;
for (n = 0; n < 160; n++)
{
if (*state->audio_out_temp_buf_pR > (float) 32767)
{
*state->audio_out_temp_buf_pR = (float) 32767;
}
else if (*state->audio_out_temp_buf_pR < (float) -32768)
{
*state->audio_out_temp_buf_pR = (float) -32768;
}
*aout_buf_p = (short) *state->audio_out_temp_buf_pR;
aout_buf_p++;
state->audio_out_temp_buf_pR++;
}
sf_write_short(opts->wav_out_fR, aout_buf, 160);
}
void writeRawSample (dsd_opts * opts, dsd_state * state, short sample)
{
UNUSED(state);
//short aout_buf[160];
//sf_write_short(opts->wav_out_raw, aout_buf, 160);
//only write if actual audio, truncate silence
if (sample != 0)
{
sf_write_short(opts->wav_out_raw, &sample, 2); //2 to match pulseaudio input sample read
}
}
void
playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
{
ssize_t result;
UNUSED(result);
//don't synthesize voice if slot is turned off
if (opts->slot1_on == 0)
{
//clear any previously buffered audio
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
state->audio_out_buf_p = state->audio_out_buf + 100;
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
memset (state->audio_out_buf, 0, 100 * sizeof (short));
state->audio_out_idx2 = 0;
state->audio_out_idx = 0;
goto end_psv;
}
if (state->audio_out_idx > opts->delay)
{
if (opts->audio_out_type == 5 || opts->audio_out_type == 1) //OSS
{
//OSS 48k/1
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
state->audio_out_idx = 0;
}
else if (opts->audio_out_type == 0)
{
pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL);
state->audio_out_idx = 0;
}
else if (opts->audio_out_type == 8) //UDP Audio Out -- Forgot some things still use this for now
{
udp_socket_blaster (opts, state, (state->audio_out_idx * 2), (state->audio_out_buf_p - state->audio_out_idx));
state->audio_out_idx = 0;
}
else state->audio_out_idx = 0; //failsafe for audio_out == 0
}
end_psv:
if (state->audio_out_idx2 >= 800000)
{
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
state->audio_out_buf_p = state->audio_out_buf + 100;
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
memset (state->audio_out_buf, 0, 100 * sizeof (short));
state->audio_out_idx2 = 0;
}
}
void
playSynthesizedVoiceR (dsd_opts * opts, dsd_state * state)
{
ssize_t result;
UNUSED(result);
if (state->audio_out_idxR > opts->delay)
{
// output synthesized speech to sound card
if (opts->audio_out_type == 5) //OSS
{
//OSS 48k/1
result = write (opts->audio_out_fd, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2));
state->audio_out_idxR = 0;
}
else if (opts->audio_out_type == 0)
{
pa_simple_write(opts->pulse_digi_dev_outR, (state->audio_out_buf_pR - state->audio_out_idxR), (state->audio_out_idxR * 2), NULL);
state->audio_out_idxR = 0;
}
else if (opts->audio_out_type == 8) //UDP Audio Out -- Not sure how this would handle, but R never gets called anymore, so just here for symmetry
{
udp_socket_blaster (opts, state, (state->audio_out_idxR * 2), (state->audio_out_buf_pR - state->audio_out_idxR));
state->audio_out_idxR = 0;
}
else state->audio_out_idxR = 0; //failsafe for audio_out == 0
}
if (state->audio_out_idx2R >= 800000)
{
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
state->audio_out_buf_pR = state->audio_out_bufR + 100;
memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
memset (state->audio_out_bufR, 0, 100 * sizeof (short));
state->audio_out_idx2R = 0;
}
}
void
openAudioOutDevice (dsd_opts * opts, int speed)
{
UNUSED(speed);
//converted to handle any calls to use portaudio
if(strncmp(opts->audio_out_dev, "pa:", 3) == 0)
{
opts->audio_out_type = 0;
fprintf (stderr,"Error, Port Audio is not supported by FME!\n");
fprintf (stderr,"Using Pulse Audio Output Stream Instead! \n");
sprintf (opts->audio_out_dev, "pulse");
}
if(strncmp(opts->audio_in_dev, "pulse", 5) == 0)
{
opts->audio_in_type = 0;
}
else
{
// struct stat stat_buf;
// if(stat(opts->audio_out_dev, &stat_buf) != 0 && strncmp(opts->audio_out_dev, "pulse", 5 != 0)) //HERE
// {
// fprintf (stderr,"Error, couldn't open %s\n", opts->audio_out_dev);
// exit(1);
// }
// if( (!(S_ISCHR(stat_buf.st_mode) || S_ISBLK(stat_buf.st_mode))) && strncmp(opts->audio_out_dev, "pulse", 5 != 0))
// {
// // this is not a device
// fprintf (stderr,"Error, %s is not a device. use -w filename for wav output.\n", opts->audio_out_dev);
// exit(1);
// }
}
fprintf (stderr,"Audio Out Device: %s\n", opts->audio_out_dev);
}
void
openAudioInDevice (dsd_opts * opts)
{
char * extension;
const char ch = '.';
extension = strrchr(opts->audio_in_dev, ch); //return extension if this is a .wav or .bin file
//if no extension set, give default of .wav -- bugfix for github issue #105
// if (extension == NULL) extension = ".wav";
// get info of device/file
if (strncmp(opts->audio_in_dev, "-", 1) == 0)
{
opts->audio_in_type = 1;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open_fd(fileno(stdin), SFM_READ, opts->audio_in_file_info, 0);
if(opts->audio_in_file == NULL)
{
fprintf(stderr, "Error, couldn't open stdin with libsndfile: %s\n", sf_strerror(NULL));
exit(1);
}
}
else if (strncmp(opts->audio_in_dev, "m17udp", 6) == 0)
{
opts->audio_in_type = 9; //NULL audio device
}
else if (strncmp(opts->audio_in_dev, "tcp", 3) == 0)
{
opts->audio_in_type = 8;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
opts->tcp_file_in = sf_open_fd(opts->tcp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
if(opts->tcp_file_in == NULL)
{
fprintf(stderr, "Error, couldn't open TCP with libsndfile: %s\n", sf_strerror(NULL));
exit(1);
}
}
// else if (strncmp(opts->audio_in_dev, "udp", 3) == 0)
// {
// opts->audio_in_type = 6;
// opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
// opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
// opts->audio_in_file_info->channels=1;
// opts->audio_in_file_info->seekable=0;
// opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
// opts->udp_file_in = sf_open_fd(opts->udp_sockfd, SFM_READ, opts->audio_in_file_info, 0);
// if(opts->udp_file_in == NULL)
// {
// fprintf(stderr, "Error, couldn't open UDP with libsndfile: %s\n", sf_strerror(NULL));
// exit(1);
// }
// }
else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0)
{
#ifdef USE_RTLSDR
opts->audio_in_type = 3;
#elif AERO_BUILD
opts->audio_in_type = 5;
sprintf (opts->audio_in_dev, "/dev/dsp");
#else
opts->audio_in_type = 0;
sprintf (opts->audio_in_dev, "pulse");
#endif
}
else if(strncmp(opts->audio_in_dev, "pulse", 5) == 0)
{
opts->audio_in_type = 0;
}
else if((strncmp(opts->audio_in_dev, "/dev/dsp", 8) == 0))
{
opts->audio_in_type = 5;
}
//if no extension set, treat as named pipe or extensionless wav file -- bugfix for github issue #105
else if (extension == NULL)
{
opts->audio_in_type = 2;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate = opts->wav_sample_rate;
opts->audio_in_file_info->channels = 1;
opts->audio_in_file_info->seekable = 0;
opts->audio_in_file_info->format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
if (opts->audio_in_file == NULL)
{
fprintf(stderr, "Error, couldn't open file/pipe with libsndfile: %s\n", sf_strerror(NULL));
exit(1);
}
}
//test .rrc files with hardset wav file settings
else if (strncmp(extension, ".rrc", 3) == 0)
{
//debug
fprintf (stderr, "Opening M17 .rrc headless wav file\n");
opts->audio_in_type = 2;
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate = 48000;
opts->audio_in_file_info->channels = 1;
opts->audio_in_file_info->seekable = 0;
opts->audio_in_file_info->format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE;
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
if(opts->audio_in_file == NULL)
{
fprintf(stderr, "Error, couldn't open %s with libsndfile: %s\n", opts->audio_in_dev, sf_strerror(NULL));
exit(1);
}
}
//TODO: test .sym files as symbol capture .bin files
else if (strncmp(extension, ".sym", 3) == 0)
{
struct stat stat_buf;
if (stat(opts->audio_in_dev, &stat_buf) != 0)
{
fprintf (stderr,"Error, couldn't open bin file %s\n", opts->audio_in_dev);
exit(1);
}
if (S_ISREG(stat_buf.st_mode))
{
opts->symbolfile = fopen(opts->audio_in_dev, "r");
opts->audio_in_type = 4; //symbol capture bin files
}
else
{
opts->audio_in_type = 0;
}
}
else if (strncmp(extension, ".bin", 3) == 0)
{
struct stat stat_buf;
if (stat(opts->audio_in_dev, &stat_buf) != 0)
{
fprintf (stderr,"Error, couldn't open bin file %s\n", opts->audio_in_dev);
exit(1);
}
if (S_ISREG(stat_buf.st_mode))
{
opts->symbolfile = fopen(opts->audio_in_dev, "r");
opts->audio_in_type = 4; //symbol capture bin files
}
else
{
opts->audio_in_type = 0;
}
}
//open as wav file as last resort, wav files subseptible to sample rate issues if not 48000
else
{
struct stat stat_buf;
if (stat(opts->audio_in_dev, &stat_buf) != 0)
{
fprintf (stderr,"Error, couldn't open wav file %s\n", opts->audio_in_dev);
exit(1);
}
if (S_ISREG(stat_buf.st_mode))
{
opts->audio_in_type = 2; //two now, seperating STDIN and wav files
opts->audio_in_file_info = calloc(1, sizeof(SF_INFO));
opts->audio_in_file_info->samplerate=opts->wav_sample_rate;
opts->audio_in_file_info->channels=1;
opts->audio_in_file_info->channels = 1;
opts->audio_in_file_info->seekable=0;
opts->audio_in_file_info->format=SF_FORMAT_RAW|SF_FORMAT_PCM_16|SF_ENDIAN_LITTLE;
//
opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info);
if(opts->audio_in_file == NULL)
{
fprintf(stderr, "Error, couldn't open wav file %s\n", opts->audio_in_dev);
exit(1);
}
}
//open pulse audio if no bin or wav
else //seems this condition is never met
{
//opts->audio_in_type = 5; //not sure if this works or needs to openPulse here
fprintf(stderr, "Error, couldn't open input file.\n");
exit(1);
}
}
if (opts->split == 1)
{
fprintf (stderr,"Audio In Device: %s\n", opts->audio_in_dev);
}
else
{
fprintf (stderr,"Audio In/Out Device: %s\n", opts->audio_in_dev);
}
}