Various code changes to reduce dropouts/pipeline execution jitter. (#949)

* Experimental changes to resampling to reduce pipeline execution jitter.

* Cap the number of times through the TX and RX loops.

* Faster resampler for ComputeRfSpectrum step (RX only).

* Ensure we're not overrunning FIFOs on RX.

* Force all Linux tests to run to see how many end up failing now.

* Fix RADE reporting test failures.

* Revert "Force all Linux tests to run to see how many end up failing now."

This reverts commit 6ba267b758.

* Only try processing FRAME_DURATION ms at a time for TX.

* Fix intermittent RADE reporting failure.

* Make sure runner can exit ASAP when ParallelStep is being destroyed.

* Make sure we can only do one stop() at a time.

* Force all Linux tests to run to see how many end up failing now.

* Remove caps on number of cycles through TX and RX loops.

* Reenable all tests on Ubuntu 22.04.

* We don't need to call opus_select_arch() every single time through the loop.

* Python 3.11 works better on 22.04.

* Forgot to update AppRun for 3.11.

* Revert fail-fast for AppImage tests.

* Revert other fail-fast.

* Slightly increase PulseAudio latency to avoid RADE dropouts.

* Test change.

* Test change.

* Test change.

* Revert "Test change."

This reverts commit 2eee1e538d.

* Revert "Test change."

This reverts commit 8205c3b097.

* Revert "Test change."

This reverts commit c9ba8b45b2.

* Revert latency changes.

* For some reason, increasing the wait in the UT code makes the RADE test pass more reliably on 22.04.

* Increase wait time to 5s.

* Revert "Increase wait time to 5s."

This reverts commit 1ca459a02a.

* Revert "For some reason, increasing the wait in the UT code makes the RADE test pass more reliably on 22.04."

This reverts commit f267814b50.

* Try another way of increasing sleep time.

* Revert "Try another way of increasing sleep time."

This reverts commit 5a11c59167.

* Re-arrange sleeps.

* Increase time again.

* Revert "Increase time again."

This reverts commit 44073477ef.

* Revert "Re-arrange sleeps."

This reverts commit edbe451601.

* Wrap globals relevant to TX in atomic.

* Slightly increase default FIFO size.

* Trigger build.

* Trigger build.

* Trigger build.

* Trigger build.

* Trigger build.

* Revert "Trigger build."

This reverts commit 7210e745de.

* Revert "Trigger build."

This reverts commit 3fc2059d76.

* Revert "Trigger build."

This reverts commit 66d64cfe8a.

* Revert "Trigger build."

This reverts commit df745e8a77.

* Revert "Trigger build."

This reverts commit 80945de3b8.

* Add macOS 15 to GitHub tests.

* Code cleanup.

* Create ifdefs for disabled logic.

* Add PR #949 to changelog.

* See if reducing default FIFO size will work.
ms-hamlib-build-dep
Mooneer Salem 2025-07-04 15:45:36 -07:00 committed by GitHub
parent 707daed225
commit d5aa1d9eb4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 153 additions and 75 deletions

View File

@ -44,13 +44,13 @@ jobs:
run: |
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install libpulse-dev sox git libasound2-dev libao-dev libgsm1-dev xvfb pipewire pulseaudio-utils pipewire-pulse wireplumber metacity at-spi2-core libdbus-1-dev libgtk-3-dev
sudo apt-get install libpulse-dev sox git libasound2-dev libao-dev libgsm1-dev xvfb pipewire pulseaudio-utils pipewire-pulse wireplumber metacity at-spi2-core libdbus-1-dev libgtk-3-dev python3.11-full python3.11-dev python3.11-venv
- name: Install Python required modules
shell: bash
working-directory: ${{github.workspace}}
run: |
python3 -m venv rade-venv
python3.11 -m venv rade-venv
. ./rade-venv/bin/activate
pip3 install torch torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install matplotlib
@ -122,7 +122,7 @@ jobs:
test-appimage-ubuntu:
strategy:
fail-fast: true
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-22.04]
@ -248,7 +248,7 @@ jobs:
if: ${{ matrix.os == 'ubuntu-22.04' }}
shell: bash
run: |
sudo apt-get install libwxgtk3.0-gtk3-dev pulseaudio
sudo apt-get install libwxgtk3.0-gtk3-dev pulseaudio python3.11-full python3.11-dev python3.11-venv
systemctl --user --now enable pulseaudio.service pulseaudio.socket
- name: Install version-specific packages
@ -256,12 +256,25 @@ jobs:
shell: bash
run: |
sudo apt-get install libwxgtk3.2-dev pipewire pipewire-pulse wireplumber
- name: Create Python venv
if: ${{ matrix.os == 'ubuntu-22.04' }}
shell: bash
working-directory: ${{github.workspace}}
run: |
python3.11 -m venv rade-venv
- name: Create Python venv
if: ${{ matrix.os == 'ubuntu-24.04' }}
shell: bash
working-directory: ${{github.workspace}}
run: |
python3 -m venv rade-venv
- name: Install Python required modules
shell: bash
working-directory: ${{github.workspace}}
run: |
python3 -m venv rade-venv
. ./rade-venv/bin/activate
pip3 install torch torchaudio --index-url https://download.pytorch.org/whl/cpu
pip3 install matplotlib

