Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 126 additions & 11 deletions T41EEE/AudioSignal.h
Original file line number Diff line number Diff line change
@@ -1,22 +1,60 @@
/*
T41EVE Copyright 2026 Gregory Raven

This file is part of T41EVE.

T41EVE is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

T41EVE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with T41EVE. If not, see <https://www.gnu.org/licenses/>.

This comment block must appear in the load page (e.g., main() or setup()) in any source code
that uses code presented as whole or part of the T41-EP source code.

(c) Frank Dziock, DD4WH, 2020_05_8
"TEENSY CONVOLUTION SDR" substantially modified by Jack Purdum, W8TEE, and Al Peter, AC8GY

This software is made available under the GNU GPLv3 license agreement. If commercial use of this
software is planned, we would appreciate it if the interested parties contact Jack Purdum, W8TEE,
and Al Peter, AC8GY.

Any and all other uses, written or implied, by the GPLv3 license are forbidden without written
permission from from Jack Purdum, W8TEE, and Al Peter, AC8GY.
*/

// Teensy and Open Audio Signal Chains include file.

// Common to Transmitter and Receiver.
const float sample_rate_Hz = 48000.0; // The transmitter operates at 48ksps.
const int audio_block_samples = 128; // Always 128
AudioSettings_F32 audio_settings(sample_rate_Hz, audio_block_samples);
#ifdef JMS_QUAD
AudioInputI2SQuad_F32 i2s_quadIn_f32(audio_settings); // 4 inputs available in experimental Open Audio library. Ussing Terrane's code
AudioSwitch4_OA_F32 switchMicMute(audio_settings); //Switch Mic between bitBucket and Normal
//AudioRecordQueue_F32 micBitBucketL(audio_settings); //DataSink when Mic not in use
#else
AudioInputI2SQuad i2s_quadIn; // 4 inputs available only in Teensy audio and not Open Audio library.
#endif
AudioOutputI2SQuad_F32 i2s_quadOut_f32(audio_settings);

// Transmitter
AudioControlSGTL5000 sgtl5000_1; // Controller for the Teensy Audio Adapter.
AudioControlSGTL5000 sgtl5000_1;
#ifdef JMS_QUAD // Controller for the Teensy Audio Adapter.
//not neeeded float conversion done in AudioInputI2SQuad_F32
#else
AudioConvert_I16toF32 int2Float1_tx; // Converts Int16 to Float.
#endif
AudioEffectGain_F32 micGain(audio_settings), compGainCompensate(audio_settings); // Microphone gain control.
AudioFilterEqualizer_F32 txEqualizer(audio_settings);
AudioEffectCompressor2_F32 compressor1; // Open Audio Compressor
radioCESSB_Z_transmit_F32 cessb1;

#ifdef JMS_QUAD
//not neeeded float conversion done in AudioInputI2SQuad_F32
#else
AudioConvert_F32toI16 float2Int1_tx, float2Int2_tx; // Converts Float to Int16. See class in AudioStream_F32.h

#endif
AudioSwitch4_OA_F32 switch3_tx, switch4_tx;
AudioMixer4_F32 mixer1_tx, mixer2_tx, mixer3_tx; // Used to switch in tone during calibration.
AudioSynthWaveformSine_F32 toneSSBCal1, toneSSBCal2; // Tones for SSB calibration and IMD testing.
Expand All @@ -29,10 +67,17 @@ AudioPlayQueue_F32 Q_out_R_Ex; // AudioPlayQueue for driving the Q channel (CW/
AudioPlayQueue_F32 cwToneData; // The tone from the CW Exciter.

// Begin transmit signal chain.
#ifdef JMS_QUAD
//don't need the int2float object so just connect input via mute mixer
AudioConnection_F32 connect31(i2s_quadIn_f32, 0, switchMicMute, 0);
AudioConnection_F32 connect3(switchMicMute, 0, mixer1_tx, 0);
//AudioConnection_F32 connect32(switchMicMute, 1, micBitBucketL, 0);
#else
AudioConnection connect0(i2s_quadIn, 0, int2Float1_tx, 0); // Microphone audio channel. Must use int2Float because Open Audio does not have quad input.

// Need a mixer to switch between microphone audio and tones used for calibration, testing, and CW.
AudioConnection_F32 connect3(int2Float1_tx, 0, mixer1_tx, 0); // Connect microphone mixer1 output 0 via gain control.
#endif

AudioConnection_F32 connect4(toneSSBCal1, 0, mixer1_tx, 1); // Connect tone for SSB calibration and IM3 testing.
AudioConnection_F32 connect22(toneSSBCal2, 0, mixer1_tx, 2); // Connect tone for IM3 testing.
Expand Down Expand Up @@ -75,15 +120,23 @@ AudioMixer4_F32 mixer4, mixer5;

