mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-26 13:48:38 -05:00
FM Stereo experiment, partly working
This commit is contained in:
parent
5f04baf873
commit
0fc47bc916
@ -70,13 +70,14 @@ public:
|
|||||||
class DemodulatorThreadPostIQData: public ReferenceCounter {
|
class DemodulatorThreadPostIQData: public ReferenceCounter {
|
||||||
public:
|
public:
|
||||||
std::vector<liquid_float_complex> data;
|
std::vector<liquid_float_complex> data;
|
||||||
|
int bandwidth;
|
||||||
float audio_resample_ratio;
|
float audio_resample_ratio;
|
||||||
msresamp_rrrf audio_resampler;
|
msresamp_rrrf audio_resampler;
|
||||||
float resample_ratio;
|
float resample_ratio;
|
||||||
msresamp_crcf resampler;
|
msresamp_crcf resampler;
|
||||||
|
|
||||||
DemodulatorThreadPostIQData() :
|
DemodulatorThreadPostIQData() :
|
||||||
audio_resample_ratio(0), audio_resampler(NULL), resample_ratio(0), resampler(NULL) {
|
bandwidth(0), audio_resample_ratio(0), audio_resampler(NULL), resample_ratio(0), resampler(NULL) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +146,16 @@ void DemodulatorInstance::setActive(bool state) {
|
|||||||
audioThread->setActive(state);
|
audioThread->setActive(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DemodulatorInstance::isStereo() {
|
||||||
|
return stereo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DemodulatorInstance::setStereo(bool state) {
|
||||||
|
stereo = state;
|
||||||
|
demodulatorThread->setStereo(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DemodulatorInstance::squelchAuto() {
|
void DemodulatorInstance::squelchAuto() {
|
||||||
DemodulatorThreadControlCommand command;
|
DemodulatorThreadControlCommand command;
|
||||||
command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_AUTO;
|
command.cmd = DemodulatorThreadControlCommand::DEMOD_THREAD_CMD_CTL_SQUELCH_AUTO;
|
||||||
|
@ -49,6 +49,9 @@ public:
|
|||||||
bool isActive();
|
bool isActive();
|
||||||
void setActive(bool state);
|
void setActive(bool state);
|
||||||
|
|
||||||
|
bool isStereo();
|
||||||
|
void setStereo(bool state);
|
||||||
|
|
||||||
void squelchAuto();bool isSquelchEnabled();
|
void squelchAuto();bool isSquelchEnabled();
|
||||||
void setSquelchEnabled(bool state);
|
void setSquelchEnabled(bool state);
|
||||||
|
|
||||||
@ -56,5 +59,6 @@ private:
|
|||||||
std::atomic<std::string *> label;bool terminated;bool demodTerminated;bool audioTerminated;bool preDemodTerminated;
|
std::atomic<std::string *> label;bool terminated;bool demodTerminated;bool audioTerminated;bool preDemodTerminated;
|
||||||
std::atomic<bool> active;
|
std::atomic<bool> active;
|
||||||
std::atomic<bool> squelch;
|
std::atomic<bool> squelch;
|
||||||
|
std::atomic<bool> stereo;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -219,6 +219,7 @@ void DemodulatorPreThread::threadMain() {
|
|||||||
resamp->audio_resampler = audio_resampler;
|
resamp->audio_resampler = audio_resampler;
|
||||||
resamp->resample_ratio = resample_ratio;
|
resamp->resample_ratio = resample_ratio;
|
||||||
resamp->resampler = resampler;
|
resamp->resampler = resampler;
|
||||||
|
resamp->bandwidth = params.bandwidth;
|
||||||
|
|
||||||
postInputQueue->push(resamp);
|
postInputQueue->push(resamp);
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
|
DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadControlCommandQueue *threadQueueControl,
|
||||||
DemodulatorThreadCommandQueue* threadQueueNotify) :
|
DemodulatorThreadCommandQueue* threadQueueNotify) :
|
||||||
postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), terminated(false), threadQueueNotify(threadQueueNotify), threadQueueControl(
|
postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), stereo(false), terminated(false), threadQueueNotify(threadQueueNotify), threadQueueControl(
|
||||||
threadQueueControl), squelch_level(0), squelch_tolerance(0), squelch_enabled(false) {
|
threadQueueControl), squelch_level(0), squelch_tolerance(0), squelch_enabled(false) {
|
||||||
|
|
||||||
float kf = 0.5; // modulation factor
|
float kf = 0.5; // modulation factor
|
||||||
@ -44,7 +44,11 @@ void DemodulatorThread::threadMain() {
|
|||||||
std::vector<liquid_float_complex> resampled_data;
|
std::vector<liquid_float_complex> resampled_data;
|
||||||
std::vector<liquid_float_complex> agc_data;
|
std::vector<liquid_float_complex> agc_data;
|
||||||
std::vector<float> demod_output;
|
std::vector<float> demod_output;
|
||||||
|
std::vector<float> demod_output_stereo;
|
||||||
std::vector<float> resampled_audio_output;
|
std::vector<float> resampled_audio_output;
|
||||||
|
std::vector<float> resampled_audio_output_stereo;
|
||||||
|
|
||||||
|
double freq_index = 0;
|
||||||
|
|
||||||
while (!terminated) {
|
while (!terminated) {
|
||||||
DemodulatorThreadPostIQData *inp;
|
DemodulatorThreadPostIQData *inp;
|
||||||
@ -89,24 +93,49 @@ void DemodulatorThread::threadMain() {
|
|||||||
if (demod_output.size() != num_written) {
|
if (demod_output.size() != num_written) {
|
||||||
if (demod_output.capacity() < num_written) {
|
if (demod_output.capacity() < num_written) {
|
||||||
demod_output.reserve(num_written);
|
demod_output.reserve(num_written);
|
||||||
|
demod_output_stereo.reserve(num_written);
|
||||||
}
|
}
|
||||||
demod_output.resize(num_written);
|
demod_output.resize(num_written);
|
||||||
|
demod_output_stereo.resize(num_written);
|
||||||
}
|
}
|
||||||
|
|
||||||
freqdem_demodulate_block(fdem, &agc_data[0], num_written, &demod_output[0]);
|
freqdem_demodulate_block(fdem, &agc_data[0], num_written, &demod_output[0]);
|
||||||
|
|
||||||
|
if (stereo) {
|
||||||
|
int shift_freq = 38000-inp->bandwidth;
|
||||||
|
double freq = (2.0 * M_PI) * (((double) abs(shift_freq)) / ((double) inp->bandwidth));
|
||||||
|
|
||||||
|
for (int i = 0; i < num_written; i++) {
|
||||||
|
freq_index+=freq;
|
||||||
|
|
||||||
|
demod_output_stereo[i] = demod_output[i] * sin(freq_index) + demod_output[i] * cos(freq_index);
|
||||||
|
while (freq_index > (M_PI*2.0)) {
|
||||||
|
freq_index -= (M_PI*2.0);
|
||||||
|
}
|
||||||
|
while (freq_index < (M_PI*2.0)) {
|
||||||
|
freq_index += (M_PI*2.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int audio_out_size = ceil((float) (num_written) * audio_resample_ratio);
|
int audio_out_size = ceil((float) (num_written) * audio_resample_ratio);
|
||||||
|
|
||||||
if (audio_out_size != resampled_audio_output.size()) {
|
if (audio_out_size != resampled_audio_output.size()) {
|
||||||
if (resampled_audio_output.capacity() < audio_out_size) {
|
if (resampled_audio_output.capacity() < audio_out_size) {
|
||||||
resampled_audio_output.reserve(audio_out_size);
|
resampled_audio_output.reserve(audio_out_size);
|
||||||
|
resampled_audio_output_stereo.reserve(audio_out_size);
|
||||||
}
|
}
|
||||||
resampled_audio_output.resize(audio_out_size);
|
resampled_audio_output.resize(audio_out_size);
|
||||||
|
resampled_audio_output_stereo.resize(audio_out_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int num_audio_written;
|
unsigned int num_audio_written;
|
||||||
msresamp_rrrf_execute(audio_resampler, &demod_output[0], num_written, &resampled_audio_output[0], &num_audio_written);
|
msresamp_rrrf_execute(audio_resampler, &demod_output[0], num_written, &resampled_audio_output[0], &num_audio_written);
|
||||||
|
|
||||||
|
if (stereo) {
|
||||||
|
msresamp_rrrf_execute(audio_resampler, &demod_output_stereo[0], num_written, &resampled_audio_output_stereo[0], &num_audio_written);
|
||||||
|
}
|
||||||
|
|
||||||
if (audioInputQueue != NULL) {
|
if (audioInputQueue != NULL) {
|
||||||
if (!squelch_enabled || ((agc_crcf_get_signal_level(agc)) >= 0.1)) {
|
if (!squelch_enabled || ((agc_crcf_get_signal_level(agc)) >= 0.1)) {
|
||||||
AudioThreadInput *ati = NULL;
|
AudioThreadInput *ati = NULL;
|
||||||
@ -124,8 +153,18 @@ void DemodulatorThread::threadMain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ati->setRefCount(1);
|
ati->setRefCount(1);
|
||||||
ati->channels = 1;
|
|
||||||
ati->data.assign(resampled_audio_output.begin(), resampled_audio_output.begin() + num_audio_written);
|
if (stereo) {
|
||||||
|
ati->channels = 2;
|
||||||
|
ati->data.resize(num_audio_written*2);
|
||||||
|
for (int i = 0; i < num_audio_written; i++) {
|
||||||
|
ati->data[i*2] = (resampled_audio_output[i]-(resampled_audio_output_stereo[i]*2.0))/2.0;
|
||||||
|
ati->data[i*2+1] = (resampled_audio_output[i]+(resampled_audio_output_stereo[i]*2.0))/2.0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ati->channels = 1;
|
||||||
|
ati->data.assign(resampled_audio_output.begin(), resampled_audio_output.begin() + num_audio_written);
|
||||||
|
}
|
||||||
|
|
||||||
audioInputQueue->push(ati);
|
audioInputQueue->push(ati);
|
||||||
}
|
}
|
||||||
@ -204,3 +243,12 @@ void DemodulatorThread::terminate() {
|
|||||||
DemodulatorThreadPostIQData *inp = new DemodulatorThreadPostIQData; // push dummy to nudge queue
|
DemodulatorThreadPostIQData *inp = new DemodulatorThreadPostIQData; // push dummy to nudge queue
|
||||||
postInputQueue->push(inp);
|
postInputQueue->push(inp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DemodulatorThread::setStereo(bool state) {
|
||||||
|
stereo = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DemodulatorThread::isStereo() {
|
||||||
|
return stereo;
|
||||||
|
}
|
||||||
|
@ -35,6 +35,9 @@ public:
|
|||||||
|
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
|
void setStereo(bool state);
|
||||||
|
bool isStereo();
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
static void *pthread_helper(void *context) {
|
static void *pthread_helper(void *context) {
|
||||||
return ((DemodulatorThread *) context)->threadMain();
|
return ((DemodulatorThread *) context)->threadMain();
|
||||||
@ -49,6 +52,7 @@ protected:
|
|||||||
freqdem fdem;
|
freqdem fdem;
|
||||||
agc_crcf agc;
|
agc_crcf agc;
|
||||||
|
|
||||||
|
std::atomic<bool> stereo;
|
||||||
std::atomic<bool> terminated;
|
std::atomic<bool> terminated;
|
||||||
|
|
||||||
DemodulatorThreadCommandQueue* threadQueueNotify;
|
DemodulatorThreadCommandQueue* threadQueueNotify;
|
||||||
|
@ -200,6 +200,16 @@ void WaterfallCanvas::OnKeyDown(wxKeyEvent& event) {
|
|||||||
activeDemod->squelchAuto();
|
activeDemod->squelchAuto();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case WXK_SPACE:
|
||||||
|
if (!activeDemod) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (activeDemod->isStereo()) {
|
||||||
|
activeDemod->setStereo(false);
|
||||||
|
} else {
|
||||||
|
activeDemod->setStereo(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
event.Skip();
|
event.Skip();
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user