View File

@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [macos-13, macos-latest] # x86_64, ARM64
os: [macos-13, macos-14, macos-15] # x86_64, ARM64, ARM64
runs-on: ${{ matrix.os }}

View File

@ -829,7 +829,9 @@ LDPC | Low Density Parity Check Codes - a family of powerful FEC codes
2. Documentation:
* Add missing dependency for macOS builds to README. (PR #925; thanks @relistan!)
* Add note about using XWayland on Linux. (PR #926)
3. Build system:
3. Enhancements:
* General improvements to backend audio processing to further reduce dropouts. (PR #949)
4. Build system:
* Update Hamlib to 4.6.3 (macOS/Windows). (PR #930)
* Reload current Git hash every time it changes. (PR #935, #951)
* Add infrastructure for generating AppImage builds. (PR #937)

View File

@ -5,7 +5,7 @@ export PATH="$APPDIR/usr/bin:$APPDIR/rade-venv/bin"
export GDK_BACKEND=x11
echo "PATH=$PATH"
export PYTHONHOME="$APPDIR/usr"
export PYTHONPATH="$APPDIR/rade_src:$APPDIR/rade-venv/lib/python3.10/site-packages"
export PYTHONPATH="$APPDIR/rade_src:$APPDIR/rade-venv/lib/python3.11/site-packages"
echo "PYTHONPATH=$PYTHONPATH"
echo "PYTHONHOME=$PYTHONHOME"
cd "$APPDIR"

View File

@ -33,7 +33,7 @@ fi
# create the virtual environment (copied from Brian's build script)
cd FreeDV.AppDir
python3 -m venv rade-venv # || { echo "ERROR: create venv failed"; exit 1; }
python3.11 -m venv rade-venv # || { echo "ERROR: create venv failed"; exit 1; }
# Activate it
source rade-venv/bin/activate # || { echo "ERROR: activate venv failed"; exit 1; }
@ -51,13 +51,13 @@ cd "$APPDIR/rade-venv/bin"
echo "Now in $(pwd)"
ln -s -f ../../usr/bin/python3 python
ln -s -f ../../usr/bin/python3 python3
ln -s -f ../../usr/bin/python3 python3.10
ln -s -f ../../usr/bin/python3 python3.11
cd - # back to the previous directory
echo "### Now in $(pwd)"
# Copy /usr/lib/python3.10 to image
# Copy /usr/lib/python3.11 to image
cd $APPDIR/usr
cp -a /usr/lib/python3.10 lib/
cp -a /usr/lib/python3.11 lib/
cd -
# Copy the models and symlink

View File

@ -64,7 +64,7 @@
#define NUM_CHANNELS 2 // I think most sound cards prefer stereo we will convert to mono
#define VOX_TONE_FREQ 1000.0 // optional left channel vox tone freq
#define VOX_TONE_AMP 30000 // optional left channel vox tone amp
#define FIFO_SIZE 440 // default fifo size in ms
#define FIFO_SIZE 540 // default fifo size in ms
#define FRAME_DURATION 0.02 // default frame length of 20 mS = 0.02 seconds
#define MAX_BITS_PER_CODEC_FRAME 64 // 1600 bit/s mode

View File

@ -102,10 +102,10 @@ int g_txLevel = 0;
int g_SquelchActive;
float g_SquelchLevel;
int g_analog;
int g_tx;
std::atomic<int> g_tx;
float g_snr;
bool g_half_duplex;
bool g_voice_keyer_tx;
std::atomic<bool> g_half_duplex;
std::atomic<bool> g_voice_keyer_tx;
SRC_STATE *g_spec_src; // sample rate converter for spectrum
// sending and receiving Call Sign data

View File

@ -30,7 +30,7 @@ extern int g_mode;
extern int g_SquelchActive;
extern float g_SquelchLevel;
extern int g_analog;
extern int g_tx;
extern std::atomic<int> g_tx;
extern int g_State, g_prev_State;
extern FreeDVInterface freedvInterface;
extern bool g_queueResync;
@ -41,7 +41,7 @@ extern int g_txLevel;
extern wxConfigBase *pConfig;
extern bool endingTx;
extern int g_outfifo1_empty;
extern bool g_voice_keyer_tx;
extern std::atomic<bool> g_voice_keyer_tx;
extern paCallBackData* g_rxUserdata;
extern SNDFILE *g_sfRecFileFromModulator;

View File

@ -256,6 +256,10 @@ std::shared_ptr<short> ParallelStep::execute(std::shared_ptr<short> inputSamples
ThreadInfo* outputTask = threads_[stepToOutput];
*numOutputSamples = codec2_fifo_used(outputTask->outputFifo);
if (numInputSamples > 0)
{
*numOutputSamples = std::min(*numOutputSamples, numInputSamples);
}
if (*numOutputSamples == 0)
{
memset(outputTask->tempOutput.get(), 0, sizeof(short) * outputSampleRate_);
@ -271,18 +275,22 @@ void ParallelStep::executeRunnerThread_(ThreadInfo* threadState) noexcept
#endif // defined(__has_feature) && __has_feature(realtime_sanitizer)
#endif // defined(__clang__)
{
int samplesIn = codec2_fifo_used(threadState->inputFifo);
int samplesOut = 0;
if (codec2_fifo_read(threadState->inputFifo, threadState->tempInput.get(), samplesIn) != 0)
int samplesIn = std::min((int)(inputSampleRate_ * FRAME_DURATION), codec2_fifo_used(threadState->inputFifo));
do
{
samplesIn = 0;
}
int samplesOut = 0;
if (codec2_fifo_read(threadState->inputFifo, threadState->tempInput.get(), samplesIn) != 0)
{
samplesIn = 0;
}
auto output = threadState->step->execute(threadState->tempInput, samplesIn, &samplesOut);
if (samplesOut > 0)
{
codec2_fifo_write(threadState->outputFifo, output.get(), samplesOut);
}
auto output = threadState->step->execute(threadState->tempInput, samplesIn, &samplesOut);
if (samplesOut > 0)
{
codec2_fifo_write(threadState->outputFifo, output.get(), samplesOut);
}
samplesIn = std::min((int)(inputSampleRate_ * FRAME_DURATION), codec2_fifo_used(threadState->inputFifo));
} while (samplesIn > 0 && !threadState->exitingThread);
}
void ParallelStep::reset()

View File

@ -83,6 +83,8 @@ RADETransmitStep::RADETransmitStep(struct rade* dv, LPCNetEncState* encState)
featureList_ = new float[rade_n_features_in_out(dv_)];
assert(featureList_ != nullptr);
arch_ = opus_select_arch();
}
RADETransmitStep::~RADETransmitStep()
@ -130,7 +132,7 @@ std::shared_ptr<short> RADETransmitStep::execute(std::shared_ptr<short> inputSam
if (numInputSamples == 0)
{
// Special case logic for EOO
*numOutputSamples = codec2_fifo_used(outputSampleFifo_);
*numOutputSamples = std::min(codec2_fifo_used(outputSampleFifo_), (int)(FRAME_DURATION * getOutputSampleRate()));
if (*numOutputSamples > 0)
{
codec2_fifo_read(outputSampleFifo_, outputSamples_.get(), *numOutputSamples);
@ -151,11 +153,9 @@ std::shared_ptr<short> RADETransmitStep::execute(std::shared_ptr<short> inputSam
short pcm[LPCNET_FRAME_SIZE];
float features[NB_TOTAL_FEATURES];
int arch = opus_select_arch();
// Feature extraction
codec2_fifo_read(inputSampleFifo_, pcm, LPCNET_FRAME_SIZE);
lpcnet_compute_single_frame_features(encState_, pcm, features, arch);
lpcnet_compute_single_frame_features(encState_, pcm, features, arch_);
if (featuresFile_)
{

View File

@ -50,7 +50,8 @@ private:
struct FIFO* outputSampleFifo_;
float* featureList_;
int featureListIdx_;
int arch_;
FILE* featuresFile_;
std::shared_ptr<short> outputSamples_;

View File

@ -68,12 +68,12 @@ static int resample_step(SRC_STATE *src,
return src_data.output_frames_gen;
}
ResampleStep::ResampleStep(int inputSampleRate, int outputSampleRate)
ResampleStep::ResampleStep(int inputSampleRate, int outputSampleRate, bool forPlotsOnly)
: inputSampleRate_(inputSampleRate)
, outputSampleRate_(outputSampleRate)
{
int src_error;
resampleState_ = src_new(SRC_SINC_MEDIUM_QUALITY, 1, &src_error);
resampleState_ = src_new(forPlotsOnly ? SRC_LINEAR : SRC_SINC_MEDIUM_QUALITY, 1, &src_error);
assert(resampleState_ != nullptr);
// Pre-allocate buffers so we don't have to do so during real-time operation.
@ -82,10 +82,10 @@ ResampleStep::ResampleStep(int inputSampleRate, int outputSampleRate)
std::default_delete<short[]>());
assert(outputSamples_ != nullptr);
tempInput_ = new float[std::max(inputSampleRate, outputSampleRate)];
tempInput_ = new float[inputSampleRate * 10 / 1000];
assert(tempInput_ != nullptr);
tempOutput_ = new float[std::max(inputSampleRate, outputSampleRate)];
tempOutput_ = new float[outputSampleRate * 10 / 1000];
assert(tempOutput_ != nullptr);
}
@ -109,19 +109,23 @@ int ResampleStep::getOutputSampleRate() const
std::shared_ptr<short> ResampleStep::execute(std::shared_ptr<short> inputSamples, int numInputSamples, int* numOutputSamples)
{
if (numInputSamples > 0)
{
double scaleFactor = ((double)outputSampleRate_)/((double)inputSampleRate_);
int outputArraySize = std::max(numInputSamples, (int)(scaleFactor*numInputSamples));
assert(outputArraySize > 0);
*numOutputSamples = 0;
*numOutputSamples = resample_step(
resampleState_, outputSamples_.get(), inputSamples.get(), outputSampleRate_,
inputSampleRate_, outputArraySize, numInputSamples, tempInput_, tempOutput_);
}
else
auto inputPtr = inputSamples.get();
auto outputPtr = outputSamples_.get();
while (numInputSamples > 0)
{
*numOutputSamples = 0;
int inputSize = std::min(numInputSamples, inputSampleRate_ * 10 / 1000);
int outputSize = ((float)outputSampleRate_ / inputSampleRate_) * inputSize;
auto numSamples = resample_step(
resampleState_, outputPtr, inputPtr, outputSampleRate_,
inputSampleRate_, outputSize, inputSize,
tempInput_, tempOutput_);
outputPtr += numSamples;
inputPtr += inputSize;
numInputSamples -= inputSize;
*numOutputSamples += numSamples;
}
return outputSamples_;

View File

@ -30,7 +30,7 @@
class ResampleStep : public IPipelineStep
{
public:
ResampleStep(int inputSampleRate, int outputSampleRate);
ResampleStep(int inputSampleRate, int outputSampleRate, bool forPlotsOnly = false);
virtual ~ResampleStep();
virtual int getInputSampleRate() const override;
@ -47,4 +47,4 @@ private:
std::shared_ptr<short> outputSamples_;
};
#endif // AUDIO_PIPELINE__RESAMPLE_STEP_H
#endif // AUDIO_PIPELINE__RESAMPLE_STEP_H

View File

@ -53,13 +53,25 @@ using namespace std::chrono_literals;
#include <wx/stopwatch.h>
// Experimental options for potential future release:
//
// * ENABLE_FASTER_PLOTS: This uses a faster resampling algorithm to reduce the CPU
// usage required to generate various plots in the user interface. Currently disabled
// due to unknown effects on visual quality. (Tech note: When enabled, libsamplerate is
// directed to use linear interpolation instead of sinc for the plot resampling.)
// * ENABLE_PROCESSING_STATS: This causes execution statistics to be collected for RX and TX
// processing and output in the log after the user pushes Stop.
//#define ENABLE_FASTER_PLOTS
//#define ENABLE_PROCESSING_STATS
// External globals
// TBD -- work on fully removing the need for these.
extern paCallBackData* g_rxUserdata;
extern int g_analog;
extern int g_nSoundCards;
extern bool g_half_duplex;
extern int g_tx;
extern std::atomic<bool> g_half_duplex;
extern std::atomic<int> g_tx;
extern int g_dump_fifo_state;
extern bool endingTx;
extern bool g_playFileToMicIn;
@ -88,7 +100,7 @@ extern int g_State;
extern int g_channel_noise;
extern float g_RxFreqOffsetHz;
extern float g_sig_pwr_av;
extern bool g_voice_keyer_tx;
extern std::atomic<bool> g_voice_keyer_tx;
extern bool g_eoo_enqueued;
#include <speex/speex_preprocess.h>
@ -126,7 +138,6 @@ void TxRxThread::initializePipeline_()
if (m_tx)
{
pipeline_ = std::shared_ptr<AudioPipeline>(new AudioPipeline(inputSampleRate_, outputSampleRate_));
// Record from mic step (optional)
auto recordMicStep = new RecordStep(
inputSampleRate_,
@ -185,7 +196,7 @@ void TxRxThread::initializePipeline_()
std::shared_ptr<IPipelineStep>(eitherOrProcessSpeex),
std::shared_ptr<IPipelineStep>(eitherOrBypassSpeex));
pipeline_->appendPipelineStep(std::shared_ptr<IPipelineStep>(eitherOrSpeexStep));
// Equalizer step (optional based on filter state)
auto equalizerStep = new EqualizerStep(
inputSampleRate_,
@ -209,6 +220,10 @@ void TxRxThread::initializePipeline_()
// Resample for plot step
auto resampleForPlotStep = new ResampleForPlotStep(g_plotSpeechInFifo);
auto resampleForPlotPipeline = new AudioPipeline(inputSampleRate_, resampleForPlotStep->getOutputSampleRate());
#if defined(ENABLE_FASTER_PLOTS)
auto resampleForPlotResampler = new ResampleStep(inputSampleRate_, resampleForPlotStep->getInputSampleRate(), true); // need to create manually to get access to "plot only" optimizations
resampleForPlotPipeline->appendPipelineStep(std::shared_ptr<IPipelineStep>(resampleForPlotResampler));
#endif // defined(ENABLE_FASTER_PLOTS)
resampleForPlotPipeline->appendPipelineStep(std::shared_ptr<IPipelineStep>(resampleForPlotStep));
auto resampleForPlotTap = new TapStep(inputSampleRate_, resampleForPlotPipeline);
@ -266,7 +281,6 @@ void TxRxThread::initializePipeline_()
else
{
pipeline_ = std::shared_ptr<AudioPipeline>(new AudioPipeline(inputSampleRate_, outputSampleRate_));
// Record from radio step (optional)
auto recordRadioStep = new RecordStep(
inputSampleRate_,
@ -323,11 +337,15 @@ void TxRxThread::initializePipeline_()
// Resample for plot step (demod in)
auto resampleForPlotStep = new ResampleForPlotStep(g_plotDemodInFifo);
auto resampleForPlotPipeline = new AudioPipeline(inputSampleRate_, resampleForPlotStep->getOutputSampleRate());
#if defined(ENABLE_FASTER_PLOTS)
auto resampleForPlotResampler = new ResampleStep(inputSampleRate_, resampleForPlotStep->getInputSampleRate(), true); // need to create manually to get access to "plot only" optimizations
resampleForPlotPipeline->appendPipelineStep(std::shared_ptr<IPipelineStep>(resampleForPlotResampler));
#endif // defined(ENABLE_FASTER_PLOTS)
resampleForPlotPipeline->appendPipelineStep(std::shared_ptr<IPipelineStep>(resampleForPlotStep));
auto resampleForPlotTap = new TapStep(inputSampleRate_, resampleForPlotPipeline);
pipeline_->appendPipelineStep(std::shared_ptr<IPipelineStep>(resampleForPlotTap));
// Tone interferer step (optional)
auto bypassToneInterferer = new AudioPipeline(inputSampleRate_, inputSampleRate_);
auto toneInterfererStep = new ToneInterfererStep(
@ -350,6 +368,10 @@ void TxRxThread::initializePipeline_()
);
auto computeRfSpectrumPipeline = new AudioPipeline(
inputSampleRate_, computeRfSpectrumStep->getOutputSampleRate());
#if defined(ENABLE_FASTER_PLOTS)
auto resampleForRfSpectrum = new ResampleStep(inputSampleRate_, computeRfSpectrumStep->getInputSampleRate(), true); // need to create manually to get access to "plot only" optimizations
computeRfSpectrumPipeline->appendPipelineStep(std::shared_ptr<IPipelineStep>(resampleForRfSpectrum));
#endif // defined(ENABLE_FASTER_PLOTS)
computeRfSpectrumPipeline->appendPipelineStep(std::shared_ptr<IPipelineStep>(computeRfSpectrumStep));
auto computeRfSpectrumTap = new TapStep(inputSampleRate_, computeRfSpectrumPipeline);
@ -439,6 +461,10 @@ void TxRxThread::initializePipeline_()
// Resample for plot step (speech out)
auto resampleForPlotOutStep = new ResampleForPlotStep(g_plotSpeechOutFifo);
auto resampleForPlotOutPipeline = new AudioPipeline(outputSampleRate_, resampleForPlotOutStep->getOutputSampleRate());
#if defined(ENABLE_FASTER_PLOTS)
auto resampleForPlotOutResampler = new ResampleStep(outputSampleRate_, resampleForPlotOutStep->getInputSampleRate(), true); // need to create manually to get access to "plot only" optimizations
resampleForPlotOutPipeline->appendPipelineStep(std::shared_ptr<IPipelineStep>(resampleForPlotOutResampler));
#endif // defined(ENABLE_FASTER_PLOTS)
resampleForPlotOutPipeline->appendPipelineStep(std::shared_ptr<IPipelineStep>(resampleForPlotOutStep));
auto resampleForPlotOutTap = new TapStep(outputSampleRate_, resampleForPlotOutPipeline);
@ -459,7 +485,15 @@ void* TxRxThread::Entry()
// Request real-time scheduling from the operating system.
helper_->setHelperRealTime();
#if defined(ENABLE_PROCESSING_STATS)
int numTimeSamples = 0;
double minDuration = 1e9;
double maxDuration = 0;
double sumDuration = 0;
double sumDoubleDuration = 0;
#endif // defined(ENABLE_PROCESSING_STATS)
while (m_run)
{
#if defined(__linux__)
@ -473,10 +507,23 @@ void* TxRxThread::Entry()
//log_info("thread woken up: m_tx=%d", (int)m_tx);
helper_->startRealTimeWork();
#if defined(ENABLE_PROCESSING_STATS)
auto b = std::chrono::high_resolution_clock::now();
#endif // defined(ENABLE_PROCESSING_STATS)
if (m_tx) txProcessing_();
else rxProcessing_();
#if defined(ENABLE_PROCESSING_STATS)
auto e = std::chrono::high_resolution_clock::now();
auto d = std::chrono::duration_cast<std::chrono::nanoseconds>(e - b).count();
numTimeSamples++;
if (d < minDuration) minDuration = d;
if (d > maxDuration) maxDuration = d;
sumDuration += d; sumDoubleDuration += pow(d, 2);
#endif // defined(ENABLE_PROCESSING_STATS)
// Determine whether we need to pause for a shorter amount
// of time to avoid dropouts.
paCallBackData *cbData = g_rxUserdata;
@ -489,7 +536,11 @@ void* TxRxThread::Entry()
auto fifoUsed = codec2_fifo_used(outFifo);
helper_->stopRealTimeWork(fifoUsed < totalFifoCapacity / 2);
}
#if defined(ENABLE_PROCESSING_STATS)
log_info("m_tx = %d, min = %f ns, max = %f ns, mean = %f ns, stdev = %f ns", m_tx, minDuration, maxDuration, sumDuration / numTimeSamples, sqrt((sumDoubleDuration - pow(sumDuration, 2)/numTimeSamples) / (numTimeSamples - 1)));
#endif // defined(ENABLE_PROCESSING_STATS)
// Force pipeline to delete itself when we're done with the thread.
pipeline_ = nullptr;
@ -596,12 +647,11 @@ void TxRxThread::txProcessing_() noexcept
codec2_fifo_used(cbData->outfifo1), codec2_fifo_free(cbData->outfifo1), nsam_one_modem_frame);
}
int nsam_in_48 = freedvInterface.getTxNumSpeechSamples() * ((float)inputSampleRate_ / (float)freedvInterface.getTxSpeechSampleRate());
int nsam_in_48 = (int)(inputSampleRate_ * FRAME_DURATION);
assert(nsam_in_48 > 0);
int nout;
while(!helper_->mustStopWork() && (unsigned)codec2_fifo_free(cbData->outfifo1) >= nsam_one_modem_frame) {
// OK to generate a frame of modem output samples we need
// an input frame of speech samples from the microphone.
@ -724,7 +774,7 @@ void TxRxThread::rxProcessing_() noexcept
auto outFifo = (g_nSoundCards == 1) ? cbData->outfifo1 : cbData->outfifo2;
// while we have enough input samples available and enough space in the output FIFO ...
while (!helper_->mustStopWork() && codec2_fifo_free(outFifo) >= nsam_one_speech_frame && codec2_fifo_read(cbData->infifo1, inputSamples_.get(), nsam) == 0 && processInputFifo) {
while (!helper_->mustStopWork() && processInputFifo && codec2_fifo_free(outFifo) >= nsam_one_speech_frame && codec2_fifo_read(cbData->infifo1, inputSamples_.get(), nsam) == 0) {
// send latest squelch level to FreeDV API, as it handles squelch internally
freedvInterface.setSquelch(g_SquelchActive, g_SquelchLevel);
@ -736,8 +786,8 @@ void TxRxThread::rxProcessing_() noexcept
}
processInputFifo =
(g_voice_keyer_tx && wxGetApp().appConfiguration.monitorVoiceKeyerAudio) ||
(g_tx && wxGetApp().appConfiguration.monitorTxAudio) ||
(!g_voice_keyer_tx && ((g_half_duplex && !g_tx) || !g_half_duplex));
(g_voice_keyer_tx && wxGetApp().appConfiguration.monitorVoiceKeyerAudio) ||
(g_tx && wxGetApp().appConfiguration.monitorTxAudio) ||
(!g_voice_keyer_tx && ((g_half_duplex && !g_tx) || !g_half_duplex));
}
}

View File

@ -34,7 +34,7 @@ int g_recFromModulatorSamples;
int g_recFileFromModulatorEventId;
extern FreeDVInterface freedvInterface;
extern bool g_tx;
extern std::atomic<bool> g_tx;
// extra panel added to file open dialog to add loop checkbox
MyExtraPlayFilePanel::MyExtraPlayFilePanel(wxWindow *parent): wxPanel(parent)
@ -374,4 +374,4 @@ void MainFrame::OnTogBtnRecord( wxCommandEvent& event )
m_audioRecord->SetBackgroundColour(*wxRED);
}
}
}

View File

@ -16,7 +16,7 @@
extern float g_RxFreqOffsetHz;
extern float g_TxFreqOffsetHz;
extern FreeDVInterface freedvInterface;
extern int g_tx;
extern std::atomic<int> g_tx;
void clickTune(float freq) {

View File

@ -9,7 +9,7 @@
extern SNDFILE *g_sfRecMicFile;
bool g_recVoiceKeyerFile;
extern bool g_voice_keyer_tx;
extern std::atomic<bool> g_voice_keyer_tx;
extern wxMutex g_mutexProtectingCallbackData;
extern bool endingTx;

View File

@ -13,7 +13,7 @@ soundCard2OutDeviceName=@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@
soundCard2OutSampleRate=48000
SquelchActive=1
SquelchLevel=-4
fifoSize_ms=440
fifoSize_ms=540
transmitLevel=0
snrSlow=0
mode=4

View File

@ -13,7 +13,7 @@ soundCard2OutDeviceName=@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@
soundCard2OutSampleRate=48000
SquelchActive=1
SquelchLevel=-4
fifoSize_ms=440
fifoSize_ms=540
transmitLevel=0
snrSlow=0
mode=257

View File

@ -13,7 +13,7 @@ soundCard2OutDeviceName=@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@
soundCard2OutSampleRate=48000
SquelchActive=1
SquelchLevel=-4
fifoSize_ms=440
fifoSize_ms=540
transmitLevel=0
snrSlow=0
mode=257

View File

@ -13,7 +13,7 @@ soundCard2OutDeviceName=@FREEDV_COMPUTER_TO_SPEAKER_DEVICE@
soundCard2OutSampleRate=48000
SquelchActive=1
SquelchLevel=-4
fifoSize_ms=440
fifoSize_ms=540
transmitLevel=0
snrSlow=0
mode=257