You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
7.3 KiB
184 lines
7.3 KiB
// VoiceClipper12.ino Bob Larkin W7PUA
|
|
// Uses radioVoiceClipper_F32.h and .cpp. See the .h file for
|
|
// more information and references. These clippers, when used with
|
|
// radio systems, are for AM and FM (or NBFM) modulation, and NOT SSB.
|
|
// See the similar class CESSBtransmit_F32 for SSB use.
|
|
//
|
|
// Tests with voice from SD Card file and a 1 second 750 Hz tone burst.
|
|
// Input is from the WAV file on the SD card. Output is to the Teensy
|
|
// Audio Adaptor left and right Line Outputs.
|
|
//
|
|
// The SD card may connect to different pins, depending on the
|
|
// hardware you are using. Configure the SD card
|
|
// pins to match your hardware. It is set for T4.x Rev D PJRC
|
|
// Teensy Audio Adaptor card here.
|
|
//
|
|
// Your microSD card must have W9GR12.WAV file loaded to it, found at
|
|
// https://github.com/chipaudette/OpenAudio_ArduinoLibrary/blob/master/utility/
|
|
//
|
|
// ******** This example runs at 12 ksps. *********
|
|
// As of March 2023, this could be adapted to any rate, 11 to 12 or 44 to 50 ksps.
|
|
//
|
|
// This example code is in the public domain.
|
|
|
|
#include <Audio.h>
|
|
#include <Wire.h>
|
|
#include <SPI.h>
|
|
#include <SD.h>
|
|
#include "OpenAudio_ArduinoLibrary.h"
|
|
//#include "radioVoiceClipper_F32.h" // part of OpenAudio_ArduinoLibrary.h
|
|
|
|
// T3.x supported sample rates: 2000, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 44117, 48000,
|
|
// 88200, 88235 (44117*2), 95680, 96000, 176400, 176470, 192000
|
|
// T4.x supports any sample rate the codec will handle.
|
|
const float sample_rate_Hz = 12000.0f;
|
|
const int audio_block_samples = 128; // Always 128
|
|
AudioSettings_F32 audio_settings(sample_rate_Hz, audio_block_samples);
|
|
|
|
AudioSynthWaveformSine_F32 sine1(audio_settings);
|
|
AudioSDPlayer_F32 playWav1(audio_settings);
|
|
AudioMixer4_F32 mixer4_0;
|
|
radioVoiceClipper_F32 clipper1(audio_settings);
|
|
AudioOutputI2S_F32 audioOutput(audio_settings);
|
|
AudioAnalyzeFFT1024_F32 fft1;
|
|
|
|
AudioConnection_F32 patchCord0(playWav1, 0, mixer4_0, 0);
|
|
AudioConnection_F32 patchCord1(sine1, 0, mixer4_0, 1);
|
|
AudioConnection_F32 patchCord2(mixer4_0, 0, clipper1, 0);
|
|
AudioConnection_F32 patchCord3(clipper1, 0, audioOutput, 0);
|
|
AudioConnection_F32 patchCord4(clipper1, 0, audioOutput, 1);
|
|
AudioConnection_F32 patchCord5(clipper1, 0, fft1, 0);
|
|
AudioControlSGTL5000 sgtl5000_1;
|
|
|
|
// Use these with the Teensy 4.x Rev D Audio Shield (NOT for T3.x)
|
|
#define SDCARD_CS_PIN_Z 10
|
|
#define SDCARD_MOSI_PIN_Z 11
|
|
#define SDCARD_SCK_PIN_Z 13
|
|
|
|
// wavData is a global struct, definined in AudioSDPlayer_F32.h
|
|
// This provides information about the current WAV file to this .INO
|
|
struct wavData* pCurrentWavData;
|
|
// And data about the clipper
|
|
struct levelClipper* pLevelData;
|
|
uint32_t writeOne = 0;
|
|
uint32_t cntFFT = 0;
|
|
uint32_t ttt; // For timing test audio
|
|
|
|
uint32_t tp;
|
|
|
|
void setup() { // ********** SETUP **********
|
|
Serial.begin(9600); delay(1000);
|
|
Serial.println("*** Test Voice Clipper from SD Card Voice Sample ***");
|
|
|
|
AudioMemory_F32(70, audio_settings);
|
|
pCurrentWavData = playWav1.getCurrentWavData();
|
|
sgtl5000_1.enable();
|
|
delay(500);
|
|
SPI.setMOSI(SDCARD_MOSI_PIN_Z);
|
|
SPI.setSCK(SDCARD_SCK_PIN_Z);
|
|
Serial.print("SD.begin() returns "); Serial.println(SD.begin(SDCARD_CS_PIN_Z));
|
|
|
|
sine1.frequency(750.0f);
|
|
sine1.amplitude(0.707107);
|
|
|
|
clipper1.setSampleRate_Hz(12000.0f);
|
|
// Set input, correction, and output gains
|
|
float32_t Pre_Clip_Gain = 1.5f; // Use to set amount of clipping, 1.0 to 2.0f, 3 is excessive
|
|
// Correction gain=1.8 leaves max output overshoot at 2.2% for W9GR sample audio
|
|
clipper1.setGains(Pre_Clip_Gain, 1.8f, 1.0f);
|
|
pLevelData = clipper1.getLevels(0); // Gets pointer to struct
|
|
|
|
audioOutput.setGain(0.02); // <<< Output volume control
|
|
fft1.setOutputType(FFT_DBFS);
|
|
fft1.windowFunction(AudioWindowBlackmanHarris1024);
|
|
fft1.setNAverage(16);
|
|
ttt = millis(); // Time test audio
|
|
tp=millis();
|
|
}
|
|
|
|
void playFile(const char *filename) {
|
|
if(playWav1.isPlaying())
|
|
return;
|
|
Serial.println("");
|
|
Serial.print("Playing file: ");
|
|
Serial.println(filename);
|
|
playWav1.play(filename); // Start playing the file.
|
|
// A brief delay for the library read WAV info
|
|
delay(25);
|
|
Serial.print("WAV file format = "); Serial.println(pCurrentWavData->audio_format);
|
|
Serial.print("WAV number channels = "); Serial.println(pCurrentWavData->num_channels);
|
|
Serial.print("WAV File Sample Rate = "); Serial.println(pCurrentWavData->sample_rate);
|
|
Serial.print("Number of bits per Sample = "); Serial.println(pCurrentWavData->bits);
|
|
Serial.print("File length, seconds = ");
|
|
Serial.println(0.001f*(float32_t)playWav1.lengthMillis(), 3);
|
|
}
|
|
|
|
void loop() {
|
|
uint32_t tt=millis() - ttt;
|
|
if(tt < 2000)
|
|
{
|
|
// Thanks to W9GR for the test file, W9GR482.WAV from which '12' was derived..
|
|
playFile("W9GR12.WAV");
|
|
mixer4_0.gain(0, 1.41421356f); // Play WAV file on
|
|
mixer4_0.gain(1, 0.0f); // Sine Wave 1 off
|
|
}
|
|
else if(tt > 12300 && tt<13300)
|
|
{
|
|
mixer4_0.gain(1, 0.0f); // Play WAV file off
|
|
// The following puts a 1-sec 750 Hz, full amplitude tone into the input
|
|
// .707 on the generator and 1.414 here make the peak sine wave 1.000 at the CESSB input
|
|
mixer4_0.gain(1, 1.41421356f); // Sine Wave 1 on, 750 Hz
|
|
}
|
|
else if(tt >= 13300)
|
|
{
|
|
mixer4_0.gain(0, 1.41421356f); // Play WAV file on
|
|
mixer4_0.gain(1, 0.0f); // Sine Wave 1 off
|
|
ttt = millis(); // Start again
|
|
}
|
|
delay(1);
|
|
|
|
// Un-comment the following to print out the spectrum
|
|
if(fft1.available() && ++cntFFT>10 && cntFFT<12) // For 12 ksps, about 8 seconds in
|
|
{
|
|
for(int kk=0; kk<512; kk++)
|
|
{
|
|
Serial.print(11.71875f*(float32_t)kk); Serial.print(",");
|
|
Serial.println(fft1.read(kk));
|
|
}
|
|
}
|
|
|
|
if(clipper1.levelDataCount() > 300) // Typically 300 to 3000
|
|
{
|
|
clipper1.getLevels(1); // Cause write of data to struct & reset
|
|
|
|
/* // Detailed Report
|
|
Serial.print(10.0f*log10f(pLevelData->pwr0));
|
|
Serial.print(" In Ave Pwr Out ");
|
|
Serial.println(10.0f*log10f(pLevelData->pwr1));
|
|
Serial.print(20.0f*log10f(pLevelData->peak0));
|
|
Serial.print(" In Peak Out ");
|
|
Serial.println(20.0f*log10f(pLevelData->peak1));
|
|
Serial.print(pLevelData->peak0, 6);
|
|
Serial.print(" In Peak Volts Out ");
|
|
Serial.println(pLevelData->peak1, 6);
|
|
Serial.print("Enhancement = ");
|
|
float32_t enhance = (10.0f*log10f(pLevelData->pwr1) - 20.0f*log10f(pLevelData->peak1)) -
|
|
(10.0f*log10f(pLevelData->pwr0) - 20.0f*log10f(pLevelData->peak0));
|
|
if(enhance<1.0f) enhance = 1.0f;
|
|
Serial.print(enhance); Serial.println(" dB");
|
|
*/
|
|
|
|
/*
|
|
// CSV Report suitable for entering to spread sheet
|
|
// InAve, InPk, OutAve, OutPk, EnhancementdB
|
|
Serial.print(pLevelData->pwr0, 5); Serial.print(",");
|
|
Serial.print(pLevelData->peak0, 5); Serial.print(",");
|
|
Serial.print(pLevelData->pwr1, 5); Serial.print(",");
|
|
Serial.print(pLevelData->peak1, 5); Serial.print(",");
|
|
float32_t enhance = (10.0f*log10f(pLevelData->pwr1) - 20.0f*log10f(pLevelData->peak1)) -
|
|
(10.0f*log10f(pLevelData->pwr0) - 20.0f*log10f(pLevelData->peak0));
|
|
if(enhance<1.0f) enhance = 1.0f;
|
|
Serial.println(enhance);
|
|
*/
|
|
}
|
|
}
|
|
|