Fix stuttering during EOO TX. (#780)
* Prevent EOO from being repeatedly sent during TX stop. * Make sure we don't accidentally overflow the output FIFO when transmitting EOO. * Add additional logging to verify EOO behavior. * Fix issue preventing EOO from being sent on voice keyer completion. * Scale EOO the same as the primary waveform. * Remove #ifdef code per PR comment. * Use main branch for RADE.pull/788/head
parent
2b2a1a6d7a
commit
7d88772dd9
|
@ -13,7 +13,7 @@ ExternalProject_Add(build_rade
|
||||||
SOURCE_DIR rade_src
|
SOURCE_DIR rade_src
|
||||||
BINARY_DIR rade_build
|
BINARY_DIR rade_build
|
||||||
GIT_REPOSITORY https://github.com/drowe67/radae.git
|
GIT_REPOSITORY https://github.com/drowe67/radae.git
|
||||||
GIT_TAG dr-cport
|
GIT_TAG main
|
||||||
CMAKE_ARGS ${RADE_CMAKE_ARGS}
|
CMAKE_ARGS ${RADE_CMAKE_ARGS}
|
||||||
#CMAKE_CACHE_ARGS -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}
|
#CMAKE_CACHE_ARGS -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=${CMAKE_OSX_DEPLOYMENT_TARGET}
|
||||||
INSTALL_COMMAND ""
|
INSTALL_COMMAND ""
|
||||||
|
|
|
@ -907,6 +907,7 @@ void MainFrame::togglePTT(void) {
|
||||||
auto diff = highResClock.now() - before;
|
auto diff = highResClock.now() - before;
|
||||||
if (diff >= std::chrono::milliseconds(1000) || (g_outfifo1_empty != sample))
|
if (diff >= std::chrono::milliseconds(1000) || (g_outfifo1_empty != sample))
|
||||||
{
|
{
|
||||||
|
log_info("All TX finished, going out of PTT");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include "codec2_fifo.h"
|
#include "codec2_fifo.h"
|
||||||
#include "RADETransmitStep.h"
|
#include "RADETransmitStep.h"
|
||||||
|
|
||||||
|
const int RADE_SCALING_FACTOR = 16383;
|
||||||
|
|
||||||
extern wxString utTxFeatureFile;
|
extern wxString utTxFeatureFile;
|
||||||
|
|
||||||
RADETransmitStep::RADETransmitStep(struct rade* dv, LPCNetEncState* encState)
|
RADETransmitStep::RADETransmitStep(struct rade* dv, LPCNetEncState* encState)
|
||||||
|
@ -80,6 +82,23 @@ std::shared_ptr<short> RADETransmitStep::execute(std::shared_ptr<short> inputSam
|
||||||
{
|
{
|
||||||
short* outputSamples = nullptr;
|
short* outputSamples = nullptr;
|
||||||
*numOutputSamples = 0;
|
*numOutputSamples = 0;
|
||||||
|
|
||||||
|
if (numInputSamples == 0)
|
||||||
|
{
|
||||||
|
// Special case logic for EOO -- make sure we only send 20ms worth at a time
|
||||||
|
*numOutputSamples = std::min(codec2_fifo_used(outputSampleFifo_), (int)(RADE_MODEM_SAMPLE_RATE * .02));
|
||||||
|
if (*numOutputSamples > 0)
|
||||||
|
{
|
||||||
|
outputSamples = new short[*numOutputSamples];
|
||||||
|
assert(outputSamples != nullptr);
|
||||||
|
|
||||||
|
codec2_fifo_read(outputSampleFifo_, outputSamples, *numOutputSamples);
|
||||||
|
|
||||||
|
log_info("Returning %d EOO samples (remaining in FIFO: %d)", *numOutputSamples, codec2_fifo_used(outputSampleFifo_));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::shared_ptr<short>(outputSamples, std::default_delete<short[]>());;
|
||||||
|
}
|
||||||
|
|
||||||
short* inputPtr = inputSamples.get();
|
short* inputPtr = inputSamples.get();
|
||||||
while (numInputSamples > 0 && inputPtr != nullptr)
|
while (numInputSamples > 0 && inputPtr != nullptr)
|
||||||
|
@ -123,7 +142,7 @@ std::shared_ptr<short> RADETransmitStep::execute(std::shared_ptr<short> inputSam
|
||||||
for (int index = 0; index < numOutputSamples; index++)
|
for (int index = 0; index < numOutputSamples; index++)
|
||||||
{
|
{
|
||||||
// We only need the real component for TX.
|
// We only need the real component for TX.
|
||||||
radeOutShort[index] = radeOut[index].real * 16383;
|
radeOutShort[index] = radeOut[index].real * RADE_SCALING_FACTOR;
|
||||||
}
|
}
|
||||||
codec2_fifo_write(outputSampleFifo_, radeOutShort, numOutputSamples);
|
codec2_fifo_write(outputSampleFifo_, radeOutShort, numOutputSamples);
|
||||||
}
|
}
|
||||||
|
@ -153,8 +172,12 @@ void RADETransmitStep::restartVocoder()
|
||||||
|
|
||||||
for (int index = 0; index < numEOOSamples; index++)
|
for (int index = 0; index < numEOOSamples; index++)
|
||||||
{
|
{
|
||||||
eooOutShort[index] = eooOut[index].real * 32767;
|
eooOutShort[index] = eooOut[index].real * RADE_SCALING_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
codec2_fifo_write(outputSampleFifo_, eooOutShort, numEOOSamples);
|
log_info("Queueing %d EOO samples to output FIFO", numEOOSamples);
|
||||||
|
if (codec2_fifo_write(outputSampleFifo_, eooOutShort, numEOOSamples) != 0)
|
||||||
|
{
|
||||||
|
log_warn("Could not queue EOO samples (remaining space in FIFO = %d)", codec2_fifo_free(outputSampleFifo_));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -267,15 +267,6 @@ void TxRxThread::initializePipeline_()
|
||||||
// TX attenuation step
|
// TX attenuation step
|
||||||
auto txAttenuationStep = new LevelAdjustStep(outputSampleRate_, []() {
|
auto txAttenuationStep = new LevelAdjustStep(outputSampleRate_, []() {
|
||||||
double dbLoss = g_txLevel / 10.0;
|
double dbLoss = g_txLevel / 10.0;
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (freedvInterface.getTxMode() == FREEDV_MODE_RADE)
|
|
||||||
{
|
|
||||||
// Attenuate by 4 dB as there's no BPF; anything louder distorts the signal
|
|
||||||
dbLoss -= 4.0;
|
|
||||||
}
|
|
||||||
#endif // 0
|
|
||||||
|
|
||||||
double scaleFactor = exp(dbLoss/20.0 * log(10.0));
|
double scaleFactor = exp(dbLoss/20.0 * log(10.0));
|
||||||
return scaleFactor;
|
return scaleFactor;
|
||||||
});
|
});
|
||||||
|
@ -653,22 +644,33 @@ void TxRxThread::txProcessing_()
|
||||||
{
|
{
|
||||||
if (freedvInterface.getCurrentMode() >= FREEDV_MODE_RADE)
|
if (freedvInterface.getCurrentMode() >= FREEDV_MODE_RADE)
|
||||||
{
|
{
|
||||||
// Special case for handling RADE EOT
|
if (!hasEooBeenSent_)
|
||||||
freedvInterface.restartTxVocoder();
|
{
|
||||||
|
log_info("Triggering sending of EOO");
|
||||||
|
|
||||||
|
// Special case for handling RADE EOT
|
||||||
|
freedvInterface.restartTxVocoder();
|
||||||
|
hasEooBeenSent_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
short* inputSamples = new short[1];
|
short* inputSamples = new short[1];
|
||||||
auto inputSamplesPtr = std::shared_ptr<short>(inputSamples, std::default_delete<short[]>());
|
auto inputSamplesPtr = std::shared_ptr<short>(inputSamples, std::default_delete<short[]>());
|
||||||
do
|
auto outputSamples = pipeline_->execute(inputSamplesPtr, 0, &nout);
|
||||||
|
if (nout > 0 && outputSamples.get() != nullptr)
|
||||||
{
|
{
|
||||||
auto outputSamples = pipeline_->execute(inputSamplesPtr, 0, &nout);
|
log_debug("Injecting %d samples of resampled EOO into TX stream", nout);
|
||||||
if (nout > 0 && outputSamples.get() != nullptr)
|
if (codec2_fifo_write(cbData->outfifo1, outputSamples.get(), nout) != 0)
|
||||||
{
|
{
|
||||||
codec2_fifo_write(cbData->outfifo1, outputSamples.get(), nout);
|
log_warn("Could not inject resampled EOO samples (space remaining in FIFO = %d)", cbData->outfifo1);
|
||||||
}
|
}
|
||||||
} while (nout > 0);
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hasEooBeenSent_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
short* inputSamples = new short[nsam_in_48];
|
short* inputSamples = new short[nsam_in_48];
|
||||||
memcpy(inputSamples, insound_card, nsam_in_48 * sizeof(short));
|
memcpy(inputSamples, insound_card, nsam_in_48 * sizeof(short));
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
, inputSampleRate_(inputSampleRate)
|
, inputSampleRate_(inputSampleRate)
|
||||||
, outputSampleRate_(outputSampleRate)
|
, outputSampleRate_(outputSampleRate)
|
||||||
, equalizedMicAudioLink_(micAudioLink)
|
, equalizedMicAudioLink_(micAudioLink)
|
||||||
|
, hasEooBeenSent_(false)
|
||||||
{
|
{
|
||||||
assert(inputSampleRate_ > 0);
|
assert(inputSampleRate_ > 0);
|
||||||
assert(outputSampleRate_ > 0);
|
assert(outputSampleRate_ > 0);
|
||||||
|
@ -72,6 +73,7 @@ private:
|
||||||
int inputSampleRate_;
|
int inputSampleRate_;
|
||||||
int outputSampleRate_;
|
int outputSampleRate_;
|
||||||
LinkStep* equalizedMicAudioLink_;
|
LinkStep* equalizedMicAudioLink_;
|
||||||
|
bool hasEooBeenSent_;
|
||||||
|
|
||||||
void initializePipeline_();
|
void initializePipeline_();
|
||||||
void txProcessing_();
|
void txProcessing_();
|
||||||
|
|
|
@ -11,6 +11,7 @@ extern SNDFILE *g_sfRecMicFile;
|
||||||
bool g_recVoiceKeyerFile;
|
bool g_recVoiceKeyerFile;
|
||||||
extern bool g_voice_keyer_tx;
|
extern bool g_voice_keyer_tx;
|
||||||
extern wxMutex g_mutexProtectingCallbackData;
|
extern wxMutex g_mutexProtectingCallbackData;
|
||||||
|
extern bool endingTx;
|
||||||
|
|
||||||
void MainFrame::OnTogBtnVoiceKeyerClick (wxCommandEvent& event)
|
void MainFrame::OnTogBtnVoiceKeyerClick (wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
|
@ -283,6 +284,7 @@ void MainFrame::VoiceKeyerProcessEvent(int vk_event) {
|
||||||
if (vk_event == VK_SPACE_BAR) {
|
if (vk_event == VK_SPACE_BAR) {
|
||||||
m_btnTogPTT->SetValue(false);
|
m_btnTogPTT->SetValue(false);
|
||||||
m_btnTogPTT->SetBackgroundColour(wxNullColour);
|
m_btnTogPTT->SetBackgroundColour(wxNullColour);
|
||||||
|
endingTx = true;
|
||||||
togglePTT();
|
togglePTT();
|
||||||
m_togBtnVoiceKeyer->SetValue(false);
|
m_togBtnVoiceKeyer->SetValue(false);
|
||||||
m_togBtnVoiceKeyer->SetBackgroundColour(wxNullColour);
|
m_togBtnVoiceKeyer->SetBackgroundColour(wxNullColour);
|
||||||
|
@ -293,7 +295,8 @@ void MainFrame::VoiceKeyerProcessEvent(int vk_event) {
|
||||||
if (vk_event == VK_PLAY_FINISHED) {
|
if (vk_event == VK_PLAY_FINISHED) {
|
||||||
m_btnTogPTT->SetValue(false);
|
m_btnTogPTT->SetValue(false);
|
||||||
m_btnTogPTT->SetBackgroundColour(wxNullColour);
|
m_btnTogPTT->SetBackgroundColour(wxNullColour);
|
||||||
togglePTT();
|
endingTx = true;
|
||||||
|
CallAfter([&]() { togglePTT(); });
|
||||||
vk_repeat_counter++;
|
vk_repeat_counter++;
|
||||||
if (vk_repeat_counter > vk_repeats) {
|
if (vk_repeat_counter > vk_repeats) {
|
||||||
m_togBtnVoiceKeyer->SetValue(false);
|
m_togBtnVoiceKeyer->SetValue(false);
|
||||||
|
@ -371,6 +374,7 @@ void MainFrame::VoiceKeyerProcessEvent(int vk_event) {
|
||||||
|
|
||||||
m_btnTogPTT->SetValue(false);
|
m_btnTogPTT->SetValue(false);
|
||||||
m_btnTogPTT->SetBackgroundColour(wxNullColour);
|
m_btnTogPTT->SetBackgroundColour(wxNullColour);
|
||||||
|
endingTx = true;
|
||||||
togglePTT();
|
togglePTT();
|
||||||
m_togBtnVoiceKeyer->SetValue(false);
|
m_togBtnVoiceKeyer->SetValue(false);
|
||||||
m_togBtnVoiceKeyer->SetBackgroundColour(wxNullColour);
|
m_togBtnVoiceKeyer->SetBackgroundColour(wxNullColour);
|
||||||
|
|
Loading…
Reference in New Issue