Merge pull request #25 from drowe67/dr-phase_est_bw

High bandwidth phase est mode & VQ EQ & DPSK & FreeDV 1.4
pull/30/head
drowe67 2019-10-11 13:56:53 +10:30 committed by GitHub
commit 8f457ab4b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 186 additions and 37 deletions

View File

@ -45,7 +45,7 @@ message(STATUS "Compilation date = XX${DATE_RESULT}XX")
set(FREEDV_VERSION_MAJOR 1) set(FREEDV_VERSION_MAJOR 1)
set(FREEDV_VERSION_MINOR 4) set(FREEDV_VERSION_MINOR 4)
set(FREEDV_VERSION_PATCH FALSE) set(FREEDV_VERSION_PATCH FALSE)
set(FREEDV_VERSION_SUFFIX "devel") set(FREEDV_VERSION_SUFFIX FALSE)
set(FREEDV_VERSION ${FREEDV_VERSION_MAJOR}.${FREEDV_VERSION_MINOR}) set(FREEDV_VERSION ${FREEDV_VERSION_MAJOR}.${FREEDV_VERSION_MINOR})
if(FREEDV_VERSION_PATCH) if(FREEDV_VERSION_PATCH)

View File

@ -12,6 +12,8 @@ This document describes how to build the FreeDV GUI program for various operatin
$ sudo apt install libc6-i386 libspeexdsp-dev libsamplerate0-dev sox git \ $ sudo apt install libc6-i386 libspeexdsp-dev libsamplerate0-dev sox git \
libwxgtk3.0-dev portaudio19-dev libhamlib-dev libasound2-dev libao-dev \ libwxgtk3.0-dev portaudio19-dev libhamlib-dev libasound2-dev libao-dev \
libgsm1-dev libsndfile-dev cmake libgsm1-dev libsndfile-dev cmake
$ git clone https://github.com/drowe67/freedv-gui.git
$ cd freedv-gui
$ ./build_linux.sh $ ./build_linux.sh
``` ```
@ -21,6 +23,8 @@ This document describes how to build the FreeDV GUI program for various operatin
$ sudo dnf install cmake wxGTK3-devel portaudio-devel libsamplerate-devel \ $ sudo dnf install cmake wxGTK3-devel portaudio-devel libsamplerate-devel \
libsndfile-devel speexdsp-devel hamlib-devel alsa-lib-devel libao-devel \ libsndfile-devel speexdsp-devel hamlib-devel alsa-lib-devel libao-devel \
gsm-devel gsm-devel
$ git clone https://github.com/drowe67/freedv-gui.git
$ cd freedv-gui
$ ./build_linux.sh $ ./build_linux.sh
``` ```

View File

