diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index c79e908..31275d9 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -49,5 +49,5 @@ if(${INCLUDE_DEBUG_BLOCKS}) endif() install(FILES ${enabled_blocks} - DESTINATION share/gnuradio/grc/blocks + satnogs_ogg_source.xml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/satnogs_block_tree.xml b/grc/satnogs_block_tree.xml index 52f236b..bda94dd 100644 --- a/grc/satnogs_block_tree.xml +++ b/grc/satnogs_block_tree.xml @@ -14,6 +14,7 @@ satnogs_morse_decoder satnogs_multi_format_msg_sink satnogs_ogg_encoder + satnogs_ogg_source satnogs_cw_to_symbol satnogs_sine_matched_filter_ff satnogs_udp_msg_source diff --git a/grc/satnogs_ogg_source.xml b/grc/satnogs_ogg_source.xml new file mode 100644 index 0000000..9795555 --- /dev/null +++ b/grc/satnogs_ogg_source.xml @@ -0,0 +1,28 @@ + + + OGG File Source + satnogs_ogg_source + [satnogs] + import satnogs + satnogs.ogg_source($filename, $channels) + + + File + filename + + file_open + + + + Channels + channels + 1 + int + + + + out + float + $channels + + diff --git a/include/satnogs/CMakeLists.txt b/include/satnogs/CMakeLists.txt index 2c16dc5..066dd1a 100644 --- a/include/satnogs/CMakeLists.txt +++ b/include/satnogs/CMakeLists.txt @@ -63,5 +63,5 @@ if(${INCLUDE_DEBUG_BLOCKS}) endif() install(FILES ${HEADER_FILES} - DESTINATION include/satnogs + ogg_source.h DESTINATION include/satnogs ) \ No newline at end of file diff --git a/include/satnogs/ogg_source.h b/include/satnogs/ogg_source.h new file mode 100644 index 0000000..18de151 --- /dev/null +++ b/include/satnogs/ogg_source.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2017, Libre Space Foundation + * + * 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 3 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, see . + */ + +#ifndef INCLUDED_SATNOGS_OGG_SOURCE_H +#define INCLUDED_SATNOGS_OGG_SOURCE_H + +#include +#include + +namespace gr +{ + namespace satnogs + { + + /*! + * \brief OGG source block. Reads a file with an OGG audio and + * convert it to float samples + * + * \ingroup satnogs + * + */ + class SATNOGS_API ogg_source : virtual public gr::sync_block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * + * @param filename the OGG audio file path + * @param number of channels of the OGG stream. If the actual OGG stream + * contains a different number of channels than specified an exception + * is raised + */ + static sptr + make (const std::string& filename, size_t channels = 1); + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_OGG_SOURCE_H */ + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index cd5e06a..a5352a5 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -59,7 +59,8 @@ list(APPEND satnogs_sources ax25_encoder_mb_impl.cc ax25_decoder_bm_impl.cc qb50_deframer_impl.cc - waterfall_sink_impl.cc) + waterfall_sink_impl.cc + ogg_source_impl.cc) if(${INCLUDE_DEBUG_BLOCKS}) list(APPEND satnogs_sources ${satnogs_debug_sources}) diff --git a/lib/ogg_source_impl.cc b/lib/ogg_source_impl.cc new file mode 100644 index 0000000..8292faa --- /dev/null +++ b/lib/ogg_source_impl.cc @@ -0,0 +1,125 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2017, Libre Space Foundation + * + * 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 3 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, see . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "ogg_source_impl.h" + +#define PCM_BUF_SIZE 4096 + +namespace gr { + namespace satnogs { + + ogg_source::sptr + ogg_source::make(const std::string& filename, size_t channels) + { + return gnuradio::get_initial_sptr + (new ogg_source_impl(filename, channels)); + } + + /* + * The private constructor + */ + ogg_source_impl::ogg_source_impl (const std::string& filename, + size_t channels) : + gr::sync_block ( + "ogg_source", gr::io_signature::make (0, 0, 0), + gr::io_signature::make (channels, channels, sizeof(float))), + d_channels (channels) + { + if (channels < 1) { + throw std::invalid_argument ("At least one output channels should" + " be specified"); + } + + if (ov_fopen (filename.c_str (), &d_ogvorb_f) < 0) { + throw std::invalid_argument ("Invalid .ogg file"); + } + + vorbis_info *vi = ov_info(&d_ogvorb_f,-1); + if(vi->channels != (int) channels) { + throw std::invalid_argument ( + std::string ("Channels number specified (") + + std::to_string (channels) + + ") does not match the channels of " + "the ogg stream (" + std::to_string (vi->channels) + ")"); + } + + const int alignment_multiple = volk_get_alignment() / sizeof(float); + set_alignment(std::max(1,alignment_multiple)); + set_max_noutput_items(PCM_BUF_SIZE); + + d_in_buffer = (int16_t *)volk_malloc(PCM_BUF_SIZE * sizeof(int16_t), + volk_get_alignment()); + d_out_buffer = (float *)volk_malloc(PCM_BUF_SIZE * sizeof(float), + volk_get_alignment()); + } + + /* + * Our virtual destructor. + */ + ogg_source_impl::~ogg_source_impl() + { + ov_clear(&d_ogvorb_f); + volk_free(d_in_buffer); + volk_free(d_out_buffer); + } + + int + ogg_source_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + long int ret; + int section = 0; + int available = (noutput_items / d_channels); + int produced = 0; + + ret = ov_read (&d_ogvorb_f, (char *)d_in_buffer, + available * sizeof(int16_t), + 0, sizeof(int16_t), 1, §ion); + if(ret < sizeof(int16_t)) { + return WORK_DONE; + } + + /* Convert to float the signed-short audio samples */ + volk_16i_s32f_convert_32f (d_out_buffer, d_in_buffer, 2 << 15, + ret / sizeof(int16_t)); + + /* De-interleave the available channels */ + for(int i = 0; i < ret / sizeof(int16_t); i += d_channels, produced++) { + for(int chan = 0; chan < d_channels; chan++){ + ((float *)output_items[chan])[produced] = d_out_buffer[i * d_channels + chan]; + } + } + + return produced; + } + + } /* namespace satnogs */ +} /* namespace gr */ + diff --git a/lib/ogg_source_impl.h b/lib/ogg_source_impl.h new file mode 100644 index 0000000..3a73f4a --- /dev/null +++ b/lib/ogg_source_impl.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2017, Libre Space Foundation + * + * 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 3 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, see . + */ + +#ifndef INCLUDED_SATNOGS_OGG_SOURCE_IMPL_H +#define INCLUDED_SATNOGS_OGG_SOURCE_IMPL_H + +#include +#include +#include + +namespace gr +{ + namespace satnogs + { + + class ogg_source_impl : public ogg_source + { + private: + const size_t d_channels; + OggVorbis_File d_ogvorb_f; + + int16_t *d_in_buffer; + float *d_out_buffer; + + public: + ogg_source_impl (const std::string& filename, size_t channels); + ~ogg_source_impl (); + + // Where all the action really happens + int + work (int noutput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_OGG_SOURCE_IMPL_H */ + diff --git a/swig/satnogs_swig.i b/swig/satnogs_swig.i index 8b3417a..bc54368 100644 --- a/swig/satnogs_swig.i +++ b/swig/satnogs_swig.i @@ -32,6 +32,7 @@ #include "satnogs/qb50_deframer.h" #include "satnogs/waterfall_sink.h" #include "satnogs/ogg_encoder.h" +#include "satnogs/ogg_source.h" %} @@ -100,3 +101,5 @@ GR_SWIG_BLOCK_MAGIC2(satnogs, qb50_deframer); GR_SWIG_BLOCK_MAGIC2(satnogs, waterfall_sink); %include "satnogs/ogg_encoder.h" GR_SWIG_BLOCK_MAGIC2(satnogs, ogg_encoder); +%include "satnogs/ogg_source.h" +GR_SWIG_BLOCK_MAGIC2(satnogs, ogg_source);