mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2025-08-04 22:52:26 -04:00
Merge pull request #65 from cjcliffe/audio_sample_rate
Configurable audio sample rate
This commit is contained in:
commit
ec22d1011d
@ -175,10 +175,12 @@ IF(USE_AUDIO_PULSE)
|
|||||||
ENDIF(USE_AUDIO_PULSE)
|
ENDIF(USE_AUDIO_PULSE)
|
||||||
|
|
||||||
IF(USE_AUDIO_JACK)
|
IF(USE_AUDIO_JACK)
|
||||||
SET (OTHER_LIBRARIES ${OTHER_LIBRARIES} jack)
|
find_package(Jack)
|
||||||
|
SET (OTHER_LIBRARIES ${OTHER_LIBRARIES} ${JACK_LIBRARIES})
|
||||||
ADD_DEFINITIONS(
|
ADD_DEFINITIONS(
|
||||||
-D__UNIX_JACK__
|
-D__UNIX_JACK__
|
||||||
)
|
)
|
||||||
|
include_directories(${JACK_INCLUDE_DIRS})
|
||||||
ENDIF(USE_AUDIO_JACK)
|
ENDIF(USE_AUDIO_JACK)
|
||||||
|
|
||||||
IF(USE_AUDIO_ALSA)
|
IF(USE_AUDIO_ALSA)
|
||||||
|
50
cmake/Modules/FindJack.cmake
Normal file
50
cmake/Modules/FindJack.cmake
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
# Try to find JACK
|
||||||
|
# This will define the following variables:
|
||||||
|
#
|
||||||
|
# JACK_FOUND - Whether Jack was found.
|
||||||
|
# JACK_INCLUDE_DIRS - Jack include directories.
|
||||||
|
# JACK_LIBRARIES - Jack libraries.
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
if(JACK_LIBRARIES AND JACK_INCLUDE_DIRS)
|
||||||
|
|
||||||
|
# in cache already
|
||||||
|
set(JACK_FOUND TRUE)
|
||||||
|
|
||||||
|
else()
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
if(PKG_CONFIG_FOUND)
|
||||||
|
pkg_check_modules(_JACK jack)
|
||||||
|
endif(PKG_CONFIG_FOUND)
|
||||||
|
|
||||||
|
find_path(JACK_INCLUDE_DIR
|
||||||
|
NAMES
|
||||||
|
jack/jack.h
|
||||||
|
PATHS
|
||||||
|
${_JACK_INCLUDEDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(JACK_LIBRARY
|
||||||
|
NAMES
|
||||||
|
jack
|
||||||
|
PATHS
|
||||||
|
${_JACK_LIBDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(JACK_INCLUDE_DIRS
|
||||||
|
${JACK_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
set(JACK_LIBRARIES
|
||||||
|
${JACK_LIBRARY}
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package_handle_standard_args(Jack DEFAULT_MSG JACK_LIBRARIES JACK_INCLUDE_DIRS)
|
||||||
|
|
||||||
|
# show the JACK_INCLUDE_DIRS and JACK_LIBRARIES variables only in the advanced view
|
||||||
|
mark_as_advanced(JACK_INCLUDE_DIR JACK_LIBRARY JACK_INCLUDE_DIRS JACK_LIBRARIES)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
@ -164,7 +164,6 @@ wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL) {
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for (mdevices_i = outputDevices.begin(); mdevices_i != outputDevices.end(); mdevices_i++) {
|
for (mdevices_i = outputDevices.begin(); mdevices_i != outputDevices.end(); mdevices_i++) {
|
||||||
wxMenuItem *itm = menu->AppendRadioItem(wxID_RT_AUDIO_DEVICE + mdevices_i->first, mdevices_i->second.name, wxT("Description?"));
|
wxMenuItem *itm = menu->AppendRadioItem(wxID_RT_AUDIO_DEVICE + mdevices_i->first, mdevices_i->second.name, wxT("Description?"));
|
||||||
@ -230,9 +229,61 @@ wxFrame(NULL, wxID_ANY, CUBICSDR_TITLE), activeDemodulator(NULL) {
|
|||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
menuBar->Append(menu, wxT("&Device"));
|
menuBar->Append(menu, wxT("Input &Device"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
menu = new wxMenu;
|
||||||
|
|
||||||
|
|
||||||
|
#define NUM_RATES_DEFAULT 4
|
||||||
|
int desired_rates[NUM_RATES_DEFAULT] = { 48000, 44100, 96000, 192000 };
|
||||||
|
|
||||||
|
for (mdevices_i = outputDevices.begin(); mdevices_i != outputDevices.end(); mdevices_i++) {
|
||||||
|
int desired_rate = 0;
|
||||||
|
int desired_rank = NUM_RATES_DEFAULT+1;
|
||||||
|
|
||||||
|
for (std::vector<unsigned int>::iterator srate = mdevices_i->second.sampleRates.begin(); srate != mdevices_i->second.sampleRates.end(); srate++) {
|
||||||
|
for (i = 0; i < NUM_RATES_DEFAULT; i++) {
|
||||||
|
if (desired_rates[i] == (*srate)) {
|
||||||
|
if (desired_rank > i) {
|
||||||
|
desired_rank = i;
|
||||||
|
desired_rate = (*srate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desired_rank > NUM_RATES_DEFAULT) {
|
||||||
|
desired_rate = mdevices_i->second.sampleRates.back();
|
||||||
|
}
|
||||||
|
AudioThread::deviceSampleRate[mdevices_i->first] = desired_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mdevices_i = outputDevices.begin(); mdevices_i != outputDevices.end(); mdevices_i++) {
|
||||||
|
new wxMenu;
|
||||||
|
int menu_id = wxID_AUDIO_BANDWIDTH_BASE + wxID_AUDIO_DEVICE_MULTIPLIER * mdevices_i->first;
|
||||||
|
wxMenu *subMenu = new wxMenu;
|
||||||
|
menu->AppendSubMenu(subMenu,mdevices_i->second.name, wxT("Description?"));
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (std::vector<unsigned int>::iterator srate = mdevices_i->second.sampleRates.begin(); srate != mdevices_i->second.sampleRates.end(); srate++) {
|
||||||
|
std::stringstream srateName;
|
||||||
|
srateName << ((float)(*srate)/1000.0f) << "kHz";
|
||||||
|
wxMenuItem *itm = subMenu->AppendRadioItem(menu_id+j, srateName.str(), wxT("Description?"));
|
||||||
|
|
||||||
|
if ((*srate) == AudioThread::deviceSampleRate[mdevices_i->first]) {
|
||||||
|
itm->Check(true);
|
||||||
|
}
|
||||||
|
audioSampleRateMenuItems[menu_id+j] = itm;
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
menuBar->Append(menu, wxT("Audio &Bandwidth"));
|
||||||
|
|
||||||
|
|
||||||
SetMenuBar(menuBar);
|
SetMenuBar(menuBar);
|
||||||
|
|
||||||
CreateStatusBar();
|
CreateStatusBar();
|
||||||
@ -346,6 +397,32 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
|
|||||||
if (event.GetId() >= wxID_DEVICE_ID && event.GetId() <= wxID_DEVICE_ID + devs->size()) {
|
if (event.GetId() >= wxID_DEVICE_ID && event.GetId() <= wxID_DEVICE_ID + devs->size()) {
|
||||||
wxGetApp().setDevice(event.GetId() - wxID_DEVICE_ID);
|
wxGetApp().setDevice(event.GetId() - wxID_DEVICE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (event.GetId() >= wxID_AUDIO_BANDWIDTH_BASE) {
|
||||||
|
int evId = event.GetId();
|
||||||
|
std::vector<RtAudio::DeviceInfo>::iterator devices_i;
|
||||||
|
std::map<int, RtAudio::DeviceInfo>::iterator mdevices_i;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (mdevices_i = outputDevices.begin(); mdevices_i != outputDevices.end(); mdevices_i++) {
|
||||||
|
int menu_id = wxID_AUDIO_BANDWIDTH_BASE + wxID_AUDIO_DEVICE_MULTIPLIER * mdevices_i->first;
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (std::vector<unsigned int>::iterator srate = mdevices_i->second.sampleRates.begin(); srate != mdevices_i->second.sampleRates.end(); srate++) {
|
||||||
|
|
||||||
|
if (evId == menu_id + j) {
|
||||||
|
//audioSampleRateMenuItems[menu_id+j];
|
||||||
|
//std::cout << "Would set audio sample rate on device " << mdevices_i->second.name << " (" << mdevices_i->first << ") to " << (*srate) << "Hz" << std::endl;
|
||||||
|
AudioThread::setDeviceSampleRate(mdevices_i->first, *srate);
|
||||||
|
}
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) {
|
void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) {
|
||||||
|
@ -33,6 +33,10 @@
|
|||||||
|
|
||||||
#define wxID_DEVICE_ID 3500
|
#define wxID_DEVICE_ID 3500
|
||||||
|
|
||||||
|
#define wxID_AUDIO_BANDWIDTH_BASE 9000
|
||||||
|
#define wxID_AUDIO_DEVICE_MULTIPLIER 50
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Define a new frame type
|
// Define a new frame type
|
||||||
class AppFrame: public wxFrame {
|
class AppFrame: public wxFrame {
|
||||||
@ -60,17 +64,15 @@ private:
|
|||||||
MeterCanvas *demodSignalMeter;
|
MeterCanvas *demodSignalMeter;
|
||||||
MeterCanvas *demodGainMeter;
|
MeterCanvas *demodGainMeter;
|
||||||
TuningCanvas *demodTuner;
|
TuningCanvas *demodTuner;
|
||||||
// event table
|
|
||||||
|
|
||||||
DemodulatorInstance *activeDemodulator;
|
DemodulatorInstance *activeDemodulator;
|
||||||
|
|
||||||
std::vector<RtAudio::DeviceInfo> devices;
|
std::vector<RtAudio::DeviceInfo> devices;
|
||||||
std::map<int,RtAudio::DeviceInfo> inputDevices;
|
std::map<int,RtAudio::DeviceInfo> inputDevices;
|
||||||
std::map<int,RtAudio::DeviceInfo> outputDevices;
|
std::map<int,RtAudio::DeviceInfo> outputDevices;
|
||||||
std::map<int,wxMenuItem *> outputDeviceMenuItems;
|
std::map<int, wxMenuItem *> outputDeviceMenuItems;
|
||||||
|
std::map<int, wxMenuItem *> sampleRateMenuItems;
|
||||||
std::map<int,wxMenuItem *> sampleRateMenuItems;
|
std::map<int, wxMenuItem *> audioSampleRateMenuItems;
|
||||||
|
|
||||||
|
|
||||||
std::string currentSessionFile;
|
std::string currentSessionFile;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* XPM */
|
/* XPM */
|
||||||
static char *cubicsdr_xpm[] = {
|
static char const *cubicsdr_xpm[] = {
|
||||||
/* columns rows colors chars-per-pixel */
|
/* columns rows colors chars-per-pixel */
|
||||||
"256 256 256 2 ",
|
"256 256 256 2 ",
|
||||||
" c #010101",
|
" c #010101",
|
||||||
|
@ -42,7 +42,6 @@ const char filePathSeparator =
|
|||||||
#define DEFAULT_FFT_SIZE 2048
|
#define DEFAULT_FFT_SIZE 2048
|
||||||
|
|
||||||
#define DEFAULT_FREQ 100000000
|
#define DEFAULT_FREQ 100000000
|
||||||
#define AUDIO_FREQUENCY 44100
|
|
||||||
#define DEFAULT_DEMOD_TYPE 1
|
#define DEFAULT_DEMOD_TYPE 1
|
||||||
#define DEFAULT_DEMOD_BW 200000
|
#define DEFAULT_DEMOD_BW 200000
|
||||||
|
|
||||||
|
@ -2,29 +2,25 @@
|
|||||||
#include "CubicSDRDefs.h"
|
#include "CubicSDRDefs.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include "CubicSDR.h"
|
||||||
#include "DemodulatorThread.h"
|
#include "DemodulatorThread.h"
|
||||||
|
#include "DemodulatorInstance.h"
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
#ifdef USE_MIXER
|
|
||||||
std::map<int, AudioThread *> AudioThread::deviceController;
|
std::map<int, AudioThread *> AudioThread::deviceController;
|
||||||
|
std::map<int, int> AudioThread::deviceSampleRate;
|
||||||
std::map<int, std::thread *> AudioThread::deviceThread;
|
std::map<int, std::thread *> AudioThread::deviceThread;
|
||||||
#endif
|
|
||||||
|
|
||||||
AudioThread::AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify) :
|
AudioThread::AudioThread(AudioThreadInputQueue *inputQueue, DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||||
currentInput(NULL), inputQueue(inputQueue), audioQueuePtr(0), underflowCount(0), terminated(false), active(false), outputDevice(-1), gain(
|
currentInput(NULL), inputQueue(inputQueue), audioQueuePtr(0), underflowCount(0), terminated(false), active(false), outputDevice(-1), gain(
|
||||||
1.0), threadQueueNotify(threadQueueNotify) {
|
1.0), threadQueueNotify(threadQueueNotify), sampleRate(0), nBufferFrames(1024) {
|
||||||
#ifdef USE_MIXER
|
|
||||||
boundThreads = new std::vector<AudioThread *>;
|
boundThreads = new std::vector<AudioThread *>;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioThread::~AudioThread() {
|
AudioThread::~AudioThread() {
|
||||||
#ifdef USE_MIXER
|
|
||||||
delete boundThreads.load();
|
delete boundThreads.load();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_MIXER
|
|
||||||
void AudioThread::bindThread(AudioThread *other) {
|
void AudioThread::bindThread(AudioThread *other) {
|
||||||
if (std::find(boundThreads.load()->begin(), boundThreads.load()->end(), other) == boundThreads.load()->end()) {
|
if (std::find(boundThreads.load()->begin(), boundThreads.load()->end(), other) == boundThreads.load()->end()) {
|
||||||
boundThreads.load()->push_back(other);
|
boundThreads.load()->push_back(other);
|
||||||
@ -74,33 +70,53 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!srcmix->currentInput) {
|
if (!srcmix->currentInput) {
|
||||||
if (srcmix->terminated) {
|
srcmix->audioQueuePtr = 0;
|
||||||
|
if (srcmix->terminated || srcmix->inputQueue->empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
srcmix->inputQueue->pop(srcmix->currentInput);
|
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||||
if (srcmix->terminated) {
|
if (srcmix->terminated) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
srcmix->audioQueuePtr = 0;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard < std::mutex > lock(srcmix->currentInput->m_mutex);
|
// std::lock_guard < std::mutex > lock(srcmix->currentInput->m_mutex);
|
||||||
|
|
||||||
|
if (srcmix->currentInput->sampleRate != src->getSampleRate()) {
|
||||||
|
while (srcmix->inputQueue->size()) {
|
||||||
|
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||||
|
if (srcmix->currentInput) {
|
||||||
|
if (srcmix->currentInput->sampleRate == src->getSampleRate()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
srcmix->currentInput->decRefCount();
|
||||||
|
}
|
||||||
|
srcmix->currentInput = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
srcmix->audioQueuePtr = 0;
|
||||||
|
|
||||||
|
if (!srcmix->currentInput) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (srcmix->currentInput->channels == 0 || !srcmix->currentInput->data.size()) {
|
if (srcmix->currentInput->channels == 0 || !srcmix->currentInput->data.size()) {
|
||||||
if (!srcmix->inputQueue->empty()) {
|
if (!srcmix->inputQueue->empty()) {
|
||||||
|
srcmix->audioQueuePtr = 0;
|
||||||
if (srcmix->currentInput) {
|
if (srcmix->currentInput) {
|
||||||
srcmix->currentInput->decRefCount();
|
srcmix->currentInput->decRefCount();
|
||||||
srcmix->currentInput = NULL;
|
srcmix->currentInput = NULL;
|
||||||
}
|
}
|
||||||
if (srcmix->terminated) {
|
if (srcmix->terminated || srcmix->inputQueue->empty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
srcmix->inputQueue->pop(srcmix->currentInput);
|
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||||
if (srcmix->terminated) {
|
if (srcmix->terminated) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
srcmix->audioQueuePtr = 0;
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -110,18 +126,18 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
|||||||
if (srcmix->currentInput->channels == 1) {
|
if (srcmix->currentInput->channels == 1) {
|
||||||
for (int i = 0; i < nBufferFrames; i++) {
|
for (int i = 0; i < nBufferFrames; i++) {
|
||||||
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
|
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
|
||||||
|
srcmix->audioQueuePtr = 0;
|
||||||
if (srcmix->currentInput) {
|
if (srcmix->currentInput) {
|
||||||
srcmix->currentInput->decRefCount();
|
srcmix->currentInput->decRefCount();
|
||||||
srcmix->currentInput = NULL;
|
srcmix->currentInput = NULL;
|
||||||
}
|
}
|
||||||
if (srcmix->terminated) {
|
if (srcmix->terminated || srcmix->inputQueue->empty()) {
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
srcmix->inputQueue->pop(srcmix->currentInput);
|
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||||
if (srcmix->terminated) {
|
if (srcmix->terminated) {
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
srcmix->audioQueuePtr = 0;
|
|
||||||
float srcPeak = srcmix->currentInput->peak * srcmix->gain;
|
float srcPeak = srcmix->currentInput->peak * srcmix->gain;
|
||||||
if (mixPeak < srcPeak) {
|
if (mixPeak < srcPeak) {
|
||||||
mixPeak = srcPeak;
|
mixPeak = srcPeak;
|
||||||
@ -137,18 +153,18 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
|||||||
} else {
|
} else {
|
||||||
for (int i = 0, iMax = srcmix->currentInput->channels * nBufferFrames; i < iMax; i++) {
|
for (int i = 0, iMax = srcmix->currentInput->channels * nBufferFrames; i < iMax; i++) {
|
||||||
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
|
if (srcmix->audioQueuePtr >= srcmix->currentInput->data.size()) {
|
||||||
|
srcmix->audioQueuePtr = 0;
|
||||||
if (srcmix->currentInput) {
|
if (srcmix->currentInput) {
|
||||||
srcmix->currentInput->decRefCount();
|
srcmix->currentInput->decRefCount();
|
||||||
srcmix->currentInput = NULL;
|
srcmix->currentInput = NULL;
|
||||||
}
|
}
|
||||||
if (srcmix->terminated) {
|
if (srcmix->terminated || srcmix->inputQueue->empty()) {
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
srcmix->inputQueue->pop(srcmix->currentInput);
|
srcmix->inputQueue->pop(srcmix->currentInput);
|
||||||
if (srcmix->terminated) {
|
if (srcmix->terminated) {
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
srcmix->audioQueuePtr = 0;
|
|
||||||
float srcPeak = srcmix->currentInput->peak * srcmix->gain;
|
float srcPeak = srcmix->currentInput->peak * srcmix->gain;
|
||||||
if (mixPeak < srcPeak) {
|
if (mixPeak < srcPeak) {
|
||||||
mixPeak = srcPeak;
|
mixPeak = srcPeak;
|
||||||
@ -172,112 +188,6 @@ static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBu
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static int audioCallback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status,
|
|
||||||
void *userData) {
|
|
||||||
AudioThread *src = (AudioThread *) userData;
|
|
||||||
float *out = (float*) outputBuffer;
|
|
||||||
memset(out, 0, nBufferFrames * 2 * sizeof(float));
|
|
||||||
if (status) {
|
|
||||||
std::cout << "Audio buffer underflow.." << (src->underflowCount++) << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src->terminated || !src->active) {
|
|
||||||
if (src->currentInput) {
|
|
||||||
src->currentInput->decRefCount();
|
|
||||||
src->currentInput = NULL;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!src->currentInput) {
|
|
||||||
if (src->inputQueue->empty()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
src->inputQueue->pop(src->currentInput);
|
|
||||||
if (src->terminated || !src->active) {
|
|
||||||
src->currentInput->decRefCount();
|
|
||||||
src->currentInput = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
src->audioQueuePtr = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard < std::mutex > lock(src->currentInput->m_mutex);
|
|
||||||
|
|
||||||
if (src->currentInput->channels == 0 || !src->currentInput->data.size()) {
|
|
||||||
if (!src->inputQueue->empty()) {
|
|
||||||
if (src->currentInput) {
|
|
||||||
src->currentInput->decRefCount();
|
|
||||||
src->currentInput = NULL;
|
|
||||||
}
|
|
||||||
if (src->terminated || !src->active) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
src->inputQueue->pop(src->currentInput);
|
|
||||||
if (src->terminated || !src->active) {
|
|
||||||
src->currentInput->decRefCount();
|
|
||||||
src->currentInput = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
src->audioQueuePtr = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (src->currentInput->channels == 1) {
|
|
||||||
for (int i = 0; i < nBufferFrames; i++) {
|
|
||||||
if (src->audioQueuePtr >= src->currentInput->data.size()) {
|
|
||||||
if (src->currentInput) {
|
|
||||||
src->currentInput->decRefCount();
|
|
||||||
src->currentInput = NULL;
|
|
||||||
}
|
|
||||||
if (src->terminated || !src->active) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
src->inputQueue->pop(src->currentInput);
|
|
||||||
if (src->terminated || !src->active) {
|
|
||||||
src->currentInput->decRefCount();
|
|
||||||
src->currentInput = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
src->audioQueuePtr = 0;
|
|
||||||
}
|
|
||||||
if (src->currentInput && src->currentInput->data.size()) {
|
|
||||||
out[i * 2] = out[i * 2 + 1] = src->currentInput->data[src->audioQueuePtr] * src->gain;
|
|
||||||
}
|
|
||||||
src->audioQueuePtr++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (int i = 0, iMax = src->currentInput->channels * nBufferFrames; i < iMax; i++) {
|
|
||||||
if (src->audioQueuePtr >= src->currentInput->data.size()) {
|
|
||||||
if (src->currentInput) {
|
|
||||||
src->currentInput->decRefCount();
|
|
||||||
src->currentInput = NULL;
|
|
||||||
}
|
|
||||||
if (src->terminated || !src->active) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
src->inputQueue->pop(src->currentInput);
|
|
||||||
if (src->terminated || !src->active) {
|
|
||||||
src->currentInput->decRefCount();
|
|
||||||
src->currentInput = NULL;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
src->audioQueuePtr = 0;
|
|
||||||
}
|
|
||||||
if (src->currentInput && src->currentInput->data.size()) {
|
|
||||||
out[i] = src->currentInput->data[src->audioQueuePtr] * src->gain;
|
|
||||||
}
|
|
||||||
src->audioQueuePtr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
|
void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
|
||||||
RtAudio endac;
|
RtAudio endac;
|
||||||
|
|
||||||
@ -330,19 +240,57 @@ void AudioThread::enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioThread::setDeviceSampleRate(int deviceId, int sampleRate) {
|
||||||
|
if (deviceController.find(deviceId) != deviceController.end()) {
|
||||||
|
AudioThreadCommand refreshDevice;
|
||||||
|
refreshDevice.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE;
|
||||||
|
refreshDevice.int_value = sampleRate;
|
||||||
|
deviceController[deviceId]->getCommandQueue()->push(refreshDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioThread::setSampleRate(int sampleRate) {
|
||||||
|
if (deviceController[outputDevice.load()] == this) {
|
||||||
|
deviceSampleRate[outputDevice.load()] = sampleRate;
|
||||||
|
|
||||||
|
dac.stopStream();
|
||||||
|
dac.closeStream();
|
||||||
|
|
||||||
|
for (int j = 0; j < boundThreads.load()->size(); j++) {
|
||||||
|
AudioThread *srcmix = (*(boundThreads.load()))[j];
|
||||||
|
srcmix->setSampleRate(sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<DemodulatorInstance *>::iterator demod_i;
|
||||||
|
std::vector<DemodulatorInstance *> *demodulators;
|
||||||
|
|
||||||
|
demodulators = &wxGetApp().getDemodMgr().getDemodulators();
|
||||||
|
|
||||||
|
for (demod_i = demodulators->begin(); demod_i != demodulators->end(); demod_i++) {
|
||||||
|
if ((*demod_i)->getOutputDevice() == outputDevice.load()) {
|
||||||
|
(*demod_i)->setAudioSampleRate(sampleRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dac.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &nBufferFrames, &audioCallback, (void *) this, &opts);
|
||||||
|
dac.startStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->sampleRate = sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AudioThread::getSampleRate() {
|
||||||
|
return this->sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
void AudioThread::setupDevice(int deviceId) {
|
void AudioThread::setupDevice(int deviceId) {
|
||||||
parameters.deviceId = deviceId;
|
parameters.deviceId = deviceId;
|
||||||
parameters.nChannels = 2;
|
parameters.nChannels = 2;
|
||||||
parameters.firstChannel = 0;
|
parameters.firstChannel = 0;
|
||||||
unsigned int sampleRate = AUDIO_FREQUENCY;
|
|
||||||
unsigned int bufferFrames = 256;
|
|
||||||
|
|
||||||
RtAudio::StreamOptions opts;
|
|
||||||
opts.streamName = "CubicSDR Audio Output";
|
opts.streamName = "CubicSDR Audio Output";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
#ifdef USE_MIXER
|
|
||||||
if (deviceController.find(outputDevice.load()) != deviceController.end()) {
|
if (deviceController.find(outputDevice.load()) != deviceController.end()) {
|
||||||
deviceController[outputDevice.load()]->removeThread(this);
|
deviceController[outputDevice.load()]->removeThread(this);
|
||||||
}
|
}
|
||||||
@ -352,43 +300,30 @@ void AudioThread::setupDevice(int deviceId) {
|
|||||||
// opts.flags = RTAUDIO_MINIMIZE_LATENCY;
|
// opts.flags = RTAUDIO_MINIMIZE_LATENCY;
|
||||||
opts.flags = RTAUDIO_SCHEDULE_REALTIME;
|
opts.flags = RTAUDIO_SCHEDULE_REALTIME;
|
||||||
|
|
||||||
|
if (deviceSampleRate.find(parameters.deviceId) != deviceSampleRate.end()) {
|
||||||
|
sampleRate = deviceSampleRate[parameters.deviceId];
|
||||||
|
} else {
|
||||||
|
std::cout << "Error, device sample rate wasn't initialized?" << std::endl;
|
||||||
|
return;
|
||||||
|
// sampleRate = AudioThread::getDefaultAudioSampleRate();
|
||||||
|
// deviceSampleRate[parameters.deviceId] = sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
if (deviceController.find(parameters.deviceId) == deviceController.end()) {
|
if (deviceController.find(parameters.deviceId) == deviceController.end()) {
|
||||||
deviceController[parameters.deviceId] = new AudioThread(NULL, NULL);
|
deviceController[parameters.deviceId] = new AudioThread(NULL, NULL);
|
||||||
deviceController[parameters.deviceId]->setInitOutputDevice(parameters.deviceId);
|
|
||||||
|
deviceController[parameters.deviceId]->setInitOutputDevice(parameters.deviceId, sampleRate);
|
||||||
deviceController[parameters.deviceId]->bindThread(this);
|
deviceController[parameters.deviceId]->bindThread(this);
|
||||||
|
|
||||||
deviceThread[parameters.deviceId] = new std::thread(&AudioThread::threadMain, deviceController[parameters.deviceId]);
|
deviceThread[parameters.deviceId] = new std::thread(&AudioThread::threadMain, deviceController[parameters.deviceId]);
|
||||||
} else if (deviceController[parameters.deviceId] == this) {
|
} else if (deviceController[parameters.deviceId] == this) {
|
||||||
dac.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &bufferFrames, &audioCallback, (void *) this, &opts);
|
dac.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &nBufferFrames, &audioCallback, (void *) this, &opts);
|
||||||
dac.startStream();
|
dac.startStream();
|
||||||
} else {
|
} else {
|
||||||
deviceController[parameters.deviceId]->bindThread(this);
|
deviceController[parameters.deviceId]->bindThread(this);
|
||||||
}
|
}
|
||||||
active = true;
|
active = true;
|
||||||
|
|
||||||
#else
|
|
||||||
if (dac.isStreamOpen()) {
|
|
||||||
if (dac.isStreamRunning()) {
|
|
||||||
dac.stopStream();
|
|
||||||
}
|
|
||||||
dac.closeStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deviceId != -1) {
|
|
||||||
active = true;
|
|
||||||
dac.openStream(¶meters, NULL, RTAUDIO_FLOAT32, sampleRate, &bufferFrames, &audioCallback, (void *) this, &opts);
|
|
||||||
dac.startStream();
|
|
||||||
} else {
|
|
||||||
active = false;
|
|
||||||
AudioThreadInput *dummy;
|
|
||||||
while (!inputQueue->empty()) { // flush queue
|
|
||||||
inputQueue->pop(dummy);
|
|
||||||
if (dummy) {
|
|
||||||
dummy->decRefCount();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
} catch (RtAudioError& e) {
|
} catch (RtAudioError& e) {
|
||||||
e.printMessage();
|
e.printMessage();
|
||||||
return;
|
return;
|
||||||
@ -405,8 +340,16 @@ int AudioThread::getOutputDevice() {
|
|||||||
return outputDevice;
|
return outputDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::setInitOutputDevice(int deviceId) {
|
void AudioThread::setInitOutputDevice(int deviceId, int sampleRate) {
|
||||||
outputDevice = deviceId;
|
outputDevice = deviceId;
|
||||||
|
if (sampleRate == -1) {
|
||||||
|
if (deviceSampleRate.find(parameters.deviceId) != deviceSampleRate.end()) {
|
||||||
|
sampleRate = deviceSampleRate[deviceId];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deviceSampleRate[deviceId] = sampleRate;
|
||||||
|
}
|
||||||
|
this->sampleRate = sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioThread::threadMain() {
|
void AudioThread::threadMain() {
|
||||||
@ -437,14 +380,11 @@ void AudioThread::threadMain() {
|
|||||||
if (command.cmd == AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE) {
|
if (command.cmd == AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE) {
|
||||||
setupDevice(command.int_value);
|
setupDevice(command.int_value);
|
||||||
}
|
}
|
||||||
|
if (command.cmd == AudioThreadCommand::AUDIO_THREAD_CMD_SET_SAMPLE_RATE) {
|
||||||
|
setSampleRate(command.int_value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !USE_MIXER
|
|
||||||
AudioThreadInput dummy;
|
|
||||||
inputQueue->push(&dummy);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_MIXER
|
|
||||||
if (deviceController[parameters.deviceId] != this) {
|
if (deviceController[parameters.deviceId] != this) {
|
||||||
deviceController[parameters.deviceId]->removeThread(this);
|
deviceController[parameters.deviceId]->removeThread(this);
|
||||||
} else {
|
} else {
|
||||||
@ -459,18 +399,6 @@ void AudioThread::threadMain() {
|
|||||||
e.printMessage();
|
e.printMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
try {
|
|
||||||
if (dac.isStreamOpen()) {
|
|
||||||
if (dac.isStreamRunning()) {
|
|
||||||
dac.stopStream();
|
|
||||||
}
|
|
||||||
dac.closeStream();
|
|
||||||
}
|
|
||||||
} catch (RtAudioError& e) {
|
|
||||||
e.printMessage();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (threadQueueNotify != NULL) {
|
if (threadQueueNotify != NULL) {
|
||||||
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED);
|
DemodulatorThreadCommand tCmd(DemodulatorThreadCommand::DEMOD_THREAD_CMD_AUDIO_TERMINATED);
|
||||||
@ -492,7 +420,6 @@ bool AudioThread::isActive() {
|
|||||||
|
|
||||||
void AudioThread::setActive(bool state) {
|
void AudioThread::setActive(bool state) {
|
||||||
|
|
||||||
#ifdef USE_MIXER
|
|
||||||
AudioThreadInput *dummy;
|
AudioThreadInput *dummy;
|
||||||
if (state && !active) {
|
if (state && !active) {
|
||||||
while (!inputQueue->empty()) { // flush queue
|
while (!inputQueue->empty()) { // flush queue
|
||||||
@ -512,22 +439,6 @@ void AudioThread::setActive(bool state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
active = state;
|
active = state;
|
||||||
#else
|
|
||||||
if (state && !active && outputDevice != -1) {
|
|
||||||
active = state;
|
|
||||||
AudioThreadCommand command;
|
|
||||||
command.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE;
|
|
||||||
command.int_value = outputDevice;
|
|
||||||
cmdQueue.push(command);
|
|
||||||
} else if (active && !state) {
|
|
||||||
active = state;
|
|
||||||
AudioThreadCommand command;
|
|
||||||
command.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE;
|
|
||||||
command.int_value = -1;
|
|
||||||
cmdQueue.push(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioThreadCommandQueue *AudioThread::getCommandQueue() {
|
AudioThreadCommandQueue *AudioThread::getCommandQueue() {
|
||||||
|
@ -11,18 +11,6 @@
|
|||||||
#include "RtAudio.h"
|
#include "RtAudio.h"
|
||||||
#include "DemodDefs.h"
|
#include "DemodDefs.h"
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#define USE_MIXER 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
#define USE_MIXER 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __WINDOWS_DS__
|
|
||||||
#define USE_MIXER 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class AudioThreadInput: public ReferenceCounter {
|
class AudioThreadInput: public ReferenceCounter {
|
||||||
public:
|
public:
|
||||||
long long frequency;
|
long long frequency;
|
||||||
@ -44,7 +32,7 @@ public:
|
|||||||
class AudioThreadCommand {
|
class AudioThreadCommand {
|
||||||
public:
|
public:
|
||||||
enum AudioThreadCommandEnum {
|
enum AudioThreadCommandEnum {
|
||||||
AUDIO_THREAD_CMD_NULL, AUDIO_THREAD_CMD_SET_DEVICE
|
AUDIO_THREAD_CMD_NULL, AUDIO_THREAD_CMD_SET_DEVICE, AUDIO_THREAD_CMD_SET_SAMPLE_RATE
|
||||||
};
|
};
|
||||||
|
|
||||||
AudioThreadCommand() :
|
AudioThreadCommand() :
|
||||||
@ -77,8 +65,10 @@ public:
|
|||||||
static void enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs);
|
static void enumerateDevices(std::vector<RtAudio::DeviceInfo> &devs);
|
||||||
|
|
||||||
void setupDevice(int deviceId);
|
void setupDevice(int deviceId);
|
||||||
void setInitOutputDevice(int deviceId);
|
void setInitOutputDevice(int deviceId, int sampleRate=-1);
|
||||||
int getOutputDevice();
|
int getOutputDevice();
|
||||||
|
void setSampleRate(int sampleRate);
|
||||||
|
int getSampleRate();
|
||||||
void threadMain();
|
void threadMain();
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
@ -92,19 +82,22 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
RtAudio dac;
|
RtAudio dac;
|
||||||
|
unsigned int nBufferFrames;
|
||||||
|
RtAudio::StreamOptions opts;
|
||||||
RtAudio::StreamParameters parameters;
|
RtAudio::StreamParameters parameters;
|
||||||
AudioThreadCommandQueue cmdQueue;
|
AudioThreadCommandQueue cmdQueue;
|
||||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||||
|
int sampleRate;
|
||||||
|
|
||||||
#ifdef USE_MIXER
|
|
||||||
public:
|
public:
|
||||||
void bindThread(AudioThread *other);
|
void bindThread(AudioThread *other);
|
||||||
void removeThread(AudioThread *other);
|
void removeThread(AudioThread *other);
|
||||||
|
|
||||||
static std::map<int,AudioThread *> deviceController;
|
static std::map<int,AudioThread *> deviceController;
|
||||||
|
static std::map<int,int> deviceSampleRate;
|
||||||
static std::map<int,std::thread *> deviceThread;
|
static std::map<int,std::thread *> deviceThread;
|
||||||
static void deviceCleanup();
|
static void deviceCleanup();
|
||||||
|
static void setDeviceSampleRate(int deviceId, int sampleRate);
|
||||||
std::atomic<std::vector<AudioThread *> *> boundThreads;
|
std::atomic<std::vector<AudioThread *> *> boundThreads;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ public:
|
|||||||
DEMOD_THREAD_CMD_NULL,
|
DEMOD_THREAD_CMD_NULL,
|
||||||
DEMOD_THREAD_CMD_SET_BANDWIDTH,
|
DEMOD_THREAD_CMD_SET_BANDWIDTH,
|
||||||
DEMOD_THREAD_CMD_SET_FREQUENCY,
|
DEMOD_THREAD_CMD_SET_FREQUENCY,
|
||||||
|
DEMOD_THREAD_CMD_SET_AUDIO_RATE,
|
||||||
DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED,
|
DEMOD_THREAD_CMD_DEMOD_PREPROCESS_TERMINATED,
|
||||||
DEMOD_THREAD_CMD_DEMOD_TERMINATED,
|
DEMOD_THREAD_CMD_DEMOD_TERMINATED,
|
||||||
DEMOD_THREAD_CMD_AUDIO_TERMINATED
|
DEMOD_THREAD_CMD_AUDIO_TERMINATED
|
||||||
@ -78,9 +79,13 @@ public:
|
|||||||
msresamp_rrrf audioResampler;
|
msresamp_rrrf audioResampler;
|
||||||
msresamp_rrrf stereoResampler;
|
msresamp_rrrf stereoResampler;
|
||||||
double audioResampleRatio;
|
double audioResampleRatio;
|
||||||
|
int audioSampleRate;
|
||||||
|
|
||||||
|
firfilt_rrrf firStereoLeft;
|
||||||
|
firfilt_rrrf firStereoRight;
|
||||||
|
|
||||||
DemodulatorThreadPostIQData() :
|
DemodulatorThreadPostIQData() :
|
||||||
sampleRate(0), audioResampler(NULL), stereoResampler(NULL), audioResampleRatio(0) {
|
sampleRate(0), audioResampler(NULL), stereoResampler(NULL), audioResampleRatio(0), audioSampleRate(0), firStereoLeft(NULL), firStereoRight(NULL) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,8 +132,8 @@ public:
|
|||||||
int demodType;
|
int demodType;
|
||||||
|
|
||||||
DemodulatorThreadParameters() :
|
DemodulatorThreadParameters() :
|
||||||
frequency(0), sampleRate(DEFAULT_SAMPLE_RATE), bandwidth(200000), audioSampleRate(
|
frequency(0), sampleRate(DEFAULT_SAMPLE_RATE), bandwidth(200000), audioSampleRate(0),
|
||||||
AUDIO_FREQUENCY), demodType(DEMOD_TYPE_FM) {
|
demodType(DEMOD_TYPE_FM) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,8 @@ void DemodulatorInstance::run() {
|
|||||||
|
|
||||||
currentFrequency = demodulatorPreThread->getParams().frequency;
|
currentFrequency = demodulatorPreThread->getParams().frequency;
|
||||||
currentDemodType = demodulatorThread->getDemodulatorType();
|
currentDemodType = demodulatorThread->getDemodulatorType();
|
||||||
|
currentAudioSampleRate = AudioThread::deviceSampleRate[getOutputDevice()];
|
||||||
|
demodulatorPreThread->getParams().audioSampleRate = currentAudioSampleRate;
|
||||||
|
|
||||||
t_Audio = new std::thread(&AudioThread::threadMain, audioThread);
|
t_Audio = new std::thread(&AudioThread::threadMain, audioThread);
|
||||||
|
|
||||||
@ -215,6 +217,8 @@ void DemodulatorInstance::setOutputDevice(int device_id) {
|
|||||||
if (!active) {
|
if (!active) {
|
||||||
audioThread->setInitOutputDevice(device_id);
|
audioThread->setInitOutputDevice(device_id);
|
||||||
} else if (audioThread) {
|
} else if (audioThread) {
|
||||||
|
setAudioSampleRate(AudioThread::deviceSampleRate[device_id]);
|
||||||
|
|
||||||
AudioThreadCommand command;
|
AudioThreadCommand command;
|
||||||
command.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE;
|
command.cmd = AudioThreadCommand::AUDIO_THREAD_CMD_SET_DEVICE;
|
||||||
command.int_value = device_id;
|
command.int_value = device_id;
|
||||||
@ -225,10 +229,10 @@ void DemodulatorInstance::setOutputDevice(int device_id) {
|
|||||||
|
|
||||||
int DemodulatorInstance::getOutputDevice() {
|
int DemodulatorInstance::getOutputDevice() {
|
||||||
if (currentOutputDevice == -1) {
|
if (currentOutputDevice == -1) {
|
||||||
return audioThread->getOutputDevice();
|
currentOutputDevice = audioThread->getOutputDevice();
|
||||||
} else {
|
|
||||||
return currentOutputDevice;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return currentOutputDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemodulatorInstance::checkBandwidth() {
|
void DemodulatorInstance::checkBandwidth() {
|
||||||
@ -302,6 +306,28 @@ long long DemodulatorInstance::getFrequency() {
|
|||||||
return currentFrequency;
|
return currentFrequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DemodulatorInstance::setAudioSampleRate(int sampleRate) {
|
||||||
|
if (terminated) {
|
||||||
|
currentAudioSampleRate = sampleRate;
|
||||||
|
demodulatorPreThread->getParams().audioSampleRate = sampleRate;
|
||||||
|
} else if (demodulatorPreThread && threadQueueCommand) {
|
||||||
|
DemodulatorThreadCommand command;
|
||||||
|
command.cmd = DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_AUDIO_RATE;
|
||||||
|
currentAudioSampleRate = sampleRate;
|
||||||
|
command.llong_value = sampleRate;
|
||||||
|
threadQueueCommand->push(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int DemodulatorInstance::getAudioSampleRate() {
|
||||||
|
if (!currentAudioSampleRate) {
|
||||||
|
currentAudioSampleRate = audioThread->getSampleRate();
|
||||||
|
}
|
||||||
|
return currentAudioSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DemodulatorInstance::setGain(float gain_in) {
|
void DemodulatorInstance::setGain(float gain_in) {
|
||||||
audioThread->setGain(gain_in);
|
audioThread->setGain(gain_in);
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,11 @@ public:
|
|||||||
|
|
||||||
void setFrequency(long long freq);
|
void setFrequency(long long freq);
|
||||||
long long getFrequency();
|
long long getFrequency();
|
||||||
|
|
||||||
|
void setAudioSampleRate(int sampleRate);
|
||||||
|
int getAudioSampleRate();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void checkBandwidth();
|
void checkBandwidth();
|
||||||
@ -90,4 +95,5 @@ private:
|
|||||||
int currentBandwidth;
|
int currentBandwidth;
|
||||||
int currentDemodType;
|
int currentDemodType;
|
||||||
int currentOutputDevice;
|
int currentOutputDevice;
|
||||||
|
int currentAudioSampleRate;
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* iqInputQueue, DemodulatorThreadPostInputQueue* iqOutputQueue,
|
DemodulatorPreThread::DemodulatorPreThread(DemodulatorThreadInputQueue* iqInputQueue, DemodulatorThreadPostInputQueue* iqOutputQueue,
|
||||||
DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) :
|
DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||||
iqInputQueue(iqInputQueue), iqOutputQueue(iqOutputQueue), terminated(false), initialized(false), audioResampler(NULL), stereoResampler(NULL), iqResampleRatio(
|
iqInputQueue(iqInputQueue), iqOutputQueue(iqOutputQueue), terminated(false), initialized(false), audioResampler(NULL), stereoResampler(NULL), iqResampleRatio(
|
||||||
1), audioResampleRatio(1), iqResampler(NULL), commandQueue(NULL), threadQueueNotify(threadQueueNotify), threadQueueControl(
|
1), audioResampleRatio(1), firStereoRight(NULL), firStereoLeft(NULL), iqResampler(NULL), commandQueue(NULL), threadQueueNotify(threadQueueNotify), threadQueueControl(
|
||||||
threadQueueControl) {
|
threadQueueControl) {
|
||||||
|
|
||||||
freqShifter = nco_crcf_create(LIQUID_VCO);
|
freqShifter = nco_crcf_create(LIQUID_VCO);
|
||||||
@ -36,8 +36,27 @@ void DemodulatorPreThread::initialize() {
|
|||||||
audioResampler = msresamp_rrrf_create(audioResampleRatio, As);
|
audioResampler = msresamp_rrrf_create(audioResampleRatio, As);
|
||||||
stereoResampler = msresamp_rrrf_create(audioResampleRatio, As);
|
stereoResampler = msresamp_rrrf_create(audioResampleRatio, As);
|
||||||
|
|
||||||
|
// Stereo filters / shifters
|
||||||
|
double firStereoCutoff = 0.5 * ((double) 36000 / (double) params.audioSampleRate); // filter cutoff frequency
|
||||||
|
float ft = 0.05f; // filter transition
|
||||||
|
float mu = 0.0f; // fractional timing offset
|
||||||
|
|
||||||
|
if (firStereoCutoff < 0) {
|
||||||
|
firStereoCutoff = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firStereoCutoff > 0.5) {
|
||||||
|
firStereoCutoff = 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int h_len = estimate_req_filter_len(ft, As);
|
||||||
|
float *h = new float[h_len];
|
||||||
|
liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
|
||||||
|
|
||||||
|
firStereoLeft = firfilt_rrrf_create(h, h_len);
|
||||||
|
firStereoRight = firfilt_rrrf_create(h, h_len);
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
// std::cout << "inputResampleRate " << params.bandwidth << std::endl;
|
|
||||||
lastParams = params;
|
lastParams = params;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +119,11 @@ void DemodulatorPreThread::threadMain() {
|
|||||||
bandwidthChanged = true;
|
bandwidthChanged = true;
|
||||||
break;
|
break;
|
||||||
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY:
|
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_FREQUENCY:
|
||||||
params.frequency = command.llong_value;
|
params.frequency = tempParams.frequency = command.llong_value;
|
||||||
|
break;
|
||||||
|
case DemodulatorThreadCommand::DEMOD_THREAD_CMD_SET_AUDIO_RATE:
|
||||||
|
tempParams.audioSampleRate = (int)command.llong_value;
|
||||||
|
rateChanged = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -228,7 +251,10 @@ void DemodulatorPreThread::threadMain() {
|
|||||||
|
|
||||||
resamp->audioResampleRatio = audioResampleRatio;
|
resamp->audioResampleRatio = audioResampleRatio;
|
||||||
resamp->audioResampler = audioResampler;
|
resamp->audioResampler = audioResampler;
|
||||||
|
resamp->audioSampleRate = params.audioSampleRate;
|
||||||
resamp->stereoResampler = stereoResampler;
|
resamp->stereoResampler = stereoResampler;
|
||||||
|
resamp->firStereoLeft = firStereoLeft;
|
||||||
|
resamp->firStereoRight = firStereoRight;
|
||||||
resamp->sampleRate = params.bandwidth;
|
resamp->sampleRate = params.bandwidth;
|
||||||
|
|
||||||
iqOutputQueue->push(resamp);
|
iqOutputQueue->push(resamp);
|
||||||
@ -245,23 +271,34 @@ void DemodulatorPreThread::threadMain() {
|
|||||||
case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS:
|
case DemodulatorWorkerThreadResult::DEMOD_WORKER_THREAD_RESULT_FILTERS:
|
||||||
msresamp_crcf_destroy(iqResampler);
|
msresamp_crcf_destroy(iqResampler);
|
||||||
|
|
||||||
|
|
||||||
if (result.iqResampler) {
|
if (result.iqResampler) {
|
||||||
iqResampler = result.iqResampler;
|
iqResampler = result.iqResampler;
|
||||||
iqResampleRatio = result.iqResampleRatio;
|
iqResampleRatio = result.iqResampleRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.firStereoLeft) {
|
||||||
|
firStereoLeft = result.firStereoLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.firStereoRight) {
|
||||||
|
firStereoRight = result.firStereoRight;
|
||||||
|
}
|
||||||
|
|
||||||
if (result.audioResampler) {
|
if (result.audioResampler) {
|
||||||
audioResampler = result.audioResampler;
|
audioResampler = result.audioResampler;
|
||||||
audioResampleRatio = result.audioResamplerRatio;
|
audioResampleRatio = result.audioResamplerRatio;
|
||||||
stereoResampler = result.stereoResampler;
|
stereoResampler = result.stereoResampler;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.audioSampleRate) {
|
||||||
params.audioSampleRate = result.audioSampleRate;
|
params.audioSampleRate = result.audioSampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.bandwidth) {
|
if (result.bandwidth) {
|
||||||
params.bandwidth = result.bandwidth;
|
params.bandwidth = result.bandwidth;
|
||||||
}
|
}
|
||||||
if (params.sampleRate) {
|
|
||||||
|
if (result.sampleRate) {
|
||||||
params.sampleRate = result.sampleRate;
|
params.sampleRate = result.sampleRate;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -58,6 +58,9 @@ protected:
|
|||||||
msresamp_rrrf stereoResampler;
|
msresamp_rrrf stereoResampler;
|
||||||
double audioResampleRatio;
|
double audioResampleRatio;
|
||||||
|
|
||||||
|
firfilt_rrrf firStereoLeft;
|
||||||
|
firfilt_rrrf firStereoRight;
|
||||||
|
|
||||||
DemodulatorThreadParameters params;
|
DemodulatorThreadParameters params;
|
||||||
DemodulatorThreadParameters lastParams;
|
DemodulatorThreadParameters lastParams;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* iqInputQue
|
|||||||
iqInputQueue(iqInputQueue), audioVisOutputQueue(NULL), audioOutputQueue(NULL), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(
|
iqInputQueue(iqInputQueue), audioVisOutputQueue(NULL), audioOutputQueue(NULL), iqAutoGain(NULL), amOutputCeil(1), amOutputCeilMA(1), amOutputCeilMAA(
|
||||||
1), stereo(false), terminated(
|
1), stereo(false), terminated(
|
||||||
false), demodulatorType(DEMOD_TYPE_FM), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelchLevel(0), signalLevel(
|
false), demodulatorType(DEMOD_TYPE_FM), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelchLevel(0), signalLevel(
|
||||||
0), squelchEnabled(false) {
|
0), squelchEnabled(false), audioSampleRate(0) {
|
||||||
|
|
||||||
demodFM = freqdem_create(0.5);
|
demodFM = freqdem_create(0.5);
|
||||||
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
|
demodAM_USB = ampmodem_create(0.5, 0.0, LIQUID_AMPMODEM_USB, 1);
|
||||||
@ -46,29 +46,6 @@ void DemodulatorThread::threadMain() {
|
|||||||
firfilt_rrrf firStereoLeft = NULL;
|
firfilt_rrrf firStereoLeft = NULL;
|
||||||
firfilt_rrrf firStereoRight = NULL;
|
firfilt_rrrf firStereoRight = NULL;
|
||||||
|
|
||||||
// Stereo filters / shifters
|
|
||||||
double firStereoCutoff = 0.5 * ((double) 36000 / (double) AUDIO_FREQUENCY); // filter cutoff frequency
|
|
||||||
float ft = 0.05f; // filter transition
|
|
||||||
float As = 120.0f; // stop-band attenuation [dB]
|
|
||||||
float mu = 0.0f; // fractional timing offset
|
|
||||||
|
|
||||||
if (firStereoCutoff < 0) {
|
|
||||||
firStereoCutoff = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firStereoCutoff > 0.5) {
|
|
||||||
firStereoCutoff = 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int h_len = estimate_req_filter_len(ft, As);
|
|
||||||
float *h = new float[h_len];
|
|
||||||
liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
|
|
||||||
|
|
||||||
firStereoLeft = firfilt_rrrf_create(h, h_len);
|
|
||||||
firStereoRight = firfilt_rrrf_create(h, h_len);
|
|
||||||
|
|
||||||
delete h;
|
|
||||||
|
|
||||||
liquid_float_complex x, y, z[2];
|
liquid_float_complex x, y, z[2];
|
||||||
float rz[2];
|
float rz[2];
|
||||||
|
|
||||||
@ -124,11 +101,15 @@ void DemodulatorThread::threadMain() {
|
|||||||
if (audioResampler == NULL) {
|
if (audioResampler == NULL) {
|
||||||
audioResampler = inp->audioResampler;
|
audioResampler = inp->audioResampler;
|
||||||
stereoResampler = inp->stereoResampler;
|
stereoResampler = inp->stereoResampler;
|
||||||
|
firStereoLeft = inp->firStereoLeft;
|
||||||
|
firStereoRight = inp->firStereoRight;
|
||||||
|
audioSampleRate = inp->audioSampleRate;
|
||||||
} else if (audioResampler != inp->audioResampler) {
|
} else if (audioResampler != inp->audioResampler) {
|
||||||
msresamp_rrrf_destroy(audioResampler);
|
msresamp_rrrf_destroy(audioResampler);
|
||||||
msresamp_rrrf_destroy(stereoResampler);
|
msresamp_rrrf_destroy(stereoResampler);
|
||||||
audioResampler = inp->audioResampler;
|
audioResampler = inp->audioResampler;
|
||||||
stereoResampler = inp->stereoResampler;
|
stereoResampler = inp->stereoResampler;
|
||||||
|
audioSampleRate = inp->audioSampleRate;
|
||||||
|
|
||||||
if (demodAM) {
|
if (demodAM) {
|
||||||
ampmodem_reset(demodAM);
|
ampmodem_reset(demodAM);
|
||||||
@ -136,6 +117,20 @@ void DemodulatorThread::threadMain() {
|
|||||||
freqdem_reset(demodFM);
|
freqdem_reset(demodFM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (firStereoLeft != inp->firStereoLeft) {
|
||||||
|
if (firStereoLeft != NULL) {
|
||||||
|
firfilt_rrrf_destroy(firStereoLeft);
|
||||||
|
}
|
||||||
|
firStereoLeft = inp->firStereoLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firStereoRight != inp->firStereoRight) {
|
||||||
|
if (firStereoRight != NULL) {
|
||||||
|
firfilt_rrrf_destroy(firStereoRight);
|
||||||
|
}
|
||||||
|
firStereoRight = inp->firStereoRight;
|
||||||
|
}
|
||||||
|
|
||||||
if (agcData.size() != bufSize) {
|
if (agcData.size() != bufSize) {
|
||||||
if (agcData.capacity() < bufSize) {
|
if (agcData.capacity() < bufSize) {
|
||||||
agcData.reserve(bufSize);
|
agcData.reserve(bufSize);
|
||||||
@ -227,7 +222,7 @@ void DemodulatorThread::threadMain() {
|
|||||||
demodStereoData.resize(bufSize);
|
demodStereoData.resize(bufSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
double freq = (2.0 * M_PI) * (((double) abs(38000)) / ((double) inp->sampleRate));
|
double freq = (2.0 * M_PI) * ((double) 38000) / ((double) inp->sampleRate);
|
||||||
|
|
||||||
if (stereoShiftFrequency != freq) {
|
if (stereoShiftFrequency != freq) {
|
||||||
nco_crcf_set_frequency(stereoShifter, freq);
|
nco_crcf_set_frequency(stereoShifter, freq);
|
||||||
@ -274,6 +269,7 @@ void DemodulatorThread::threadMain() {
|
|||||||
outputBuffers.push_back(ati);
|
outputBuffers.push_back(ati);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ati->sampleRate = audioSampleRate;
|
||||||
ati->setRefCount(1);
|
ati->setRefCount(1);
|
||||||
|
|
||||||
if (stereo) {
|
if (stereo) {
|
||||||
|
@ -75,6 +75,7 @@ protected:
|
|||||||
std::atomic<bool> stereo;
|
std::atomic<bool> stereo;
|
||||||
std::atomic<bool> terminated;
|
std::atomic<bool> terminated;
|
||||||
std::atomic<int> demodulatorType;
|
std::atomic<int> demodulatorType;
|
||||||
|
int audioSampleRate;
|
||||||
|
|
||||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||||
DemodulatorThreadControlCommandQueue *threadQueueControl;
|
DemodulatorThreadControlCommandQueue *threadQueueControl;
|
||||||
|
@ -49,6 +49,26 @@ void DemodulatorWorkerThread::threadMain() {
|
|||||||
result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
|
result.audioResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
|
||||||
result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
|
result.stereoResampler = msresamp_rrrf_create(result.audioResamplerRatio, As);
|
||||||
result.audioSampleRate = filterCommand.audioSampleRate;
|
result.audioSampleRate = filterCommand.audioSampleRate;
|
||||||
|
|
||||||
|
// Stereo filters / shifters
|
||||||
|
double firStereoCutoff = 0.5 * ((double) 36000 / (double) filterCommand.audioSampleRate); // filter cutoff frequency
|
||||||
|
float ft = 0.05f; // filter transition
|
||||||
|
float mu = 0.0f; // fractional timing offset
|
||||||
|
|
||||||
|
if (firStereoCutoff < 0) {
|
||||||
|
firStereoCutoff = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firStereoCutoff > 0.5) {
|
||||||
|
firStereoCutoff = 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int h_len = estimate_req_filter_len(ft, As);
|
||||||
|
float *h = new float[h_len];
|
||||||
|
liquid_firdes_kaiser(h_len, firStereoCutoff, As, mu, h);
|
||||||
|
|
||||||
|
result.firStereoLeft = firfilt_rrrf_create(h, h_len);
|
||||||
|
result.firStereoRight = firfilt_rrrf_create(h, h_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filterCommand.bandwidth) {
|
if (filterCommand.bandwidth) {
|
||||||
|
@ -16,14 +16,13 @@ public:
|
|||||||
|
|
||||||
DemodulatorWorkerThreadResult() :
|
DemodulatorWorkerThreadResult() :
|
||||||
cmd(DEMOD_WORKER_THREAD_RESULT_NULL), iqResampler(NULL), iqResampleRatio(0), audioResampler(NULL), stereoResampler(NULL), audioResamplerRatio(
|
cmd(DEMOD_WORKER_THREAD_RESULT_NULL), iqResampler(NULL), iqResampleRatio(0), audioResampler(NULL), stereoResampler(NULL), audioResamplerRatio(
|
||||||
0), sampleRate(0), bandwidth(0), audioSampleRate(0) {
|
0), firStereoLeft(NULL), firStereoRight(NULL), sampleRate(0), bandwidth(0), audioSampleRate(0) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DemodulatorWorkerThreadResult(DemodulatorThreadResultEnum cmd) :
|
DemodulatorWorkerThreadResult(DemodulatorThreadResultEnum cmd) :
|
||||||
cmd(cmd), iqResampler(NULL), iqResampleRatio(0), audioResampler(NULL), stereoResampler(NULL), audioResamplerRatio(0), sampleRate(0), bandwidth(
|
DemodulatorWorkerThreadResult() {
|
||||||
0), audioSampleRate(0) {
|
this->cmd = cmd;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DemodulatorThreadResultEnum cmd;
|
DemodulatorThreadResultEnum cmd;
|
||||||
@ -34,6 +33,9 @@ public:
|
|||||||
msresamp_rrrf stereoResampler;
|
msresamp_rrrf stereoResampler;
|
||||||
double audioResamplerRatio;
|
double audioResamplerRatio;
|
||||||
|
|
||||||
|
firfilt_rrrf firStereoLeft;
|
||||||
|
firfilt_rrrf firStereoRight;
|
||||||
|
|
||||||
long long sampleRate;
|
long long sampleRate;
|
||||||
unsigned int bandwidth;
|
unsigned int bandwidth;
|
||||||
unsigned int audioSampleRate;
|
unsigned int audioSampleRate;
|
||||||
|
@ -683,7 +683,12 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
|
|||||||
near_dist = dist;
|
near_dist = dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dist <= halfBw && dist >= (int) ((float) halfBw / (1.5 - (0.65 * (1.0-(float)(wxGetApp().getSampleRate() - getBandwidth())/(float)wxGetApp().getSampleRate()))))) {
|
|
||||||
|
if (dist <= halfBw && dist >= (int)((float) halfBw / 1.5)) {
|
||||||
|
if ((freqDiff > 0 && activeDemodulator->getDemodulatorType() == DEMOD_TYPE_USB) ||
|
||||||
|
(freqDiff < 0 && activeDemodulator->getDemodulatorType() == DEMOD_TYPE_LSB)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
long edge_dist = abs(halfBw - dist);
|
long edge_dist = abs(halfBw - dist);
|
||||||
if (edge_dist < near_dist) {
|
if (edge_dist < near_dist) {
|
||||||
activeDemodulator = demod;
|
activeDemodulator = demod;
|
||||||
@ -704,9 +709,13 @@ void WaterfallCanvas::OnMouseMoved(wxMouseEvent& event) {
|
|||||||
SetCursor(wxCURSOR_SIZEWE);
|
SetCursor(wxCURSOR_SIZEWE);
|
||||||
|
|
||||||
if (freqDiff > 0) {
|
if (freqDiff > 0) {
|
||||||
nextDragState = WF_DRAG_BANDWIDTH_LEFT;
|
if (activeDemodulator->getDemodulatorType() != DEMOD_TYPE_USB) {
|
||||||
|
nextDragState = WF_DRAG_BANDWIDTH_LEFT;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nextDragState = WF_DRAG_BANDWIDTH_RIGHT;
|
if (activeDemodulator->getDemodulatorType() != DEMOD_TYPE_LSB) {
|
||||||
|
nextDragState = WF_DRAG_BANDWIDTH_RIGHT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mouseTracker.setVertDragLock(true);
|
mouseTracker.setVertDragLock(true);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user