From d063382a5b123daf85d91432825e4470f845e7a5 Mon Sep 17 00:00:00 2001 From: drowe67 Date: Mon, 3 Dec 2012 01:41:38 +0000 Subject: [PATCH] real time EQ adjustment working, designing filters on the fly, but still a few GUI and context save/restore bugs git-svn-id: https://svn.code.sf.net/p/freetel/code@1112 01035d8c-6547-0410-b346-abe4f91aad63 --- fdmdv2/src/dlg_filter.cpp | 87 +++++++++------- fdmdv2/src/dlg_filter.h | 12 ++- fdmdv2/src/fdmdv2_main.cpp | 197 ++++++++++++++++++++++++++++--------- fdmdv2/src/fdmdv2_main.h | 31 +++++- 4 files changed, 243 insertions(+), 84 deletions(-) diff --git a/fdmdv2/src/dlg_filter.cpp b/fdmdv2/src/dlg_filter.cpp index e0874527..96528e76 100644 --- a/fdmdv2/src/dlg_filter.cpp +++ b/fdmdv2/src/dlg_filter.cpp @@ -19,7 +19,6 @@ // //========================================================================== #include "dlg_filter.h" -#include "sox_biquad.h" #define SLIDER_MAX 100 #define SLIDER_LENGTH 155 @@ -49,9 +48,12 @@ extern struct CODEC2 *g_pCodec2; //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= // Class FilterDlg //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= -FilterDlg::FilterDlg(wxWindow* parent, bool running, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) +FilterDlg::FilterDlg(wxWindow* parent, bool running, bool *newMicInFilter, bool *newSpkOutFilter, + wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style) : wxDialog(parent, id, title, pos, size, style) { m_running = running; + m_newMicInFilter = newMicInFilter; + m_newSpkOutFilter = newSpkOutFilter; this->SetSizeHints(wxDefaultSize, wxDefaultSize); @@ -206,7 +208,6 @@ FilterDlg::FilterDlg(wxWindow* parent, bool running, wxWindowID id, const wxStri m_sdbSizer5Cancel->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnCancel), NULL, this); m_sdbSizer5OK->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnOK), NULL, this); - sox_biquad_start(); } //------------------------------------------------------------------------- @@ -216,7 +217,6 @@ FilterDlg::~FilterDlg() { delete m_MicInMagdB; delete m_SpkOutMagdB; - sox_biquad_finish(); // Disconnect Events @@ -304,7 +304,7 @@ EQ FilterDlg::newEQ(wxSizer *bs, wxString eqName, float maxFreqHz, bool enableQ) //------------------------------------------------------------------------- // ExchangeData() //------------------------------------------------------------------------- -void FilterDlg::ExchangeData(int inout) +void FilterDlg::ExchangeData(int inout, bool storePersistent) { wxConfigBase *pConfig = wxConfigBase::Get(); if(inout == EXCHANGE_DATA_IN) @@ -335,7 +335,7 @@ void FilterDlg::ExchangeData(int inout) m_MicInMid.Q = wxGetApp().m_MicInMidQ; setQ(&m_MicInMid); m_MicInMid.Q = limit(m_MicInMid.Q, pow(10.0,MIN_LOG10_Q), pow(10.0, MAX_LOG10_Q)); - m_MicInEnable->SetValue(wxGetApp().m_MicInEnable); + m_MicInEnable->SetValue(wxGetApp().m_MicInEQEnable); setFreq(&m_MicInBass); setGain(&m_MicInBass); plotMicInFilterSpectrum(); @@ -358,7 +358,7 @@ void FilterDlg::ExchangeData(int inout) m_SpkOutMid.Q = wxGetApp().m_SpkOutMidQ; setQ(&m_SpkOutMid); m_SpkOutMid.Q = limit(m_SpkOutMid.Q, pow(10.0,MIN_LOG10_Q), pow(10.0, MAX_LOG10_Q)); - m_SpkOutEnable->SetValue(wxGetApp().m_SpkOutEnable); + m_SpkOutEnable->SetValue(wxGetApp().m_SpkOutEQEnable); setFreq(&m_SpkOutBass); setGain(&m_SpkOutBass); plotSpkOutFilterSpectrum(); } @@ -371,50 +371,54 @@ void FilterDlg::ExchangeData(int inout) wxGetApp().m_codec2LPCPostFilterBeta = m_beta; wxGetApp().m_codec2LPCPostFilterGamma = m_gamma; - pConfig->Write(wxT("/Filter/codec2LPCPostFilterEnable"), wxGetApp().m_codec2LPCPostFilterEnable); - pConfig->Write(wxT("/Filter/codec2LPCPostFilterBassBoost"), wxGetApp().m_codec2LPCPostFilterBassBoost); - pConfig->Write(wxT("/Filter/codec2LPCPostFilterBeta"), (int)(m_beta*100.0)); - pConfig->Write(wxT("/Filter/codec2LPCPostFilterGamma"), (int)(m_gamma*100.0)); - // Mic In Equaliser wxGetApp().m_MicInBassFreqHz = m_MicInBass.freqHz; - pConfig->Write(wxT("/Filter/MicInBassFreqHz"), (int)m_MicInBass.freqHz); wxGetApp().m_MicInBassGaindB = m_MicInBass.gaindB; - pConfig->Write(wxT("/Filter/MicInBassGaindB"), (int)(10.0*m_MicInBass.gaindB)); wxGetApp().m_MicInTrebleFreqHz = m_MicInTreble.freqHz; - pConfig->Write(wxT("/Filter/MicInTrebleFreqHz"), (int)m_MicInTreble.freqHz); wxGetApp().m_MicInTrebleGaindB = m_MicInTreble.gaindB; - pConfig->Write(wxT("/Filter/MicInTrebleGaindB"), (int)(10.0*m_MicInTreble.gaindB)); wxGetApp().m_MicInMidFreqHz = m_MicInMid.freqHz; - pConfig->Write(wxT("/Filter/MicInMidFreqHz"), (int)m_MicInMid.freqHz); wxGetApp().m_MicInMidGaindB = m_MicInMid.gaindB; - pConfig->Write(wxT("/Filter/MicInMidGaindB"), (int)(10.0*m_MicInMid.gaindB)); wxGetApp().m_MicInMidQ = m_MicInMid.Q; - pConfig->Write(wxT("/Filter/MicInMidQ"), (int)(100.0*m_MicInMid.Q)); // Spk Out Equaliser wxGetApp().m_SpkOutBassFreqHz = m_SpkOutBass.freqHz; - pConfig->Write(wxT("/Filter/SpkOutBassFreqHz"), (int)m_SpkOutBass.freqHz); wxGetApp().m_SpkOutBassGaindB = m_SpkOutBass.gaindB; - pConfig->Write(wxT("/Filter/SpkOutBassGaindB"), (int)(10.0*m_SpkOutBass.gaindB)); wxGetApp().m_SpkOutTrebleFreqHz = m_SpkOutTreble.freqHz; - pConfig->Write(wxT("/Filter/SpkOutTrebleFreqHz"), (int)m_SpkOutTreble.freqHz); wxGetApp().m_SpkOutTrebleGaindB = m_SpkOutTreble.gaindB; - pConfig->Write(wxT("/Filter/SpkOutTrebleGaindB"), (int)(10.0*m_SpkOutTreble.gaindB)); wxGetApp().m_SpkOutMidFreqHz = m_SpkOutMid.freqHz; - pConfig->Write(wxT("/Filter/SpkOutMidFreqHz"), (int)m_SpkOutMid.freqHz); wxGetApp().m_SpkOutMidGaindB = m_SpkOutMid.gaindB; - pConfig->Write(wxT("/Filter/SpkOutMidGaindB"), (int)(10.0*m_SpkOutMid.gaindB)); wxGetApp().m_SpkOutMidQ = m_SpkOutMid.Q; - pConfig->Write(wxT("/Filter/SpkOutMidQ"), (int)(100.0*m_SpkOutMid.Q)); - pConfig->Flush(); + if (storePersistent) { + pConfig->Write(wxT("/Filter/codec2LPCPostFilterEnable"), wxGetApp().m_codec2LPCPostFilterEnable); + pConfig->Write(wxT("/Filter/codec2LPCPostFilterBassBoost"), wxGetApp().m_codec2LPCPostFilterBassBoost); + pConfig->Write(wxT("/Filter/codec2LPCPostFilterBeta"), (int)(m_beta*100.0)); + pConfig->Write(wxT("/Filter/codec2LPCPostFilterGamma"), (int)(m_gamma*100.0)); + + pConfig->Write(wxT("/Filter/MicInBassFreqHz"), (int)m_MicInBass.freqHz); + pConfig->Write(wxT("/Filter/MicInBassGaindB"), (int)(10.0*m_MicInBass.gaindB)); + pConfig->Write(wxT("/Filter/MicInTrebleFreqHz"), (int)m_MicInTreble.freqHz); + pConfig->Write(wxT("/Filter/MicInTrebleGaindB"), (int)(10.0*m_MicInTreble.gaindB)); + pConfig->Write(wxT("/Filter/MicInMidFreqHz"), (int)m_MicInMid.freqHz); + pConfig->Write(wxT("/Filter/MicInMidGaindB"), (int)(10.0*m_MicInMid.gaindB)); + pConfig->Write(wxT("/Filter/MicInMidQ"), (int)(100.0*m_MicInMid.Q)); + + pConfig->Write(wxT("/Filter/SpkOutBassFreqHz"), (int)m_SpkOutBass.freqHz); + pConfig->Write(wxT("/Filter/SpkOutBassGaindB"), (int)(10.0*m_SpkOutBass.gaindB)); + pConfig->Write(wxT("/Filter/SpkOutTrebleFreqHz"), (int)m_SpkOutTreble.freqHz); + pConfig->Write(wxT("/Filter/SpkOutTrebleGaindB"), (int)(10.0*m_SpkOutTreble.gaindB)); + pConfig->Write(wxT("/Filter/SpkOutMidQ"), (int)(100.0*m_SpkOutMid.Q)); + pConfig->Write(wxT("/Filter/SpkOutMidFreqHz"), (int)m_SpkOutMid.freqHz); + pConfig->Write(wxT("/Filter/SpkOutMidGaindB"), (int)(10.0*m_SpkOutMid.gaindB)); + + pConfig->Flush(); + } } delete wxConfigBase::Set((wxConfigBase *) NULL); } @@ -487,7 +491,7 @@ void FilterDlg::OnSpkOutDefault(wxCommandEvent& event) void FilterDlg::OnOK(wxCommandEvent& event) { //printf("FilterDlg::OnOK\n"); - ExchangeData(EXCHANGE_DATA_OUT); + ExchangeData(EXCHANGE_DATA_OUT, true); this->EndModal(wxID_OK); } @@ -505,7 +509,7 @@ void FilterDlg::OnClose(wxCloseEvent& event) void FilterDlg::OnInitDialog(wxInitDialogEvent& event) { //printf("FilterDlg::OnInitDialog\n"); - ExchangeData(EXCHANGE_DATA_IN); + ExchangeData(EXCHANGE_DATA_IN, false); //printf("m_beta: %f\n", m_beta); } @@ -555,13 +559,14 @@ void FilterDlg::OnGammaScroll(wxScrollEvent& event) { setCodec2(); } -// immediately change rather using ExchangeData() so we can switch on and off at run time +// immediately change enable flags rather using ExchangeData() so we can switch on and off at run time + void FilterDlg::OnMicInEnable(wxScrollEvent& event) { - wxGetApp().m_MicInEnable = m_MicInEnable->GetValue(); + wxGetApp().m_MicInEQEnable = m_MicInEnable->GetValue(); } void FilterDlg::OnSpkOutEnable(wxScrollEvent& event) { - wxGetApp().m_SpkOutEnable = m_SpkOutEnable->GetValue(); + wxGetApp().m_SpkOutEQEnable = m_SpkOutEnable->GetValue(); } void FilterDlg::setFreq(EQ *eq) @@ -635,10 +640,26 @@ void FilterDlg::sliderToQ(EQ *eq, bool micIn) void FilterDlg::plotMicInFilterSpectrum(void) { plotFilterSpectrum(&m_MicInBass, &m_MicInMid, &m_MicInTreble, m_MicInFreqRespPlot, m_MicInMagdB); + + // signal an adjustment in running filter coeffs + + if (m_running) { + ExchangeData(EXCHANGE_DATA_OUT, false); + *m_newMicInFilter = true; + } + } void FilterDlg::plotSpkOutFilterSpectrum(void) { plotFilterSpectrum(&m_SpkOutBass, &m_SpkOutMid, &m_SpkOutTreble, m_SpkOutFreqRespPlot, m_SpkOutMagdB); + + // signal an adjustment in running filter coeffs + + if (m_running) { + ExchangeData(EXCHANGE_DATA_OUT, false); + *m_newSpkOutFilter = true; + } + } void FilterDlg::plotFilterSpectrum(EQ *eqBass, EQ *eqMid, EQ *eqTreble, PlotSpectrum* freqRespPlot, float *magdB) { @@ -709,7 +730,7 @@ void FilterDlg::calcFilterSpectrum(float magdB[], int argc, char *argv[]) { //out[0] = IMP_AMP; // calculate discrete time continous frequency Fourer transform - // doing this from basic principles rather than FFT for no good reason + // doing this from first principles rather than FFT for no good reason for(f=0,i=0; fRead(wxT("/MainFrame/show_speech_out"), 1); wxGetApp().m_show_demod_in = pConfig->Read(wxT("/MainFrame/show_demod_in"), 1); + wxGetApp().m_rxNbookCtrl = pConfig->Read(wxT("/MainFrame/rxNbookCtrl"), (long)0); + g_SquelchActive = pConfig->Read(wxT("/Audio/SquelchActive"), 1); g_SquelchLevel = pConfig->Read(wxT("/Audio/SquelchLevel"), (int)(SQ_DEFAULT_SNR*2)); g_SquelchLevel /= 2.0; @@ -338,7 +340,8 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent) wxGetApp().m_MicInMidGaindB = (float)pConfig->Read(wxT("/Filter/MicInMidGaindB"), (long)0)/10.0; wxGetApp().m_MicInMidQ = (float)pConfig->Read(wxT("/Filter/MicInMidQ"), (long)100)/100.0; - wxGetApp().m_MicInEnable = (float)pConfig->Read(wxT("/Filter/MicInEnable"), t); + bool f = false; + wxGetApp().m_MicInEQEnable = (float)pConfig->Read(wxT("/Filter/MicInEQEnable"), f); wxGetApp().m_SpkOutBassFreqHz = (float)pConfig->Read(wxT("/Filter/SpkOutBassFreqHz"), 1); wxGetApp().m_SpkOutBassGaindB = (float)pConfig->Read(wxT("/Filter/SpkOutBassGaindB"), (long)0)/10.0; @@ -348,7 +351,7 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent) wxGetApp().m_SpkOutMidGaindB = (float)pConfig->Read(wxT("/Filter/SpkOutMidGaindB"), (long)0)/10.0; wxGetApp().m_SpkOutMidQ = (float)pConfig->Read(wxT("/Filter/SpkOutMidQ"), (long)100)/100.0; - wxGetApp().m_SpkOutEnable = (float)pConfig->Read(wxT("/Filter/SpkOutEnable"), t); + wxGetApp().m_SpkOutEQEnable = (float)pConfig->Read(wxT("/Filter/SpkOutEQEnable"), f); wxGetApp().m_callSign = pConfig->Read("/Data/CallSign", wxT("")); @@ -430,6 +433,9 @@ MainFrame::MainFrame(wxWindow *parent) : TopFrame(parent) g_txDataInFifo = fifo_create(MAX_CALLSIGN*VARICODE_MAX_BITS); g_rxDataOutFifo = fifo_create(MAX_CALLSIGN*VARICODE_MAX_BITS); varicode_decode_init(&g_varicode_dec_states); + + sox_biquad_start(); + } //------------------------------------------------------------------------- @@ -461,6 +467,8 @@ MainFrame::~MainFrame() pConfig->Write(wxT("/MainFrame/show_speech_out"), wxGetApp().m_show_speech_out); pConfig->Write(wxT("/MainFrame/show_demod_in"), wxGetApp().m_show_demod_in); + pConfig->Write(wxT("/MainFrame/rxNbookCtrl"), wxGetApp().m_rxNbookCtrl); + pConfig->Write(wxT("/Audio/SquelchActive"), g_SquelchActive); pConfig->Write(wxT("/Audio/SquelchLevel"), (int)(g_SquelchLevel*2.0)); @@ -495,8 +503,8 @@ MainFrame::~MainFrame() pConfig->Write(wxT("/Data/CallSign"), wxGetApp().m_callSign); - pConfig->Write(wxT("/Filter/MicInEnable"), wxGetApp().m_MicInEnable); - pConfig->Write(wxT("/Filter/SpkOutEnable"), wxGetApp().m_SpkOutEnable); + pConfig->Write(wxT("/Filter/MicInEQEnable"), wxGetApp().m_MicInEQEnable); + pConfig->Write(wxT("/Filter/SpkOutEQEnable"), wxGetApp().m_SpkOutEQEnable); } //m_togRxID->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnRxIDUI), NULL, this); @@ -508,6 +516,7 @@ MainFrame::~MainFrame() m_btnTogPTT->Disconnect(wxEVT_UPDATE_UI, wxUpdateUIEventHandler(MainFrame::OnTogBtnTXClickUI), NULL, this); CloseSerialPort(); + sox_biquad_finish(); if (m_RxRunning) { @@ -660,7 +669,7 @@ void MainFrame::OnTimer(wxTimerEvent &evt) m_maxLevel *= LEVEL_BETA; - // sync LED (Colours don't work on Windows) + // sync LED (Colours don't work on Windows) ------------------------ if (g_State) { m_rbSync->SetForegroundColour( wxColour( 0, 255, 0 ) ); // green @@ -671,7 +680,7 @@ void MainFrame::OnTimer(wxTimerEvent &evt) m_rbSync->SetValue(false); } - // send Callsign + // send Callsign ---------------------------------------------------- if (fifo_used(g_txDataInFifo) == 0) { char callsign[MAX_CALLSIGN]; @@ -688,7 +697,7 @@ void MainFrame::OnTimer(wxTimerEvent &evt) //printf("Callsign sending: %s nout: %d\n", callsign, nout); } - // See if any callsign info received + // See if any Callsign info received -------------------------------- short ashort; while (fifo_read(g_rxDataOutFifo, &ashort, 1) == 0) { @@ -705,7 +714,20 @@ void MainFrame::OnTimer(wxTimerEvent &evt) } } + // Run time upodate of EQ filters ----------------------------------- + + if (m_newMicInFilter || m_newSpkOutFilter) { + printf("new filter...\n"); + g_mutexProtectingCallbackData.Lock(); + deleteEQFilters(g_rxUserdata); + designEQFilters(g_rxUserdata); + g_mutexProtectingCallbackData.Unlock(); + g_rxUserdata->micInEQEnable = wxGetApp().m_MicInEQEnable; + g_rxUserdata->spkOutEQEnable = wxGetApp().m_SpkOutEQEnable; + m_newMicInFilter = m_newSpkOutFilter = false; + } } + #endif #ifdef _USE_ONIDLE @@ -868,15 +890,19 @@ void MainFrame::OnTogBtnTXClick(wxCommandEvent& event) { if (g_tx) { - // tx-> rx transition, swap to Waterfall - m_auiNbookCtrl->ChangeSelection(0); + // tx-> rx transition, swap to the page we were on for last rx + m_auiNbookCtrl->ChangeSelection(wxGetApp().m_rxNbookCtrl); } else { // rx-> tx transition, swap to Mic In page to monitor speech + + wxGetApp().m_rxNbookCtrl = m_auiNbookCtrl->GetSelection(); m_auiNbookCtrl->ChangeSelection(4); // is there a way to avoid hard coding this? + } g_tx = m_btnTogPTT->GetValue(); + // The following sets and clears may be exactly inverted. // I don't know and I'm not set up to tell yet. // If so, one just needs to invert the polarity selection @@ -931,7 +957,7 @@ void MainFrame::OnTogBtnTXClick(wxCommandEvent& event) } } } - + // reset level gauge m_maxLevel = 0; m_textLevel->SetLabel(wxT("")); @@ -1355,7 +1381,7 @@ void MainFrame::OnToolsAudio(wxCommandEvent& event) void MainFrame::OnToolsFilter(wxCommandEvent& event) { wxUnusedVar(event); - FilterDlg *dlg = new FilterDlg(NULL, m_RxRunning); + FilterDlg *dlg = new FilterDlg(NULL, m_RxRunning, &m_newMicInFilter, &m_newSpkOutFilter); dlg->ShowModal(); delete dlg; } @@ -1476,7 +1502,7 @@ void MainFrame::OnHelpAbout(wxCommandEvent& event) //printf("In OK\n"); wxStringOutputStream html_stream(&htmldata); in->Read(html_stream); - wxLogDebug(htmldata); + //wxLogDebug(htmldata); wxString s("

