add support for MSi2500 based DVB-T dongles through libmirisdr

this has been tested with analog modes only and still has to be
verified with the usual digital modes for proper implementation.
gr3.6
Dimitri Stolnikov 11 years ago
parent c51b04ee74
commit 2878501284
  1. 1
      CMakeLists.txt
  2. 27
      cmake/Modules/FindLibMiriSDR.cmake
  3. 2
      grc/gen_osmosdr_blocks.py
  4. 10
      lib/CMakeLists.txt
  5. 1
      lib/config.h.in
  6. 37
      lib/miri/CMakeLists.txt
  7. 450
      lib/miri/miri_source_c.cc
  8. 133
      lib/miri/miri_source_c.h
  9. 9
      lib/osmosdr_device.cc
  10. 22
      lib/osmosdr_source_c_impl.cc

@ -114,6 +114,7 @@ find_package(GnuradioUHD)
find_package(GnuradioFCD)
find_package(LibOsmoSDR)
find_package(LibRTLSDR)
find_package(LibMiriSDR)
if(NOT GRUEL_FOUND)
message(FATAL_ERROR "Gruel required to compile osmosdr")

@ -0,0 +1,27 @@
if(NOT LIBMIRISDR_FOUND)
pkg_check_modules (LIBMIRISDR_PKG libmirisdr)
find_path(LIBMIRISDR_INCLUDE_DIR NAMES mirisdr.h
PATHS
${LIBMIRISDR_PKG_INCLUDE_DIRS}
/usr/include
/usr/local/include
)
find_library(LIBMIRISDR_LIBRARIES NAMES mirisdr
PATHS
${LIBMIRISDR_PKG_LIBRARY_DIRS}
/usr/lib
/usr/local/lib
)
if(LIBMIRISDR_INCLUDE_DIR AND LIBMIRISDR_LIBRARIES)
set(LIBMIRISDR_FOUND TRUE CACHE INTERNAL "libmirisdr found")
message(STATUS "Found libmirisdr: ${LIBMIRISDR_INCLUDE_DIR}, ${LIBMIRISDR_LIBRARIES}")
else(LIBMIRISDR_INCLUDE_DIR AND LIBMIRISDR_LIBRARIES)
set(LIBMIRISDR_FOUND FALSE CACHE INTERNAL "libmirisdr found")
message(STATUS "libmirisdr not found.")
endif(LIBMIRISDR_INCLUDE_DIR AND LIBMIRISDR_LIBRARIES)
mark_as_advanced(LIBMIRISDR_INCLUDE_DIR LIBMIRISDR_LIBRARIES)
endif(NOT LIBMIRISDR_FOUND)

@ -108,6 +108,7 @@ While primarily being developed for the OsmoSDR hardware, this block also suppor
* Ettus USRP Devices through Ettus UHD library
* RTL2832U based DVB-T dongles through librtlsdr
* rtl-tcp spectrum server (see librtlsdr project)
* MSi2500 based DVB-T dongles through libmirisdr
* gnuradio .cfile input through libgnuradio-core
By using the OsmoSDR block you can take advantage of a common software api in your application(s) independent of the underlying radio hardware.
@ -121,6 +122,7 @@ Use the device id or name (if applicable) to specify a certain device or list of
Examples (some arguments may be optional):
fcd=0
miri=0
rtl=0,rtl_xtal=28.80001e6,tuner_xtal=26e6,buffers=64 ...
rtl_tcp=127.0.0.1:1234,psize=16384
uhd,serial=...,type=usrp1,mcr=52e6,nchan=2,subdev='\\\\'B:0 A:0\\\\'' ...

@ -107,6 +107,16 @@ if(ENABLE_UHD)
GR_INCLUDE_SUBDIRECTORY(uhd)
endif(ENABLE_UHD)
########################################################################
# Setup MiriSDR component
########################################################################
include(GrComponent)
GR_REGISTER_COMPONENT("Osmocom MiriSDR" ENABLE_MIRI LIBMIRISDR_FOUND)
if(ENABLE_MIRI)
GR_INCLUDE_SUBDIRECTORY(miri)
endif(ENABLE_MIRI)
########################################################################
# Setup configuration file
########################################################################