@ -372,7 +372,6 @@ about 90% of speakers tested work well.
section below). section below).
1. It requires a modern (post 2010) Intel CPU with AVX support. If you 1. It requires a modern (post 2010) Intel CPU with AVX support. If you
don't have AVX the FreeDV 2020 mode button will be grayed out. don't have AVX the FreeDV 2020 mode button will be grayed out.
1. The audio in **Analog** mode is choppy.
### Horus Binary Mode ### Horus Binary Mode
@ -396,6 +395,44 @@ work in Windows if Tools-Options "Windows Debug Console" is checked.
A Python script is required to upload the telemetry messages to the HabHub A Python script is required to upload the telemetry messages to the HabHub
server, please see https://github.com/projecthorus/horusbinary#usage---via-freedv server, please see https://github.com/projecthorus/horusbinary#usage---via-freedv
## Tools - Filter
This section describes features on Tools-Filter.
Control | Description
--- | --- |
Noise Supression | Enable noise supression, dereverberation, AGC of mic signal using the Speex pre-processor
700C/700D Auto EQ | Automatic equalisation for FreeDV 700C and FreeDV 700D Codec input audio
Auto EQ (Automatic Equalisation) adjusts the input speech spectrum to best fit the speech codec. It can remove annoying bass artefacts and make the codec speech easier to understand.
[Blog Post on Auto EQ Part 1](http://www.rowetel.com/?p=6778)
[Blog Post on Auto EQ Part 2](http://www.rowetel.com/?p=6860)
## Tools - Options
This section describes features on Tools-Options. Many of these features are also described in other parts of this manual.
### FreeDV 700 Options
Control | Description
--- | --- |
Clipping | Hard clipping of transmit waveform to increase the average power, at the expense of some distortion
700C Diversity Combine | Combining of two sets of 700C carriers for better fading channel performance
700D Interleaver | How many 700D frames to Interleave, larger leads to better fading channel performance but more latency
700D Tx Band Pass Filter | Reduces 700D TX spectrum bandwidth
700D Manual Unsync | Forces 700D to remain in sync, and not drop sync automatically
### OFDM Modem Phase Estimator Options
These options apply to the FreeDV 700D and 2020 modes that use the OFDM modem:
1. The High Bandwidth option gives better performance on channels where the phase changes quickly, for example fast fading HF channels, and the Es'Hail 2 satellite. When unchecked, the phase estimator bandwidth is automatically selected. It starts off high to enable fast sync, then switches to low bandwidth to optimise performance for low SNR HF channels.
1. The DPSK (differential PSK) checkbox has a similar effect - better performance on High SNR channels where the phase changes rapidly. This option converts the OFDM modem to use differential PSK, rather than coherent PSK. DPSK is used by earlier FreeDV modes such as FreeDV 1600. It affects the Tx and Rx side, so both sides must select DPSK.
If you problems with 700D or 2020 sync even though you have a strong signal - try these option.
## Advanced/Developer Features ## Advanced/Developer Features
### Stats Window ### Stats Window
@ -410,6 +447,7 @@ Resyncs | Number of times the demodulator has resynced
ClkOff | Estimated sample clock offset in parts per million ClkOff | Estimated sample clock offset in parts per million
FreqOff | Estimated frequency offset in Hz FreqOff | Estimated frequency offset in Hz
Sync | Sync metric (OFDM modes like 700D and 2020) Sync | Sync metric (OFDM modes like 700D and 2020)
Var | Speech encoder distortion for 700C/700D (see Auto EQ)
The sample clock offset is the estimated difference between the The sample clock offset is the estimated difference between the
modulator (tx) and demodulator (rx) sample clocks. For example if the modulator (tx) and demodulator (rx) sample clocks. For example if the
@ -561,12 +599,13 @@ LDPC | Low Density Parity Check Codes, a powerful family of FEC codes
## Release Notes ## Release Notes
### V1.4 June-August 2019 ### V1.4 June-October 2019
1. FreeDV 2020 Beta, Project Horus Binary Mode. 1. FreeDV 2020, Project Horus Binary Modes.
1. [Improved OFDM Modem Acquisition](http://www.rowetel.com/?p=6824), this will improve sync time on 1. [Improved OFDM Modem Acquisition](http://www.rowetel.com/?p=6824), this will improve sync time on FreeDV 700D and 2020 on HF fading channels, and can also handle +/- 60 Hz frequency offsets when tuning.
FreeDV 700D and 2020 on HF fading channels. We can also handle +/- 60 Hz frequency offsets now.
1. Fixed FreeDV 700C frequency offset bug fix, was losing sync at certain frequency offsets. 1. Fixed FreeDV 700C frequency offset bug fix, was losing sync at certain frequency offsets.
1. Wide bandwidth phase estimation and DPSK for OFDM modes (700D/2020) for fast fading/QO-100 channels (Tools-Options)
1. Better speech quality on FreeDV 700C/700D with Auto equaliser (Tools-Filter)
### V1.3 May 2018 ### V1.3 May 2018

View File

@ -8,10 +8,13 @@ export FREEDVGUIDIR=${PWD}
export CODEC2DIR=$FREEDVGUIDIR/codec2 export CODEC2DIR=$FREEDVGUIDIR/codec2
export LPCNETDIR=$FREEDVGUIDIR/LPCNet export LPCNETDIR=$FREEDVGUIDIR/LPCNet
# change this when working on combined codec2/freedv-gui changes
CODEC2_BRANCH=master
# First build and install vanilla codec2 as we need -lcodec2 to build LPCNet # First build and install vanilla codec2 as we need -lcodec2 to build LPCNet
cd $FREEDVGUIDIR cd $FREEDVGUIDIR
git clone https://github.com/drowe67/codec2.git git clone https://github.com/drowe67/codec2.git
cd codec2 && git checkout master && git pull cd codec2 && git checkout $CODEC2_BRANCH && git pull
mkdir -p build_linux && cd build_linux && rm -Rf * && cmake .. && make mkdir -p build_linux && cd build_linux && rm -Rf * && cmake .. && make
# OK, build and test LPCNet # OK, build and test LPCNet

View File

@ -11,9 +11,6 @@ docker-compose -f docker-compose-win.yml build
``` ```
## Running the image(s) ## Running the image(s)
```bash ```bash
export DEV_STLINK=`./get_stlink.sh`
export GIT_REF=my-super-branch
export GIT_REPO=http://github.com/dummy/codec2.git
docker-compose -f docker-compose-win.yml up docker-compose -f docker-compose-win.yml up
``` ```

View File

@ -21,7 +21,7 @@ echo "FDV_CMAKE=$CMAKE"
# OK lets get started ----------------------------------------------- # OK lets get started -----------------------------------------------
if [ ! -d freedv-gui ] ; then git clone --depth=1 $GIT_REPO ; fi if [ ! -d freedv-gui ] ; then git clone --depth=1 $GIT_REPO ; fi
cd freedv-gui && git checkout $GIT_BRANCH && git pull cd freedv-gui && git pull && git checkout $GIT_BRANCH
echo "--------------------- starting build_windows.sh ---------------------" echo "--------------------- starting build_windows.sh ---------------------"
GIT_REPO=$GIT_REPO GIT_REF=$GIT_REF CMAKE=$CMAKE ./build_windows.sh GIT_REPO=$GIT_REPO GIT_REF=$GIT_REF CMAKE=$CMAKE ./build_windows.sh
if [ $CMAKE = "mingw64-cmake" ]; then if [ $CMAKE = "mingw64-cmake" ]; then

View File

@ -44,6 +44,7 @@
#define F_MAG_N (int)(MAX_F_HZ/F_STEP_DFT) // number of frequency steps #define F_MAG_N (int)(MAX_F_HZ/F_STEP_DFT) // number of frequency steps
extern struct freedv *g_pfreedv; extern struct freedv *g_pfreedv;
extern int g_mode;
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-= //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=
// Class FilterDlg // Class FilterDlg
@ -84,12 +85,16 @@ FilterDlg::FilterDlg(wxWindow* parent, bool running, bool *newMicInFilter, bool
// Speex pre-processor -------------------------------------------------- // Speex pre-processor --------------------------------------------------
wxStaticBoxSizer* sbSizer_speexpp; wxStaticBoxSizer* sbSizer_speexpp;
wxStaticBox *sb_speexpp = new wxStaticBox(this, wxID_ANY, _("Speex Mic Audio Pre-Processor")); wxStaticBox *sb_speexpp = new wxStaticBox(this, wxID_ANY, _("Mic Audio Pre-Processing"));
sbSizer_speexpp = new wxStaticBoxSizer(sb_speexpp, wxVERTICAL); sbSizer_speexpp = new wxStaticBoxSizer(sb_speexpp, wxHORIZONTAL);
m_ckboxSpeexpp = new wxCheckBox(this, wxID_ANY, _("Enable"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE); m_ckboxSpeexpp = new wxCheckBox(this, wxID_ANY, _("Speex Noise Suppression"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
sb_speexpp->SetToolTip(_("Enable noise supression, dereverberation, AGC of mic signal"));
sbSizer_speexpp->Add(m_ckboxSpeexpp, wxALIGN_LEFT, 2); sbSizer_speexpp->Add(m_ckboxSpeexpp, wxALIGN_LEFT, 2);
m_ckboxSpeexpp->SetToolTip(_("Enable noise supression, dereverberation, AGC of mic signal"));
m_ckbox700C_EQ = new wxCheckBox(this, wxID_ANY, _("700C/700D Auto EQ"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
sbSizer_speexpp->Add(m_ckbox700C_EQ, wxALIGN_LEFT, 2);
m_ckbox700C_EQ->SetToolTip(_("Automatic equalisation for FreeDV 700C and FreeDV 700D Codec input audio"));
bSizer30->Add(sbSizer_speexpp, 0, wxALL, 0); bSizer30->Add(sbSizer_speexpp, 0, wxALL, 0);
@ -180,6 +185,7 @@ FilterDlg::FilterDlg(wxWindow* parent, bool running, bool *newMicInFilter, bool
m_LPCPostFilterDefault->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnLPCPostFilterDefault), NULL, this); m_LPCPostFilterDefault->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnLPCPostFilterDefault), NULL, this);
m_ckboxSpeexpp->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnSpeexppEnable), NULL, this); m_ckboxSpeexpp->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnSpeexppEnable), NULL, this);
m_ckbox700C_EQ->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::On700C_EQ), NULL, this);
m_MicInBass.sliderFreq->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassFreqScroll), NULL, this); m_MicInBass.sliderFreq->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassFreqScroll), NULL, this);
m_MicInBass.sliderGain->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassGainScroll), NULL, this); m_MicInBass.sliderGain->Connect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassGainScroll), NULL, this);
@ -224,6 +230,8 @@ FilterDlg::~FilterDlg()
m_codec2LPCPostFilterGamma->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnGammaScroll), NULL, this); m_codec2LPCPostFilterGamma->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnGammaScroll), NULL, this);
m_LPCPostFilterDefault->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnLPCPostFilterDefault), NULL, this); m_LPCPostFilterDefault->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FilterDlg::OnLPCPostFilterDefault), NULL, this);
m_ckboxSpeexpp->Disconnect(wxEVT_COMMAND_CHECKBOX_CLICKED, wxScrollEventHandler(FilterDlg::OnSpeexppEnable), NULL, this);
m_MicInBass.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassFreqScroll), NULL, this); m_MicInBass.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassFreqScroll), NULL, this);
m_MicInBass.sliderGain->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassGainScroll), NULL, this); m_MicInBass.sliderGain->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInBassGainScroll), NULL, this);
m_MicInTreble.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInTrebleFreqScroll), NULL, this); m_MicInTreble.sliderFreq->Disconnect(wxEVT_SCROLL_CHANGED, wxScrollEventHandler(FilterDlg::OnMicInTrebleFreqScroll), NULL, this);
@ -316,6 +324,9 @@ void FilterDlg::ExchangeData(int inout, bool storePersistent)
m_ckboxSpeexpp->SetValue(wxGetApp().m_speexpp_enable); m_ckboxSpeexpp->SetValue(wxGetApp().m_speexpp_enable);
// Codec 2 700C EQ
m_ckbox700C_EQ->SetValue(wxGetApp().m_700C_EQ);
// Mic In Equaliser // Mic In Equaliser
m_MicInBass.freqHz = wxGetApp().m_MicInBassFreqHz; m_MicInBass.freqHz = wxGetApp().m_MicInBassFreqHz;
@ -386,8 +397,10 @@ void FilterDlg::ExchangeData(int inout, bool storePersistent)
wxGetApp().m_codec2LPCPostFilterGamma = m_gamma; wxGetApp().m_codec2LPCPostFilterGamma = m_gamma;
// Speex Pre-Processor // Speex Pre-Processor
wxGetApp().m_speexpp_enable = m_ckboxSpeexpp->GetValue(); wxGetApp().m_speexpp_enable = m_ckboxSpeexpp->GetValue();
// Codec 2 700C EQ
wxGetApp().m_700C_EQ = m_ckbox700C_EQ->GetValue();
// Mic In Equaliser // Mic In Equaliser
@ -421,6 +434,8 @@ void FilterDlg::ExchangeData(int inout, bool storePersistent)
pConfig->Write(wxT("/Filter/speexpp_enable"), wxGetApp().m_speexpp_enable); pConfig->Write(wxT("/Filter/speexpp_enable"), wxGetApp().m_speexpp_enable);
pConfig->Write(wxT("/Filter/700C_EQ"), wxGetApp().m_700C_EQ);
pConfig->Write(wxT("/Filter/MicInBassFreqHz"), (int)m_MicInBass.freqHz); pConfig->Write(wxT("/Filter/MicInBassFreqHz"), (int)m_MicInBass.freqHz);
pConfig->Write(wxT("/Filter/MicInBassGaindB"), (int)(10.0*m_MicInBass.gaindB)); pConfig->Write(wxT("/Filter/MicInBassGaindB"), (int)(10.0*m_MicInBass.gaindB));
pConfig->Write(wxT("/Filter/MicInTrebleFreqHz"), (int)m_MicInTreble.freqHz); pConfig->Write(wxT("/Filter/MicInTrebleFreqHz"), (int)m_MicInTreble.freqHz);
@ -545,10 +560,13 @@ void FilterDlg::setBeta(void) {
void FilterDlg::setCodec2(void) { void FilterDlg::setCodec2(void) {
if (m_running) { if (m_running) {
codec2_set_lpc_post_filter(freedv_get_codec2(g_pfreedv), struct CODEC2 *c2 = freedv_get_codec2(g_pfreedv);
m_codec2LPCPostFilterEnable->GetValue(), if (c2 != NULL) {
m_codec2LPCPostFilterBassBoost->GetValue(), codec2_set_lpc_post_filter(c2,
m_beta, m_gamma); m_codec2LPCPostFilterEnable->GetValue(),
m_codec2LPCPostFilterBassBoost->GetValue(),
m_beta, m_gamma);
}
} }
} }
@ -586,6 +604,13 @@ void FilterDlg::OnSpeexppEnable(wxScrollEvent& event) {
wxGetApp().m_speexpp_enable = m_ckboxSpeexpp->GetValue(); wxGetApp().m_speexpp_enable = m_ckboxSpeexpp->GetValue();
} }
void FilterDlg::On700C_EQ(wxScrollEvent& event) {
wxGetApp().m_700C_EQ = m_ckbox700C_EQ->GetValue();
if (m_running && ((g_mode == FREEDV_MODE_700C) || (g_mode == FREEDV_MODE_700D))) {
freedv_set_eq(g_pfreedv, wxGetApp().m_700C_EQ);
}
}
void FilterDlg::OnMicInEnable(wxScrollEvent& event) { void FilterDlg::OnMicInEnable(wxScrollEvent& event) {
wxGetApp().m_MicInEQEnable = m_MicInEnable->GetValue(); wxGetApp().m_MicInEQEnable = m_MicInEnable->GetValue();
} }