freetel - Revision "); int startIndex = htmldata.find(s) + s.Length(); @@ -1511,6 +1537,10 @@ void MainFrame::OnTogBtnOnOff(wxCommandEvent& event) if (startStop.IsSameAs("Start")) { + // + // Start Running ------------------------------------------------- + // + m_togBtnSplit->Enable(); //m_togRxID->Enable(); //m_togTxID->Enable(); @@ -1561,6 +1591,10 @@ void MainFrame::OnTogBtnOnOff(wxCommandEvent& event) if (startStop.IsSameAs("Stop") || !m_RxRunning ) { + // + // Stop Running ------------------------------------------------- + // + #ifdef _USE_TIMER m_plotTimer.Stop(); #endif // _USE_TIMER @@ -1628,34 +1662,6 @@ void MainFrame::destroy_src(void) src_delete(g_rxUserdata->outsrc2); } -void MainFrame::autoDetectSoundCards(PortAudioWrap *pa) -{ - const PaDeviceInfo *deviceInfo; - int i; - - // trap zero sound devices - - if (pa->getDeviceCount() == 0) { - wxMessageBox(wxT("No sound devices found"), wxT("Error"), wxOK); - return; - } - - for(i=0; igetDeviceCount(); i++) { - deviceInfo = Pa_GetDeviceInfo( i ); - - // supports full duplex and 44800 and 44100 - // is there something unique so we know it's a hw device? - // does this work on Linux & Windows? - - printf( "--------------------------------------- device #%d\n", i ); - printf( "Name = %s\n", deviceInfo->name ); - printf( "Host API = %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name ); - printf( "Max inputs = %d", deviceInfo->maxInputChannels ); - printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels ); - printf( "Default sample rate = %8.2f\n", deviceInfo->defaultSampleRate ); - } -} - void MainFrame::initPortAudioDevice(PortAudioWrap *pa, int inDevice, int outDevice, int soundCard, int sampleRate, int inputChannels) { @@ -1812,6 +1818,12 @@ void MainFrame::startRxStream() g_rxUserdata->rxinfifo = fifo_create(3 * FDMDV_NOM_SAMPLES_PER_FRAME); g_rxUserdata->rxoutfifo = fifo_create(2 * codec2_samples_per_frame(g_pCodec2)); + // Init Equaliser Filters ------------------------------------------------------ + + designEQFilters(g_rxUserdata); + g_rxUserdata->micInEQEnable = wxGetApp().m_MicInEQEnable; + g_rxUserdata->spkOutEQEnable = wxGetApp().m_SpkOutEQEnable; + // Start sound card 1 ---------------------------------------------------------- m_rxPa->setUserData(g_rxUserdata); @@ -1897,11 +1909,88 @@ void MainFrame::startRxStream() { wxLogError(wxT("Can't start thread!")); } - } + } } +#define SBQ_MAX_ARGS 4 + +void *MainFrame::designAnEQFilter(const char filterType[], float freqHz, float gaindB, float Q) +{ + char *arg[SBQ_MAX_ARGS]; + char argstorage[SBQ_MAX_ARGS][80]; + void *sbq; + int i, argc; + + assert((strcmp(filterType, "bass") == 0) || + (strcmp(filterType, "treble") == 0) || + (strcmp(filterType, "equalizer") == 0)); + + for(i=0; isbqMicInBass = designAnEQFilter("bass", wxGetApp().m_MicInBassFreqHz, wxGetApp().m_MicInBassGaindB); + cb->sbqMicInTreble = designAnEQFilter("treble", wxGetApp().m_MicInTrebleFreqHz, wxGetApp().m_MicInTrebleGaindB); + cb->sbqMicInMid = designAnEQFilter("equalizer", wxGetApp().m_MicInMidFreqHz, wxGetApp().m_MicInMidGaindB, wxGetApp().m_MicInMidQ); + } + + // init Spk Out Equaliser Filters + + if (m_newSpkOutFilter) { + printf("designing new Spk Out filters\n"); + cb->sbqSpkOutBass = designAnEQFilter("bass", wxGetApp().m_SpkOutBassFreqHz, wxGetApp().m_SpkOutBassGaindB); + cb->sbqSpkOutTreble = designAnEQFilter("treble", wxGetApp().m_SpkOutTrebleFreqHz, wxGetApp().m_SpkOutTrebleGaindB); + cb->sbqSpkOutMid = designAnEQFilter("equalizer", wxGetApp().m_SpkOutMidFreqHz, wxGetApp().m_SpkOutMidGaindB, wxGetApp().m_SpkOutMidQ); + } + +} + +void MainFrame::deleteEQFilters(paCallBackData *cb) +{ + if (m_newMicInFilter) { + sox_biquad_destroy(cb->sbqMicInBass); + sox_biquad_destroy(cb->sbqMicInTreble); + sox_biquad_destroy(cb->sbqMicInMid); + } + if (m_newSpkOutFilter) { + sox_biquad_destroy(cb->sbqSpkOutBass); + sox_biquad_destroy(cb->sbqSpkOutTreble); + sox_biquad_destroy(cb->sbqSpkOutMid); + } +} + // returns number of output samples generated by resampling int resample(SRC_STATE *src, @@ -2030,7 +2119,7 @@ void txRxProcessing() g_mutexProtectingCallbackData.Lock(); if (g_playFileFromRadio && (g_sfPlayFileFromRadio != NULL)) { - int n = sf_read_short(g_sfPlayFileFromRadio, in8k_short, N8); + int n = sf_read_short(g_sfPlayFileFromRadio, in8k_short, n8k); if (n != N8) { if (g_loopPlayFileFromRadio) sf_seek(g_sfPlayFileFromRadio, 0, SEEK_SET); @@ -2043,7 +2132,7 @@ void txRxProcessing() } } g_mutexProtectingCallbackData.Unlock(); - + fifo_write(cbData->rxinfifo, in8k_short, n8k); resample_for_plot(g_plotDemodInFifo, in8k_short, n8k); @@ -2059,6 +2148,15 @@ void txRxProcessing() fifo_read(cbData->rxoutfifo, out8k_short, N8); } + // Opional Spk Out EQ Filtering, need mutex as filter can change at run time + g_mutexProtectingCallbackData.Lock(); + if (cbData->spkOutEQEnable) { + sox_biquad_filter(cbData->sbqSpkOutBass, out8k_short, out8k_short, N8); + sox_biquad_filter(cbData->sbqSpkOutTreble, out8k_short, out8k_short, N8); + sox_biquad_filter(cbData->sbqSpkOutMid, out8k_short, out8k_short, N8); + } + g_mutexProtectingCallbackData.Unlock(); + if (g_SquelchActive && (g_SquelchLevel > g_snr)) { //printf("g_SquelchLevel: %f g_snr: %f\n", g_SquelchLevel, g_snr); memset(out8k_short, 0, sizeof(short)*N8); @@ -2113,8 +2211,8 @@ void txRxProcessing() // optionally use file for mic input signal g_mutexProtectingCallbackData.Lock(); if (g_playFileToMicIn && (g_sfPlayFile != NULL)) { - int n = sf_read_short(g_sfPlayFile, in8k_short, 2*N8); - if (n != 2*N8) { + int n = sf_read_short(g_sfPlayFile, in8k_short, nout); + if (n != nout) { if (g_loopPlayFileToMicIn) sf_seek(g_sfPlayFile, 0, SEEK_SET); else { @@ -2126,6 +2224,15 @@ void txRxProcessing() } g_mutexProtectingCallbackData.Unlock(); + // Opional Mic In EQ Filtering, need mutex as filter can change at run time + g_mutexProtectingCallbackData.Lock(); + if (cbData->micInEQEnable) { + sox_biquad_filter(cbData->sbqMicInBass, in8k_short, in8k_short, nout); + sox_biquad_filter(cbData->sbqMicInTreble, in8k_short, in8k_short, nout); + sox_biquad_filter(cbData->sbqMicInMid, in8k_short, in8k_short, nout); + } + g_mutexProtectingCallbackData.Unlock(); + resample_for_plot(g_plotSpeechInFifo, in8k_short, nout); if (g_analog) diff --git a/fdmdv2/src/fdmdv2_main.h b/fdmdv2/src/fdmdv2_main.h index 694df2bf..8de702ae 100644 --- a/fdmdv2/src/fdmdv2_main.h +++ b/fdmdv2/src/fdmdv2_main.h @@ -69,6 +69,7 @@ #include "dlg_audiooptions.h" #include "dlg_filter.h" #include "varicode.h" +#include "sox_biquad.h" #define _USE_TIMER 1 #define _USE_ONIDLE 1 @@ -160,7 +161,7 @@ class MainApp : public wxApp float m_MicInMidFreqHz; float m_MicInMidGaindB; float m_MicInMidQ; - bool m_MicInEnable; + bool m_MicInEQEnable; // Spk Out Equaliser float m_SpkOutBassFreqHz; @@ -170,7 +171,7 @@ class MainApp : public wxApp float m_SpkOutMidFreqHz; float m_SpkOutMidGaindB; float m_SpkOutMidQ; - bool m_SpkOutEnable; + bool m_SpkOutEQEnable; // Flags for displaying windows int m_show_wf; @@ -182,6 +183,9 @@ class MainApp : public wxApp int m_show_speech_out; int m_show_demod_in; + // notebook display after tx->rxtransition + int m_rxNbookCtrl; + wxRect m_rTopWindow; int m_framesPerBuffer; @@ -223,6 +227,19 @@ typedef struct struct FIFO *rxoutfifo; int inputChannels1, inputChannels2; + + // EQ filter states + + void *sbqMicInBass; + void *sbqMicInTreble; + void *sbqMicInMid; + void *sbqSpkOutBass; + void *sbqSpkOutTreble; + void *sbqSpkOutMid; + + bool micInEQEnable; + bool spkOutEQEnable; + } paCallBackData; // panel with custom loop checkbox for play file dialog @@ -396,6 +413,16 @@ class MainFrame : public TopFrame // level Gauge float m_maxLevel; + + // flags to indicate when new EQ filters need to be designed + + bool m_newMicInFilter; + bool m_newSpkOutFilter; + + void* designAnEQFilter(const char filterType[], float freqHz, float gaindB, float Q = 0.0); + void designEQFilters(paCallBackData *cb); + void deleteEQFilters(paCallBackData *cb); + }; void resample_for_plot(struct FIFO *plotFifo, short buf[], int length); -- 2.25.1