diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index 794817a..7281b1f 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -150,7 +150,16 @@ AppFrame::AppFrame() : } wxMenuBar *menuBar = new wxMenuBar; - menuBar->Append(menu, wxT("&Device")); + menuBar->Append(menu, wxT("Output &Device")); + + wxMenu *demodMenu = new wxMenu; + demod_menuitems[DemodulatorType::DEMOD_TYPE_FM] = demodMenu->AppendRadioItem(wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_FM,wxT("FM"),wxT("Description?")); + demod_menuitems[DemodulatorType::DEMOD_TYPE_AM] = demodMenu->AppendRadioItem(wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_AM,wxT("AM"),wxT("Description?")); + demod_menuitems[DemodulatorType::DEMOD_TYPE_LSB] = demodMenu->AppendRadioItem(wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_LSB,wxT("LSB"),wxT("Description?")); + demod_menuitems[DemodulatorType::DEMOD_TYPE_USB] = demodMenu->AppendRadioItem(wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_USB,wxT("USB"),wxT("Description?")); + + menuBar->Append(demodMenu, wxT("Demodulaton &Type")); + SetMenuBar(menuBar); @@ -177,6 +186,22 @@ void AppFrame::OnMenu(wxCommandEvent& event) { activeDemodulator = NULL; } } + + if (activeDemodulator) { + if (event.GetId() == wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_FM) { + activeDemodulator->setDemodulatorType(DemodulatorType::DEMOD_TYPE_FM); + activeDemodulator = NULL; + } else if (event.GetId() == wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_AM) { + activeDemodulator->setDemodulatorType(DemodulatorType::DEMOD_TYPE_AM); + activeDemodulator = NULL; + } else if (event.GetId() == wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_LSB) { + activeDemodulator->setDemodulatorType(DemodulatorType::DEMOD_TYPE_LSB); + activeDemodulator = NULL; + } else if (event.GetId() == wxID_DEMOD_TYPE+DemodulatorType::DEMOD_TYPE_USB) { + activeDemodulator->setDemodulatorType(DemodulatorType::DEMOD_TYPE_USB); + activeDemodulator = NULL; + } + } } void AppFrame::OnClose(wxCommandEvent& WXUNUSED(event)) { @@ -207,6 +232,8 @@ void AppFrame::OnIdle(wxIdleEvent& event) { int outputDevice = demod->getOutputDevice(); scopeCanvas->setDeviceName(output_devices[outputDevice].name); output_device_menuitems[outputDevice]->Check(true); + DemodulatorType dType = demod->getDemodulatorType(); + demod_menuitems[dType]->Check(true); } if (demodWaterfallCanvas->getDragState() == WaterfallCanvas::WF_DRAG_NONE) { if (demod->getParams().frequency != demodWaterfallCanvas->GetCenterFrequency()) { diff --git a/src/AppFrame.h b/src/AppFrame.h index 7dc83a9..c8144da 100644 --- a/src/AppFrame.h +++ b/src/AppFrame.h @@ -11,6 +11,7 @@ #include #define wxID_RT_AUDIO_DEVICE 1000 +#define wxID_DEMOD_TYPE 1500 // Define a new frame type class AppFrame: public wxFrame { @@ -41,5 +42,7 @@ private: std::map output_devices; std::map output_device_menuitems; + std::map demod_menuitems; + wxDECLARE_EVENT_TABLE(); }; diff --git a/src/demod/DemodulatorInstance.cpp b/src/demod/DemodulatorInstance.cpp index fefe5c4..3e67f56 100644 --- a/src/demod/DemodulatorInstance.cpp +++ b/src/demod/DemodulatorInstance.cpp @@ -207,3 +207,12 @@ void DemodulatorInstance::setOutputDevice(int device_id) { int DemodulatorInstance::getOutputDevice() { return audioThread->getOutputDevice(); } + +void DemodulatorInstance::setDemodulatorType(DemodulatorType demod_type_in) { + demodulatorThread->setDemodulatorType(demod_type_in); +} + +DemodulatorType DemodulatorInstance::getDemodulatorType() { + return demodulatorThread->getDemodulatorType(); +} + diff --git a/src/demod/DemodulatorInstance.h b/src/demod/DemodulatorInstance.h index a88b8a6..cc943ba 100644 --- a/src/demod/DemodulatorInstance.h +++ b/src/demod/DemodulatorInstance.h @@ -63,6 +63,9 @@ public: void setOutputDevice(int device_id); int getOutputDevice(); + void setDemodulatorType(DemodulatorType demod_type_in); + DemodulatorType getDemodulatorType(); + private: std::atomic label; // bool terminated; // diff --git a/src/demod/DemodulatorThread.cpp b/src/demod/DemodulatorThread.cpp index 50aa8dd..f12ae2a 100644 --- a/src/demod/DemodulatorThread.cpp +++ b/src/demod/DemodulatorThread.cpp @@ -8,10 +8,18 @@ DemodulatorThread::DemodulatorThread(DemodulatorThreadPostInputQueue* pQueue, DemodulatorThreadControlCommandQueue *threadQueueControl, DemodulatorThreadCommandQueue* threadQueueNotify) : - postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), stereo(false), terminated(false), threadQueueNotify( - threadQueueNotify), threadQueueControl(threadQueueControl), squelch_level(0), squelch_tolerance(0), signal_level(0), squelch_enabled(false) { + postInputQueue(pQueue), visOutQueue(NULL), audioInputQueue(NULL), agc(NULL), am_max(1), am_max_ma(1), am_max_maa(1), stereo(false), terminated( + false), demodulatorType(DemodulatorType::DEMOD_TYPE_FM), threadQueueNotify(threadQueueNotify), threadQueueControl(threadQueueControl), squelch_level( + 0), squelch_tolerance(0), signal_level(0), squelch_enabled(false) { fdem = freqdem_create(0.5); + liquid_ampmodem_type type_lsb = LIQUID_AMPMODEM_LSB; + ampdem_lsb = ampmodem_create(1.0, 0.5, type_lsb, 1); + liquid_ampmodem_type type_usb = LIQUID_AMPMODEM_USB; + ampdem_usb = ampmodem_create(1.0, -0.5, type_usb, 1); + liquid_ampmodem_type type_dsb = LIQUID_AMPMODEM_DSB; + ampdem = ampmodem_create(0.5, 0.0, type_dsb, 0); + } DemodulatorThread::~DemodulatorThread() { } @@ -66,16 +74,6 @@ void DemodulatorThread::threadMain() { std::cout << "Demodulator thread started.." << std::endl; - std::deque buffers; - std::deque::iterator buffers_i; - - std::vector resampled_data; - std::vector agc_data; - std::vector demod_output; - std::vector demod_output_stereo; - std::vector resampled_audio_output; - std::vector resampled_audio_output_stereo; - double freq_index = 0; while (!terminated) { @@ -101,6 +99,11 @@ void DemodulatorThread::threadMain() { resampler = inp->resampler; audio_resampler = inp->audio_resampler; stereo_resampler = inp->stereo_resampler; + + ampmodem_reset(ampdem_lsb); + ampmodem_reset(ampdem_usb); + ampmodem_reset(ampdem); + freqdem_reset(fdem); } int out_size = ceil((double) (bufSize) * inp->resample_ratio); @@ -108,17 +111,17 @@ void DemodulatorThread::threadMain() { if (agc_data.size() != out_size) { if (agc_data.capacity() < out_size) { agc_data.reserve(out_size); + agc_am_data.reserve(out_size); resampled_data.reserve(out_size); } agc_data.resize(out_size); resampled_data.resize(out_size); + agc_am_data.resize(out_size); } unsigned int num_written; msresamp_crcf_execute(resampler, &(inp->data[0]), bufSize, &resampled_data[0], &num_written); - agc_crcf_execute_block(agc, &resampled_data[0], num_written, &agc_data[0]); - double audio_resample_ratio = inp->audio_resample_ratio; if (demod_output.size() != num_written) { @@ -130,7 +133,51 @@ void DemodulatorThread::threadMain() { int audio_out_size = ceil((double) (num_written) * audio_resample_ratio); - freqdem_demodulate_block(fdem, &agc_data[0], num_written, &demod_output[0]); + agc_crcf_execute_block(agc, &resampled_data[0], num_written, &agc_data[0]); + + float current_level = 0; + + current_level = ((60.0 / fabs(agc_crcf_get_rssi(agc))) / 15.0 - signal_level); + + if (agc_crcf_get_signal_level(agc) > current_level) { + current_level = agc_crcf_get_signal_level(agc); + } + + switch (demodulatorType) { + case DemodulatorType::DEMOD_TYPE_FM: + freqdem_demodulate_block(fdem, &agc_data[0], num_written, &demod_output[0]); + break; + case DemodulatorType::DEMOD_TYPE_LSB: + for (int i = 0; i < num_written; i++) { + ampmodem_demodulate(ampdem_lsb, resampled_data[i], &demod_output[i]); + } + + break; + case DemodulatorType::DEMOD_TYPE_USB: + for (int i = 0; i < num_written; i++) { + ampmodem_demodulate(ampdem_usb, resampled_data[i], &demod_output[i]); + } + + break; + case DemodulatorType::DEMOD_TYPE_AM: + am_max = 0; + for (int i = 0; i < num_written; i++) { + ampmodem_demodulate(ampdem, resampled_data[i], &demod_output[i]); + if (demod_output[i] > am_max) { + am_max = demod_output[i]; + } + } + am_max_ma = am_max_ma + (am_max - am_max_ma) * 0.03; + am_max_maa = am_max_maa + (am_max_ma - am_max_maa) * 0.03; + + float gain = 0.95/am_max_maa; + + for (int i = 0; i < num_written; i++) { + demod_output[i] *= gain; + } + + break; + } if (audio_out_size != resampled_audio_output.size()) { if (resampled_audio_output.capacity() < audio_out_size) { @@ -174,15 +221,12 @@ void DemodulatorThread::threadMain() { msresamp_rrrf_execute(stereo_resampler, &demod_output_stereo[0], num_written, &resampled_audio_output_stereo[0], &num_audio_written); } - float current_level = ((60.0/fabs(agc_crcf_get_rssi(agc)))/15.0 - signal_level); //agc_crcf_get_signal_level(agc); - if (current_level > signal_level) { - signal_level = signal_level + (current_level-signal_level) * 0.5; + signal_level = signal_level + (current_level - signal_level) * 0.5; } else { - signal_level = signal_level + (current_level-signal_level) * 0.05; + signal_level = signal_level + (current_level - signal_level) * 0.05; } - AudioThreadInput *ati = NULL; if (audioInputQueue != NULL) { @@ -242,8 +286,8 @@ void DemodulatorThread::threadMain() { ati_vis->data.resize(stereoSize); for (int i = 0; i < stereoSize / 2; i++) { - ati_vis->data[i] = ati->data[i*2]; - ati_vis->data[i + stereoSize / 2] = ati->data[i*2+1]; + ati_vis->data[i] = ati->data[i * 2]; + ati_vis->data[i + stereoSize / 2] = ati->data[i * 2 + 1]; } } else { ati_vis->channels = 1; @@ -352,3 +396,11 @@ void DemodulatorThread::setSquelchLevel(float signal_level_in) { float DemodulatorThread::getSquelchLevel() { return squelch_level; } + +void DemodulatorThread::setDemodulatorType(DemodulatorType demod_type_in) { + demodulatorType = demod_type_in; +} + +DemodulatorType DemodulatorThread::getDemodulatorType() { + return demodulatorType; +} diff --git a/src/demod/DemodulatorThread.h b/src/demod/DemodulatorThread.h index 7843a69..8d7f5f1 100644 --- a/src/demod/DemodulatorThread.h +++ b/src/demod/DemodulatorThread.h @@ -34,13 +34,14 @@ public: void initialize(); void terminate(); - void setStereo(bool state); - bool isStereo(); + void setStereo(bool state);bool isStereo(); float getSignalLevel(); void setSquelchLevel(float signal_level_in); float getSquelchLevel(); + void setDemodulatorType(DemodulatorType demod_type_in); + DemodulatorType getDemodulatorType(); #ifdef __APPLE__ static void *pthread_helper(void *context) { @@ -49,20 +50,39 @@ public: #endif protected: + std::deque buffers; + std::deque::iterator buffers_i; + + std::vector resampled_data; + std::vector agc_data; + std::vector agc_am_data; + std::vector demod_output; + std::vector demod_output_stereo; + std::vector resampled_audio_output; + std::vector resampled_audio_output_stereo; + DemodulatorThreadPostInputQueue* postInputQueue; DemodulatorThreadOutputQueue* visOutQueue; AudioThreadInputQueue *audioInputQueue; freqdem fdem; + ampmodem ampdem; + ampmodem ampdem_usb; + ampmodem ampdem_lsb; + agc_crcf agc; + float am_max; + float am_max_ma; + float am_max_maa; + std::atomic stereo; std::atomic terminated; + std::atomic demodulatorType; DemodulatorThreadCommandQueue* threadQueueNotify; DemodulatorThreadControlCommandQueue *threadQueueControl; std::atomic squelch_level; float squelch_tolerance; - std::atomic signal_level; - bool squelch_enabled; + std::atomic signal_level;bool squelch_enabled; }; diff --git a/src/visual/WaterfallCanvas.cpp b/src/visual/WaterfallCanvas.cpp index 4f69b82..4c56c59 100644 --- a/src/visual/WaterfallCanvas.cpp +++ b/src/visual/WaterfallCanvas.cpp @@ -17,7 +17,9 @@ #include -#define MIN_FM_BANDWIDTH 10000 +#define MIN_FM_BANDWIDTH 2000 +#define MIN_AM_BANDWIDTH 2000 + wxBEGIN_EVENT_TABLE(WaterfallCanvas, wxGLCanvas) EVT_PAINT(WaterfallCanvas::OnPaint) EVT_KEY_DOWN(WaterfallCanvas::OnKeyDown)