@ -7,5 +7,6 @@
#cmakedefine ENABLE_RTL
#cmakedefine ENABLE_RTL_TCP
#cmakedefine ENABLE_UHD
#cmakedefine ENABLE_MIRI
#endif // CONFIG_H_IN

@ -0,0 +1,37 @@
# Copyright 2012 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio 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, or (at your option)
# any later version.
#
# GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
########################################################################
# This file included, use CMake directory variables
########################################################################
include_directories(APPEND
${CMAKE_CURRENT_SOURCE_DIR}
${LIBMIRISDR_INCLUDE_DIR}
)
set(mirisdr_srcs
${CMAKE_CURRENT_SOURCE_DIR}/miri_source_c.cc
)
########################################################################
# Append gnuradio-mirisdr library sources
########################################################################
list(APPEND gr_osmosdr_srcs ${mirisdr_srcs})
list(APPEND gr_osmosdr_libs ${LIBMIRISDR_LIBRARIES})

@ -0,0 +1,450 @@
/* -*- c++ -*- */
/*
* Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net>
* Copyright 2012 Steve Markgraf <steve@steve-m.de>
*
* GNU Radio 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, or (at your option)
* any later version.
*
* GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
/*
* config.h is generated by configure. It contains the results
* of probing for features, options etc. It should be the first
* file included in your .cc file.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "miri_source_c.h"
#include <gr_io_signature.h>
#include <boost/assign.hpp>
#include <boost/format.hpp>
#include <stdexcept>
#include <iostream>
#include <stdio.h>
#include <mirisdr.h>
#include <osmosdr_arg_helpers.h>
using namespace boost::assign;
#define BUF_SIZE 2304 * 8 * 2
#define BUF_NUM 32
#define BUF_SKIP 1 // buffers to skip due to garbage
#define BYTES_PER_SAMPLE 4 // mirisdr device delivers 16 bit signed IQ data
// containing 12 bits of information
/*
* Create a new instance of miri_source_c and return
* a boost shared_ptr. This is effectively the public constructor.
*/
miri_source_c_sptr
make_miri_source_c (const std::string &args)
{
return gnuradio::get_initial_sptr(new miri_source_c (args));
}
/*
* Specify constraints on number of input and output streams.
* This info is used to construct the input and output signatures
* (2nd & 3rd args to gr_block's constructor). The input and
* output signatures are used by the runtime system to
* check that a valid number and type of inputs and outputs
* are connected to this block. In this case, we accept
* only 0 input and 1 output.
*/
static const int MIN_IN = 0; // mininum number of input streams
static const int MAX_IN = 0; // maximum number of input streams
static const int MIN_OUT = 1; // minimum number of output streams
static const int MAX_OUT = 1; // maximum number of output streams
/*
* The private constructor
*/
miri_source_c::miri_source_c (const std::string &args)
: gr_sync_block ("miri_source_c",
gr_make_io_signature (MIN_IN, MAX_IN, sizeof (gr_complex)),
gr_make_io_signature (MIN_OUT, MAX_OUT, sizeof (gr_complex))),
_running(true),
_auto_gain(false),
_skipped(0)
{
int ret;
unsigned int dev_index = 0;
dict_t dict = params_to_dict(args);
if (dict.count("miri"))
dev_index = boost::lexical_cast< unsigned int >( dict["miri"] );
_buf_num = BUF_NUM;
_buf_head = _buf_used = _buf_offset = 0;
_samp_avail = BUF_SIZE / BYTES_PER_SAMPLE;
if (dict.count("buffers")) {
_buf_num = (unsigned int)boost::lexical_cast< double >( dict["buffers"] );
if (0 == _buf_num)
_buf_num = BUF_NUM;
std::cerr << "Using " << _buf_num << " buffers of size " << BUF_SIZE << "."
<< std::endl;
}
if ( dev_index >= mirisdr_get_device_count() )
throw std::runtime_error("Wrong mirisdr device index given.");
std::cerr << "Using device #" << dev_index << ": "
<< mirisdr_get_device_name(dev_index)
<< std::endl;
_dev = NULL;
ret = mirisdr_open( &_dev, dev_index );
if (ret < 0)
throw std::runtime_error("Failed to open mirisdr device.");
#if 0
ret = mirisdr_set_sample_rate( _dev, 500000 );
if (ret < 0)
throw std::runtime_error("Failed to set default samplerate.");
ret = mirisdr_set_tuner_gain_mode(_dev, int(!_auto_gain));
if (ret < 0)
throw std::runtime_error("Failed to enable manual gain mode.");
#endif
ret = mirisdr_reset_buffer( _dev );
if (ret < 0)
throw std::runtime_error("Failed to reset usb buffers.");
_buf = (unsigned short **) malloc(_buf_num * sizeof(unsigned short *));
if (_buf) {
for(unsigned int i = 0; i < _buf_num; ++i)
_buf[i] = (unsigned short *) malloc(BUF_SIZE);
}
_thread = gruel::thread(_mirisdr_wait, this);
}
/*
* Our virtual destructor.
*/
miri_source_c::~miri_source_c ()
{
if (_dev) {
_running = false;
mirisdr_cancel_async( _dev );
_thread.join();
mirisdr_close( _dev );
_dev = NULL;
}
if (_buf) {
for(unsigned int i = 0; i < _buf_num; ++i) {
if (_buf[i])
free(_buf[i]);
}
free(_buf);
_buf = NULL;
}
}
void miri_source_c::_mirisdr_callback(unsigned char *buf, uint32_t len, void *ctx)
{
miri_source_c *obj = (miri_source_c *)ctx;
obj->mirisdr_callback(buf, len);
}
void miri_source_c::mirisdr_callback(unsigned char *buf, uint32_t len)
{
if (_skipped < BUF_SKIP) {
_skipped++;
return;
}
{
boost::mutex::scoped_lock lock( _buf_mutex );
int buf_tail = (_buf_head + _buf_used) % _buf_num;
memcpy(_buf[buf_tail], buf, len);
if (_buf_used == _buf_num) {
std::cerr << "O" << std::flush;
_buf_head = (_buf_head + 1) % _buf_num;
} else {
_buf_used++;
}
}
_buf_cond.notify_one();
}
void miri_source_c::_mirisdr_wait(miri_source_c *obj)
{
obj->mirisdr_wait();
}
void miri_source_c::mirisdr_wait()
{
int ret = mirisdr_read_async( _dev, _mirisdr_callback, (void *)this, 0, BUF_SIZE );
_running = false;
if ( ret != 0 )
std::cerr << "mirisdr_read_async returned with " << ret << std::endl;
}
int miri_source_c::work( int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items )
{
gr_complex *out = (gr_complex *)output_items[0];
{
boost::mutex::scoped_lock lock( _buf_mutex );
while (_buf_used < 3 && _running) // collect at least 3 buffers
_buf_cond.wait( lock );
}
if (!_running)
return WORK_DONE;
short *buf = (short *)_buf[_buf_head] + _buf_offset;
if (noutput_items <= _samp_avail) {
for (int i = 0; i < noutput_items; i++)
*out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/4096.0f),
float(*(buf + i * 2 + 1)) * (1.0f/4096.0f) );
_buf_offset += noutput_items * 2;
_samp_avail -= noutput_items;
} else {
for (int i = 0; i < _samp_avail; i++)
*out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/4096.0f),
float(*(buf + i * 2 + 1)) * (1.0f/4096.0f) );
{
boost::mutex::scoped_lock lock( _buf_mutex );
_buf_head = (_buf_head + 1) % _buf_num;
_buf_used--;
}
buf = (short *)_buf[_buf_head];
int remaining = noutput_items - _samp_avail;
for (int i = 0; i < remaining; i++)
*out++ = gr_complex( float(*(buf + i * 2 + 0)) * (1.0f/4096.0f),
float(*(buf + i * 2 + 1)) * (1.0f/4096.0f) );
_buf_offset = remaining * 2;
_samp_avail = (BUF_SIZE / BYTES_PER_SAMPLE) - remaining;
}
return noutput_items;
}
std::vector<std::string> miri_source_c::get_devices()
{
std::vector<std::string> devices;
for (unsigned int i = 0; i < mirisdr_get_device_count(); i++) {
std::string args = "miri=" + boost::lexical_cast< std::string >( i );
args += ",label='" + std::string(mirisdr_get_device_name( i )) + "'";
devices.push_back( args );
}
return devices;
}
size_t miri_source_c::get_num_channels()
{
return 1;
}
osmosdr::meta_range_t miri_source_c::get_sample_rates()
{
osmosdr::meta_range_t range;
if (_dev) {
int count = mirisdr_get_sample_rates(_dev, NULL);
if (count > 0) {
uint32_t* rates = new uint32_t[ count ];
count = mirisdr_get_sample_rates(_dev, rates);
for (int i = 0; i < count; i++)
range += osmosdr::range_t( rates[i] );
delete[] rates;
}
}
return range;
}
double miri_source_c::set_sample_rate(double rate)
{
if (_dev) {
mirisdr_set_sample_rate( _dev, (uint32_t)rate );
}
return get_sample_rate();
}
double miri_source_c::get_sample_rate()
{
if (_dev)
return (double)mirisdr_get_sample_rate( _dev );
return 0;
}
osmosdr::freq_range_t miri_source_c::get_freq_range( size_t chan )
{
osmosdr::freq_range_t range;
range += osmosdr::range_t( 150e3, 30e6 ); /* LW/MW/SW (150 kHz - 30 MHz) */
range += osmosdr::range_t( 64e6, 108e6 ); /* VHF Band II (64 - 108 MHz) */
range += osmosdr::range_t( 162e6, 240e6 ); /* Band III (162 - 240 MHz) */
range += osmosdr::range_t( 470e6, 960e6 ); /* Band IV/V (470 - 960 MHz) */
range += osmosdr::range_t( 1450e6, 1675e6 ); /* L-Band (1450 - 1675 MHz) */
return range;
}
double miri_source_c::set_center_freq( double freq, size_t chan )
{
if (_dev)
mirisdr_set_center_freq( _dev, (uint32_t)freq );
return get_center_freq( chan );
}
double miri_source_c::get_center_freq( size_t chan )
{
if (_dev)
return (double)mirisdr_get_center_freq( _dev );
return 0;
}
double miri_source_c::set_freq_corr( double ppm, size_t chan )
{
return get_freq_corr( chan );
}
double miri_source_c::get_freq_corr( size_t chan )
{
return 0;
}
std::vector<std::string> miri_source_c::get_gain_names( size_t chan )
{
std::vector< std::string > gains;
gains += "LNA";
return gains;
}
osmosdr::gain_range_t miri_source_c::get_gain_range( size_t chan )
{
osmosdr::gain_range_t range;
if (_dev) {
int count = mirisdr_get_tuner_gains(_dev, NULL);
if (count > 0) {
int* gains = new int[ count ];
count = mirisdr_get_tuner_gains(_dev, gains);
for (int i = 0; i < count; i++)
range += osmosdr::range_t( gains[i] / 10.0 );
delete[] gains;
}
}
return range;
}
osmosdr::gain_range_t miri_source_c::get_gain_range( const std::string & name, size_t chan )
{
return get_gain_range( chan );
}
bool miri_source_c::set_gain_mode( bool automatic, size_t chan )
{
if (_dev) {
if (!mirisdr_set_tuner_gain_mode(_dev, int(!automatic))) {
_auto_gain = automatic;
}
}
return get_gain_mode(chan);
}
bool miri_source_c::get_gain_mode( size_t chan )
{
return _auto_gain;
}
double miri_source_c::set_gain( double gain, size_t chan )
{
osmosdr::gain_range_t rf_gains = miri_source_c::get_gain_range( chan );
if (_dev) {
mirisdr_set_tuner_gain( _dev, int(rf_gains.clip(gain) * 10.0) );
}
return get_gain( chan );
}
double miri_source_c::set_gain( double gain, const std::string & name, size_t chan)
{
return set_gain( gain, chan );
}
double miri_source_c::get_gain( size_t chan )
{
if ( _dev )
return ((double)mirisdr_get_tuner_gain( _dev )) / 10.0;
return 0;
}
double miri_source_c::get_gain( const std::string & name, size_t chan )
{
return get_gain( chan );
}
std::vector< std::string > miri_source_c::get_antennas( size_t chan )
{
std::vector< std::string > antennas;
antennas += get_antenna( chan );
return antennas;
}
std::string miri_source_c::set_antenna( const std::string & antenna, size_t chan )
{
return get_antenna( chan );
}
std::string miri_source_c::get_antenna( size_t chan )
{
return "ANT";
}

