diff --git a/src/AppFrame.cpp b/src/AppFrame.cpp index c07a95e..02d2c5e 100644 --- a/src/AppFrame.cpp +++ b/src/AppFrame.cpp @@ -1003,6 +1003,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) { waterfallSpeedMeter->Refresh(); spectrumAvgMeter->Refresh(); gainCanvas->setThemeColors(); + modemProps->updateTheme(); } switch (event.GetId()) { @@ -1498,6 +1499,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) { modemProps->initProperties(demod->getModemArgs()); modemPropertiesUpdated.store(false); demodTray->Layout(); + modemProps->fitColumns(); #if ENABLE_DIGITAL_LAB if (demod->getModemType() == "digital") { ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)demod->getOutput(); @@ -1510,6 +1512,18 @@ void AppFrame::OnIdle(wxIdleEvent& event) { #endif } + if (modemProps->isCollapsed() && modemProps->GetMinWidth() > 22) { + modemProps->SetMinSize(wxSize(22,-1)); + modemProps->SetMaxSize(wxSize(22,-1)); + demodTray->Layout(); + modemProps->fitColumns(); + } else if (!modemProps->isCollapsed() && modemProps->GetMinWidth() < 200) { + modemProps->SetMinSize(wxSize(200,-1)); + modemProps->SetMaxSize(wxSize(200,-1)); + demodTray->Layout(); + modemProps->fitColumns(); + } + int peakHoldMode = peakHoldButton->getSelection(); if (peakHoldButton->modeChanged()) { wxGetApp().getSpectrumProcessor()->setPeakHold(peakHoldMode == 1); diff --git a/src/ModemProperties.cpp b/src/ModemProperties.cpp index bd0901b..981f479 100644 --- a/src/ModemProperties.cpp +++ b/src/ModemProperties.cpp @@ -4,24 +4,62 @@ ModemProperties::ModemProperties(wxWindow *parent, wxWindowID winid, const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxPanel(parent, winid, pos, size, style, name) { - m_propertyGrid = new wxPropertyGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE); - + m_propertyGrid = new wxPropertyGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE | wxPG_NO_INTERNAL_BORDER); + bSizer = new wxBoxSizer( wxVERTICAL ); - bSizer->Add(m_propertyGrid, 1, wxEXPAND, 5); + bSizer->Add(m_propertyGrid, 1, wxEXPAND, 0); this->SetSizer(bSizer); + m_propertyGrid->Connect( wxEVT_PG_ITEM_COLLAPSED, wxPropertyGridEventHandler( ModemProperties::OnCollapse ), NULL, this ); + m_propertyGrid->Connect( wxEVT_PG_ITEM_EXPANDED, wxPropertyGridEventHandler( ModemProperties::OnExpand ), NULL, this ); m_propertyGrid->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( ModemProperties::OnChange ), NULL, this ); this->Connect( wxEVT_SHOW, wxShowEventHandler( ModemProperties::OnShow ), NULL, this ); this->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseEnter ), NULL, this); this->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseLeave ), NULL, this); - + + updateTheme(); + mouseInView = false; + collapsed = false; } void ModemProperties::OnShow(wxShowEvent & /* event */) { + updateTheme(); +} + +void ModemProperties::updateTheme() { + wxColour bgColor( + (unsigned char) (ThemeMgr::mgr.currentTheme->generalBackground.r * 255.0), + (unsigned char) (ThemeMgr::mgr.currentTheme->generalBackground.g * 255.0), + (unsigned char) (ThemeMgr::mgr.currentTheme->generalBackground.b * 255.0)); + + wxColour textColor( + (unsigned char) (ThemeMgr::mgr.currentTheme->text.r * 255.0), + (unsigned char) (ThemeMgr::mgr.currentTheme->text.g * 255.0), + (unsigned char) (ThemeMgr::mgr.currentTheme->text.b * 255.0)); + + wxColour btn( + (unsigned char) (ThemeMgr::mgr.currentTheme->button.r * 255.0), + (unsigned char) (ThemeMgr::mgr.currentTheme->button.g * 255.0), + (unsigned char) (ThemeMgr::mgr.currentTheme->button.b * 255.0)); + + wxColour btnHl( + (unsigned char) (ThemeMgr::mgr.currentTheme->buttonHighlight.r * 255.0), + (unsigned char) (ThemeMgr::mgr.currentTheme->buttonHighlight.g * 255.0), + (unsigned char) (ThemeMgr::mgr.currentTheme->buttonHighlight.b * 255.0)); + + + m_propertyGrid->SetEmptySpaceColour(bgColor); + m_propertyGrid->SetCellBackgroundColour(bgColor); + m_propertyGrid->SetCellTextColour(textColor); + m_propertyGrid->SetSelectionTextColour(bgColor); + m_propertyGrid->SetSelectionBackgroundColour(btnHl); + m_propertyGrid->SetCaptionTextColour(bgColor); + m_propertyGrid->SetCaptionBackgroundColour(btn); + m_propertyGrid->SetLineColour(btn); } ModemProperties::~ModemProperties() { @@ -51,6 +89,10 @@ void ModemProperties::initProperties(ModemArgInfoList newArgs) { } m_propertyGrid->FitColumns(); + + if (collapsed) { + m_propertyGrid->CollapseAll(); + } } wxPGProperty *ModemProperties::addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg) { @@ -166,6 +208,14 @@ void ModemProperties::OnChange(wxPropertyGridEvent &event) { } } +void ModemProperties::OnCollapse(wxPropertyGridEvent &event) { + collapsed = true; +} + +void ModemProperties::OnExpand(wxPropertyGridEvent &event) { + collapsed = false; +} + void ModemProperties::OnMouseEnter(wxMouseEvent & /* event */) { mouseInView = true; } @@ -177,3 +227,11 @@ void ModemProperties::OnMouseLeave(wxMouseEvent & /* event */) { bool ModemProperties::isMouseInView() { return mouseInView || (m_propertyGrid && m_propertyGrid->IsEditorFocused()); } + +bool ModemProperties::isCollapsed() { + return collapsed; +} + +void ModemProperties::fitColumns() { + m_propertyGrid->FitColumns(); +} diff --git a/src/ModemProperties.h b/src/ModemProperties.h index 326c947..2f1efc9 100644 --- a/src/ModemProperties.h +++ b/src/ModemProperties.h @@ -21,12 +21,18 @@ public: void initProperties(ModemArgInfoList newArgs); bool isMouseInView(); - + bool isCollapsed(); + void fitColumns(); + + void updateTheme(); + private: wxPGProperty *addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg); std::string readProperty(std::string); void OnChange(wxPropertyGridEvent &event); void OnShow(wxShowEvent &event); + void OnCollapse(wxPropertyGridEvent &event); + void OnExpand(wxPropertyGridEvent &event); void OnMouseEnter(wxMouseEvent &event); void OnMouseLeave(wxMouseEvent &event); @@ -35,5 +41,5 @@ private: wxPropertyGrid* m_propertyGrid; ModemArgInfoList args; std::map props; - bool mouseInView; + bool mouseInView, collapsed; }; \ No newline at end of file diff --git a/src/modules/modem/analog/ModemFMStereo.cpp b/src/modules/modem/analog/ModemFMStereo.cpp index acc7078..f98fa21 100644 --- a/src/modules/modem/analog/ModemFMStereo.cpp +++ b/src/modules/modem/analog/ModemFMStereo.cpp @@ -2,6 +2,7 @@ ModemFMStereo::ModemFMStereo() { demodFM = freqdem_create(0.5); + _demph = 75; } ModemFMStereo::~ModemFMStereo() { @@ -34,6 +35,54 @@ int ModemFMStereo::getDefaultSampleRate() { return 200000; } +ModemArgInfoList ModemFMStereo::getSettings() { + ModemArgInfoList args; + + ModemArgInfo demphArg; + demphArg.key = "demph"; + demphArg.name = "De-emphasis"; + demphArg.value = std::to_string(_demph); + demphArg.description = "FM Stereo De-Emphasis, typically 75us in US/Canada, 50us elsewhere."; + + demphArg.type = ModemArgInfo::STRING; + + std::vector demphOptNames; + demphOptNames.push_back("None"); + demphOptNames.push_back("10us"); + demphOptNames.push_back("25us"); + demphOptNames.push_back("32us"); + demphOptNames.push_back("50us"); + demphOptNames.push_back("75us"); + demphArg.optionNames = demphOptNames; + + std::vector demphOpts; + demphOpts.push_back("0"); + demphOpts.push_back("10"); + demphOpts.push_back("25"); + demphOpts.push_back("32"); + demphOpts.push_back("50"); + demphOpts.push_back("75"); + demphArg.options = demphOpts; + + args.push_back(demphArg); + + return args; +} + +void ModemFMStereo::writeSetting(std::string setting, std::string value) { + if (setting == "demph") { + _demph = std::stoi(value); + rebuildKit(); + } +} + +std::string ModemFMStereo::readSetting(std::string setting) { + if (setting == "demph") { + return std::to_string(_demph); + } + return ""; +} + ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) { ModemKitFMStereo *kit = new ModemKitFMStereo; @@ -87,6 +136,24 @@ ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) { nco_crcf_reset(kit->stereoPilot); nco_crcf_pll_set_bandwidth(kit->stereoPilot, 0.25f); + kit->demph = _demph; + + if (_demph) { + float f = (1.0f / (2.0f * M_PI * double(_demph) * 1e-6)); + float t = 1.0f / (2.0f * M_PI * f); + t = 1.0f / (2.0f * float(audioSampleRate) * tan(1.0f / (2.0f * float(audioSampleRate) * t))); + + float tb = (1.0f + 2.0f * t * float(audioSampleRate)); + float b_demph[2] = { 1.0f / tb, 1.0f / tb }; + float a_demph[2] = { 1.0f, (1.0f - 2.0f * t * float(audioSampleRate)) / tb }; + + kit->iirDemphL = iirfilt_rrrf_create(b_demph, 2, a_demph, 2); + kit->iirDemphR = iirfilt_rrrf_create(b_demph, 2, a_demph, 2); + } else { + kit->iirDemphL = nullptr; + kit->iirDemphR = nullptr; + kit->demph = 0; + } return kit; } @@ -100,6 +167,8 @@ void ModemFMStereo::disposeKit(ModemKit *kit) { firhilbf_destroy(fmkit->firStereoR2C); firhilbf_destroy(fmkit->firStereoC2R); nco_crcf_destroy(fmkit->stereoPilot); + if (fmkit->iirDemphR) { iirfilt_rrrf_destroy(fmkit->iirDemphR); } + if (fmkit->iirDemphL) { iirfilt_rrrf_destroy(fmkit->iirDemphL); } } @@ -189,12 +258,24 @@ void ModemFMStereo::demodulate(ModemKit *kit, ModemIQData *input, AudioThreadInp audioOut->data.resize(numAudioWritten * 2); for (size_t i = 0; i < numAudioWritten; i++) { float l, r; - - firfilt_rrrf_push(fmkit->firStereoLeft, 0.568f * (resampledOutputData[i] - (resampledStereoData[i]))); - firfilt_rrrf_execute(fmkit->firStereoLeft, &l); - - firfilt_rrrf_push(fmkit->firStereoRight, 0.568f * (resampledOutputData[i] + (resampledStereoData[i]))); - firfilt_rrrf_execute(fmkit->firStereoRight, &r); + float ld, rd; + + if (fmkit->demph) { + iirfilt_rrrf_execute(fmkit->iirDemphL, 0.568f * (resampledOutputData[i] - (resampledStereoData[i])), &ld); + iirfilt_rrrf_execute(fmkit->iirDemphR, 0.568f * (resampledOutputData[i] + (resampledStereoData[i])), &rd); + + firfilt_rrrf_push(fmkit->firStereoLeft, ld); + firfilt_rrrf_execute(fmkit->firStereoLeft, &l); + + firfilt_rrrf_push(fmkit->firStereoRight, rd); + firfilt_rrrf_execute(fmkit->firStereoRight, &r); + } else { + firfilt_rrrf_push(fmkit->firStereoLeft, 0.568f * (resampledOutputData[i] - (resampledStereoData[i]))); + firfilt_rrrf_execute(fmkit->firStereoLeft, &l); + + firfilt_rrrf_push(fmkit->firStereoRight, 0.568f * (resampledOutputData[i] + (resampledStereoData[i]))); + firfilt_rrrf_execute(fmkit->firStereoRight, &r); + } audioOut->data[i * 2] = l; audioOut->data[i * 2 + 1] = r; diff --git a/src/modules/modem/analog/ModemFMStereo.h b/src/modules/modem/analog/ModemFMStereo.h index 6cf9768..ccba7dd 100644 --- a/src/modules/modem/analog/ModemFMStereo.h +++ b/src/modules/modem/analog/ModemFMStereo.h @@ -13,7 +13,11 @@ public: firfilt_rrrf firStereoLeft; firfilt_rrrf firStereoRight; iirfilt_crcf iirStereoPilot; - + + int demph; + iirfilt_rrrf iirDemphR; + iirfilt_rrrf iirDemphL; + firhilbf firStereoR2C; firhilbf firStereoC2R; @@ -34,6 +38,10 @@ public: int checkSampleRate(long long sampleRate, int audioSampleRate); int getDefaultSampleRate(); + ModemArgInfoList getSettings(); + void writeSetting(std::string setting, std::string value); + std::string readSetting(std::string setting); + ModemKit *buildKit(long long sampleRate, int audioSampleRate); void disposeKit(ModemKit *kit); @@ -45,4 +53,6 @@ private: std::vector resampledOutputData; std::vector resampledStereoData; freqdem demodFM; + + int _demph; }; \ No newline at end of file