Merge pull request #414 from cjcliffe/fms_deemphasis

FM Stereo de-emphasis
This commit is contained in:
Charles J. Cliffe 2016-07-27 19:16:42 -05:00 committed by GitHub
commit 61aa57884f
5 changed files with 182 additions and 13 deletions

View File

@ -1003,6 +1003,7 @@ void AppFrame::OnMenu(wxCommandEvent& event) {
waterfallSpeedMeter->Refresh(); waterfallSpeedMeter->Refresh();
spectrumAvgMeter->Refresh(); spectrumAvgMeter->Refresh();
gainCanvas->setThemeColors(); gainCanvas->setThemeColors();
modemProps->updateTheme();
} }
switch (event.GetId()) { switch (event.GetId()) {
@ -1498,6 +1499,7 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
modemProps->initProperties(demod->getModemArgs()); modemProps->initProperties(demod->getModemArgs());
modemPropertiesUpdated.store(false); modemPropertiesUpdated.store(false);
demodTray->Layout(); demodTray->Layout();
modemProps->fitColumns();
#if ENABLE_DIGITAL_LAB #if ENABLE_DIGITAL_LAB
if (demod->getModemType() == "digital") { if (demod->getModemType() == "digital") {
ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)demod->getOutput(); ModemDigitalOutputConsole *outp = (ModemDigitalOutputConsole *)demod->getOutput();
@ -1510,6 +1512,18 @@ void AppFrame::OnIdle(wxIdleEvent& event) {
#endif #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(); int peakHoldMode = peakHoldButton->getSelection();
if (peakHoldButton->modeChanged()) { if (peakHoldButton->modeChanged()) {
wxGetApp().getSpectrumProcessor()->setPeakHold(peakHoldMode == 1); wxGetApp().getSpectrumProcessor()->setPeakHold(peakHoldMode == 1);

View File

@ -4,24 +4,62 @@
ModemProperties::ModemProperties(wxWindow *parent, wxWindowID winid, ModemProperties::ModemProperties(wxWindow *parent, wxWindowID winid,
const wxPoint& pos, const wxSize& size, long style, const wxString& name) : wxPanel(parent, winid, pos, size, style, name) { 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 = new wxBoxSizer( wxVERTICAL );
bSizer->Add(m_propertyGrid, 1, wxEXPAND, 5); bSizer->Add(m_propertyGrid, 1, wxEXPAND, 0);
this->SetSizer(bSizer); 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 ); m_propertyGrid->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( ModemProperties::OnChange ), NULL, this );
this->Connect( wxEVT_SHOW, wxShowEventHandler( ModemProperties::OnShow ), NULL, this ); this->Connect( wxEVT_SHOW, wxShowEventHandler( ModemProperties::OnShow ), NULL, this );
this->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseEnter ), NULL, this); this->Connect( wxEVT_ENTER_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseEnter ), NULL, this);
this->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseLeave ), NULL, this); this->Connect( wxEVT_LEAVE_WINDOW, wxMouseEventHandler( ModemProperties::OnMouseLeave ), NULL, this);
updateTheme();
mouseInView = false; mouseInView = false;
collapsed = false;
} }
void ModemProperties::OnShow(wxShowEvent & /* event */) { 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() { ModemProperties::~ModemProperties() {
@ -51,6 +89,10 @@ void ModemProperties::initProperties(ModemArgInfoList newArgs) {
} }
m_propertyGrid->FitColumns(); m_propertyGrid->FitColumns();
if (collapsed) {
m_propertyGrid->CollapseAll();
}
} }
wxPGProperty *ModemProperties::addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg) { 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 */) { void ModemProperties::OnMouseEnter(wxMouseEvent & /* event */) {
mouseInView = true; mouseInView = true;
} }
@ -177,3 +227,11 @@ void ModemProperties::OnMouseLeave(wxMouseEvent & /* event */) {
bool ModemProperties::isMouseInView() { bool ModemProperties::isMouseInView() {
return mouseInView || (m_propertyGrid && m_propertyGrid->IsEditorFocused()); return mouseInView || (m_propertyGrid && m_propertyGrid->IsEditorFocused());
} }
bool ModemProperties::isCollapsed() {
return collapsed;
}
void ModemProperties::fitColumns() {
m_propertyGrid->FitColumns();
}

View File

@ -21,12 +21,18 @@ public:
void initProperties(ModemArgInfoList newArgs); void initProperties(ModemArgInfoList newArgs);
bool isMouseInView(); bool isMouseInView();
bool isCollapsed();
void fitColumns();
void updateTheme();
private: private:
wxPGProperty *addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg); wxPGProperty *addArgInfoProperty(wxPropertyGrid *pg, ModemArgInfo arg);
std::string readProperty(std::string); std::string readProperty(std::string);
void OnChange(wxPropertyGridEvent &event); void OnChange(wxPropertyGridEvent &event);
void OnShow(wxShowEvent &event); void OnShow(wxShowEvent &event);
void OnCollapse(wxPropertyGridEvent &event);
void OnExpand(wxPropertyGridEvent &event);
void OnMouseEnter(wxMouseEvent &event); void OnMouseEnter(wxMouseEvent &event);
void OnMouseLeave(wxMouseEvent &event); void OnMouseLeave(wxMouseEvent &event);
@ -35,5 +41,5 @@ private:
wxPropertyGrid* m_propertyGrid; wxPropertyGrid* m_propertyGrid;
ModemArgInfoList args; ModemArgInfoList args;
std::map<std::string, wxPGProperty *> props; std::map<std::string, wxPGProperty *> props;
bool mouseInView; bool mouseInView, collapsed;
}; };