AudioSwitch4_OA_F32 switch1_rx, switch2_rx;
AudioConvert_F32toI16 float2Int3, float2Int4, float2Int5, float2Int6;

#ifdef JMS_QUAD
AudioRecordQueue_F32 ADC_RX_I(audio_settings); // Receiver I channel from ADC PCM1808, 32 bit.
AudioRecordQueue_F32 ADC_RX_Q(audio_settings); // Receiver Q channel from ADC PCM1808, 32 bit.
#else
AudioRecordQueue ADC_RX_I; // Receiver I channel from ADC PCM1808, 16 bit.
AudioRecordQueue ADC_RX_Q; // Receiver Q channel from ADC PCM1808, 16 bit.
#endif

AudioPlayQueue_F32 audioOutQueue; // Receiver audio out and CW sidetone.
AudioPlayQueue_F32 sidetoneOutQueue; // Receiver audio out and CW sidetone.

#ifdef JMS_QUAD
AudioConnection_F32 patchCord1(i2s_quadIn_f32, 3, ADC_RX_I, 0); // Receiver I and Q channel data stream.
AudioConnection_F32 patchCord2(i2s_quadIn_f32, 2, ADC_RX_Q, 0); // This data stream goes to sketch code for processing.
#else
AudioConnection patchCord1(i2s_quadIn, 3, ADC_RX_I, 0); // Receiver I and Q channel data stream.
AudioConnection patchCord2(i2s_quadIn, 2, ADC_RX_Q, 0); // This data stream goes to sketch code for processing.
#endif