View File

@ -91,6 +91,7 @@ class FilterDlg : public wxDialog
void OnBassBoost(wxScrollEvent& event); void OnBassBoost(wxScrollEvent& event);
void OnSpeexppEnable(wxScrollEvent& event); void OnSpeexppEnable(wxScrollEvent& event);
void On700C_EQ(wxScrollEvent& event);
void OnMicInBassFreqScroll(wxScrollEvent& event) { sliderToFreq(&m_MicInBass, true); } void OnMicInBassFreqScroll(wxScrollEvent& event) { sliderToFreq(&m_MicInBass, true); }
void OnMicInBassGainScroll(wxScrollEvent& event) { sliderToGain(&m_MicInBass, true); } void OnMicInBassGainScroll(wxScrollEvent& event) { sliderToGain(&m_MicInBass, true); }
@ -125,7 +126,8 @@ class FilterDlg : public wxDialog
wxButton* m_LPCPostFilterDefault; wxButton* m_LPCPostFilterDefault;
wxCheckBox* m_ckboxSpeexpp; wxCheckBox* m_ckboxSpeexpp;
wxCheckBox* m_ckbox700C_EQ;
wxStdDialogButtonSizer* m_sdbSizer5; wxStdDialogButtonSizer* m_sdbSizer5;
wxButton* m_sdbSizer5OK; wxButton* m_sdbSizer5OK;
wxButton* m_sdbSizer5Cancel; wxButton* m_sdbSizer5Cancel;

