mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-06-15 21:12:27 -04:00
Removed old DV serial engine files. Make serialDV dependency mandatory. Updated various readmes
This commit is contained in:
parent
0d26936e61
commit
71192a4130
@ -364,7 +364,7 @@ else()
|
||||
find_package(Codec2)
|
||||
find_package(CM256cc)
|
||||
find_package(LibMbe)
|
||||
find_package(SerialDV)
|
||||
find_package(SerialDV REQUIRED)
|
||||
find_package(LibDSDcc)
|
||||
endif()
|
||||
|
||||
|
@ -156,21 +156,16 @@ This is the `demoddsd` plugin. At present it can be used to decode the following
|
||||
|
||||
It is based on the [DSDcc](https://github.com/f4exb/dsdcc) C++ library which is a rewrite of the original [DSD](https://github.com/szechyjs/dsd) program. So you will need to have DSDcc installed in your system. Please follow instructions in [DSDcc readme](https://github.com/f4exb/dsdcc/blob/master/Readme.md) to build and install DSDcc.
|
||||
|
||||
If you have one or more serial devices interfacing the AMBE3000 chip in packet mode you can use them to decode AMBE voice frames. For that purpose you will need to compile with [SerialDV](https://github.com/f4exb/serialDV) support. Please refer to this project Readme.md to compile and install SerialDV. Note that your user must be a member of group `dialout` (Ubuntu/Debian) or `uucp` (Arch) to be able to use the dongle.
|
||||
Note that you will need to compile with [SerialDV](https://github.com/f4exb/serialDV) support. This makes possible to use AMBE serial dongles or AMBE server connections. Please refer to this project Readme.md to compile and install SerialDV. Note that your user must be a member of group `dialout` (Ubuntu/Debian) or `uucp` (Arch) to be able to use the dongle.
|
||||
|
||||
Although such serial devices work with a serial interface at 400 kb in practice maybe for other reasons they are capable of handling only one conversation at a time. The software will allocate the device dynamically to a conversation with an inactivity timeout of 1 second so that conversations do not get interrupted constantly making the audio output too choppy. In practice you will have to have as many devices connected to your system as the number of conversations you would like to be handled in parallel.
|
||||
|
||||
Alternatively you can use [mbelib](https://github.com/szechyjs/mbelib) but mbelib comes with some copyright issues.
|
||||
When no AMBE devices or servers are activated [mbelib](https://github.com/szechyjs/mbelib) is used to decode AMBE frames but mbelib comes with some copyright issues.
|
||||
|
||||
While DSDcc is intended to be patent-free, `mbelib` that it uses describes functions that may be covered by one or more U.S. patents owned by DVSI Inc. The source code itself should not be infringing as it merely describes possible methods of implementation. Compiling or using `mbelib` may infringe on patents rights in your jurisdiction and/or require licensing. It is unknown if DVSI will sell licenses for software that uses `mbelib`.
|
||||
|
||||
Possible copyright issues apart the audio quality with the DVSI AMBE chip is much better.
|
||||
|
||||
If you are not comfortable with this just do not install DSDcc and/or mbelib and the plugin will not be compiled and added to SDRangel. For packaged distributions just remove from the installation directory:
|
||||
|
||||
- For Linux distributions: `plugins/channel/libdemoddsd.so`
|
||||
- For Windows distribution: `dsdcc.dll`, `mbelib.dll`, `plugins\channel\demoddsd.dll`
|
||||
|
||||
<h1>Binary distributions</h1>
|
||||
|
||||
In the [releases](https://github.com/f4exb/sdrangel/releases) section of the Github repository one can find binary distributions for Ubuntu and Windows
|
||||
|
@ -18,16 +18,17 @@ To enable this plugin at compile time you will need to have DSDcc installed in y
|
||||
|
||||
<h2>DV serial device support</h2>
|
||||
|
||||
You can use a serial device connected to your system that implements and exposes the packet interface of the AMBE3000 chip. This can be for example a ThumbDV USB dongle. In order to support DV serial devices in your system you will need two things:
|
||||
You can use a serial device connected to your system that implements and exposes the packet interface of the AMBE3000 chip. This can be for example a ThumbDV USB dongle. You may also connect to an AMBE server instance over the network.
|
||||
|
||||
- Compile with [SerialDV](https://github.com/f4exb/serialDV) support Please refer to this project Readme.md to compile and install SerialDV. If you install it in a custom location say `/opt/install/serialdv` you will need to add these defines to the cmake command: `-DSERIALDV_DIR=/opt/install/serialdv`
|
||||
- Enable DV serial devices in your system by checking the option in the Preferences menu. You will need to enable the DV serial devices each time you start SDRangel.
|
||||
DV serial devices are supported using the [SerialDV](https://github.com/f4exb/serialDV) library that is a mandatory requirement. Therefore you have to compile and install it in your system. Please refer to this project Readme.md to compile and install SerialDV. f you install it in a custom location say `/opt/install/serialdv` you will need to add this define to the cmake command: `-DSERIALDV_DIR=/opt/install/serialdv`
|
||||
|
||||
To effectively use serial DV devices for AMBE decoding you will have to add at least one device to the list of AMBE devices in use using the `AMBE devices control` dialog opened with the `AMBE` option in the `Preferences` menu. The list of devices is saved in the program preferences so that they are persistent across program stop/start. However if the device name or server address changes in between the corresponding reference will be lost.
|
||||
|
||||
Although such serial devices work with a serial interface at 400 kb in practice maybe for other reasons they are capable of handling only one conversation at a time. The software will allocate the device dynamically to a conversation with an inactivity timeout of 1 second so that conversations do not get interrupted constantly making the audio output too choppy. In practice you will have to have as many devices connected to your system as the number of conversations you would like to be handled in parallel.
|
||||
|
||||
Note also that this is not supported in Windows because of trouble with COM port support (contributors welcome!).
|
||||
Note also that hardware serial devices are not supported in Windows because of trouble with COM port support (contributors welcome!).
|
||||
|
||||
Alternatively you can use software decoding with Mbelib. Possible copyright issues apart (see next) the audio quality with the DVSI AMBE chip is much better.
|
||||
If no AMBE devices or servers are activated with the `AMBE devices control` AMBE decoding will take place with Mbelib. Possible copyright issues apart (see next) the audio quality with the DVSI AMBE chip is much better.
|
||||
|
||||
---
|
||||
⚠ With kernel 4.4.52 and maybe other 4.4 versions the default for FTDI devices (that is in the ftdi_sio kernel module) is not to set it as low latency. This results in the ThumbDV dongle not working anymore because its response is too slow to sustain the normal AMBE packets flow. The solution is to force low latency by changing the variable for your device (ex: /dev/ttyUSB0) as follows:
|
||||
|
@ -31,22 +31,10 @@ else(FFTW3F_FOUND)
|
||||
add_definitions(-DUSE_KISSFFT)
|
||||
endif(FFTW3F_FOUND)
|
||||
|
||||
if (LIBSERIALDV_FOUND)
|
||||
set(sdrbase_SOURCES
|
||||
${sdrbase_SOURCES}
|
||||
dsp/dvserialworker.cpp
|
||||
dsp/dvserialengine.cpp
|
||||
)
|
||||
set(sdrbase_HEADERS
|
||||
${sdrbase_HEADERS}
|
||||
dsp/dvserialworker.h
|
||||
dsp/dvserialengine.h
|
||||
)
|
||||
message(STATUS "Will have SerialDV support")
|
||||
add_definitions(-DDSD_USE_SERIALDV)
|
||||
include_directories(${LIBSERIALDV_INCLUDE_DIR})
|
||||
set(sdrbase_SERIALDV_LIB ${LIBSERIALDV_LIBRARY})
|
||||
endif(LIBSERIALDV_FOUND)
|
||||
# serialdv now required
|
||||
add_definitions(-DDSD_USE_SERIALDV)
|
||||
include_directories(${LIBSERIALDV_INCLUDE_DIR})
|
||||
set(sdrbase_SERIALDV_LIB ${LIBSERIALDV_LIBRARY})
|
||||
|
||||
set(sdrbase_SOURCES
|
||||
${sdrbase_SOURCES}
|
||||
|
@ -1,296 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2016 F4EXB //
|
||||
// written by Edouard Griffiths //
|
||||
// //
|
||||
// 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 as 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 V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifndef __APPLE__
|
||||
#include <linux/serial.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <QDebug>
|
||||
#include <QThread>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include "audio/audiooutput.h"
|
||||
#include "dvserialengine.h"
|
||||
#include "dvserialworker.h"
|
||||
|
||||
DVSerialEngine::DVSerialEngine()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DVSerialEngine::~DVSerialEngine()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
void DVSerialEngine::getComList()
|
||||
{
|
||||
m_comList.clear();
|
||||
m_comList8250.clear();
|
||||
char comCStr[16];
|
||||
|
||||
// Arbitrarily set the list to the 20 first COM ports
|
||||
for (int i = 1; i <= 20; i++)
|
||||
{
|
||||
sprintf(comCStr, "COM%d", i);
|
||||
m_comList.push_back(std::string(comCStr));
|
||||
}
|
||||
}
|
||||
#else
|
||||
std::string DVSerialEngine::get_driver(const std::string& tty)
|
||||
{
|
||||
struct stat st;
|
||||
std::string devicedir = tty;
|
||||
|
||||
// Append '/device' to the tty-path
|
||||
devicedir += "/device";
|
||||
|
||||
// Stat the devicedir and handle it if it is a symlink
|
||||
if (lstat(devicedir.c_str(), &st) == 0 && S_ISLNK(st.st_mode))
|
||||
{
|
||||
char buffer[1024];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
|
||||
// Append '/driver' and return basename of the target
|
||||
devicedir += "/driver";
|
||||
|
||||
if (readlink(devicedir.c_str(), buffer, sizeof(buffer)) > 0)
|
||||
{
|
||||
return basename(buffer);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void DVSerialEngine::register_comport(std::list<std::string>& comList,
|
||||
std::list<std::string>& comList8250, const std::string& dir)
|
||||
{
|
||||
// Get the driver the device is using
|
||||
std::string driver = get_driver(dir);
|
||||
|
||||
// Skip devices without a driver
|
||||
if (driver.size() > 0)
|
||||
{
|
||||
//std::cerr << "register_comport: dir: "<< dir << " driver: " << driver << std::endl;
|
||||
std::string devfile = std::string("/dev/") + basename((char *) dir.c_str());
|
||||
|
||||
// Put serial8250-devices in a seperate list
|
||||
if (driver == "serial8250")
|
||||
{
|
||||
comList8250.push_back(devfile);
|
||||
}
|
||||
else
|
||||
comList.push_back(devfile);
|
||||
}
|
||||
}
|
||||
|
||||
void DVSerialEngine::probe_serial8250_comports(std::list<std::string>& comList,
|
||||
std::list<std::string> comList8250)
|
||||
{
|
||||
struct serial_struct serinfo;
|
||||
std::list<std::string>::iterator it = comList8250.begin();
|
||||
|
||||
// Iterate over all serial8250-devices
|
||||
while (it != comList8250.end())
|
||||
{
|
||||
|
||||
// Try to open the device
|
||||
int fd = open((*it).c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
// Get serial_info
|
||||
if (ioctl(fd, TIOCGSERIAL, &serinfo) == 0)
|
||||
{
|
||||
// If device type is no PORT_UNKNOWN we accept the port
|
||||
if (serinfo.type != PORT_UNKNOWN)
|
||||
comList.push_back(*it);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void DVSerialEngine::getComList()
|
||||
{
|
||||
int n;
|
||||
struct dirent **namelist;
|
||||
m_comList.clear();
|
||||
m_comList8250.clear();
|
||||
const char* sysdir = "/sys/class/tty/";
|
||||
|
||||
// Scan through /sys/class/tty - it contains all tty-devices in the system
|
||||
n = scandir(sysdir, &namelist, NULL, alphasort);
|
||||
if (n < 0)
|
||||
perror("scandir");
|
||||
else
|
||||
{
|
||||
while (n--)
|
||||
{
|
||||
if (strcmp(namelist[n]->d_name, "..")
|
||||
&& strcmp(namelist[n]->d_name, "."))
|
||||
{
|
||||
|
||||
// Construct full absolute file path
|
||||
std::string devicedir = sysdir;
|
||||
devicedir += namelist[n]->d_name;
|
||||
|
||||
// Register the device
|
||||
register_comport(m_comList, m_comList8250, devicedir);
|
||||
}
|
||||
free(namelist[n]);
|
||||
}
|
||||
free(namelist);
|
||||
}
|
||||
|
||||
// Only non-serial8250 has been added to comList without any further testing
|
||||
// serial8250-devices must be probe to check for validity
|
||||
probe_serial8250_comports(m_comList, m_comList8250);
|
||||
}
|
||||
#endif // __WINDOWS__
|
||||
|
||||
bool DVSerialEngine::scan()
|
||||
{
|
||||
getComList();
|
||||
std::list<std::string>::iterator it = m_comList.begin();
|
||||
|
||||
while (it != m_comList.end())
|
||||
{
|
||||
DVSerialWorker *worker = new DVSerialWorker();
|
||||
|
||||
if (worker->open(*it))
|
||||
{
|
||||
DVSerialController controller;
|
||||
controller.worker = worker;
|
||||
controller.device = *it;
|
||||
controller.thread = new QThread();
|
||||
|
||||
controller.worker->moveToThread(controller.thread);
|
||||
//connect(controller.thread, SIGNAL(started()), controller.worker, SLOT(process()));
|
||||
connect(controller.worker, SIGNAL(finished()), controller.thread, SLOT(quit()));
|
||||
connect(controller.worker, SIGNAL(finished()), controller.worker, SLOT(deleteLater()));
|
||||
connect(controller.thread, SIGNAL(finished()), controller.thread, SLOT(deleteLater()));
|
||||
connect(&controller.worker->m_inputMessageQueue, SIGNAL(messageEnqueued()), controller.worker, SLOT(handleInputMessages()));
|
||||
controller.thread->start();
|
||||
|
||||
m_controllers.push_back(controller);
|
||||
qDebug() << "DVSerialEngine::scan: found device at: " << it->c_str();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete worker;
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
return m_controllers.size() > 0;
|
||||
}
|
||||
|
||||
void DVSerialEngine::release()
|
||||
{
|
||||
qDebug("DVSerialEngine::release");
|
||||
std::vector<DVSerialController>::iterator it = m_controllers.begin();
|
||||
|
||||
while (it != m_controllers.end())
|
||||
{
|
||||
disconnect(&it->worker->m_inputMessageQueue, SIGNAL(messageEnqueued()), it->worker, SLOT(handleInputMessages()));
|
||||
it->worker->stop();
|
||||
it->thread->wait(100);
|
||||
it->worker->m_inputMessageQueue.clear();
|
||||
it->worker->close();
|
||||
qDebug() << "DVSerialEngine::release: closed device at: " << it->device.c_str();
|
||||
++it;
|
||||
}
|
||||
|
||||
m_controllers.clear();
|
||||
}
|
||||
|
||||
void DVSerialEngine::getDevicesNames(std::vector<std::string>& deviceNames)
|
||||
{
|
||||
std::vector<DVSerialController>::iterator it = m_controllers.begin();
|
||||
|
||||
while (it != m_controllers.end())
|
||||
{
|
||||
deviceNames.push_back(it->device);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
void DVSerialEngine::pushMbeFrame(
|
||||
const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useLP,
|
||||
int upsampling,
|
||||
AudioFifo *audioFifo)
|
||||
{
|
||||
std::vector<DVSerialController>::iterator it = m_controllers.begin();
|
||||
std::vector<DVSerialController>::iterator itAvail = m_controllers.end();
|
||||
bool done = false;
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
while (it != m_controllers.end())
|
||||
{
|
||||
if (it->worker->hasFifo(audioFifo))
|
||||
{
|
||||
it->worker->pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, useLP, upsampling, audioFifo);
|
||||
done = true;
|
||||
}
|
||||
else if (it->worker->isAvailable())
|
||||
{
|
||||
itAvail = it;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
if (!done)
|
||||
{
|
||||
if (itAvail != m_controllers.end())
|
||||
{
|
||||
int wNum = itAvail - m_controllers.begin();
|
||||
|
||||
qDebug("DVSerialEngine::pushMbeFrame: push %p on empty queue %d", audioFifo, wNum);
|
||||
itAvail->worker->pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, useLP, upsampling, audioFifo);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("DVSerialEngine::pushMbeFrame: no DV serial device available. MBE frame dropped");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2016 F4EXB //
|
||||
// written by Edouard Griffiths //
|
||||
// //
|
||||
// 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 as 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 V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SDRBASE_DSP_DVSERIALENGINE_H_
|
||||
#define SDRBASE_DSP_DVSERIALENGINE_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class QThread;
|
||||
class DVSerialWorker;
|
||||
class AudioFifo;
|
||||
|
||||
class SDRBASE_API DVSerialEngine : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DVSerialEngine();
|
||||
~DVSerialEngine();
|
||||
|
||||
bool scan();
|
||||
void release();
|
||||
|
||||
int getNbDevices() const { return m_controllers.size(); }
|
||||
void getDevicesNames(std::vector<std::string>& devicesNames);
|
||||
|
||||
void pushMbeFrame(
|
||||
const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
int upsampling,
|
||||
AudioFifo *audioFifo);
|
||||
|
||||
private:
|
||||
struct DVSerialController
|
||||
{
|
||||
QThread *thread;
|
||||
DVSerialWorker *worker;
|
||||
std::string device;
|
||||
};
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
static std::string get_driver(const std::string& tty);
|
||||
static void register_comport(std::list<std::string>& comList, std::list<std::string>& comList8250, const std::string& dir);
|
||||
static void probe_serial8250_comports(std::list<std::string>& comList, std::list<std::string> comList8250);
|
||||
#endif
|
||||
void getComList();
|
||||
|
||||
std::list<std::string> m_comList;
|
||||
std::list<std::string> m_comList8250;
|
||||
std::vector<DVSerialController> m_controllers;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* SDRBASE_DSP_DVSERIALENGINE_H_ */
|
@ -1,279 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2016 F4EXB //
|
||||
// written by Edouard Griffiths //
|
||||
// //
|
||||
// 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 as 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 V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "dsp/dvserialworker.h"
|
||||
#include "audio/audiofifo.h"
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(DVSerialWorker::MsgMbeDecode, Message)
|
||||
MESSAGE_CLASS_DEFINITION(DVSerialWorker::MsgTest, Message)
|
||||
|
||||
DVSerialWorker::DVSerialWorker() :
|
||||
m_running(false),
|
||||
m_currentGainIn(0),
|
||||
m_currentGainOut(0),
|
||||
m_upsamplerLastValue(0.0f),
|
||||
m_phase(0),
|
||||
m_upsampling(1),
|
||||
m_volume(1.0f)
|
||||
{
|
||||
m_audioBuffer.resize(48000);
|
||||
m_audioBufferFill = 0;
|
||||
m_audioFifo = 0;
|
||||
memset(m_dvAudioSamples, 0, SerialDV::MBE_AUDIO_BLOCK_SIZE*sizeof(short));
|
||||
setVolumeFactors();
|
||||
}
|
||||
|
||||
DVSerialWorker::~DVSerialWorker()
|
||||
{
|
||||
}
|
||||
|
||||
bool DVSerialWorker::open(const std::string& serialDevice)
|
||||
{
|
||||
return m_dvController.open(serialDevice);
|
||||
}
|
||||
|
||||
void DVSerialWorker::close()
|
||||
{
|
||||
m_dvController.close();
|
||||
}
|
||||
|
||||
void DVSerialWorker::process()
|
||||
{
|
||||
m_running = true;
|
||||
qDebug("DVSerialWorker::process: started");
|
||||
|
||||
while (m_running)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
qDebug("DVSerialWorker::process: stopped");
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void DVSerialWorker::stop()
|
||||
{
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
void DVSerialWorker::handleInputMessages()
|
||||
{
|
||||
Message* message;
|
||||
m_audioBufferFill = 0;
|
||||
AudioFifo *audioFifo = 0;
|
||||
|
||||
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||
{
|
||||
if (MsgMbeDecode::match(*message))
|
||||
{
|
||||
MsgMbeDecode *decodeMsg = (MsgMbeDecode *) message;
|
||||
int dBVolume = (decodeMsg->getVolumeIndex() - 30) / 4;
|
||||
float volume = pow(10.0, dBVolume / 10.0f);
|
||||
int upsampling = decodeMsg->getUpsampling();
|
||||
upsampling = upsampling > 6 ? 6 : upsampling < 1 ? 1 : upsampling;
|
||||
|
||||
if ((volume != m_volume) || (upsampling != m_upsampling))
|
||||
{
|
||||
m_volume = volume;
|
||||
m_upsampling = upsampling;
|
||||
setVolumeFactors();
|
||||
}
|
||||
|
||||
m_upsampleFilter.useHP(decodeMsg->getUseHP());
|
||||
|
||||
if (m_dvController.decode(m_dvAudioSamples, decodeMsg->getMbeFrame(), decodeMsg->getMbeRate()))
|
||||
{
|
||||
if (upsampling > 1) {
|
||||
upsample(upsampling, m_dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE, decodeMsg->getChannels());
|
||||
} else {
|
||||
noUpsample(m_dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE, decodeMsg->getChannels());
|
||||
}
|
||||
|
||||
audioFifo = decodeMsg->getAudioFifo();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("DVSerialWorker::handleInputMessages: MsgMbeDecode: decode failed");
|
||||
}
|
||||
}
|
||||
|
||||
delete message;
|
||||
}
|
||||
|
||||
if (audioFifo)
|
||||
{
|
||||
uint res = audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill);
|
||||
|
||||
if (res != m_audioBufferFill)
|
||||
{
|
||||
qDebug("DVSerialWorker::handleInputMessages: %u/%u audio samples written", res, m_audioBufferFill);
|
||||
}
|
||||
}
|
||||
|
||||
m_timestamp = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
void DVSerialWorker::pushMbeFrame(const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
int upsampling,
|
||||
AudioFifo *audioFifo)
|
||||
{
|
||||
m_audioFifo = audioFifo;
|
||||
m_inputMessageQueue.push(MsgMbeDecode::create(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, useHP, upsampling, audioFifo));
|
||||
}
|
||||
|
||||
bool DVSerialWorker::isAvailable()
|
||||
{
|
||||
if (m_audioFifo == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return m_timestamp.time().msecsTo(QDateTime::currentDateTime().time()) > 1000; // 1 second inactivity timeout
|
||||
}
|
||||
|
||||
bool DVSerialWorker::hasFifo(AudioFifo *audioFifo)
|
||||
{
|
||||
return m_audioFifo == audioFifo;
|
||||
}
|
||||
|
||||
void DVSerialWorker::upsample(int upsampling, short *in, int nbSamplesIn, unsigned char channels)
|
||||
{
|
||||
for (int i = 0; i < nbSamplesIn; i++)
|
||||
{
|
||||
//float cur = m_upsampleFilter.usesHP() ? m_upsampleFilter.runHP((float) m_compressor.compress(in[i])) : (float) m_compressor.compress(in[i]);
|
||||
float cur = m_upsampleFilter.usesHP() ? m_upsampleFilter.runHP((float) in[i]) : (float) in[i];
|
||||
float prev = m_upsamplerLastValue;
|
||||
qint16 upsample;
|
||||
|
||||
for (int j = 1; j <= upsampling; j++)
|
||||
{
|
||||
upsample = (qint16) m_upsampleFilter.runLP(cur*m_upsamplingFactors[j] + prev*m_upsamplingFactors[upsampling-j]);
|
||||
m_audioBuffer[m_audioBufferFill].l = channels & 1 ? m_compressor.compress(upsample) : 0;
|
||||
m_audioBuffer[m_audioBufferFill].r = (channels>>1) & 1 ? m_compressor.compress(upsample) : 0;
|
||||
|
||||
if (m_audioBufferFill < m_audioBuffer.size() - 1)
|
||||
{
|
||||
++m_audioBufferFill;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("DVSerialWorker::upsample6: audio buffer is full check its size");
|
||||
}
|
||||
}
|
||||
|
||||
m_upsamplerLastValue = cur;
|
||||
}
|
||||
}
|
||||
|
||||
void DVSerialWorker::noUpsample(short *in, int nbSamplesIn, unsigned char channels)
|
||||
{
|
||||
for (int i = 0; i < nbSamplesIn; i++)
|
||||
{
|
||||
float cur = m_upsampleFilter.usesHP() ? m_upsampleFilter.runHP((float) in[i]) : (float) in[i];
|
||||
m_audioBuffer[m_audioBufferFill].l = channels & 1 ? cur*m_upsamplingFactors[0] : 0;
|
||||
m_audioBuffer[m_audioBufferFill].r = (channels>>1) & 1 ? cur*m_upsamplingFactors[0] : 0;
|
||||
|
||||
if (m_audioBufferFill < m_audioBuffer.size() - 1)
|
||||
{
|
||||
++m_audioBufferFill;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("DVSerialWorker::noUpsample: audio buffer is full check its size");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DVSerialWorker::setVolumeFactors()
|
||||
{
|
||||
m_upsamplingFactors[0] = m_volume;
|
||||
|
||||
for (int i = 1; i <= m_upsampling; i++) {
|
||||
m_upsamplingFactors[i] = (i*m_volume) / (float) m_upsampling;
|
||||
}
|
||||
}
|
||||
|
||||
//void DVSerialWorker::upsample6(short *in, short *out, int nbSamplesIn)
|
||||
//{
|
||||
// for (int i = 0; i < nbSamplesIn; i++)
|
||||
// {
|
||||
// int cur = (int) in[i];
|
||||
// int prev = (int) m_upsamplerLastValue;
|
||||
// short up;
|
||||
//
|
||||
//// DEBUG:
|
||||
//// for (int j = 0; j < 6; j++)
|
||||
//// {
|
||||
//// up = 32768.0f * cos(m_phase);
|
||||
//// *out = up;
|
||||
//// out ++;
|
||||
//// *out = up;
|
||||
//// out ++;
|
||||
//// m_phase += M_PI / 6.0;
|
||||
//// }
|
||||
////
|
||||
//// if ((i % 2) == 1)
|
||||
//// {
|
||||
//// m_phase = 0.0f;
|
||||
//// }
|
||||
//
|
||||
// up = m_upsampleFilter.run((cur*1 + prev*5) / 6);
|
||||
// *out = up;
|
||||
// out++;
|
||||
// *out = up;
|
||||
// out++;
|
||||
//
|
||||
// up = m_upsampleFilter.run((cur*2 + prev*4) / 6);
|
||||
// *out = up;
|
||||
// out++;
|
||||
// *out = up;
|
||||
// out++;
|
||||
//
|
||||
// up = m_upsampleFilter.run((cur*3 + prev*3) / 6);
|
||||
// *out = up;
|
||||
// out++;
|
||||
// *out = up;
|
||||
// out++;
|
||||
//
|
||||
// up = m_upsampleFilter.run((cur*4 + prev*2) / 6);
|
||||
// *out = up;
|
||||
// out++;
|
||||
// *out = up;
|
||||
// out++;
|
||||
//
|
||||
// up = m_upsampleFilter.run((cur*5 + prev*1) / 6);
|
||||
// *out = up;
|
||||
// out++;
|
||||
// *out = up;
|
||||
// out++;
|
||||
//
|
||||
// up = m_upsampleFilter.run(in[i]);
|
||||
// *out = up;
|
||||
// out++;
|
||||
// *out = up;
|
||||
// out++;
|
||||
//
|
||||
// m_upsamplerLastValue = in[i];
|
||||
// }
|
||||
//}
|
@ -1,161 +0,0 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2016 F4EXB //
|
||||
// written by Edouard Griffiths //
|
||||
// //
|
||||
// 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 as 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 V3 for more details. //
|
||||
// //
|
||||
// You should have received a copy of the GNU General Public License //
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SDRBASE_DSP_DVSERIALWORKER_H_
|
||||
#define SDRBASE_DSP_DVSERIALWORKER_H_
|
||||
|
||||
#include <QObject>
|
||||
#include <QDebug>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "dvcontroller.h"
|
||||
#include "util/message.h"
|
||||
#include "util/syncmessenger.h"
|
||||
#include "util/messagequeue.h"
|
||||
#include "export.h"
|
||||
#include "dsp/filtermbe.h"
|
||||
#include "dsp/dsptypes.h"
|
||||
#include "audio/audiocompressor.h"
|
||||
|
||||
class AudioFifo;
|
||||
|
||||
class SDRBASE_API DVSerialWorker : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
class MsgTest : public Message
|
||||
{
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
public:
|
||||
static MsgTest* create() { return new MsgTest(); }
|
||||
private:
|
||||
MsgTest() {}
|
||||
};
|
||||
|
||||
class MsgMbeDecode : public Message
|
||||
{
|
||||
MESSAGE_CLASS_DECLARATION
|
||||
public:
|
||||
const unsigned char *getMbeFrame() const { return m_mbeFrame; }
|
||||
SerialDV::DVRate getMbeRate() const { return m_mbeRate; }
|
||||
int getVolumeIndex() const { return m_volumeIndex; }
|
||||
unsigned char getChannels() const { return m_channels % 4; }
|
||||
bool getUseHP() const { return m_useHP; }
|
||||
int getUpsampling() const { return m_upsampling; }
|
||||
AudioFifo *getAudioFifo() { return m_audioFifo; }
|
||||
|
||||
static MsgMbeDecode* create(
|
||||
const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int volumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
int upsampling,
|
||||
AudioFifo *audioFifo)
|
||||
{
|
||||
return new MsgMbeDecode(mbeFrame, (SerialDV::DVRate) mbeRateIndex, volumeIndex, channels, useHP, upsampling, audioFifo);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char m_mbeFrame[SerialDV::MBE_FRAME_MAX_LENGTH_BYTES];
|
||||
SerialDV::DVRate m_mbeRate;
|
||||
int m_volumeIndex;
|
||||
unsigned char m_channels;
|
||||
bool m_useHP;
|
||||
int m_upsampling;
|
||||
AudioFifo *m_audioFifo;
|
||||
|
||||
MsgMbeDecode(const unsigned char *mbeFrame,
|
||||
SerialDV::DVRate mbeRate,
|
||||
int volumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
int upsampling,
|
||||
AudioFifo *audioFifo) :
|
||||
Message(),
|
||||
m_mbeRate(mbeRate),
|
||||
m_volumeIndex(volumeIndex),
|
||||
m_channels(channels),
|
||||
m_useHP(useHP),
|
||||
m_upsampling(upsampling),
|
||||
m_audioFifo(audioFifo)
|
||||
{
|
||||
memcpy((void *) m_mbeFrame, (const void *) mbeFrame, SerialDV::DVController::getNbMbeBytes(m_mbeRate));
|
||||
}
|
||||
};
|
||||
|
||||
DVSerialWorker();
|
||||
~DVSerialWorker();
|
||||
|
||||
void pushMbeFrame(const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
int upsampling,
|
||||
AudioFifo *audioFifo);
|
||||
|
||||
bool open(const std::string& serialDevice);
|
||||
void close();
|
||||
void process();
|
||||
void stop();
|
||||
bool isAvailable();
|
||||
bool hasFifo(AudioFifo *audioFifo);
|
||||
|
||||
void postTest()
|
||||
{
|
||||
//emit inputMessageReady();
|
||||
m_inputMessageQueue.push(MsgTest::create());
|
||||
}
|
||||
|
||||
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
|
||||
AudioFifo *m_audioFifo;
|
||||
QDateTime m_timestamp;
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
public slots:
|
||||
void handleInputMessages();
|
||||
|
||||
private:
|
||||
//void upsample6(short *in, short *out, int nbSamplesIn);
|
||||
void upsample(int upsampling, short *in, int nbSamplesIn, unsigned char channels);
|
||||
void noUpsample(short *in, int nbSamplesIn, unsigned char channels);
|
||||
void setVolumeFactors();
|
||||
|
||||
SerialDV::DVController m_dvController;
|
||||
volatile bool m_running;
|
||||
int m_currentGainIn;
|
||||
int m_currentGainOut;
|
||||
short m_dvAudioSamples[SerialDV::MBE_AUDIO_BLOCK_SIZE];
|
||||
//short m_audioSamples[SerialDV::MBE_AUDIO_BLOCK_SIZE * 6 * 2]; // upsample to 48k and duplicate channel
|
||||
AudioVector m_audioBuffer;
|
||||
uint m_audioBufferFill;
|
||||
float m_upsamplerLastValue;
|
||||
float m_phase;
|
||||
MBEAudioInterpolatorFilter m_upsampleFilter;
|
||||
int m_upsampling;
|
||||
float m_volume;
|
||||
float m_upsamplingFactors[7];
|
||||
AudioCompressor m_compressor;
|
||||
};
|
||||
|
||||
#endif /* SDRBASE_DSP_DVSERIALWORKER_H_ */
|
Loading…
x
Reference in New Issue
Block a user