diff --git a/dsd.h b/dsd.h index 1285cc88..90c8d1f9 100644 --- a/dsd.h +++ b/dsd.h @@ -256,3 +256,5 @@ 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); diff --git a/dsd_audio.c b/dsd_audio.c index 6e48c9e5..4d353848 100644 --- a/dsd_audio.c +++ b/dsd_audio.c @@ -240,83 +240,78 @@ openAudioOutDevice (dsd_opts * opts, int speed) { // get info of device/file struct stat stat_buf; - stat(opts->audio_out_dev, &stat_buf); - if(S_ISREG(stat_buf.st_mode)) { // is this a regular file? then process with libsndfile. - opts->audio_out_type = 1; - opts->audio_out_file_info = calloc(1, sizeof(SF_INFO)); - opts->audio_out_file_info->samplerate = 48000; - opts->audio_out_file_info->channels = 1; - opts->audio_out_file_info->format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; - opts->audio_out_file = sf_open(opts->audio_out_dev, SFM_READ, opts->audio_out_file_info); - if(opts->audio_out_file == NULL) { - printf ("Error, couldn't open file %s\n", opts->audio_in_dev); - } + if(stat(opts->audio_out_dev, &stat_buf) != 0) { + printf("Error, couldn't open %s\n", opts->audio_out_dev); + exit(1); } - else { // this is a device, use old handling + 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); - } + 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; - } - - 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"); - } - + + 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); } @@ -325,7 +320,10 @@ openAudioInDevice (dsd_opts * opts) { // get info of device/file struct stat stat_buf; - stat(opts->audio_in_dev, &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)); @@ -333,6 +331,7 @@ openAudioInDevice (dsd_opts * opts) 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 @@ -353,7 +352,8 @@ openAudioInDevice (dsd_opts * opts) } if (opts->audio_in_fd == -1) { - printf ("Error, couldn't open /dev/audio\n"); + printf ("Error, couldn't open %s\n", opts->audio_in_dev); + exit(1); } // get current diff --git a/dsd_filters.c b/dsd_filters.c new file mode 100644 index 00000000..aff98dd4 --- /dev/null +++ b/dsd_filters.c @@ -0,0 +1,116 @@ +// DMR filter +#define NZEROS 60 +float ngain = 7.423339364f; +static float xv[NZEROS+1]; +float xcoeffs[] = +{ -0.0083649323f, -0.0265444850f, -0.0428141462f, -0.0537571943f, +-0.0564141052f, -0.0489161045f, -0.0310068662f, -0.0043393881f, ++0.0275375106f, +0.0595423283f, +0.0857543325f, +0.1003565948f, ++0.0986944931f, +0.0782804830f, +0.0395670487f, -0.0136691535f, +-0.0744390415f, -0.1331834575f, -0.1788967208f, -0.2005995448f, +-0.1889627181f, -0.1378439993f, -0.0454976231f, +0.0847488694f, ++0.2444859269f, +0.4209222342f, +0.5982295474f, +0.7593684540f, ++0.8881539892f, +0.9712773915f, +0.9999999166f, +0.9712773915f, ++0.8881539892f, +0.7593684540f, +0.5982295474f, +0.4209222342f, ++0.2444859269f, +0.0847488694f, -0.0454976231f, -0.1378439993f, +-0.1889627181f, -0.2005995448f, -0.1788967208f, -0.1331834575f, +-0.0744390415f, -0.0136691535f, +0.0395670487f, +0.0782804830f, ++0.0986944931f, +0.1003565948f, +0.0857543325f, +0.0595423283f, ++0.0275375106f, -0.0043393881f, -0.0310068662f, -0.0489161045f, +-0.0564141052f, -0.0537571943f, -0.0428141462f, -0.0265444850f, +-0.0083649323f, +}; + +// NXDN filter +#define NXZEROS 134 +float nxgain = 15.95930463f; + +static float nxv[NXZEROS+1]; + +float nxcoeffs[] = +{ +0.031462429f, +0.031747267f, +0.030401148f, +0.027362877f, ++0.022653298f, +0.016379869f, +0.008737200f, +0.000003302f, +-0.009468531f, -0.019262057f, -0.028914291f, -0.037935027f, +-0.045828927f, -0.052119261f, -0.056372283f, -0.058221106f, +-0.057387924f, -0.053703443f, -0.047122444f, -0.037734535f, +-0.025769308f, -0.011595336f, +0.004287292f, +0.021260954f, ++0.038610717f, +0.055550276f, +0.071252765f, +0.084885375f, ++0.095646450f, +0.102803611f, +0.105731303f, +0.103946126f, ++0.097138329f, +0.085197939f, +0.068234131f, +0.046586711f, ++0.020828821f, -0.008239664f, -0.039608255f, -0.072081234f, +-0.104311776f, -0.134843790f, -0.162160200f, -0.184736015f, +-0.201094346f, -0.209863285f, -0.209831516f, -0.200000470f, +-0.179630919f, -0.148282051f, -0.105841323f, -0.052543664f, ++0.011020985f, +0.083912428f, +0.164857408f, +0.252278939f, ++0.344336996f, +0.438979335f, +0.534000832f, +0.627109358f, ++0.715995947f, +0.798406824f, +0.872214756f, +0.935487176f, ++0.986548646f, +1.024035395f, +1.046939951f, +1.054644241f, ++1.046939951f, +1.024035395f, +0.986548646f, +0.935487176f, ++0.872214756f, +0.798406824f, +0.715995947f, +0.627109358f, ++0.534000832f, +0.438979335f, +0.344336996f, +0.252278939f, ++0.164857408f, +0.083912428f, +0.011020985f, -0.052543664f, +-0.105841323f, -0.148282051f, -0.179630919f, -0.200000470f, +-0.209831516f, -0.209863285f, -0.201094346f, -0.184736015f, +-0.162160200f, -0.134843790f, -0.104311776f, -0.072081234f, +-0.039608255f, -0.008239664f, +0.020828821f, +0.046586711f, ++0.068234131f, +0.085197939f, +0.097138329f, +0.103946126f, ++0.105731303f, +0.102803611f, +0.095646450f, +0.084885375f, ++0.071252765f, +0.055550276f, +0.038610717f, +0.021260954f, ++0.004287292f, -0.011595336f, -0.025769308f, -0.037734535f, +-0.047122444f, -0.053703443f, -0.057387924f, -0.058221106f, +-0.056372283f, -0.052119261f, -0.045828927f, -0.037935027f, +-0.028914291f, -0.019262057f, -0.009468531f, +0.000003302f, ++0.008737200f, +0.016379869f, +0.022653298f, +0.027362877f, ++0.030401148f, +0.031747267f, +0.031462429f, +}; + +short dsd_input_filter(short sample, int mode); + +short +dmr_filter(short sample) +{ + return dsd_input_filter(sample, 1); +} + +short +nxdn_filter(short sample) +{ + return dsd_input_filter(sample, 2); +} + + +short +dsd_input_filter(short sample, int mode) +{ + float sum; int i; + float gain; + int zeros; + float *v, *coeffs; + switch(mode) { + case 1: + gain = ngain; + v = xv; + coeffs = xcoeffs; + zeros = NZEROS; + break; + case 2: + gain = nxgain; + v = nxv; + coeffs = nxcoeffs; + zeros = NXZEROS; + break; + default: + return sample; + } + + for (i = 0; i < zeros; i++) + v[i] = v[i+1]; + + v[zeros] = sample; // unfiltered sample in + sum = 0.0f; + + for (i = 0; i <= zeros; i++) + sum += (coeffs[i] * v[i]); + + return sum / ngain; // filtered sample out +} \ No newline at end of file diff --git a/dsd_main.c b/dsd_main.c index 7cbe5f62..3ea4408f 100644 --- a/dsd_main.c +++ b/dsd_main.c @@ -257,13 +257,13 @@ usage () printf ("Decoder options:\n"); printf (" -fa Auto-detect frame type (default)\n"); printf (" -f1 Decode only P25 Phase 1\n"); - printf (" -fd Decode only D-STAR*\n"); + printf (" -fd Decode only D-STAR\n"); printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n"); printf (" -fn Decode only NXDN96 (12.5 kHz)\n"); printf (" -fp Decode only ProVoice*\n"); printf (" -fr Decode only DMR/MOTOTRBO\n"); printf (" -fx Decode only X2-TDMA\n"); - printf (" -l Disable cosine filter (improves D-STAR performance)*\n"); + printf (" -l Disable DMR/MOTOTRBO and NXDN input filtering\n"); printf (" -ma Auto-select modulation optimizations (default)\n"); printf (" -mc Use only C4FM modulation optimizations\n"); printf (" -mg Use only GFSK modulation optimizations\n"); @@ -409,13 +409,16 @@ main (int argc, char **argv) printf ("Setting datascope frame rate to %i frame per second.\n", opts.scoperate); break; case 'i': - sscanf (optarg, "%s", opts.audio_in_dev); + strncpy(opts.audio_in_dev, optarg, 1023); + opts.audio_in_dev[1023] = '\0'; break; case 'o': - sscanf (optarg, "%s", opts.audio_out_dev); + strncpy(opts.audio_out_dev, optarg, 1023); + opts.audio_out_dev[1023] = '\0'; break; case 'd': - sscanf (optarg, "%s", opts.mbe_out_dir); + strncpy(opts.mbe_out_dir, optarg, 1023); + opts.mbe_out_dir[1023] = '\0'; printf ("Writing mbe data files to directory %s\n", opts.mbe_out_dir); break; case 'g': @@ -440,7 +443,8 @@ main (int argc, char **argv) printf ("Disabling audio output to soundcard.\n"); break; case 'w': - sscanf (optarg, "%s", opts.wav_out_file); + strncpy(opts.wav_out_file, optarg, 1023); + opts.wav_out_file[1023] = '\0'; printf ("Writing audio to file %s\n", opts.wav_out_file); openWavOutFile (&opts, &state); break; @@ -448,7 +452,8 @@ main (int argc, char **argv) sscanf (optarg, "%d", &opts.serial_baud); break; case 'C': - sscanf (optarg, "%s", opts.serial_dev); + strncpy(opts.serial_dev, optarg, 1023); + opts.serial_dev[1023] = '\0'; break; case 'R': sscanf (optarg, "%d", &opts.resume); @@ -675,14 +680,24 @@ main (int argc, char **argv) opts.split = 1; opts.playoffset = 0; opts.delay = 0; - openAudioOutDevice (&opts, 8000); + if(strlen(opts.wav_out_file) > 0) { + openWavOutFile (&opts, &state); + } + else { + openAudioOutDevice (&opts, 8000); + } } else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0) { opts.split = 1; opts.playoffset = 0; opts.delay = 0; - openAudioOutDevice (&opts, 8000); + if(strlen(opts.wav_out_file) > 0) { + openWavOutFile (&opts, &state); + } + else { + openAudioOutDevice (&opts, 8000); + } openAudioInDevice (&opts); } else diff --git a/dsd_symbol.c b/dsd_symbol.c index c9d18e17..8915b55c 100644 --- a/dsd_symbol.c +++ b/dsd_symbol.c @@ -90,43 +90,13 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync) // printf("res: %zd\n, offset: %lld", result, sf_seek(opts->audio_in_file, 0, SEEK_CUR)); if (opts->use_cosine_filter) { - #define NZEROS 60 - #define GAIN 7.423339364e+00 - - static float xv[NZEROS+1]; - - static float xcoeffs[] = - { -0.0083649323, -0.0265444850, -0.0428141462, -0.0537571943, - -0.0564141052, -0.0489161045, -0.0310068662, -0.0043393881, - +0.0275375106, +0.0595423283, +0.0857543325, +0.1003565948, - +0.0986944931, +0.0782804830, +0.0395670487, -0.0136691535, - -0.0744390415, -0.1331834575, -0.1788967208, -0.2005995448, - -0.1889627181, -0.1378439993, -0.0454976231, +0.0847488694, - +0.2444859269, +0.4209222342, +0.5982295474, +0.7593684540, - +0.8881539892, +0.9712773915, +0.9999999166, +0.9712773915, - +0.8881539892, +0.7593684540, +0.5982295474, +0.4209222342, - +0.2444859269, +0.0847488694, -0.0454976231, -0.1378439993, - -0.1889627181, -0.2005995448, -0.1788967208, -0.1331834575, - -0.0744390415, -0.0136691535, +0.0395670487, +0.0782804830, - +0.0986944931, +0.1003565948, +0.0857543325, +0.0595423283, - +0.0275375106, -0.0043393881, -0.0310068662, -0.0489161045, - -0.0564141052, -0.0537571943, -0.0428141462, -0.0265444850, - -0.0083649323, - }; - - float sum; int i; - - for (i = 0; i < NZEROS; i++) - xv[i] = xv[i+1]; - - xv[NZEROS] = sample; // unfiltered sample in - sum = 0.0; - - for (i = 0; i <= NZEROS; i++) - sum += (xcoeffs[i] * xv[i]); - - sample = sum / GAIN; // filtered sample out + if (state->lastsynctype >= 10 && state->lastsynctype <= 13) + sample = dmr_filter(sample); + else if (state->lastsynctype == 8 || state->lastsynctype == 9 || + state->lastsynctype == 16 || state->lastsynctype == 17) + sample = nxdn_filter(sample); } + if ((sample > state->max) && (have_sync == 1) && (state->rf_mod == 0)) { sample = state->max;