View File

@ -115,6 +115,21 @@ OptionsDlg::OptionsDlg(wxWindow* parent, wxWindowID id, const wxString& title, c
bSizer30->Add(sbSizer_freedv700, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3); bSizer30->Add(sbSizer_freedv700, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
//------------------------------
// Phase Est Options
//------------------------------
wxStaticBoxSizer* sbSizer_freedvPhaseEst;
wxStaticBox *sb_freedvPhaseEst = new wxStaticBox(this, wxID_ANY, _("OFDM Modem Phase Estimator Options"));
sbSizer_freedvPhaseEst = new wxStaticBoxSizer(sb_freedvPhaseEst, wxHORIZONTAL);
m_ckboxPhaseEstBW = new wxCheckBox(this, wxID_ANY, _("High Bandwidth"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
sbSizer_freedvPhaseEst->Add(m_ckboxPhaseEstBW, 0, wxALIGN_LEFT, 0);
m_ckboxPhaseEstDPSK = new wxCheckBox(this, wxID_ANY, _("DPSK"), wxDefaultPosition, wxDefaultSize, wxCHK_2STATE);
sbSizer_freedvPhaseEst->Add(m_ckboxPhaseEstDPSK, 0, wxALIGN_LEFT, 0);
bSizer30->Add(sbSizer_freedvPhaseEst, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);
//------------------------------ //------------------------------
// Half/Full duplex selection // Half/Full duplex selection
//------------------------------ //------------------------------
@ -489,6 +504,9 @@ void OptionsDlg::ExchangeData(int inout, bool storePersistent)
m_txtInterleave->SetValue(wxString::Format(wxT("%i"),wxGetApp().m_FreeDV700Interleave)); m_txtInterleave->SetValue(wxString::Format(wxT("%i"),wxGetApp().m_FreeDV700Interleave));
m_ckboxFreeDV700ManualUnSync->SetValue(wxGetApp().m_FreeDV700ManualUnSync); m_ckboxFreeDV700ManualUnSync->SetValue(wxGetApp().m_FreeDV700ManualUnSync);
m_ckboxPhaseEstBW->SetValue(wxGetApp().m_PhaseEstBW);
m_ckboxPhaseEstDPSK->SetValue(wxGetApp().m_PhaseEstDPSK);
#ifdef __WXMSW__ #ifdef __WXMSW__
m_ckboxDebugConsole->SetValue(wxGetApp().m_debug_console); m_ckboxDebugConsole->SetValue(wxGetApp().m_debug_console);
#endif #endif
@ -593,6 +611,9 @@ void OptionsDlg::ExchangeData(int inout, bool storePersistent)
wxGetApp().m_FreeDV700Interleave = (int)interleave; wxGetApp().m_FreeDV700Interleave = (int)interleave;
wxGetApp().m_FreeDV700ManualUnSync = m_ckboxFreeDV700ManualUnSync->GetValue(); wxGetApp().m_FreeDV700ManualUnSync = m_ckboxFreeDV700ManualUnSync->GetValue();
wxGetApp().m_PhaseEstBW = m_ckboxPhaseEstBW->GetValue();
wxGetApp().m_PhaseEstDPSK = m_ckboxPhaseEstDPSK->GetValue();
#ifdef __WXMSW__ #ifdef __WXMSW__
wxGetApp().m_debug_console = m_ckboxDebugConsole->GetValue(); wxGetApp().m_debug_console = m_ckboxDebugConsole->GetValue();
#endif #endif

View File

@ -114,6 +114,9 @@ class OptionsDlg : public wxDialog
wxTextCtrl *m_txtInterleave; wxTextCtrl *m_txtInterleave;
wxCheckBox *m_ckboxFreeDV700ManualUnSync; wxCheckBox *m_ckboxFreeDV700ManualUnSync;
wxCheckBox *m_ckboxPhaseEstBW;
wxCheckBox *m_ckboxPhaseEstDPSK;
wxRadioButton *m_rb_textEncoding1; wxRadioButton *m_rb_textEncoding1;
wxRadioButton *m_rb_textEncoding2; wxRadioButton *m_rb_textEncoding2;
wxCheckBox *m_ckboxEnableChecksum; wxCheckBox *m_ckboxEnableChecksum;

View File

@ -501,6 +501,7 @@ MainFrame::MainFrame(wxString plugInName, wxWindow *parent) : TopFrame(plugInNam
//printf("main(): m_codec2LPCPostFilterBeta: %f\n", wxGetApp().m_codec2LPCPostFilterBeta); //printf("main(): m_codec2LPCPostFilterBeta: %f\n", wxGetApp().m_codec2LPCPostFilterBeta);
wxGetApp().m_speexpp_enable = pConfig->Read(wxT("/Filter/speexpp_enable"), t); wxGetApp().m_speexpp_enable = pConfig->Read(wxT("/Filter/speexpp_enable"), t);
wxGetApp().m_700C_EQ = pConfig->Read(wxT("/Filter/700C_EQ"), t);
wxGetApp().m_MicInBassFreqHz = (float)pConfig->Read(wxT("/Filter/MicInBassFreqHz"), 1); wxGetApp().m_MicInBassFreqHz = (float)pConfig->Read(wxT("/Filter/MicInBassFreqHz"), 1);
wxGetApp().m_MicInBassGaindB = (float)pConfig->Read(wxT("/Filter/MicInBassGaindB"), (long)0)/10.0; wxGetApp().m_MicInBassGaindB = (float)pConfig->Read(wxT("/Filter/MicInBassGaindB"), (long)0)/10.0;
@ -550,6 +551,9 @@ MainFrame::MainFrame(wxString plugInName, wxWindow *parent) : TopFrame(plugInNam
wxGetApp().m_FreeDV700Interleave = (int)pConfig->Read(wxT("/FreeDV700/interleave"), 1); wxGetApp().m_FreeDV700Interleave = (int)pConfig->Read(wxT("/FreeDV700/interleave"), 1);
wxGetApp().m_FreeDV700ManualUnSync = (float)pConfig->Read(wxT("/FreeDV700/manualUnSync"), f); wxGetApp().m_FreeDV700ManualUnSync = (float)pConfig->Read(wxT("/FreeDV700/manualUnSync"), f);
wxGetApp().m_PhaseEstBW = (float)pConfig->Read(wxT("/OFDM/PhaseEstBW"), f);
wxGetApp().m_PhaseEstDPSK = (float)pConfig->Read(wxT("/OFDM/PhaseEstDPSK"), f);
wxGetApp().m_noise_snr = (float)pConfig->Read(wxT("/Noise/noise_snr"), 2); wxGetApp().m_noise_snr = (float)pConfig->Read(wxT("/Noise/noise_snr"), 2);
wxGetApp().m_debug_console = (float)pConfig->Read(wxT("/Debug/console"), f); wxGetApp().m_debug_console = (float)pConfig->Read(wxT("/Debug/console"), f);
@ -814,6 +818,8 @@ MainFrame::~MainFrame()
pConfig->Write(wxT("/Filter/SpkOutEQEnable"), wxGetApp().m_SpkOutEQEnable); pConfig->Write(wxT("/Filter/SpkOutEQEnable"), wxGetApp().m_SpkOutEQEnable);
pConfig->Write(wxT("/FreeDV700/txClip"), wxGetApp().m_FreeDV700txClip); pConfig->Write(wxT("/FreeDV700/txClip"), wxGetApp().m_FreeDV700txClip);
pConfig->Write(wxT("/OFDM/PhaseEstBW"), wxGetApp().m_PhaseEstBW);
pConfig->Write(wxT("/OFDM/PhaseEstDPSK"), wxGetApp().m_PhaseEstDPSK);
pConfig->Write(wxT("/Noise/noise_snr"), wxGetApp().m_noise_snr); pConfig->Write(wxT("/Noise/noise_snr"), wxGetApp().m_noise_snr);
pConfig->Write(wxT("/Debug/console"), wxGetApp().m_debug_console); pConfig->Write(wxT("/Debug/console"), wxGetApp().m_debug_console);
@ -1241,11 +1247,13 @@ void MainFrame::OnTimer(wxTimerEvent &evt)
//wxString clockoffset_string(clockoffset); m_textClockOffset->SetLabel(clockoffset_string); //wxString clockoffset_string(clockoffset); m_textClockOffset->SetLabel(clockoffset_string);
} }
else { else {
// Run time update of FreeDV 700 tx clipper and 700D BPF // set some run time options (if applicable to this mode)
freedv_set_clip(g_pfreedv, (int)wxGetApp().m_FreeDV700txClip); freedv_set_clip(g_pfreedv, (int)wxGetApp().m_FreeDV700txClip); // 700C/700D/2020
freedv_set_tx_bpf(g_pfreedv, (int)wxGetApp().m_FreeDV700txBPF); freedv_set_tx_bpf(g_pfreedv, (int)wxGetApp().m_FreeDV700txBPF); // 700D
freedv_set_phase_est_bandwidth_mode(g_pfreedv, (int)wxGetApp().m_PhaseEstBW); // 700D/2020
freedv_set_dpsk(g_pfreedv, (int)wxGetApp().m_PhaseEstDPSK); // 700D/2020
// Test Frame Bit Error Updates ------------------------------------ // Test Frame Bit Error Updates ------------------------------------
// Toggle test frame mode at run time // Toggle test frame mode at run time
@ -1275,6 +1283,15 @@ void MainFrame::OnTimer(wxTimerEvent &evt)
wxString freqoffset_string(freqoffset); m_textFreqOffset->SetLabel(freqoffset_string); wxString freqoffset_string(freqoffset); m_textFreqOffset->SetLabel(freqoffset_string);
sprintf(syncmetric, "Sync: %3.2f", g_stats.sync_metric); sprintf(syncmetric, "Sync: %3.2f", g_stats.sync_metric);
wxString syncmetric_string(syncmetric); m_textSyncMetric->SetLabel(syncmetric_string); wxString syncmetric_string(syncmetric); m_textSyncMetric->SetLabel(syncmetric_string);
// Codec 2 700C VQ "auto EQ" equaliser variance
if ((g_mode == FREEDV_MODE_700C) || (g_mode == FREEDV_MODE_700D)) {
struct CODEC2 *c2 = freedv_get_codec2(g_pfreedv);
assert(c2 != NULL);
float var = codec2_get_var(c2);
char var_str[80]; sprintf(var_str, "Var: %4.1f", var);
wxString var_string(var_str); m_textCodec2Var->SetLabel(var_string);
}
if (g_State) { if (g_State) {
@ -1949,6 +1966,8 @@ void MainFrame::OnBerReset(wxCommandEvent& event)
g_error_hist[i] = 0; g_error_hist[i] = 0;
g_error_histn[i] = 0; g_error_histn[i] = 0;
} }
// resets variance stats every time it is called
freedv_set_eq(g_pfreedv, wxGetApp().m_700C_EQ);
} }
} }
} }
@ -2072,7 +2091,7 @@ void MainFrame::OnPlayFileFromRadio(wxCommandEvent& event)
printf("OnPlayFileFromRadio:: %d\n", (int)g_playFileFromRadio); printf("OnPlayFileFromRadio:: %d\n", (int)g_playFileFromRadio);
if (g_playFileFromRadio) if (g_playFileFromRadio)
{ {
printf("OnPlayFileFromRadio:: Stop\n"); fprintf(stderr, "OnPlayFileFromRadio:: Stop\n");
g_mutexProtectingCallbackData.Lock(); g_mutexProtectingCallbackData.Lock();
g_playFileFromRadio = false; g_playFileFromRadio = false;
sf_close(g_sfPlayFileFromRadio); sf_close(g_sfPlayFileFromRadio);
@ -2177,7 +2196,7 @@ void MainFrame::OnRecFileFromRadio(wxCommandEvent& event)
wxUnusedVar(event); wxUnusedVar(event);
if (g_recFileFromRadio) { if (g_recFileFromRadio) {
printf("Stopping Record....\n"); fprintf(stderr, "Stopping Record....\n");
g_mutexProtectingCallbackData.Lock(); g_mutexProtectingCallbackData.Lock();
g_recFileFromRadio = false; g_recFileFromRadio = false;
sf_close(g_sfRecFile); sf_close(g_sfRecFile);
@ -2607,6 +2626,7 @@ void MainFrame::OnTogBtnOnOff(wxCommandEvent& event)
if (startStop.IsSameAs("Start")) if (startStop.IsSameAs("Start"))
{ {
fprintf(stderr, "Start .....\n");
// //
// Start Running ------------------------------------------------- // Start Running -------------------------------------------------
// //
@ -2672,6 +2692,7 @@ void MainFrame::OnTogBtnOnOff(wxCommandEvent& event)
m_textSync->Disable(); m_textSync->Disable();
m_textInterleaverSync->SetLabel(""); m_textInterleaverSync->SetLabel("");
g_modemInbufferSize = (int)(FRAME_DURATION * horus_get_Fs(g_horus));
} }
if (m_rb2020->GetValue() && isAvxPresent) { if (m_rb2020->GetValue() && isAvxPresent) {
g_mode = FREEDV_MODE_2020; g_mode = FREEDV_MODE_2020;
@ -2703,6 +2724,11 @@ void MainFrame::OnTogBtnOnOff(wxCommandEvent& event)
m_textInterleaverSync->SetLabel(""); m_textInterleaverSync->SetLabel("");
} }
// Codec 2 VQ Equaliser
if ((g_mode == FREEDV_MODE_700C) || (g_mode == FREEDV_MODE_700D)) {
freedv_set_eq(g_pfreedv, wxGetApp().m_700C_EQ);
}
if (g_freedv_verbose) if (g_freedv_verbose)
freedv_set_verbose(g_pfreedv, 2); freedv_set_verbose(g_pfreedv, 2);
else else
@ -2819,7 +2845,7 @@ void MainFrame::OnTogBtnOnOff(wxCommandEvent& event)
// Stop was pressed or start up failed // Stop was pressed or start up failed
if (startStop.IsSameAs("Stop") || !m_RxRunning ) { if (startStop.IsSameAs("Stop") || !m_RxRunning ) {
fprintf(stderr, "Stop .....\n");
// //
// Stop Running ------------------------------------------------- // Stop Running -------------------------------------------------
// //
@ -3024,9 +3050,9 @@ void MainFrame::startRxStream()
bool two_rx=false; bool two_rx=false;
bool two_tx=false; bool two_tx=false;
fprintf(stderr, "startRxStream .....\n");
if(!m_RxRunning) { if(!m_RxRunning) {
m_RxRunning = true; m_RxRunning = true;
if(Pa_Initialize()) if(Pa_Initialize())
{ {
wxMessageBox(wxT("Port Audio failed to initialize"), wxT("Pa_Initialize"), wxOK); wxMessageBox(wxT("Port Audio failed to initialize"), wxT("Pa_Initialize"), wxOK);
@ -3038,7 +3064,7 @@ void MainFrame::startRxStream()
if(g_soundCard2InDeviceNum != g_soundCard2OutDeviceNum) if(g_soundCard2InDeviceNum != g_soundCard2OutDeviceNum)
two_tx=true; two_tx=true;
//fprintf(stderr, "two_rx: %d two_tx: %d\n", two_rx, two_tx); fprintf(stderr, "two_rx: %d two_tx: %d\n", two_rx, two_tx);
if(two_rx) if(two_rx)
m_rxOutPa = new PortAudioWrap(); m_rxOutPa = new PortAudioWrap();
else else
@ -3061,7 +3087,7 @@ void MainFrame::startRxStream()
wxMessageBox(wxT("Sound Card 1 not present"), wxT("Error"), wxOK); wxMessageBox(wxT("Sound Card 1 not present"), wxT("Error"), wxOK);
delete m_rxInPa; delete m_rxInPa;
if(two_rx) if(two_rx)
delete m_rxOutPa; delete m_rxOutPa;
m_RxRunning = false; m_RxRunning = false;
return; return;
} }
@ -3322,6 +3348,8 @@ void MainFrame::startRxStream()
} }
} }
fprintf(stderr, "started stream 1\n");
// Start sound card 2 ---------------------------------------------------------- // Start sound card 2 ----------------------------------------------------------
if (g_nSoundCards == 2) { if (g_nSoundCards == 2) {
@ -3437,6 +3465,8 @@ void MainFrame::startRxStream()
} }
} }
fprintf(stderr, "starting tx/rx processing thread\n");
// start tx/rx processing thread // start tx/rx processing thread
m_txRxThread = new txRxThread; m_txRxThread = new txRxThread;
@ -3735,9 +3765,10 @@ void txRxProcessing()
// (20ms), number of samples is scaled for the sound card sample // (20ms), number of samples is scaled for the sound card sample
// rate, so we get the right number of samples for the output // rate, so we get the right number of samples for the output
// decoded audio // decoded audio
int nsam = g_soundCard1SampleRate * (float)g_modemInbufferSize/freedv_samplerate; int nsam = g_soundCard1SampleRate * (float)g_modemInbufferSize/freedv_samplerate;
assert(nsam <= 10*N48); assert(nsam <= 10*N48);
assert(nsam != 0);
while ((codec2_fifo_read(cbData->infifo1, insound_card, nsam) == 0) && ((g_half_duplex && !g_tx) || !g_half_duplex)) { while ((codec2_fifo_read(cbData->infifo1, insound_card, nsam) == 0) && ((g_half_duplex && !g_tx) || !g_half_duplex)) {
/* convert sound card sample rate FreeDV input sample rate */ /* convert sound card sample rate FreeDV input sample rate */
@ -3895,13 +3926,27 @@ void txRxProcessing()
codec2_fifo_write(cbData->outfifo1, outsound_card, nout); codec2_fifo_write(cbData->outfifo1, outsound_card, nout);
} }
else { else {
nout = resample(cbData->outsrc2, outsound_card, outfreedv, g_soundCard1SampleRate, freedv_get_speech_sample_rate(g_pfreedv), N48, g_speechOutbufferSize); if (g_analog) /* special case */
nout = resample(cbData->outsrc2, outsound_card, outfreedv, g_soundCard1SampleRate, freedv_get_modem_sample_rate(g_pfreedv), N48, nfreedv);
else
nout = resample(cbData->outsrc2, outsound_card, outfreedv, g_soundCard1SampleRate, freedv_get_speech_sample_rate(g_pfreedv), N48, g_speechOutbufferSize);
codec2_fifo_write(cbData->outfifo1, outsound_card, nout); codec2_fifo_write(cbData->outfifo1, outsound_card, nout);
} }
} }
else { else {
nout = resample(cbData->outsrc2, outsound_card, outfreedv, g_soundCard2SampleRate, freedv_get_speech_sample_rate(g_pfreedv), N48, g_speechOutbufferSize); if (g_mode == -1) {
codec2_fifo_write(cbData->outfifo2, outsound_card, nout); // Horus demod is special case, just echo input samples as it's nice to hear the
// off-air modem signal
nout = resample(cbData->outsrc2, outsound_card, infreedv, g_soundCard1SampleRate, freedv_samplerate, N48, nfreedv);
codec2_fifo_write(cbData->outfifo2, outsound_card, nout);
}
else {
if (g_analog) /* special case */
nout = resample(cbData->outsrc2, outsound_card, outfreedv, g_soundCard2SampleRate, freedv_get_modem_sample_rate(g_pfreedv), N48, nfreedv);
else
nout = resample(cbData->outsrc2, outsound_card, outfreedv, g_soundCard2SampleRate, freedv_get_speech_sample_rate(g_pfreedv), N48, g_speechOutbufferSize);
codec2_fifo_write(cbData->outfifo2, outsound_card, nout);
}
} }
} }
@ -4041,7 +4086,10 @@ void txRxProcessing()
// output one frame of modem signal // output one frame of modem signal
nout = resample(cbData->outsrc1, outsound_card, outfreedv, g_soundCard1SampleRate, freedv_samplerate, 10*N48, nfreedv); if (g_analog)
nout = resample(cbData->outsrc1, outsound_card, outfreedv, g_soundCard1SampleRate, freedv_get_speech_sample_rate(g_pfreedv), 10*N48, nfreedv);
else
nout = resample(cbData->outsrc1, outsound_card, outfreedv, g_soundCard1SampleRate, freedv_samplerate, 10*N48, nfreedv);
if (g_dump_fifo_state) { if (g_dump_fifo_state) {
fprintf(stderr, " nout: %d\n", nout); fprintf(stderr, " nout: %d\n", nout);
} }
@ -4054,7 +4102,6 @@ void txRxProcessing()
if (g_dump_timing) { if (g_dump_timing) {
fprintf(stderr, "%4ld", sw.Time()); fprintf(stderr, "%4ld", sw.Time());
} }
} }
//---------------------------------------------------------------- //----------------------------------------------------------------