AudioConnection_F32 patchCord3(audioOutQueue, 0, mixer5, 0); // mixer5 selects receiver or CW sidetone audio.
AudioConnection_F32 patchCord35(sidetoneOutQueue, 0, mixer5, 1);
Expand Down Expand Up @@ -220,11 +273,19 @@ void SetAudioOperatingState(RadioState operatingState) {
mixer3_tx.gain(1, 0.0);

// Connect audio paths
#ifdef JMS_QUAD
// AudioConnection_F32 doesn't support connect/disconnect
#else
patchCord1.connect();
patchCord2.connect();
#endif
mixer5.gain(0, 1.0); // Connect receiver audio from DSP.
mixer5.gain(1, 0); // Disconnect CW sidetone.
#ifdef JMS_QUAD
switchMicMute.setChannel(1);// Bypass tx audio chain, mic straight to micBitBucket
#else
connect0.disconnect(); // Disconnect microphone input data stream.
#endif

// Configure audio compressor (AGC)
if (ConfigData.AGCMode == true) { // Activate compressor2_1 path.
Expand Down Expand Up @@ -264,17 +325,27 @@ void SetAudioOperatingState(RadioState operatingState) {
// QSD disabled and disconnected
controlAudioOut(ConfigData.audioOut, true); // Mute all receiver audio.
sgtl5000_1.unmuteLineout();
#ifdef JMS_QUAD
// AudioConnection_F32 doesn't support connect/disconnect
#else
patchCord1.disconnect(); // Receiver I channel
patchCord2.disconnect(); // Receiver Q channel
#endif
mixer5.gain(0, 0); // Stop receiver audio.
mixer5.gain(1, 0); // Stop sidetone audio.
#ifdef JMS_QUAD
// AudioConnection_F32 doesn't support connect/disconnect
#else
connect0.connect(); // Connect microphone input data stream.

#endif
ADC_RX_I.end();
ADC_RX_I.clear();
ADC_RX_Q.end();
ADC_RX_Q.clear();

#ifdef JMS_QUAD
switchMicMute.setChannel(0); // Connect Mic to tx audio chain
#endif

mixer1_tx.gain(0, 1); // microphone audio on.
mixer1_tx.gain(1, 0); // testTone off.
mixer_rxtx_I.gain(0, 1.0); // Connect transmitter back-end to Audio Adapter.
Expand Down Expand Up @@ -305,29 +376,38 @@ void SetAudioOperatingState(RadioState operatingState) {

Q_in_L_Ex.begin(); // I channel Microphone audio
Q_in_R_Ex.begin(); // Q channel Microphone audio

// Update equalizer. Update first 14 only. Last two are constant.
// Update equalizer. Update first 14 only. Last two are constant.
for (int i = 0; i < 14; i = i + 1) dbBand1[i] = static_cast<float32_t>(ConfigData.equalizerXmt[i]);

txEqualizer.equalizerNew(16, &fBand1[0], &dbBand1[0], 249, &equalizeCoeffs[0], 65.0f);
updateMic();

break;

case RadioState::SSB_CALIBRATE_STATE:
case RadioState::SSB_CALIBRATE_STATE:// TRANSMIT
SampleRate = SAMPLE_RATE_48K;
InitializeDataArrays(); // I2S sample rate set in this function.
controlAudioOut(AudioState::MUTE_BOTH, true); // Mute all audio.
sgtl5000_1.unmuteLineout();
#ifdef JMS_QUAD
// AudioConnection_F32 doesn't support connect/disconnect
#else
patchCord1.connect(); // Receiver I channel
patchCord2.connect(); // Receiver Q channel
#endif
mixer5.gain(0, 0); // Stop receiver audio.
mixer5.gain(1, 0); // Stop sidetone audio.
ADC_RX_I.end();
ADC_RX_I.clear();
ADC_RX_Q.end();
ADC_RX_Q.clear();

#ifdef JMS_QUAD
// Just stop everything This changes behaviour
Q_in_L_Ex.end(); // Transmit I channel path.
Q_in_R_Ex.end(); // Transmit Q channel path.
Q_in_L_Ex.clear();
Q_in_R_Ex.clear();
#endif
cessb1.setSampleRate_Hz(48000); ////

// Test tone enabled and connected
Expand All @@ -340,7 +420,14 @@ void SetAudioOperatingState(RadioState operatingState) {
mixer1_tx.gain(1, 1); // testTone on.
mixer1_tx.gain(2, 0); // testTone 2 off.

#ifdef JMS_QUAD
// AudioConnection_F32 doesn't support connect/disconnect
//switchMicMute.setChannel(1); // Bypass tx audio chain straight to micBitBucket
switchMicMute.setChannel(0); // May need tx audio chain to be running so tones are generated???

#else
connect0.disconnect(); // Disconnect microphone input data stream.
#endif
mixer_rxtx_I.gain(0, 1.0); // Connect transmitter back-end to Audio Adapter.
mixer_rxtx_Q.gain(0, 1.0);
mixer_rxtx_I.gain(1, 0); // Disconnect headphone path to Audio Adapter.
Expand Down Expand Up @@ -388,12 +475,20 @@ void SetAudioOperatingState(RadioState operatingState) {
// QSD disabled and disconnected
controlAudioOut(AudioState::MUTE_BOTH, true); // Mute all audio.
sgtl5000_1.unmuteLineout();
#ifdef JMS_QUAD
// AudioConnection_F32 doesn't support connect/disconnect
#else
patchCord1.disconnect(); // Receiver I channel
patchCord2.disconnect(); // Receiver Q channel
#endif
mixer5.gain(0, 0); // Stop receiver audio.
mixer5.gain(1, 0); // Stop sidetone audio.
#ifdef JMS_QUAD
// AudioConnection_F32 doesn't support connect/disconnect
switchMicMute.setChannel(1); // Bypass tx audio chain straight to micBitBucket
#else
connect0.disconnect(); // Disconnect microphone input data stream.

#endif
ADC_RX_I.end();
ADC_RX_I.clear();
ADC_RX_Q.end();
Expand Down Expand Up @@ -458,11 +553,19 @@ void SetAudioOperatingState(RadioState operatingState) {
controlAudioOut(ConfigData.audioOut, true); // Mute all audio. Unmuted at end of configuration.
sgtl5000_1.unmuteLineout();
// QSD disabled and disconnected
#ifdef JMS_QUAD
// AudioConnection_F32 doesn't support connect/disconnect
#else
patchCord1.disconnect(); // Receiver I channel
patchCord2.disconnect(); // Receiver Q channel
#endif
mixer5.gain(0, 0); // Disconnect receiver audio from DSP.
mixer5.gain(1, 1.0); // Connect CW sidetone.
#ifdef JMS_QUAD
switchMicMute.setChannel(1); // Bypass tx audio chain straight to micBitBucket
#else
connect0.disconnect(); // Disconnect microphone input data stream.
#endif
// Speaker and headphones should be unmuted according to current audio out state for sidetone.
controlAudioOut(ConfigData.audioOut, false);

Expand Down Expand Up @@ -522,7 +625,11 @@ void SetAudioOperatingState(RadioState operatingState) {
InitializeDataArrays(); // I2S sample rate set in this function.
controlAudioOut(AudioState::MUTE_BOTH, true); // Mute all audio.
sgtl5000_1.unmuteLineout();
#ifdef JMS_QUAD
switchMicMute.setChannel(1); // Bypass tx audio chain straight to micBitBucket
#else
connect0.disconnect(); // Disconnect microphone input data stream.
#endif
mixer5.gain(0, 0); // Stop receiver audio.
mixer5.gain(1, 0); // Stop sidetone audio.

Expand Down Expand Up @@ -563,8 +670,12 @@ void SetAudioOperatingState(RadioState operatingState) {
cessb1.setIQCorrections(true, CalData.IQCWAmpCorrectionFactorUSB[ConfigData.currentBand], CalData.IQCWPhaseCorrectionFactorUSB[ConfigData.currentBand], 0.0);
}

#ifdef JMS_QUAD
switchMicMute.setChannel(1); // Bypass tx audio chain straight to micBitBucket
#else
patchCord1.connect(); // Connect I and Q receiver data converters.
patchCord2.connect();
#endif
ADC_RX_I.begin(); // Calibration is full duplex!
ADC_RX_Q.begin();

Expand Down Expand Up @@ -603,8 +714,12 @@ void SetAudioOperatingState(RadioState operatingState) {
mixer_rxtx_Q.gain(0, 1.0);
mixer_rxtx_I.gain(1, 0.0); // Disconnect headphone path to Audio Adapter.
mixer_rxtx_Q.gain(1, 0.0);
#ifdef JMS_QUAD
switchMicMute.setChannel(1); // Bypass tx audio chain straight to micBitBucket
#else
patchCord1.connect();
patchCord2.connect();
#endif
ADC_RX_I.begin(); // Calibration is full duplex!
ADC_RX_Q.begin();

Expand Down
30 changes: 28 additions & 2 deletions T41EEE/Button.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
/*
T41EVE Copyright 2026 Gregory Raven

This file is part of T41EVE.

T41EVE is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

T41EVE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with T41EVE. If not, see <https://www.gnu.org/licenses/>.

This comment block must appear in the load page (e.g., main() or setup()) in any source code
that uses code presented as whole or part of the T41-EP source code.

(c) Frank Dziock, DD4WH, 2020_05_8
"TEENSY CONVOLUTION SDR" substantially modified by Jack Purdum, W8TEE, and Al Peter, AC8GY

This software is made available under the GNU GPLv3 license agreement. If commercial use of this
software is planned, we would appreciate it if the interested parties contact Jack Purdum, W8TEE,
and Al Peter, AC8GY.

Any and all other uses, written or implied, by the GPLv3 license are forbidden without written
permission from from Jack Purdum, W8TEE, and Al Peter, AC8GY.
*/

// Button class

#include "SDT.h"
Expand Down Expand Up @@ -191,15 +216,15 @@ void Button::ExecuteButtonPress(MenuSelect val) {

switch (val) {
case MenuSelect::MENU_OPTION_SELECT: // 1

menucontrol.top = false;
ShowMenu(&topMenus[mainMenuIndex], PRIMARY_MENU);
functionPtr[mainMenuIndex](); // These are processed in MenuProcessing.cpp
break;

case MenuSelect::MAIN_MENU_UP: // 2
ButtonMenuIncrease();
ShowMenu(&topMenus[mainMenuIndex], PRIMARY_MENU);

menucontrol.top = true;
break;

case MenuSelect::BAND_UP: // 3
Expand All @@ -213,6 +238,7 @@ void Button::ExecuteButtonPress(MenuSelect val) {
case MenuSelect::MAIN_MENU_DN: // 5
ButtonMenuDecrease();
ShowMenu(&topMenus[mainMenuIndex], PRIMARY_MENU);
menucontrol.top = true;
break;

case MenuSelect::BAND_DN: // 6
Expand Down
27 changes: 26 additions & 1 deletion T41EEE/MyConfigurationFile.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
/*
T41EVE Copyright 2026 Gregory Raven

This file is part of T41EVE.

T41EVE is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

T41EVE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with T41EVE. If not, see <https://www.gnu.org/licenses/>.

This comment block must appear in the load page (e.g., main() or setup()) in any source code
that uses code presented as whole or part of the T41-EP source code.

(c) Frank Dziock, DD4WH, 2020_05_8
"TEENSY CONVOLUTION SDR" substantially modified by Jack Purdum, W8TEE, and Al Peter, AC8GY

This software is made available under the GNU GPLv3 license agreement. If commercial use of this
software is planned, we would appreciate it if the interested parties contact Jack Purdum, W8TEE,
and Al Peter, AC8GY.

Any and all other uses, written or implied, by the GPLv3 license are forbidden without written
permission from from Jack Purdum, W8TEE, and Al Peter, AC8GY.
*/

// User configuration file.

#pragma once
Expand All @@ -10,7 +35,7 @@ const int RIGNAME_X_OFFSET = 570; // Pixel count to rig name field.
//#define DEBUG_SWITCH_CAL // Uncomment to run switch cal by pushing and holding a button at power-up.
// Debug switch cal must be disabled for normal radio operation!
//#define DEBUG_CESSB // Uncomment to get CESSB operating parameters printed to the serial monitor.
//#define LOOP_TIMER
#define LOOP_TIMER
#define FAST_TUNE // Uncomment to activate variable speed fast tune by Harry GM3RVL.
#define DEFAULT_KEYER_WPM 15 // Startup value for keyer wpm
#define FREQ_SEP_CHARACTER '.' // Some may prefer period, space, or combo
Expand Down
Loading