From 28b907dd9a7fe257bce2d3a18463ff36b7716a7c Mon Sep 17 00:00:00 2001 From: Hannes Matuschek Date: Wed, 3 Jun 2015 19:41:15 +0200 Subject: [PATCH] Fixed 8-bit issue with WavSource. --- examples/sdr_ax25.cc | 187 +++++++++++++++++++++++++++++++++++++---- examples/sdr_pocsag.cc | 43 ++++++---- src/wavfile.cc | 2 +- 3 files changed, 195 insertions(+), 37 deletions(-) diff --git a/examples/sdr_ax25.cc b/examples/sdr_ax25.cc index 9350ba1..be875db 100644 --- a/examples/sdr_ax25.cc +++ b/examples/sdr_ax25.cc @@ -1,41 +1,192 @@ -#include "wavfile.hh" +/* + * sdr_ax25 -- A AX.25 and APRS receiver using libsdr. + * + * (c) 2015 Hannes Matuschek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "options.hh" #include "autocast.hh" -#include "interpolate.hh" +#include "rtlsource.hh" +#include "baseband.hh" +#include "demod.hh" +#include "portaudio.hh" +#include "wavfile.hh" #include "fsk.hh" -#include "aprs.hh" #include "utils.hh" +#include "aprs.hh" + +#include +#include +#include using namespace sdr; +// On SIGINT -> stop queue properly +static void __sigint_handler(int signo) { + Queue::get().stop(); +} + +// Command line options +static Options::Definition options[] = { + {"frequency", 'F', Options::FLOAT, + "Selects a RTL2832 as the source and specifies the frequency in Hz."}, + {"correction", 0, Options::FLOAT, + "Specifies the frequency correction for the RTL2832 device in parts-per-million (ppm)."}, + {"audio", 'a', Options::FLAG, "Selects the system audio as the source."}, + {"file", 'f', Options::ANY, "Selects a WAV file as the source."}, + {"monitor", 'M', Options::FLAG, "Enable sound monitor."}, + {"help", 0, Options::FLAG, "Prints this help message."}, + {0,0,Options::FLAG,0} +}; -int main(int argc, char *argv[]) { - if (2 > argc) { std::cout << "USAGE: sdr_afsk1200 FILENAME" << std::endl; return -1; } +void print_help() { + std::cerr << "USAGE: sdr_ax25 SOURCE [OPTIONS]" << std::endl << std::endl; + Options::print_help(std::cerr, options); +} +int main(int argc, char *argv[]) +{ + // Install log handler sdr::Logger::get().addHandler( new sdr::StreamLogHandler(std::cerr, sdr::LOG_DEBUG)); + // Register signal handler: + signal(SIGINT, __sigint_handler); + + // Parse command line options. + Options opts; + if (! Options::parse(options, argc, argv, opts)) { + print_help(); return -1; + } + + // If help flag is present -> print and done. + if (opts.has("help")) { print_help(); return 0; } + + // If no source has been selected + if (! (opts.has("frequency")|opts.has("audio")|opts.has("file"))) { + print_help(); return -1; + } + + // Init audio system + PortAudio::init(); + + // Get the global queue Queue &queue = Queue::get(); - WavSource src(argv[1], 1024); - if (! src.isOpen()) { std::cout << "Can not open file " << argv[1] << std::endl; return -1; } + // pointer to the selected source + Source *src = 0; - AutoCast< int16_t > cast; - FSKDetector demod(1200, 1200, 2200); + // nodes for WAV file input + WavSource *wav_src=0; + AutoCast *wav_cast=0; + + // nodes for PortAudio input + PortSource *audio_src=0; + + // nodes for RTL2832 input + RTLSource *rtl_source=0; + AutoCast< std::complex > *rtl_cast=0; + IQBaseBand *rtl_baseband=0; + FMDemod *rtl_demod=0; + FMDeemph *rtl_deemph=0; + + if (opts.has("frequency")) { + // Assemble processing chain for the RTL2832 intput + rtl_source = new RTLSource(opts.get("frequency").toFloat()); + if (opts.has("correction")) { + // Apply specified frequency correction. + rtl_source->setFreqCorrection(opts.get("correction").toFloat()); + } + rtl_cast = new AutoCast< std::complex >(); + rtl_baseband = new IQBaseBand(0, 12.5e3, 21, 0, 22050.0); + rtl_demod = new FMDemod(); + rtl_deemph = new FMDeemph(); + // Connect nodes + rtl_source->connect(rtl_cast); + rtl_cast->connect(rtl_baseband, true); + rtl_baseband->connect(rtl_demod); + rtl_demod->connect(rtl_deemph); + // FM deemph. is source for decoder + src = rtl_deemph; + // On queue start, start RTL source + Queue::get().addStart(rtl_source, &RTLSource::start); + // On queue stop, stop RTL source + Queue::get().addStop(rtl_source, &RTLSource::stop); + } else if (opts.has("audio")) { + // Configure audio source + audio_src = new PortSource(22010., 1024); + src = audio_src; + // On queue idle, read next chunk from audio source + Queue::get().addIdle(audio_src, &PortSource::next); + } else if (opts.has("file")) { + // Assemble processing chain for WAV file input + wav_src = new WavSource(opts.get("file").toString()); + wav_cast = new AutoCast(); + wav_src->connect(wav_cast); + src = wav_cast; + // On queue idle, read next chunk from file + Queue::get().addIdle(wav_src, &WavSource::next); + // On end of file, stop queue + wav_src->addEOS(&(Queue::get()), &Queue::stop); + } + + /* Common demodulation nodes. */ + + // (A)FSK detector + FSKDetector detector(1200, 1200, 2200); + // Bit decoder BitStream bits(1200, BitStream::TRANSITION); - APRS decode; + // APRS decoder + APRS aprs; + // Audio sink for monitor + PortSink sink; - src.connect(&cast); - cast.connect(&demod); - demod.connect(&bits); - bits.connect(&decode); + // connect source ASK detector + src->connect(&detector); + // detector to bit decoder + detector.connect(&bits); + // and bit decoder to APRS decoder and print + bits.connect(&aprs); - Queue::get().addIdle(&src, &WavSource::next); - src.addEOS(&queue, &Queue::stop); + // If monitor is enabled -> connect to sink + if (opts.has("monitor")) { + src->connect(&sink); + } - Queue::get().start(); - Queue::get().wait(); + // Start queue + queue.start(); + // wait for queue to exit + queue.wait(); + // Free allocated nodes + if (rtl_source) { delete rtl_source; } + if (rtl_cast) { delete rtl_cast; } + if (rtl_baseband) { delete rtl_baseband; } + if (rtl_demod) { delete rtl_demod; } + if (rtl_deemph) { delete rtl_deemph; } + if (audio_src) { delete audio_src; } + if (wav_src) { delete wav_src; } + if (wav_cast) { delete wav_cast; } + + // terminate port audio system properly + PortAudio::terminate(); + + // quit. return 0; } diff --git a/examples/sdr_pocsag.cc b/examples/sdr_pocsag.cc index 757a12f..c29e6e9 100644 --- a/examples/sdr_pocsag.cc +++ b/examples/sdr_pocsag.cc @@ -40,6 +40,25 @@ static void __sigint_handler(int signo) { Queue::get().stop(); } +// Command line options +static Options::Definition options[] = { + {"frequency", 'F', Options::FLOAT, + "Selects a RTL2832 as the source and specifies the frequency in Hz."}, + {"correction", 0, Options::FLOAT, + "Specifies the frequency correction for the RTL2832 device in parts-per-million (ppm)."}, + {"audio", 'a', Options::FLAG, "Selects the system audio as the source."}, + {"file", 'f', Options::ANY, "Selects a WAV file as the source."}, + {"monitor", 'M', Options::FLAG, "Enable sound monitor."}, + {"invert", 0, Options::FLAG, "Inverts mark/space logic."}, + {"help", 0, Options::FLAG, "Prints this help message."}, + {0,0,Options::FLAG,0} +}; + +void print_help() { + std::cerr << "USAGE: sdr_pocsag SOURCE [OPTIONS]" << std::endl << std::endl; + Options::print_help(std::cerr, options); +} + int main(int argc, char *argv[]) { @@ -50,34 +69,19 @@ int main(int argc, char *argv[]) // Register signal handler: signal(SIGINT, __sigint_handler); - // Command line options - Options::Definition options[] = { - {"frequency", 'F', Options::FLOAT, - "Selects a RTL2832 as the source and specifies the frequency in Hz."}, - {"audio", 'a', Options::FLAG, "Selects the system audio as the source."}, - {"file", 'f', Options::ANY, "Selects a WAV file as the source."}, - {"monitor", 'M', Options::FLAG, "Enable sound monitor."}, - {"invert", 0, Options::FLAG, "Inverts mark/space logic."}, - {"help", 0, Options::FLAG, "Prints this help message."}, - {0,0,Options::FLAG,0} - }; - // Parse command line options. Options opts; if (! Options::parse(options, argc, argv, opts)) { - Options::print_help(std::cerr, options); - return -1; + print_help(); return -1; } if (opts.has("help")) { - Options::print_help(std::cout, options); - return 0; + print_help(); return 0; } // If no source has been selected if (! (opts.has("frequency")|opts.has("audio")|opts.has("file"))) { - Options::print_help(std::cerr, options); - return -1; + print_help(); return -1; } // Init audio system @@ -106,6 +110,9 @@ int main(int argc, char *argv[]) if (opts.has("frequency")) { // Assemble processing chain for the RTL2832 intput rtl_source = new RTLSource(opts.get("frequency").toFloat()); + if (opts.has("correction")) { + rtl_source->setFreqCorrection(opts.get("correction").toFloat()); + } rtl_cast = new AutoCast< std::complex >(); rtl_baseband = new IQBaseBand(0, 12.5e3, 21, 0, 22050.0); rtl_demod = new FMDemod(); diff --git a/src/wavfile.cc b/src/wavfile.cc index 4dc5ff9..b8342b3 100644 --- a/src/wavfile.cc +++ b/src/wavfile.cc @@ -135,7 +135,7 @@ WavSource::open(const std::string &filename) _file.read((char *)&chunk_size, 4); // read frame count // Configure source - _frame_count = chunk_size/(2*n_chanels); + _frame_count = chunk_size/(n_chanels*(bits_per_sample/8)); if ((1 == n_chanels) && (8 == bits_per_sample)) { _type = Config::Type_u8; } else if ((1==n_chanels) && (16 == bits_per_sample)) { _type = Config::Type_s16; } else if ((2==n_chanels) && ( 8 == bits_per_sample)) { _type = Config::Type_cu8; }