View File

@ -228,6 +228,8 @@ class MainApp : public wxApp
// Speex Pre-Processor // Speex Pre-Processor
bool m_speexpp_enable; bool m_speexpp_enable;
// Codec 2 700C Equaliser
bool m_700C_EQ;
// Mic In Equaliser // Mic In Equaliser
float m_MicInBassFreqHz; float m_MicInBassFreqHz;
@ -311,6 +313,9 @@ class MainApp : public wxApp
bool m_FreeDV700Combine; bool m_FreeDV700Combine;
int m_FreeDV700Interleave; int m_FreeDV700Interleave;
bool m_FreeDV700ManualUnSync; bool m_FreeDV700ManualUnSync;
bool m_PhaseEstBW;
bool m_PhaseEstDPSK;
// Noise simulation // Noise simulation

View File

@ -187,6 +187,8 @@ TopFrame::TopFrame(wxString plugInName, wxWindow* parent, wxWindowID id, const w
sbSizer_ber->Add(m_textFreqOffset, 0, wxALIGN_LEFT, 1); sbSizer_ber->Add(m_textFreqOffset, 0, wxALIGN_LEFT, 1);
m_textSyncMetric = new wxStaticText(this, wxID_ANY, wxT("Sync: 0"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); m_textSyncMetric = new wxStaticText(this, wxID_ANY, wxT("Sync: 0"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
sbSizer_ber->Add(m_textSyncMetric, 0, wxALIGN_LEFT, 1); sbSizer_ber->Add(m_textSyncMetric, 0, wxALIGN_LEFT, 1);
m_textCodec2Var = new wxStaticText(this, wxID_ANY, wxT("Var: 0"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
sbSizer_ber->Add(m_textCodec2Var, 0, wxALIGN_LEFT, 1);
leftSizer->Add(sbSizer_ber,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3); leftSizer->Add(sbSizer_ber,0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 3);

View File

@ -106,6 +106,7 @@ class TopFrame : public wxFrame
wxStaticText *m_textClockOffset; wxStaticText *m_textClockOffset;
wxStaticText *m_textFreqOffset; wxStaticText *m_textFreqOffset;
wxStaticText *m_textSyncMetric; wxStaticText *m_textSyncMetric;
wxStaticText *m_textCodec2Var;
wxStaticText *m_textSync; wxStaticText *m_textSync;
wxStaticText *m_textInterleaverSync; wxStaticText *m_textInterleaverSync;