@ -0,0 +1,133 @@
/* -*- c++ -*- */
/*
* Copyright 2012 Dimitri Stolnikov <horiz0n@gmx.net>
*
* GNU Radio 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, or (at your option)
* any later version.
*
* GNU Radio 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 GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDED_MIRI_SOURCE_C_H
#define INCLUDED_MIRI_SOURCE_C_H
#include <gr_sync_block.h>
#include <gruel/thread.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include "osmosdr_src_iface.h"
class miri_source_c;
typedef struct mirisdr_dev mirisdr_dev_t;
/*
* We use boost::shared_ptr's instead of raw pointers for all access
* to gr_blocks (and many other data structures). The shared_ptr gets
* us transparent reference counting, which greatly simplifies storage
* management issues. This is especially helpful in our hybrid
* C++ / Python system.
*
* See http://www.boost.org/libs/smart_ptr/smart_ptr.htm
*
* As a convention, the _sptr suffix indicates a boost::shared_ptr
*/
typedef boost::shared_ptr<miri_source_c> miri_source_c_sptr;
/*!
* \brief Return a shared_ptr to a new instance of miri_source_c.
*
* To avoid accidental use of raw pointers, miri_source_c's
* constructor is private. make_miri_source_c is the public
* interface for creating new instances.
*/
miri_source_c_sptr make_miri_source_c (const std::string & args = "");
/*!
* \brief Provides a stream of complex samples.
* \ingroup block
*/
class miri_source_c :
public gr_sync_block,
public osmosdr_src_iface
{
private:
// The friend declaration allows make_miri_source_c to
// access the private constructor.
friend miri_source_c_sptr make_miri_source_c (const std::string & args);
/*!
* \brief Provides a stream of complex samples.
*/
miri_source_c (const std::string & args); // private constructor
public:
~miri_source_c (); // public destructor
int work( int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items );
static std::vector< std::string > get_devices();
size_t get_num_channels( void );
osmosdr::meta_range_t get_sample_rates( void );
double set_sample_rate( double rate );
double get_sample_rate( void );
osmosdr::freq_range_t get_freq_range( size_t chan = 0 );
double set_center_freq( double freq, size_t chan = 0 );
double get_center_freq( size_t chan = 0 );
double set_freq_corr( double ppm, size_t chan = 0 );
double get_freq_corr( size_t chan = 0 );
std::vector<std::string> get_gain_names( size_t chan = 0 );
osmosdr::gain_range_t get_gain_range( size_t chan = 0 );
osmosdr::gain_range_t get_gain_range( const std::string & name, size_t chan = 0 );
bool set_gain_mode( bool automatic, size_t chan = 0 );
bool get_gain_mode( size_t chan = 0 );
double set_gain( double gain, size_t chan = 0 );
double set_gain( double gain, const std::string & name, size_t chan = 0 );
double get_gain( size_t chan = 0 );
double get_gain( const std::string & name, size_t chan = 0 );
std::vector< std::string > get_antennas( size_t chan = 0 );
std::string set_antenna( const std::string & antenna, size_t chan = 0 );
std::string get_antenna( size_t chan = 0 );
private:
static void _mirisdr_callback(unsigned char *buf, uint32_t len, void *ctx);
void mirisdr_callback(unsigned char *buf, uint32_t len);
static void _mirisdr_wait(miri_source_c *obj);
void mirisdr_wait();
mirisdr_dev_t *_dev;
gruel::thread _thread;
unsigned short **_buf;
unsigned int _buf_num;
unsigned int _buf_head;
unsigned int _buf_used;
boost::mutex _buf_mutex;
boost::condition_variable _buf_cond;
bool _running;
unsigned int _buf_offset;
int _samp_avail;
bool _auto_gain;
unsigned int _skipped;
};
#endif /* INCLUDED_MIRI_SOURCE_C_H */

