void test_mixer(Mixer<double>& mixer) { int N = 10; std::vector<double> a(N), b(N); for (int i = 0; i < N; i++) { a[i] = i + 1; b[i] = i + 2; } double beta = mixer.beta(); printf("beta: %f\n", beta); for (int i = 0; i < N; i++) mixer.input_shared(i, a[i]); mixer.initialize(); for (int i = 0; i < N; i++) mixer.input_shared(i, b[i]); mixer.mix(); std::vector<double> c(N); for (int i = 0; i < N; i++) c[i] = mixer.output_shared(i); for (int i = 0; i < N; i++) printf("diff: %18.12f\n", std::abs(c[i] - (beta * b[i] + (1 - beta) * a[i]))); }
unsigned MixerGroup::mix(float *outputs, unsigned space) { Mixer *mixer = _first; unsigned index = 0; while ((mixer != nullptr) && (index < space)) { index += mixer->mix(outputs + index, space - index); mixer = mixer->_next; } return index; }
unsigned MixerGroup::mix(float *outputs, unsigned space, uint16_t *status_reg) { Mixer *mixer = _first; unsigned index = 0; while ((mixer != NULL) && (index < space)) { index += mixer->mix(outputs + index, space - index, status_reg); mixer = mixer->_next; } return index; }
int main(int argc, char **argv) { int c; extern char *optarg; extern int optind __attribute__((unused)); extern int optopt __attribute__((unused)); extern int opterr; DSDcc::DSDDecoder dsdDecoder; DSDcc::DSDUpsampler upsamplingEngine; char in_file[1023]; int in_file_fd = -1; char out_file[1023]; int out_file_fd = -1; char log_file[1023]; log_file[0] = '\0'; char formattext_file[1023]; formattext_file[0] = '\0'; FILE *formattext_fp = 0; float formattext_refresh = 0.1f; char formattext[128]; char serialDevice[16]; std::string dvSerialDevice; int dvGain_dB = 0; int slots = 1; Mixer mixer; float lat = 0.0f; float lon = 0.0f; fprintf(stderr, "Digital Speech Decoder DSDcc\n"); exitflag = 0; signal(SIGINT, sigfun); while ((c = getopt(argc, argv, "hHep:qtv:i:o:g:nR:f:u:U:lL:D:d:T:M:m:P:Q:x")) != -1) { opterr = 0; switch (c) { case 'h': usage(); exit(0); case 'H': dsdDecoder.useHPMbelib(true); break; case 'e': dsdDecoder.showErrorBars(); break; case 'p': if (optarg[0] == 'e') { dsdDecoder.setP25DisplayOptions(DSDcc::DSDDecoder::DSDShowP25EncryptionSyncBits, true); } else if (optarg[0] == 'l') { dsdDecoder.setP25DisplayOptions(DSDcc::DSDDecoder::DSDShowP25LinkControlBits, true); } else if (optarg[0] == 's') { dsdDecoder.setP25DisplayOptions(DSDcc::DSDDecoder::DSDShowP25EncryptionSyncBits, true); } else if (optarg[0] == 't') { dsdDecoder.setP25DisplayOptions(DSDcc::DSDDecoder::DSDShowP25TalkGroupInfo, true); } else if (optarg[0] == 'u') { dsdDecoder.muteEncryptedP25(false); } break; case 'q': dsdDecoder.setQuiet(); break; case 't': dsdDecoder.showSymbolTiming(); break; case 'v': int verbosity; sscanf(optarg, "%d", &verbosity); dsdDecoder.setLogVerbosity(verbosity); break; case 'L': strncpy(log_file, (const char *) optarg, 1023); log_file[1022] = '\0'; break; case 'M': strncpy(formattext_file, (const char *) optarg, 1023); formattext_file[1022] = '\0'; break; case 'm': float rate; sscanf(optarg, "%f", &rate); if (rate > 0.1f) { formattext_refresh = rate; } break; case 'i': strncpy(in_file, (const char *) optarg, 1023); in_file[1022] = '\0'; break; case 'o': strncpy(out_file, (const char *) optarg, 1023); out_file[1022] = '\0'; break; #ifdef DSD_USE_SERIALDV case 'D': strncpy(serialDevice, (const char *) optarg, 16); serialDevice[15] = '\0'; dvSerialDevice = serialDevice; break; #endif case 'g': float gain; sscanf(optarg, "%f", &gain); dsdDecoder.setAudioGain(gain); #ifdef DSD_USE_SERIALDV if (gain > 0) { dvGain_dB = (int) (10.0f * log10f(gain)); } #endif break; case 'n': dsdDecoder.enableAudioOut(false); break; case 'R': int resume; sscanf(optarg, "%d", &resume); dsdDecoder.enableScanResumeAfterTDULCFrames(resume); break; case 'd': int dataRateIndex; sscanf(optarg, "%d", &dataRateIndex); if ((dataRateIndex >= 0) && (dataRateIndex <= 2)) { dsdDecoder.setDataRate((DSDcc::DSDDecoder::DSDRate) dataRateIndex); } break; case 'T': int tmpSlots; sscanf(optarg, "%d", &tmpSlots); if ((tmpSlots >= 0) && (tmpSlots <= 3)) { slots = tmpSlots; } break; case 'f': dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeNone, true); if (optarg[0] == 'a') // auto detect { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeAuto, true); } else if (optarg[0] == 'r') // DMR/MOTOTRBO { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeDMR, true); } else if (optarg[0] == 'd') // D-Star { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeDStar, true); } else if (optarg[0] == 'x') // X2-TDMA { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeX2TDMA, true); } else if (optarg[0] == 'p') // ProVoice { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeProVoice, true); } else if (optarg[0] == '0') // P25 Phase 1 { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeP25P1, true); } else if (optarg[0] == 'i') // NXDN48 IDAS { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeNXDN48, true); } else if (optarg[0] == 'n') // NXDN96 { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeNXDN96, true); } else if (optarg[0] == 'm') // DPMR Tier 1 or 2 { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeDPMR, true); } else if (optarg[0] == 'y') // YSF { dsdDecoder.setDecodeMode(DSDcc::DSDDecoder::DSDDecodeYSF, true); } break; case 'u': int uvquality; sscanf(optarg, "%i", &uvquality); dsdDecoder.setUvQuality(uvquality); break; case 'U': int upsampling; sscanf(optarg, "%d", &upsampling); dsdDecoder.setUpsampling(upsampling); break; case 'l': dsdDecoder.enableCosineFiltering(false); break; case 'P': sscanf(optarg, "%f", &lat); break; case 'Q': sscanf(optarg, "%f", &lon); break; case 'x': dsdDecoder.setSymbolPLLLock(false); break; default: usage(); exit(0); } } dsdDecoder.setMyPoint(lat, lon); if (strlen(log_file) > 0) { dsdDecoder.setLogFile(log_file); } if (strncmp(in_file, (const char *) "-", 1) == 0) { in_file_fd = STDIN_FILENO; } else { in_file_fd = open(in_file, O_RDONLY); } if (in_file_fd > -1) { fprintf(stderr, "Opened %s for input.\n", in_file); } else { fprintf(stderr, "Cannot open %s for input. Aborting\n", in_file); return 0; } if (strncmp(out_file, (const char *) "-", 1) == 0) { out_file_fd = STDOUT_FILENO; } else { out_file_fd = open(out_file, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); } if (out_file_fd > -1) { fprintf(stderr, "Opened %s for output.\n", in_file); } else { if (in_file_fd != STDIN_FILENO) { close(in_file_fd); } fprintf(stderr, "Cannot open %s for output. Aborting\n", out_file); return 0; } #ifdef DSD_USE_SERIALDV SerialDV::DVController dvController; short dvAudioSamples[SerialDV::MBE_AUDIO_BLOCK_SIZE * 8]; if (!dvSerialDevice.empty()) { if (dvController.open(dvSerialDevice)) { fprintf(stderr, "SerialDV up. Disable mbelib support\n"); dsdDecoder.enableMbelib(false); // de-activate mbelib decoding } } #endif int formattext_nsamples; if (formattext_file[0] == 0) { formattext_nsamples = 0; } else { formattext_nsamples = 48000.0f * formattext_refresh; formattext_fp = fopen(formattext_file, "w"); if (!formattext_fp) { formattext_nsamples = 0; } } int formattext_sample_count = 0; while (exitflag == 0) { short sample; int nbAudioSamples1 = 0, nbAudioSamples2 = 0; short *audioSamples1, *audioSamples2; int result = read(in_file_fd, (void *) &sample, sizeof(short)); if (result == 0) { fprintf(stderr, "No more input\n"); break; } dsdDecoder.run(sample); #ifdef DSD_USE_SERIALDV if (dvController.isOpen()) { if (dsdDecoder.mbeDVReady1()) { dvController.decode(dvAudioSamples, (const unsigned char *) dsdDecoder.getMbeDVFrame1(), (SerialDV::DVRate) dsdDecoder.getMbeRate(), dvGain_dB); if (dsdDecoder.upsampling()) { upsamplingEngine.upsample(dsdDecoder.upsampling(), dvAudioSamples, &dvAudioSamples[SerialDV::MBE_AUDIO_BLOCK_SIZE], SerialDV::MBE_AUDIO_BLOCK_SIZE); result = write(out_file_fd, (const void *) &dvAudioSamples[SerialDV::MBE_AUDIO_BLOCK_SIZE], SerialDV::MBE_AUDIO_BLOCK_BYTES * dsdDecoder.upsampling()); } else { result = write(out_file_fd, (const void *) dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_BYTES); // TODO: upsampling } dsdDecoder.resetMbeDV1(); } if (dsdDecoder.mbeDVReady2()) { dvController.decode(dvAudioSamples, (const unsigned char *) dsdDecoder.getMbeDVFrame2(), (SerialDV::DVRate) dsdDecoder.getMbeRate(), dvGain_dB); if (dsdDecoder.upsampling()) { upsamplingEngine.upsample(dsdDecoder.upsampling(), dvAudioSamples, &dvAudioSamples[SerialDV::MBE_AUDIO_BLOCK_SIZE], SerialDV::MBE_AUDIO_BLOCK_SIZE); result = write(out_file_fd, (const void *) &dvAudioSamples[SerialDV::MBE_AUDIO_BLOCK_SIZE], SerialDV::MBE_AUDIO_BLOCK_BYTES * dsdDecoder.upsampling()); } else { result = write(out_file_fd, (const void *) dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_BYTES); // TODO: upsampling } dsdDecoder.resetMbeDV2(); } } else #endif { if (slots & 1) { audioSamples1 = dsdDecoder.getAudio1(nbAudioSamples1); } if (slots & 2) { audioSamples2 = dsdDecoder.getAudio2(nbAudioSamples2); } if ((nbAudioSamples1 > 0) && (nbAudioSamples2 == 0)) { result = write(out_file_fd, (const void *) audioSamples1, sizeof(short) * nbAudioSamples1); if (result < 0) { fprintf(stderr, "Error writing to output\n"); } else if ((unsigned int) result != sizeof(short) * nbAudioSamples1) { fprintf(stderr, "Written %d out of %d audio samples\n", result/2, nbAudioSamples1); } dsdDecoder.resetAudio1(); } if ((nbAudioSamples2 > 0) && (nbAudioSamples1 == 0)) { result = write(out_file_fd, (const void *) audioSamples2, sizeof(short) * nbAudioSamples2); if (result < 0) { fprintf(stderr, "Error writing to output\n"); } else if ((unsigned int) result != sizeof(short) * nbAudioSamples2) { fprintf(stderr, "Written %d out of %d audio samples\n", result/2, nbAudioSamples2); } dsdDecoder.resetAudio2(); } if ((nbAudioSamples1 > 0) && (nbAudioSamples2 > 0)) { short *mix; int mixSize; mixer.mix(nbAudioSamples1, nbAudioSamples2, audioSamples1, audioSamples2); mix = mixer.getMix(mixSize); result = write(out_file_fd, (const void *) mix, sizeof(short) * mixSize); if (result < 0) { fprintf(stderr, "Error writing to output\n"); } else if ((unsigned int) result != sizeof(short) * mixSize) { fprintf(stderr, "Written %d out of %d audio samples\n", result/2, mixSize); } dsdDecoder.resetAudio1(); dsdDecoder.resetAudio2(); } } if (formattext_nsamples > 0) { if (formattext_sample_count < formattext_nsamples) { formattext_sample_count++; } else { dsdDecoder.formatStatusText(formattext); fputs(formattext, formattext_fp); putc('\n', formattext_fp); formattext_sample_count = 0; } } } if (formattext_fp) { fclose(formattext_fp); } fprintf(stderr, "End of process\n"); #ifdef DSD_USE_SERIALDV if (dvController.isOpen()) { dvController.close(); } #endif if ((out_file_fd > -1) && (out_file_fd != STDOUT_FILENO)) { close(out_file_fd); } if ((in_file_fd > -1) && (in_file_fd != STDIN_FILENO)) { close(in_file_fd); } return (0); }