View File

@ -2,6 +2,7 @@
ModemFMStereo::ModemFMStereo() { ModemFMStereo::ModemFMStereo() {
demodFM = freqdem_create(0.5); demodFM = freqdem_create(0.5);
_demph = 75;
} }
ModemFMStereo::~ModemFMStereo() { ModemFMStereo::~ModemFMStereo() {
@ -34,6 +35,54 @@ int ModemFMStereo::getDefaultSampleRate() {
return 200000; 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<std::string> 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<std::string> 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) { ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) {
ModemKitFMStereo *kit = new ModemKitFMStereo; ModemKitFMStereo *kit = new ModemKitFMStereo;
@ -87,6 +136,24 @@ ModemKit *ModemFMStereo::buildKit(long long sampleRate, int audioSampleRate) {
nco_crcf_reset(kit->stereoPilot); nco_crcf_reset(kit->stereoPilot);
nco_crcf_pll_set_bandwidth(kit->stereoPilot, 0.25f); 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; return kit;
} }
@ -100,6 +167,8 @@ void ModemFMStereo::disposeKit(ModemKit *kit) {
firhilbf_destroy(fmkit->firStereoR2C); firhilbf_destroy(fmkit->firStereoR2C);
firhilbf_destroy(fmkit->firStereoC2R); firhilbf_destroy(fmkit->firStereoC2R);
nco_crcf_destroy(fmkit->stereoPilot); 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); audioOut->data.resize(numAudioWritten * 2);
for (size_t i = 0; i < numAudioWritten; i++) { for (size_t i = 0; i < numAudioWritten; i++) {
float l, r; float l, 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_push(fmkit->firStereoLeft, 0.568f * (resampledOutputData[i] - (resampledStereoData[i])));
firfilt_rrrf_execute(fmkit->firStereoLeft, &l); firfilt_rrrf_execute(fmkit->firStereoLeft, &l);
firfilt_rrrf_push(fmkit->firStereoRight, 0.568f * (resampledOutputData[i] + (resampledStereoData[i]))); firfilt_rrrf_push(fmkit->firStereoRight, 0.568f * (resampledOutputData[i] + (resampledStereoData[i])));
firfilt_rrrf_execute(fmkit->firStereoRight, &r); firfilt_rrrf_execute(fmkit->firStereoRight, &r);
}
audioOut->data[i * 2] = l; audioOut->data[i * 2] = l;
audioOut->data[i * 2 + 1] = r; audioOut->data[i * 2 + 1] = r;

View File

@ -14,6 +14,10 @@ public:
firfilt_rrrf firStereoRight; firfilt_rrrf firStereoRight;
iirfilt_crcf iirStereoPilot; iirfilt_crcf iirStereoPilot;
int demph;
iirfilt_rrrf iirDemphR;
iirfilt_rrrf iirDemphL;
firhilbf firStereoR2C; firhilbf firStereoR2C;
firhilbf firStereoC2R; firhilbf firStereoC2R;
@ -34,6 +38,10 @@ public:
int checkSampleRate(long long sampleRate, int audioSampleRate); int checkSampleRate(long long sampleRate, int audioSampleRate);
int getDefaultSampleRate(); 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); ModemKit *buildKit(long long sampleRate, int audioSampleRate);
void disposeKit(ModemKit *kit); void disposeKit(ModemKit *kit);
@ -45,4 +53,6 @@ private:
std::vector<float> resampledOutputData; std::vector<float> resampledOutputData;
std::vector<float> resampledStereoData; std::vector<float> resampledStereoData;
freqdem demodFM; freqdem demodFM;
int _demph;
}; };