@ -34,6 +34,7 @@
#define ENABLE_FCD
#define ENABLE_RTL
#define ENABLE_UHD
#define ENABLE_MIRI
*/
#ifdef ENABLE_OSMOSDR
#include <osmosdr_src_c.h>
@ -51,6 +52,10 @@
#include <uhd_source_c.h>
#endif
#ifdef ENABLE_MIRI
#include <miri_source_c.h>
#endif
#include "osmosdr_arg_helpers.h"
using namespace osmosdr;
@ -118,6 +123,10 @@ devices_t device::find(const device_t &hint)
BOOST_FOREACH( std::string dev, uhd_source_c::get_devices() )
devices.push_back( device_t(dev) );
#endif
#ifdef ENABLE_MIRI
BOOST_FOREACH( std::string dev, miri_source_c::get_devices() )
devices.push_back( device_t(dev) );
#endif
return devices;
}

@ -54,6 +54,10 @@
#include <uhd_source_c.h>
#endif
#ifdef ENABLE_MIRI
#include <miri_source_c.h>
#endif
#include <osmosdr_arg_helpers.h>
/* This avoids throws in ctor of gr_hier_block2, as gnuradio is unable to deal
@ -99,6 +103,9 @@ osmosdr_source_c_impl::osmosdr_source_c_impl (const std::string &args)
#ifdef ENABLE_UHD
dev_types.push_back("uhd");
#endif
#ifdef ENABLE_MIRI
dev_types.push_back("miri");
#endif
std::cerr << "gr-osmosdr supported device types: ";
BOOST_FOREACH(std::string dev_type, dev_types)
@ -134,6 +141,10 @@ osmosdr_source_c_impl::osmosdr_source_c_impl (const std::string &args)
BOOST_FOREACH( std::string dev, uhd_source_c::get_devices() )
dev_list.push_back( dev );
#endif
#ifdef ENABLE_MIRI
BOOST_FOREACH( std::string dev, miri_source_c::get_devices() )
dev_list.push_back( dev );
#endif
// std::cerr << std::endl;
// BOOST_FOREACH( std::string dev, dev_list )
// std::cerr << "'" << dev << "'" << std::endl;
@ -206,6 +217,17 @@ osmosdr_source_c_impl::osmosdr_source_c_impl (const std::string &args)
_devs.push_back( src.get() );
}
#endif
#ifdef ENABLE_MIRI
if ( dict.count("miri") ) {
miri_source_c_sptr src = make_miri_source_c( arg );
for (size_t i = 0; i < src->get_num_channels(); i++)
connect(src, i, self(), channel++);
_devs.push_back( src.get() );
}
#endif
}
if (!_devs.size())

Loading…
Cancel
Save