diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ad902c..96a0dc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,25 +9,32 @@ git_describe(GIT_TAG) find_package(LibSndFile REQUIRED) find_package(MBE REQUIRED) find_package(ITPP REQUIRED) -find_package(LibPortAudio) #disabled for testing +#find_package(LibPortAudio) #disabled for testing find_package(RTLSDR) #more messing around #find_package(Curses REQUIRED) +find_package(PULSEAUDIO) #include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${CURSES_INCLUDE_DIR}) #set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${CURSES_LIBRARY}) -include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${CURSES_INCLUDE_DIR}) -set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY}) +include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ) +set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY}) #going to disable PortAudio, works just fine with padsp in Linux, #hoping disabling this doesn't break OSX or cygwin, etc builds -if(PORTAUDIO_FOUND) - include_directories(SYSTEM ${PORTAUDIO_INCLUDE_DIRS}) - list(APPEND LIBS ${PORTAUDIO_LIBRARIES}) - add_definitions(-DUSE_PORTAUDIO) -endif(PORTAUDIO_FOUND) +#if(PORTAUDIO_FOUND) +# include_directories(SYSTEM ${PORTAUDIO_INCLUDE_DIRS}) +# list(APPEND LIBS ${PORTAUDIO_LIBRARIES}) +# add_definitions(-DUSE_PORTAUDIO) +#endif(PORTAUDIO_FOUND) + +#if(PULSEAUDIO_FOUND) ##I don't think this will be necessary +# include_directories(SYSTEM ${PULSEAUDIO_INCLUDE_DIRS}) +# list(APPEND LIBS ${PULSEAUDIO_LIBRARIES}) +# add_definitions(-DUSE_PULSEAUDIO) +#endif(PULSEAUDIO_FOUND) if(RTLSDR_FOUND) find_package(Threads) diff --git a/include/dsd.h b/include/dsd.h index 89f71bc..fc10e1f 100644 --- a/include/dsd.h +++ b/include/dsd.h @@ -42,6 +42,8 @@ #include "p25p1_heuristics.h" +#include //PULSE AUDIO +#include //PULSE AUDIO #define SAMPLE_RATE_IN 48000 //48000 #define SAMPLE_RATE_OUT 8000 //8000, @@ -144,6 +146,15 @@ typedef struct int rtl_udp_port; int rtl_bandwidth; int monitor_input_audio; + int pulse_raw_rate_in; + int pulse_raw_rate_out; + int pulse_digi_rate_in; + int pulse_digi_rate_out; + pa_simple *pulse_raw_dev_in; + pa_simple *pulse_raw_dev_out; + pa_simple *pulse_digi_dev_in; + pa_simple *pulse_digi_dev_out; + } dsd_opts; typedef struct @@ -296,8 +307,10 @@ typedef struct void processDMRdata (dsd_opts * opts, dsd_state * state); void processDMRvoice (dsd_opts * opts, dsd_state * state); void processAudio (dsd_opts * opts, dsd_state * state); -void playRawAudio (dsd_opts * opts, dsd_state * state); //added this one HERE HERE +void playRawAudio (dsd_opts * opts, dsd_state * state); //added this one HERE HERE void processRawAudio (dsd_opts * opts, dsd_state * state); //added this one HERE HERE +void openPulseInput (dsd_opts * opts); //not sure if we need to just pass opts, or opts and state yet +void openPulseOutput (dsd_opts * opts); //not sure if we need to just pass opts, or opts and state yet void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state); void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); void openAudioOutDevice (dsd_opts * opts, int speed); diff --git a/include/dsd.h.bkp b/include/dsd.h.bkp new file mode 100644 index 0000000..89f71bc --- /dev/null +++ b/include/dsd.h.bkp @@ -0,0 +1,369 @@ +#ifndef DSD_H +#define DSD_H +/* + * 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 "config.h" +#include +#include +#include +#include +#define __USE_XOPEN //compiler warning on this, needed for strptime, seems benign +#include +#include +#include +#include +#include +#include +#include +#ifdef SOLARIS +#include +#endif +#if defined(BSD) && !defined(__APPLE__) +#include +#endif +#include +#include +#include + +#include "p25p1_heuristics.h" + + +#define SAMPLE_RATE_IN 48000 //48000 +#define SAMPLE_RATE_OUT 8000 //8000, + +#ifdef USE_PORTAUDIO +#include "portaudio.h" +#define PA_FRAMES_PER_BUFFER 64 +//Buffer needs to be large enough to prevent input buffer overruns while DSD is doing other struff (like outputting voice) +//else you get skipped samples which result in incomplete/erronous decodes and a mountain of error messages. +#define PA_LATENCY_IN 0.500 +//Buffer needs to be large enough to prevent output buffer underruns while DSD is doing other stuff (like decoding input) +//else you get choppy audio and in 'extreme' cases errors. +//Buffer also needs to be as small as possible so we don't have a lot of audio delay. +#define PA_LATENCY_OUT 0.100 +#endif + +#ifdef USE_RTLSDR +#include +#endif + +/* + * global variables + */ + +static volatile int exitflag; +//volatile int exitflag; //didn't work, couldn't build, multiple definitions of exitflag + + +typedef struct +{ + int onesymbol; + char mbe_in_file[1024]; + FILE *mbe_in_f; + int errorbars; + int datascope; + int symboltiming; + int verbose; + int p25enc; + int p25lc; + int p25status; + int p25tg; + int scoperate; + char audio_in_dev[1024]; + int audio_in_fd; + SNDFILE *audio_in_file; + SF_INFO *audio_in_file_info; +#ifdef USE_PORTAUDIO + PaStream* audio_in_pa_stream; +#endif + uint32_t rtlsdr_center_freq; + int rtlsdr_ppm_error; + int audio_in_type; // 0 for device, 1 for file, 2 for portaudio, 3 for rtlsdr + char audio_out_dev[1024]; + int audio_out_fd; + SNDFILE *audio_out_file; + SF_INFO *audio_out_file_info; +#ifdef USE_PORTAUDIO + PaStream* audio_out_pa_stream; +#endif + int audio_out_type; // 0 for device, 1 for file, 2 for portaudio + int split; + int playoffset; + char mbe_out_dir[1024]; + char mbe_out_file[1024]; + char mbe_out_path[1024]; + FILE *mbe_out_f; + float audio_gain; + int audio_out; + char wav_out_file[1024]; + SNDFILE *wav_out_f; + //int wav_out_fd; + int serial_baud; + char serial_dev[1024]; + int serial_fd; + int resume; + int frame_dstar; + int frame_x2tdma; + int frame_p25p1; + int frame_nxdn48; + int frame_nxdn96; + int frame_dmr; + int frame_provoice; + int mod_c4fm; + int mod_qpsk; + int mod_gfsk; + int uvquality; + int inverted_x2tdma; + int inverted_dmr; + int mod_threshold; + int ssize; + int msize; + int playfiles; + int delay; + int use_cosine_filter; + int unmute_encrypted_p25; + int rtl_dev_index; + int rtl_gain_value; + int rtl_squelch_level; + int rtl_volume_multiplier; + int rtl_udp_port; + int rtl_bandwidth; + int monitor_input_audio; +} dsd_opts; + +typedef struct +{ + int *dibit_buf; + int *dibit_buf_p; + int repeat; + short *audio_out_buf; + short *audio_out_buf_p; + float *audio_out_float_buf; + float *audio_out_float_buf_p; + float audio_out_temp_buf[160]; + float *audio_out_temp_buf_p; + int audio_out_idx; + int audio_out_idx2; + //int wav_out_bytes; + int center; + int jitter; + int synctype; + int min; + int max; + int lmid; + int umid; + int minref; + int maxref; + int lastsample; + int sbuf[128]; + int sidx; + int maxbuf[1024]; + int minbuf[1024]; + int midx; + char err_str[64]; + char fsubtype[16]; + char ftype[16]; + int symbolcnt; + int rf_mod; + int numflips; + int lastsynctype; + int lastp25type; + int offset; + int carrier; + char tg[25][16]; + int tgcount; + int lasttg; + int lastsrc; + int nac; + int errs; + int errs2; + int mbe_file_type; + int optind; + int numtdulc; + int firstframe; + char slot0light[8]; + char slot1light[8]; + float aout_gain; + float aout_max_buf[200]; + float *aout_max_buf_p; + int aout_max_buf_idx; + int samplesPerSymbol; + int symbolCenter; + char algid[9]; + char keyid[17]; + int currentslot; + mbe_parms *cur_mp; + mbe_parms *prev_mp; + mbe_parms *prev_mp_enhanced; + int p25kid; + + unsigned int debug_audio_errors; + unsigned int debug_header_errors; + unsigned int debug_header_critical_errors; + + // Last dibit read + int last_dibit; + + // Heuristics state data for +P5 signals + P25Heuristics p25_heuristics; + + // Heuristics state data for -P5 signals + P25Heuristics inv_p25_heuristics; + + //input sample buffer for monitoring Input + short input_sample_buffer; //HERE HERE + //float *input_sample_buffer; //HERE HERE + +#ifdef TRACE_DSD + char debug_prefix; + char debug_prefix_2; + unsigned int debug_sample_index; + unsigned int debug_sample_left_edge; + unsigned int debug_sample_right_edge; + FILE* debug_label_file; + FILE* debug_label_dibit_file; + FILE* debug_label_imbe_file; +#endif + +} dsd_state; + +/* + * Frame sync patterns + */ +#define INV_P25P1_SYNC "333331331133111131311111" +#define P25P1_SYNC "111113113311333313133333" + +#define X2TDMA_BS_VOICE_SYNC "113131333331313331113311" +#define X2TDMA_BS_DATA_SYNC "331313111113131113331133" +#define X2TDMA_MS_DATA_SYNC "313113333111111133333313" +#define X2TDMA_MS_VOICE_SYNC "131331111333333311111131" + +#define DSTAR_HD "131313131333133113131111" +#define INV_DSTAR_HD "313131313111311331313333" +#define DSTAR_SYNC "313131313133131113313111" +#define INV_DSTAR_SYNC "131313131311313331131333" +// original sync numbers which is FSW plus LICH +#define NXDN_MS_DATA_SYNC "313133113131111333" +#define INV_NXDN_MS_DATA_SYNC "131311331313333111" +#define NXDN_MS_VOICE_SYNC "313133113131113133" +#define INV_NXDN_MS_VOICE_SYNC "131311331313331311" +#define INV_NXDN_BS_DATA_SYNC "131311331313333131" +#define NXDN_BS_DATA_SYNC "313133113131111313" +#define INV_NXDN_BS_VOICE_SYNC "131311331313331331" +#define NXDN_BS_VOICE_SYNC "313133113131113113" + +//Try using only FSW and no LICH +/* +#define NXDN_MS_DATA_SYNC "3131331131" +#define INV_NXDN_MS_DATA_SYNC "1313113313" +#define NXDN_MS_VOICE_SYNC "313133113131113133" +#define INV_NXDN_MS_VOICE_SYNC "131311331313331311" +#define INV_NXDN_BS_DATA_SYNC "1313113313" +#define NXDN_BS_DATA_SYNC "3131331131" +#define INV_NXDN_BS_VOICE_SYNC "131311331313331331" +#define NXDN_BS_VOICE_SYNC "313133113131113113" +//how do two values equate to 4 symbol types? shouldn't it be -3, -1, 1, 3? +*/ + +#define DMR_BS_DATA_SYNC "313333111331131131331131" +#define DMR_BS_VOICE_SYNC "131111333113313313113313" +#define DMR_MS_DATA_SYNC "311131133313133331131113" +#define DMR_MS_VOICE_SYNC "133313311131311113313331" + +#define INV_PROVOICE_SYNC "31313111333133133311331133113311" +#define PROVOICE_SYNC "13131333111311311133113311331133" +#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311" +#define PROVOICE_EA_SYNC "31131311331331111133131311311133" + +/* + * function prototypes + */ +void processDMRdata (dsd_opts * opts, dsd_state * state); +void processDMRvoice (dsd_opts * opts, dsd_state * state); +void processAudio (dsd_opts * opts, dsd_state * state); +void playRawAudio (dsd_opts * opts, dsd_state * state); //added this one HERE HERE +void processRawAudio (dsd_opts * opts, dsd_state * state); //added this one HERE HERE +void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state); +void playSynthesizedVoice (dsd_opts * opts, dsd_state * state); +void openAudioOutDevice (dsd_opts * opts, int speed); +void openAudioInDevice (dsd_opts * opts); + +int getDibit (dsd_opts * opts, dsd_state * state); +int get_dibit_and_analog_signal (dsd_opts * opts, dsd_state * state, int * out_analog_signal); + +void skipDibit (dsd_opts * opts, dsd_state * state, int count); +void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); +void saveAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d); +int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d); +int readAmbe2450Data (dsd_opts * opts, dsd_state * state, char *ambe_d); +void openMbeInFile (dsd_opts * opts, dsd_state * state); +void closeMbeOutFile (dsd_opts * opts, dsd_state * state); +void openMbeOutFile (dsd_opts * opts, dsd_state * state); +void openWavOutFile (dsd_opts * opts, dsd_state * state); +void closeWavOutFile (dsd_opts * opts, dsd_state * state); +void printFrameInfo (dsd_opts * opts, dsd_state * state); +void processFrame (dsd_opts * opts, dsd_state * state); +void printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation); +int getFrameSync (dsd_opts * opts, dsd_state * state); +int comp (const void *a, const void *b); +void noCarrier (dsd_opts * opts, dsd_state * state); +void initOpts (dsd_opts * opts); +void initState (dsd_state * state); +void usage (); +void liveScanner (dsd_opts * opts, dsd_state * state); +void cleanupAndExit (dsd_opts * opts, dsd_state * state); +void sigfun (int sig); +int main (int argc, char **argv); +void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv); +void processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]); +void openSerial (dsd_opts * opts, dsd_state * state); +void resumeScan (dsd_opts * opts, dsd_state * state); +int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync); +void upsample (dsd_state * state, float invalue); +void processDSTAR (dsd_opts * opts, dsd_state * state); +void processNXDNVoice (dsd_opts * opts, dsd_state * state); +void processNXDNData (dsd_opts * opts, dsd_state * state); +void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo); +void processHDU (dsd_opts * opts, dsd_state * state); +void processLDU1 (dsd_opts * opts, dsd_state * state); +void processLDU2 (dsd_opts * opts, dsd_state * state); +void processTDU (dsd_opts * opts, dsd_state * state); +void processTDULC (dsd_opts * opts, dsd_state * state); +void processProVoice (dsd_opts * opts, dsd_state * state); +void processX2TDMAdata (dsd_opts * opts, dsd_state * state); +void processX2TDMAvoice (dsd_opts * opts, dsd_state * state); +void processDSTAR_HD (dsd_opts * opts, dsd_state * state); +short dmr_filter(short sample); +short nxdn_filter(short sample); + +//borrow from LEH for testing 'improved NXDN detection' +int strncmperr(const char *s1, const char *s2, size_t size, int MaxErr); +// + +#ifdef __cplusplus +extern "C" { +#endif +void open_rtlsdr_stream(dsd_opts *opts); +void cleanup_rtlsdr_stream(); +void get_rtlsdr_sample(int16_t *sample); +void rtlsdr_sighandler(); +#ifdef __cplusplus +} +#endif + +#endif // DSD_H diff --git a/src/dsd_audio.c b/src/dsd_audio.c index 1f5de6d..e793568 100644 --- a/src/dsd_audio.c +++ b/src/dsd_audio.c @@ -17,67 +17,107 @@ #include "dsd.h" +pa_sample_spec ss; +pa_sample_spec tt; +pa_sample_spec zz; +pa_sample_spec cc; + +void openPulseOutput(dsd_opts * opts) +{ + + ss.format = PA_SAMPLE_S16NE; + ss.channels = 1; + ss.rate = opts->pulse_raw_rate_out; //48000 + + tt.format = PA_SAMPLE_S16NE; + tt.channels = 1; + tt.rate = opts->pulse_digi_rate_out; //48000, switches to 8000 when using RTL dongle + //printf("digi rate out = %d\n", opts->pulse_digi_rate_out); + +//ss + if (opts->monitor_input_audio == 1) + { + opts->pulse_raw_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Raw Audio Out", &ss, NULL, NULL, NULL); + } + +//tt + opts->pulse_digi_dev_out = pa_simple_new(NULL, "DSD FME", PA_STREAM_PLAYBACK, NULL, "Digi Audio Out", &tt, NULL, NULL, NULL); + +} + +void openPulseInput(dsd_opts * opts) +{ + + zz.format = PA_SAMPLE_S16NE; + zz.channels = 1; + zz.rate = opts->pulse_raw_rate_in; //48000 + + cc.format = PA_SAMPLE_S16NE; + cc.channels = 1; + cc.rate = opts->pulse_digi_rate_in; //48000 + + //zz + if (opts->monitor_input_audio == 1) + { + opts->pulse_raw_dev_in = pa_simple_new(NULL, "DSD FME", PA_STREAM_RECORD, NULL, "Raw Audio In", &zz, NULL, NULL, NULL); + } + //cc + opts->pulse_digi_dev_in = pa_simple_new(NULL, "DSD FME", PA_STREAM_RECORD, NULL, "Digi Audio In", &cc, NULL, NULL, NULL); + +} void playRawAudio(dsd_opts * opts, dsd_state * state) { - short obuf, outl, sample2, i, something; - something = state->samplesPerSymbol / 5; - /* //this method gets excellent results on gfsk provoice, but not at all on the others - if (opts->audio_in_type == 0 && opts->frame_provoice == 1){ //hack, but might as well for this particular type since its nearly perfect - read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation - obuf = sample2; - } - #ifdef USE_PORTAUDIO - if (opts->audio_in_type == 2){ - Pa_ReadStream( opts->audio_in_pa_stream, &sample2, 1 ); //reading here seems to get same speed as gfsk modulation - obuf = sample2; - } - #endif - if (opts->audio_in_type == 3){ //can't seem to grab get_rtlsdr_sample here, can't share it with dsd_symbol.c - state->input_sample_buffer = state->lastsample; - } //grabbing this one from dsd_symbol.c but its already been processed - */ + short obuf, outl, i, sample2, something; + something = state->samplesPerSymbol / 1; //this was 5 in OSS, changed to 1 for pulse audio, no idea how it affects Port Audio + if (opts->audio_in_type == 0 && opts->audio_out_type == 0){ //hack, but might as well for this particular type since its nearly perfect for (i=0; i < something; i++){ - read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation + //read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation + pa_simple_read(opts->pulse_raw_dev_in, &sample2, 2, NULL ); obuf = sample2 / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping - write (opts->audio_out_fd, (void*)&obuf, 2); + //write (opts->audio_out_fd, (void*)&obuf, 2); + pa_simple_write(opts->pulse_raw_dev_out, (void*)&obuf, 2, NULL); } } #ifdef USE_PORTAUDIO if (opts->audio_in_type == 2 && opts->audio_out_type == 0){ //hack, but might as well for this particular type since its nearly perfect - for (i=0; i < something; i++){ + for (i=0; i < something * 5; i++){ //not sure if this should be 'something' or something * 5 like is was with OSS Pa_ReadStream( opts->audio_in_pa_stream, &sample2, 1 ); //reading here seems to get same speed as gfsk modulation obuf = sample2 / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping - write (opts->audio_out_fd, (void*)&obuf, 2); + //write (opts->audio_out_fd, (void*)&obuf, 2); + pa_simple_write(opts->pulse_raw_dev_out, (void*)&obuf, 2, NULL); } } if (opts->audio_in_type == 0 && opts->audio_out_type == 2){ //hack, but might as well for this particular type since its nearly perfect for (i=0; i < something; i++){ - read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation + //read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation + pa_simple_read(opts->pulse_raw_dev_in, &sample2, 2, NULL ); obuf = sample2 / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping - Pa_StartStream( opts->audio_out_pa_stream ); //no promises this shit'll work - Pa_WriteStream( opts->audio_out_pa_stream, (void*)&obuf, 2); //no promises this shit'll work + Pa_StartStream( opts->audio_out_pa_stream ); //no promises this work + Pa_WriteStream( opts->audio_out_pa_stream, (void*)&obuf, 2); //no promises this work } } if (opts->audio_in_type == 2 && opts->audio_out_type == 2){ //hack, but might as well for this particular type since its nearly perfect - for (i=0; i < something; i++){ + for (i=0; i < something * 5; i++){ //not sure if this should be 'something' or something * 5 like is was with OSS Pa_ReadStream( opts->audio_in_pa_stream, &sample2, 1 ); //reading here seems to get same speed as gfsk modulation obuf = sample2 / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping - Pa_StartStream( opts->audio_out_pa_stream ); //no promises this shit'll work - Pa_WriteStream( opts->audio_out_pa_stream, (void*)&obuf, 2); //no promises this shit'll work + Pa_StartStream( opts->audio_out_pa_stream ); //no promises this work + Pa_WriteStream( opts->audio_out_pa_stream, (void*)&obuf, 2); //no promises this work } } #endif - //shouldn't need to use ifdef rtl here since audio_in_type will never set to 3 unless its there in main - if (opts->audio_in_type == 1 || opts->audio_in_type == 3){ //only plays at 83% and sounds like shit sadly, but can't get samples directly from sdr when its already being polled for samples + + if (opts->audio_in_type == 1 || opts->audio_in_type == 3){ //only plays at 83% and sounds like s sadly, but can't get samples directly from sdr when its already being polled for samples //also, can't get samples from stdin more than once either it seems, unless I borked it when I tried it earlier, so lumping it in here as well for (i=0; i < something; i++) { obuf = state->input_sample_buffer; //dividing here 'quietens' it down a little bit, helps with clicking and clipping outl = sizeof(obuf) ; //obuf length, I think its always equal to 2 if (opts->audio_out_type == 0){ - write (opts->audio_out_fd, (void*)&obuf, outl);} + //write (opts->audio_out_fd, (void*)&obuf, outl); + pa_simple_write(opts->pulse_raw_dev_out, (void*)&obuf, 2, NULL); + } #ifdef USE_PORTAUDIO //no idea if this method will work, since I can't test it if (opts->audio_out_type == 2){ @@ -342,7 +382,6 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state) if( err != paNoError ) break; - //printf("write stream %d\n", state->audio_out_idx); err = Pa_WriteStream( opts->audio_out_pa_stream, (state->audio_out_buf_p - state->audio_out_idx), state->audio_out_idx ); if( err != paNoError ) break; @@ -357,9 +396,10 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state) #endif } - else - result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2)); //12 - state->audio_out_idx = 0; + else{ + pa_simple_flush(opts->pulse_raw_dev_out, NULL); + pa_simple_write(opts->pulse_digi_dev_out, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2), NULL); //Yay! It works. + state->audio_out_idx = 0; } } if (state->audio_out_idx2 >= 800000) @@ -450,6 +490,12 @@ void openAudioOutDevice (dsd_opts * opts, int speed) { // get info of device/file + /* + if(strncmp(opts->audio_out_dev, "pulse", 5) == 0) + { + opts->audio_out_type == 0; + } + */ if(strncmp(opts->audio_out_dev, "pa:", 3) == 0) { opts->audio_out_type = 2; @@ -462,21 +508,26 @@ openAudioOutDevice (dsd_opts * opts, int speed) exit(1); #endif } + 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) + if(stat(opts->audio_out_dev, &stat_buf) != 0 && strncmp(opts->audio_out_dev, "pulse", 5 != 0)) //HERE { printf("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))) + 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 printf("Error, %s is not a device. use -w filename for wav output.\n", opts->audio_out_dev); exit(1); } +/* #ifdef SOLARIS sample_info_t aset, aget; @@ -484,7 +535,7 @@ openAudioOutDevice (dsd_opts * opts, int speed) if (opts->audio_out_fd == -1) { printf ("Error, couldn't open %s\n", opts->audio_out_dev); - exit (1); + //exit (1); } // get current @@ -514,7 +565,7 @@ openAudioOutDevice (dsd_opts * opts, int speed) { printf ("Error, couldn't open %s\n", opts->audio_out_dev); opts->audio_out = 0; - exit(1); + //exit(1); } fmt = 0; @@ -539,6 +590,7 @@ openAudioOutDevice (dsd_opts * opts, int speed) } #endif +*/ } printf ("Audio Out Device: %s\n", opts->audio_out_dev); } @@ -559,7 +611,7 @@ openAudioInDevice (dsd_opts * opts) if(opts->audio_in_file == NULL) { printf ("Error, couldn't open stdin with libsndfile: %s\n", sf_strerror(NULL)); - exit(1); + //exit(1); } } else if(strncmp(opts->audio_in_dev, "pa:", 2) == 0) @@ -585,6 +637,10 @@ openAudioInDevice (dsd_opts * opts) else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0) { opts->audio_in_type = 3; + } + else if(strncmp(opts->audio_in_dev, "pulse", 5) == 0) + { + opts->audio_in_type = 0; } else { @@ -610,8 +666,9 @@ openAudioInDevice (dsd_opts * opts) } else { - // this is a device, use old handling + // this is a device, use old handling, pulse audio now opts->audio_in_type = 0; +/* #ifdef SOLARIS sample_info_t aset, aget; int rgain; @@ -629,7 +686,7 @@ openAudioInDevice (dsd_opts * opts) if (opts->audio_in_fd == -1) { printf ("Error, couldn't open %s\n", opts->audio_in_dev); - exit(1); + //exit(1); } // get current @@ -652,7 +709,8 @@ openAudioInDevice (dsd_opts * opts) exit (1); } #endif - +*/ +/* #if defined(BSD) && !defined(__APPLE__) int fmt; @@ -692,6 +750,7 @@ openAudioInDevice (dsd_opts * opts) printf ("ioctl setfmt error \n"); } #endif +*/ } } diff --git a/src/dsd_audio.c.bkp b/src/dsd_audio.c.bkp new file mode 100644 index 0000000..1f5de6d --- /dev/null +++ b/src/dsd_audio.c.bkp @@ -0,0 +1,706 @@ +/* + * 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" + + +void playRawAudio(dsd_opts * opts, dsd_state * state) { + short obuf, outl, sample2, i, something; + something = state->samplesPerSymbol / 5; + /* //this method gets excellent results on gfsk provoice, but not at all on the others + if (opts->audio_in_type == 0 && opts->frame_provoice == 1){ //hack, but might as well for this particular type since its nearly perfect + read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation + obuf = sample2; + } + #ifdef USE_PORTAUDIO + if (opts->audio_in_type == 2){ + Pa_ReadStream( opts->audio_in_pa_stream, &sample2, 1 ); //reading here seems to get same speed as gfsk modulation + obuf = sample2; + } + #endif + if (opts->audio_in_type == 3){ //can't seem to grab get_rtlsdr_sample here, can't share it with dsd_symbol.c + state->input_sample_buffer = state->lastsample; + } //grabbing this one from dsd_symbol.c but its already been processed + */ + if (opts->audio_in_type == 0 && opts->audio_out_type == 0){ //hack, but might as well for this particular type since its nearly perfect + for (i=0; i < something; i++){ + read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation + obuf = sample2 / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping + write (opts->audio_out_fd, (void*)&obuf, 2); + } + } + #ifdef USE_PORTAUDIO + if (opts->audio_in_type == 2 && opts->audio_out_type == 0){ //hack, but might as well for this particular type since its nearly perfect + for (i=0; i < something; i++){ + Pa_ReadStream( opts->audio_in_pa_stream, &sample2, 1 ); //reading here seems to get same speed as gfsk modulation + obuf = sample2 / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping + write (opts->audio_out_fd, (void*)&obuf, 2); + } + } + if (opts->audio_in_type == 0 && opts->audio_out_type == 2){ //hack, but might as well for this particular type since its nearly perfect + for (i=0; i < something; i++){ + read (opts->audio_in_fd, &sample2, 2); //reading here seems to get same speed as gfsk modulation + obuf = sample2 / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping + Pa_StartStream( opts->audio_out_pa_stream ); //no promises this shit'll work + Pa_WriteStream( opts->audio_out_pa_stream, (void*)&obuf, 2); //no promises this shit'll work + } + } + + if (opts->audio_in_type == 2 && opts->audio_out_type == 2){ //hack, but might as well for this particular type since its nearly perfect + for (i=0; i < something; i++){ + Pa_ReadStream( opts->audio_in_pa_stream, &sample2, 1 ); //reading here seems to get same speed as gfsk modulation + obuf = sample2 / 4; //dividing here 'quietens' it down a little bit, helps with clicking and clipping + Pa_StartStream( opts->audio_out_pa_stream ); //no promises this shit'll work + Pa_WriteStream( opts->audio_out_pa_stream, (void*)&obuf, 2); //no promises this shit'll work + } + } + #endif + //shouldn't need to use ifdef rtl here since audio_in_type will never set to 3 unless its there in main + if (opts->audio_in_type == 1 || opts->audio_in_type == 3){ //only plays at 83% and sounds like shit sadly, but can't get samples directly from sdr when its already being polled for samples + //also, can't get samples from stdin more than once either it seems, unless I borked it when I tried it earlier, so lumping it in here as well + for (i=0; i < something; i++) + { + obuf = state->input_sample_buffer; //dividing here 'quietens' it down a little bit, helps with clicking and clipping + outl = sizeof(obuf) ; //obuf length, I think its always equal to 2 + if (opts->audio_out_type == 0){ + write (opts->audio_out_fd, (void*)&obuf, outl);} + + #ifdef USE_PORTAUDIO //no idea if this method will work, since I can't test it + if (opts->audio_out_type == 2){ + short err; + err = Pa_IsStreamActive( opts->audio_out_pa_stream ); + if(err == 0) + { + err = Pa_StartStream( opts->audio_out_pa_stream ); + if( err != paNoError ){ + printf("Can't Start PA Stream"); + } + err = Pa_WriteStream( opts->audio_out_pa_stream, (void*)&obuf, outl ); + if( err != paNoError ){ + printf("Can't Write PA Stream"); + } + } + } + #endif + } // end for loop + } //end if statement + +} //end playRawAudio + + +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; + if (opts->split == 0) + { + 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; + 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; + state->audio_out_buf_p++; + state->audio_out_temp_buf_p++; + state->audio_out_idx++; + state->audio_out_idx2++; + } + } +} + +void +writeSynthesizedVoice (dsd_opts * opts, dsd_state * state) +{ + int n; + short aout_buf[160]; + short *aout_buf_p; + +// for(n=0; n<160; n++) +// printf("%d ", ((short*)(state->audio_out_temp_buf))[n]); +// printf("\n"); + + 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); + /* + + int n; + short aout_buf[160]; + short *aout_buf_p; + ssize_t result; + + 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) 32760) + { + *state->audio_out_temp_buf_p = (float) 32760; + } + else if (*state->audio_out_temp_buf_p < (float) -32760) + { + *state->audio_out_temp_buf_p = (float) -32760; + } + *aout_buf_p = (short) *state->audio_out_temp_buf_p; + aout_buf_p++; + state->audio_out_temp_buf_p++; + } + + result = write (opts->wav_out_fd, aout_buf, 320); + fflush (opts->wav_out_f); + state->wav_out_bytes += 320; + */ +} + +void +playSynthesizedVoice (dsd_opts * opts, dsd_state * state) +{ + ssize_t result; + + if (state->audio_out_idx > opts->delay) + { + // output synthesized speech to sound card + if(opts->audio_out_type == 2) + { +#ifdef USE_PORTAUDIO + PaError err = paNoError; + do + { + long available = Pa_GetStreamWriteAvailable( opts->audio_out_pa_stream ); + if(available < 0) + err = available; + //printf("Frames available: %d\n", available); + if( err != paNoError ) + break; + if(available > SAMPLE_RATE_OUT * PA_LATENCY_OUT) + { + //It looks like this might not be needed for very small latencies. However, it's definitely needed for a bit larger ones. + //When PA_LATENCY_OUT == 0.500 I get output buffer underruns if I don't use this. With PA_LATENCY_OUT <= 0.100 I don't see those happen. + //But with PA_LATENCY_OUT < 0.100 I run the risk of choppy audio and stream errors. + printf("\nSyncing voice output stream\n"); + err = Pa_StopStream( opts->audio_out_pa_stream ); + if( err != paNoError ) + break; + } + + err = Pa_IsStreamActive( opts->audio_out_pa_stream ); + if(err == 0) + { + printf("Start voice output stream\n"); + err = Pa_StartStream( opts->audio_out_pa_stream ); + } + else if(err == 1) + { + err = paNoError; + } + if( err != paNoError ) + break; + + //printf("write stream %d\n", state->audio_out_idx); + err = Pa_WriteStream( opts->audio_out_pa_stream, (state->audio_out_buf_p - state->audio_out_idx), state->audio_out_idx ); + if( err != paNoError ) + break; + } while(0); + + if( err != paNoError ) + { + fprintf( stderr, "An error occured while using the portaudio output stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + } + +#endif + } + else + result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2)); //12 + state->audio_out_idx = 0; + } + + 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; + } +} + +#ifdef USE_PORTAUDIO +int getPADevice(char* dev, int input, PaStream** stream) +{ + int devnum = atoi(dev + 3); + printf("Using portaudio device %d.\n", devnum); + + PaError err; + + int numDevices = Pa_GetDeviceCount(); + if( numDevices < 0 ) + { + printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices ); + err = numDevices; + goto error; + } + if( devnum >= numDevices) + { + printf( "ERROR: Requested device %d is larger than number of devices.\n", devnum ); + return(1); + } + + const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( devnum ); + + /* print device name */ +#ifdef WIN32 + { /* Use wide char on windows, so we can show UTF-8 encoded device names */ + wchar_t wideName[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, deviceInfo->name, -1, wideName, MAX_PATH-1); + wprintf( L"Name = %s\n", wideName ); + } +#else + printf( "Name = %s\n", deviceInfo->name ); +#endif + if((input == 1) && (deviceInfo->maxInputChannels == 0)) + { + printf( "ERROR: Requested device %d is not an input device.\n", devnum ); + return(1); + } + if((input == 0) && (deviceInfo->maxOutputChannels == 0)) + { + printf( "ERROR: Requested device %d is not an output device.\n", devnum ); + return(1); + } + + //Create stream parameters + PaStreamParameters parameters; + parameters.device = devnum; + parameters.channelCount = 1; /* mono */ + parameters.sampleFormat = paInt16; //Shorts + parameters.suggestedLatency = (input == 1) ? PA_LATENCY_IN : PA_LATENCY_OUT; + parameters.hostApiSpecificStreamInfo = NULL; + + //Open stream + err = Pa_OpenStream( + stream, + (input == 1) ? ¶meters : NULL, + (input == 0) ? ¶meters : NULL, + (input == 1) ? SAMPLE_RATE_IN : SAMPLE_RATE_OUT, + PA_FRAMES_PER_BUFFER, + paClipOff, + NULL /*callback*/, + NULL ); + if( err != paNoError ) goto error; + + return 0; + +error: + fprintf( stderr, "An error occured while initializing a portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return err; +} +#endif + +void +openAudioOutDevice (dsd_opts * opts, int speed) +{ + // get info of device/file + if(strncmp(opts->audio_out_dev, "pa:", 3) == 0) + { + opts->audio_out_type = 2; +#ifdef USE_PORTAUDIO + int err = getPADevice(opts->audio_out_dev, 0, &opts->audio_out_pa_stream); + if(err != 0) + exit(err); +#else + printf("Error, Portaudio support not compiled.\n"); + exit(1); +#endif + } + else + { + struct stat stat_buf; + if(stat(opts->audio_out_dev, &stat_buf) != 0) + { + printf("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))) + { + // this is not a device + printf("Error, %s is not a device. use -w filename for wav output.\n", opts->audio_out_dev); + exit(1); + } +#ifdef SOLARIS + sample_info_t aset, aget; + + opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY); + if (opts->audio_out_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->audio_out_dev); + exit (1); + } + + // get current + ioctl (opts->audio_out_fd, AUDIO_GETINFO, &aset); + aset.record.sample_rate = speed; + aset.play.sample_rate = speed; + aset.record.channels = 1; + aset.play.channels = 1; + aset.record.precision = 16; + aset.play.precision = 16; + aset.record.encoding = AUDIO_ENCODING_LINEAR; + aset.play.encoding = AUDIO_ENCODING_LINEAR; + + if (ioctl (opts->audio_out_fd, AUDIO_SETINFO, &aset) == -1) + { + printf ("Error setting sample device parameters\n"); + exit (1); + } +#endif + +#if defined(BSD) && !defined(__APPLE__) + + int fmt; + + opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY); + if (opts->audio_out_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->audio_out_dev); + opts->audio_out = 0; + exit(1); + } + + fmt = 0; + if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0) + { + printf ("ioctl reset error \n"); + } + fmt = speed; + if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0) + { + printf ("ioctl speed error \n"); + } + fmt = 0; + if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0) + { + printf ("ioctl stereo error \n"); + } + fmt = AFMT_S16_LE; + if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + { + printf ("ioctl setfmt error \n"); + } + +#endif + } + printf ("Audio Out Device: %s\n", opts->audio_out_dev); +} + +void +openAudioInDevice (dsd_opts * opts) +{ + // 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=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_fd(fileno(stdin), SFM_READ, opts->audio_in_file_info, 0); + + if(opts->audio_in_file == NULL) { + printf ("Error, couldn't open stdin with libsndfile: %s\n", sf_strerror(NULL)); + exit(1); + } + } + else if(strncmp(opts->audio_in_dev, "pa:", 2) == 0) + { + opts->audio_in_type = 2; +#ifdef USE_PORTAUDIO + int err = getPADevice(opts->audio_in_dev, 1, &opts->audio_in_pa_stream); + if(err != 0) + exit(err); + + if (opts->split == 0) + { + int err = getPADevice(opts->audio_in_dev, 0, &opts->audio_out_pa_stream); + if(err != 0) + exit(err); + } + +#else + printf("Error, Portaudio support not compiled.\n"); + exit(1); +#endif + } + else if(strncmp(opts->audio_in_dev, "rtl", 3) == 0) + { + opts->audio_in_type = 3; + } + else + { + struct stat stat_buf; + if (stat(opts->audio_in_dev, &stat_buf) != 0) + { + printf("Error, couldn't open %s\n", opts->audio_in_dev); + exit(1); + } + if (S_ISREG(stat_buf.st_mode)) + { + // is this a regular file? then process with libsndfile. + opts->audio_in_type = 1; + opts->audio_in_file_info = calloc(1, sizeof(SF_INFO)); + opts->audio_in_file_info->channels = 1; + opts->audio_in_file = sf_open(opts->audio_in_dev, SFM_READ, opts->audio_in_file_info); + + if(opts->audio_in_file == NULL) + { + printf ("Error, couldn't open file %s\n", opts->audio_in_dev); + exit(1); + } + } + else + { + // this is a device, use old handling + opts->audio_in_type = 0; +#ifdef SOLARIS + sample_info_t aset, aget; + int rgain; + + rgain = 64; + + if (opts->split == 1) + { + opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY); + } + else + { + opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR); + } + if (opts->audio_in_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->audio_in_dev); + exit(1); + } + + // get current + ioctl (opts->audio_in_fd, AUDIO_GETINFO, &aset); + + aset.record.sample_rate = SAMPLE_RATE_IN; + aset.play.sample_rate = SAMPLE_RATE_IN; + aset.record.channels = 1; + aset.play.channels = 1; + aset.record.precision = 16; + aset.play.precision = 16; + aset.record.encoding = AUDIO_ENCODING_LINEAR; + aset.play.encoding = AUDIO_ENCODING_LINEAR; + aset.record.port = AUDIO_LINE_IN; + aset.record.gain = rgain; + + if (ioctl (opts->audio_in_fd, AUDIO_SETINFO, &aset) == -1) + { + printf ("Error setting sample device parameters\n"); + exit (1); + } +#endif + +#if defined(BSD) && !defined(__APPLE__) + int fmt; + + if (opts->split == 1) + { + opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY); + } + else + { + opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR); + } + + if (opts->audio_in_fd == -1) + { + printf ("Error, couldn't open %s\n", opts->audio_in_dev); + opts->audio_out = 0; + } + + fmt = 0; + if (ioctl (opts->audio_in_fd, SNDCTL_DSP_RESET) < 0) + { + printf ("ioctl reset error \n"); + } + fmt = SAMPLE_RATE_IN; + if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0) + { + printf ("ioctl speed error \n"); + } + fmt = 0; + if (ioctl (opts->audio_in_fd, SNDCTL_DSP_STEREO, &fmt) < 0) + { + printf ("ioctl stereo error \n"); + } + fmt = AFMT_S16_LE; + if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + { + printf ("ioctl setfmt error \n"); + } +#endif + } + } + + if (opts->split == 1) + { + printf ("Audio In Device: %s\n", opts->audio_in_dev); + } + else + { + printf ("Audio In/Out Device: %s\n", opts->audio_in_dev); + } +} diff --git a/src/dsd_frame_sync.c b/src/dsd_frame_sync.c index 5cdf374..971746f 100644 --- a/src/dsd_frame_sync.c +++ b/src/dsd_frame_sync.c @@ -184,6 +184,11 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } while (sync == 0) { + //printf("now=%d\n", now); //okay, so this is incrementing as expected + if ( opts->monitor_input_audio == 1 && (time(NULL) - now) > 1 ) //okay, still something going on, still doing the read part for some reason + { + playRawAudio(opts, state); //this is on line 21 in dsd_audio.c + } t++; symbol = getSymbol (opts, state, 0); @@ -586,6 +591,7 @@ getFrameSync (dsd_opts * opts, dsd_state * state) } else if ((strcmp (synctest32, INV_PROVOICE_SYNC) == 0) || (strcmp (synctest32, INV_PROVOICE_EA_SYNC) == 0)) { + now = time(NULL); state->carrier = 1; state->offset = synctest_pos; state->max = ((state->max) + lmax) / 2; @@ -929,20 +935,12 @@ getFrameSync (dsd_opts * opts, dsd_state * state) { printf ("Sync: no sync\n"); printf("Press CTRL + C to close.\n"); //Kindly remind user to double tap CTRL + C - } + } noCarrier (opts, state); return (-1); } } - if ( (opts->monitor_input_audio == 1 && (time(NULL) - now) > 1 ) || (opts->monitor_input_audio == 1 && state->lastsynctype == -1) ) - { - //printf ("Playing Raw Audio - Should Keep Printing Over and over\n"); - playRawAudio(opts, state); //this is on line 21 in dsd_audio.c - //currently working on playRawAudio and samples grabbed in dsd_symbol, going to do it outside of the other big loop - - } - } return (-1); diff --git a/src/dsd_main.c b/src/dsd_main.c index 9870a8c..04723cd 100644 --- a/src/dsd_main.c +++ b/src/dsd_main.c @@ -136,12 +136,14 @@ initOpts (dsd_opts * opts) opts->p25status = 0; opts->p25tg = 0; opts->scoperate = 15; - sprintf (opts->audio_in_dev, "/dev/audio"); + //sprintf (opts->audio_in_dev, "/dev/audio"); + sprintf (opts->audio_in_dev, "pulse"); opts->audio_in_fd = -1; #ifdef USE_PORTAUDIO opts->audio_in_pa_stream = NULL; #endif - sprintf (opts->audio_out_dev, "/dev/audio"); + //sprintf (opts->audio_out_dev, "/dev/audio"); + sprintf (opts->audio_out_dev, "pulse"); opts->audio_out_fd = -1; #ifdef USE_PORTAUDIO opts->audio_out_pa_stream = NULL; @@ -186,6 +188,10 @@ initOpts (dsd_opts * opts) opts->rtl_volume_multiplier = 1; //set multipler from rtl sample to 'boost volume' opts->rtl_udp_port = 6020; //set UDP port for RTL remote opts->rtl_bandwidth = 48; //48000 default value + opts->pulse_raw_rate_in = 48000; + opts->pulse_raw_rate_out = 48000; + opts->pulse_digi_rate_in = 48000; + opts->pulse_digi_rate_out = 48000; //need to copy this to rtl type in and change rate out to 8000 } void @@ -312,8 +318,10 @@ usage () printf (" -z Frame rate for datascope\n"); printf ("\n"); printf ("Input/Output options:\n"); - printf (" -i Audio input device (default is /dev/audio, - for piped stdin, rtl for rtl device)\n"); - printf (" -o Audio output device (default is /dev/audio)\n"); + //printf (" -i Audio input device (default is /dev/audio, - for piped stdin, rtl for rtl device)\n"); + printf (" -i Audio input device (default is pulse audio, - for piped stdin, rtl for rtl device)\n"); + //printf (" -o Audio output device (default is /dev/audio)\n"); + printf (" -o Audio output device (default is pulse audio)\n"); printf (" -d Create mbe data files, use this directory\n"); printf (" -r Read/Play saved mbe data from file(s)\n"); printf (" -g Audio output gain (default = 0 = auto, disable = -1)\n"); @@ -372,6 +380,7 @@ usage () void liveScanner (dsd_opts * opts, dsd_state * state) { +//move open pulse below rtl type to set up audio rate out hopefully #ifdef USE_PORTAUDIO if(opts->audio_in_type == 2) { @@ -388,9 +397,18 @@ liveScanner (dsd_opts * opts, dsd_state * state) #ifdef USE_RTLSDR if(opts->audio_in_type == 3) { + opts->pulse_digi_rate_out = 8000; //rtl currently needs rate out to be 8000, will investigate this further open_rtlsdr_stream(opts); } #endif +if (opts->audio_in_type == 0){ + openPulseInput(opts); +} +if (opts->audio_out_type == 0){ + openPulseOutput(opts); +} + //openPulse(opts); + while (1) { noCarrier (opts, state); @@ -951,6 +969,15 @@ main (int argc, char **argv) openSerial (&opts, &state); } + if((strncmp(opts.audio_in_dev, "pulse", 5) == 0)) + { + opts.audio_in_type == 0; + } + + if((strncmp(opts.audio_out_dev, "pulse", 5) == 0)) + { + opts.audio_out_type == 0; + } #ifdef USE_PORTAUDIO if((strncmp(opts.audio_in_dev, "pa:", 3) == 0) @@ -996,6 +1023,7 @@ main (int argc, char **argv) openAudioOutDevice (&opts, SAMPLE_RATE_OUT); } openAudioInDevice (&opts); + /* setlocale(LC_ALL, ""); sleep(3); @@ -1022,12 +1050,14 @@ main (int argc, char **argv) opts.split = 0; opts.playoffset = 25; // 38 opts.delay = 0; - openAudioInDevice (&opts); + openAudioInDevice (&opts); //disabled all four instances of openAudio devices, in and out for now opts.audio_out_fd = opts.audio_in_fd; } if (opts.playfiles == 1) { + opts.pulse_digi_rate_out = 8000; //need set to 8000 for amb/imb playback + openPulseOutput(&opts); //need to open it up for output playMbeFiles (&opts, &state, argc, argv); } diff --git a/src/dsd_symbol.c b/src/dsd_symbol.c index 93f24b9..d7e324b 100644 --- a/src/dsd_symbol.c +++ b/src/dsd_symbol.c @@ -16,6 +16,22 @@ */ #include "dsd.h" +/* +pa_simple *c; +pa_sample_spec cc; + +void openPulseDigi(dsd_opts * opts){ + + cc.format = PA_SAMPLE_S16NE; + cc.channels = 1; + //cc.rate = 48000; //for some reason, if INPUT is 8000, and output is 48000, sounds correct on NXDN48 + cc.rate = opts->pulse_digi_rate_in; + + c = pa_simple_new(NULL, "DSD FME", PA_STREAM_RECORD, NULL, "Digi Audio In", &cc, NULL, NULL, NULL); + +} +*/ + int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) @@ -81,10 +97,9 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) } // Read the new sample from the input - if(opts->audio_in_type == 0) { - result = read (opts->audio_in_fd, &sample, 2); - - + if(opts->audio_in_type == 0) + { + pa_simple_read(opts->pulse_digi_dev_in, &sample, 2, NULL ); } else if (opts->audio_in_type == 1) { result = sf_read_short(opts->audio_in_file, &sample, 1);