FM Stereo experiment, partly working

This commit is contained in:
Charles J. Cliffe 2014-12-26 20:58:42 -05:00
parent 5f04baf873
commit 0fc47bc916
7 changed files with 82 additions and 4 deletions

View File

@ -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) {
} }

View File

@ -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;

View File

@ -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;
}; };

View File

@ -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);
} }

View File

@ -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);
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->channels = 1;
ati->data.assign(resampled_audio_output.begin(), resampled_audio_output.begin() + num_audio_written); 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;
}

View File

@ -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;

View File

@ -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;