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.
OpenAudio_ArduinoLibrary/AudioControlTester.h

539 lines
18 KiB

#ifndef _AudioControlTester_h
#define _AudioControlTester_h
//include <Tympan_Library.h>
#include <OpenAudio_ArduinoLibrary.h>
#define max_steps 64
#define max_num_chan 16 //max number of test signal inputs to the AudioTestSignalMeasurementMulti_F32
//prototypes
class AudioTestSignalGenerator_F32;
class AudioTestSignalMeasurementInterface_F32;
class AudioTestSignalMeasurement_F32;
class AudioTestSignalMeasurementMulti_F32;
class AudioControlSignalTesterInterface_F32;
class AudioControlSignalTester_F32;
class AudioControlTestAmpSweep_F32;
class AudioControlTestFreqSweep_F32;
// class definitions
class AudioTestSignalGenerator_F32 : public AudioStream_F32
{
//GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
//GUI: shortName: testSignGen
public:
AudioTestSignalGenerator_F32(void): AudioStream_F32(1,inputQueueArray) {
setSampleRate_Hz(AUDIO_SAMPLE_RATE);
setDefaultValues();
makeConnections();
}
AudioTestSignalGenerator_F32(const AudioSettings_F32 &settings): AudioStream_F32(1,inputQueueArray) {
setAudioSettings(settings);
setDefaultValues();
makeConnections();
}
~AudioTestSignalGenerator_F32(void) {
if (patchCord1 != NULL) delete patchCord1;
}
void setAudioSettings(const AudioSettings_F32 &settings) {
setSampleRate_Hz(settings.sample_rate_Hz);
}
void setSampleRate_Hz(const float _fs_Hz) {
//pass this data on to its components that care
sine_gen.setSampleRate_Hz(_fs_Hz);
}
void makeConnections(void) {
patchCord1 = new AudioConnection_F32(sine_gen, 0, gain_alg, 0);
patchCord2 = new AudioConnection_F32(gain_alg, 0, record_queue, 0);
}
virtual void update(void);
void begin(void) {
is_testing = true;
//if (Serial) Serial.println("AudioTestSignalGenerator_F32: begin(): ...");
}
void end(void) { is_testing = false; }
AudioSynthWaveformSine_F32 sine_gen;
AudioEffectGain_F32 gain_alg;
AudioRecordQueue_F32 record_queue;
AudioConnection_F32 *patchCord1;
AudioConnection_F32 *patchCord2;
void amplitude(float val) {
sine_gen.amplitude(1.0);
gain_alg.setGain(val);
}
void frequency(float val) {
sine_gen.frequency(val);
}
virtual void setSignalAmplitude_dBFS(float val_dBFS) {
amplitude(sqrtf(2.0)*sqrtf(powf(10.0f,0.1*val_dBFS)));
};
virtual void setSignalFrequency_Hz(float val_Hz) {
frequency(val_Hz);
}
private:
bool is_testing = false;
audio_block_f32_t *inputQueueArray[1];
void setDefaultValues(void) {
sine_gen.end(); //disable it for now
record_queue.end(); //disable it for now;
is_testing = false;
frequency(1000.f);
amplitude(0.0f);
}
};
// //////////////////////////////////////////////////////////////////////////
class AudioTestSignalMeasurementInterface_F32 {
public:
AudioTestSignalMeasurementInterface_F32 (void) {};
void setAudioSettings(const AudioSettings_F32 &settings) {
setSampleRate_Hz(settings.sample_rate_Hz);
}
void setSampleRate_Hz(const float _fs_Hz) {
//pass this data on to its components that care. None care right now.
}
virtual void update(void);
virtual float computeRMS(float data[], int n) {
float rms_value;
arm_rms_f32 (data, n, &rms_value);
return rms_value;
}
virtual void begin(AudioControlSignalTester_F32 *p_controller) {
//if (Serial) Serial.println("AudioTestSignalMeasurement_F32: begin(): ...");
testController = p_controller;
is_testing = true;
}
virtual void end(void) {
//if (Serial) Serial.println("AudioTestSignalMeasurement_F32: end(): ...");
testController = NULL;
is_testing = false;
}
protected:
bool is_testing = false;
//audio_block_f32_t *inputQueueArray[2];
AudioControlSignalTester_F32 *testController = NULL;
virtual void setDefaultValues(void) {
is_testing = false;
}
};
class AudioTestSignalMeasurement_F32 : public AudioStream_F32, public AudioTestSignalMeasurementInterface_F32
{
//GUI: inputs:2, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: testSigMeas
public:
AudioTestSignalMeasurement_F32(void): AudioStream_F32(2,inputQueueArray) {
setSampleRate_Hz(AUDIO_SAMPLE_RATE);
setDefaultValues();
}
AudioTestSignalMeasurement_F32(const AudioSettings_F32 &settings): AudioStream_F32(2,inputQueueArray) {
setAudioSettings(settings);
setDefaultValues();
}
void update(void);
private:
audio_block_f32_t *inputQueueArray[2];
};
class AudioTestSignalMeasurementMulti_F32 : public AudioStream_F32, public AudioTestSignalMeasurementInterface_F32
{
//GUI: inputs:10, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: testSigMeas
public:
AudioTestSignalMeasurementMulti_F32(void): AudioStream_F32(max_num_chan+1,inputQueueArray) {
setSampleRate_Hz(AUDIO_SAMPLE_RATE);
setDefaultValues();
}
AudioTestSignalMeasurementMulti_F32(const AudioSettings_F32 &settings): AudioStream_F32(max_num_chan+1,inputQueueArray) {
setAudioSettings(settings);
setDefaultValues();
}
void update(void);
private:
//int num_input_connections = max_num_chan+1;
int num_test_values = max_num_chan;
audio_block_f32_t *inputQueueArray[max_num_chan+1];
};
// ///////////////////////////////////////////////////////////////////////////////////
class AudioControlSignalTesterInterface_F32 {
public:
AudioControlSignalTesterInterface_F32(void) {};
//virtual void setAudioBlockSamples(void) = 0;
//virtual void setSampleRate_hz(void) = 0;
virtual void begin(void) = 0;
virtual void end(void) = 0;
virtual void setStepPattern(float, float, float) = 0;
virtual void transferRMSValues(float, float) = 0;
virtual void transferRMSValues(float, float *, int) = 0;
virtual bool available(void) = 0;
};
class AudioControlSignalTester_F32 : public AudioControlSignalTesterInterface_F32
{
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: sigTest(Abstract)
public:
AudioControlSignalTester_F32(AudioSettings_F32 &settings, AudioTestSignalGenerator_F32 &_sig_gen, AudioTestSignalMeasurementInterface_F32 &_sig_meas)
: AudioControlSignalTesterInterface_F32(), sig_gen(_sig_gen), sig_meas(_sig_meas) {
setAudioBlockSamples(settings.audio_block_samples);
setSampleRate_Hz(settings.sample_rate_Hz);
resetState();
}
virtual void begin(void) {
Serial.println("AudioControlSignalTester_F32: begin(): ...");
recomputeTargetCountsPerStep(); //not needed, just to print some debugging messages
//activate the instrumentation
sig_gen.begin();
sig_meas.begin(this);
//start the test
resetState();
gotoNextStep();
}
//use this to cancel the test
virtual void end(void) {
finishTest();
}
void setAudioSettings(AudioSettings_F32 audio_settings) {
setAudioBlockSamples(audio_settings.audio_block_samples);
setSampleRate_Hz(audio_settings.sample_rate_Hz);
}
void setAudioBlockSamples(int block_samples) {
audio_block_samples = block_samples;
recomputeTargetCountsPerStep();
}
void setSampleRate_Hz(float fs_Hz) {
sample_rate_Hz = fs_Hz;
recomputeTargetCountsPerStep();
}
//define how long (seconds) to spend at each step of the test
void setTargetDurPerStep_sec(float sec) {
if (sec > 0.001) {
target_dur_per_step_sec = sec;
recomputeTargetCountsPerStep();
} else {
Serial.print(F("AudioControlSignalTester_F32: setTargetDurPerStep_sec: given duration too short: "));
Serial.print(target_dur_per_step_sec);
Serial.print(F(". Ignoring..."));
return;
}
}
virtual void setStepPattern(float _start_val, float _end_val, float _step_val) {
start_val = _start_val; end_val = _end_val; step_val = _step_val;
recomputeTargetNumberOfSteps();
}
virtual void transferRMSValues(float baseline_rms, float test_rms) {
transferRMSValues(baseline_rms, &test_rms, 1);
}
virtual void transferRMSValues(float baseline_rms, float *test_rms, int num_chan) {
if (counter_ignore > 0) {
//ignore this reading
counter_ignore--;
return;
}
given_num_chan = num_chan;
if (given_num_chan > max_num_chan) {
Serial.println(F("AudioControlSignalTester_F32: transferRMSValues: *** ERROR ***"));
Serial.print(F(" : num_chan (")); Serial.print(num_chan); Serial.print(")");
Serial.print(F(" is bigger max_num_chan (")); Serial.println(max_num_chan);
Serial.println(F(" : Skipping..."));
return;
}
//add this number
sum_sig_pow_baseline[counter_step] += (baseline_rms*baseline_rms);
for (int Ichan=0; Ichan < num_chan; Ichan++) {
sum_sig_pow_test[counter_step][Ichan] += (test_rms[Ichan]*test_rms[Ichan]);
}
freq_at_each_step_Hz[counter_step] = signal_frequency_Hz;
counter_sum[counter_step]++;
//have all the channels checked in?
if (counter_sum[counter_step] >= target_counts_per_step) {
gotoNextStep();
}
}
virtual void setSignalFrequency_Hz(float freq_Hz) {
signal_frequency_Hz = freq_Hz;
sig_gen.setSignalFrequency_Hz(signal_frequency_Hz);
}
virtual void setSignalAmplitude_dBFS(float amp_dBFS) {
signal_amplitude_dBFS = amp_dBFS;
sig_gen.setSignalAmplitude_dBFS(amp_dBFS);
}
virtual void printTableOfResults(Stream *s) {
float ave1_dBFS, ave2_dBFS, ave3_dBFS, gain_dB, total_pow, total_wav, foo_pow;
s->println(" : Freq (Hz), Input (dBFS), Per-Chan Output (dBFS), Total Gain (inc) (dB), Total Gain (coh) (dB)");
//s->print(" : given_num_chan = ");s->println(given_num_chan);
for (int i=0; i < target_n_steps; i++) {
ave1_dBFS = 10.f*log10f(sum_sig_pow_baseline[i]/counter_sum[i]);
s->print(" "); s->print(freq_at_each_step_Hz[i],0);
s->print(", "); s->print(ave1_dBFS,1);
total_pow = 0.0f;
total_wav = 0.0f;
for (int Ichan=0; Ichan < given_num_chan; Ichan++) {
if (Ichan==0) {
s->print(", ");
} else {
s->print(", ");
}
foo_pow = sum_sig_pow_test[i][Ichan]/counter_sum[i];
ave2_dBFS = 10.f*log10f(foo_pow);
s->print(ave2_dBFS,1);
total_pow += foo_pow; //sum as if it's noise being recombined incoherently
total_wav += sqrtf(foo_pow); //sum as it it's a in-phase tone being combined coherently
}
ave2_dBFS = 10.f*log10f(total_pow);
gain_dB = ave2_dBFS - ave1_dBFS;
s->print(", "); s->print(gain_dB,2);
ave3_dBFS = 20.f*log10f(total_wav);
gain_dB = ave3_dBFS - ave1_dBFS;
s->print(", "); s->println(gain_dB,2);
}
}
bool isDataAvailable = false;
bool available(void) { return isDataAvailable; }
protected:
AudioTestSignalGenerator_F32 &sig_gen;
AudioTestSignalMeasurementInterface_F32 &sig_meas;
float signal_frequency_Hz = 1000.f;
float signal_amplitude_dBFS = -50.0f;
int counter_ignore = 0;
//bool is_testing = 0;
int audio_block_samples = AUDIO_BLOCK_SAMPLES;
float sample_rate_Hz = AUDIO_SAMPLE_RATE_EXACT;
float target_dur_per_step_sec = 0.2;
int target_counts_per_step = 1;
//const int max_steps = 64;
float start_val = 0, end_val = 1.f, step_val = 1.f;
int target_n_steps = 1;
int given_num_chan = max_num_chan;
float sum_sig_pow_baseline[max_steps];
float sum_sig_pow_test[max_steps][max_num_chan];
float freq_at_each_step_Hz[max_steps];
int counter_sum[max_steps], counter_step=-1;
int recomputeTargetCountsPerStep(void) {
target_counts_per_step = max(1,(int)((target_dur_per_step_sec * sample_rate_Hz / ((float)audio_block_samples))+0.5)); //round
// if (Serial) {
// Serial.println("AudioControlSignalTester_F32: recomputeTargetCountsPerStep: ");
// Serial.print(" : target_dur_per_step_sec = "); Serial.println(target_dur_per_step_sec);
// Serial.print(" : sample_rate_Hz = "); Serial.println(sample_rate_Hz);
// Serial.print(" : audio_block_samples = "); Serial.println(audio_block_samples);
// Serial.print(" : target_counts_per_step = "); Serial.println(target_counts_per_step);
// }
return target_counts_per_step;
}
virtual int recomputeTargetNumberOfSteps(void) {
return target_n_steps = (int)((end_val - start_val)/step_val + 0.5)+1; //round
}
virtual void resetState(void) {
isDataAvailable = false;
for (int i=0; i<max_steps; i++) {
sum_sig_pow_baseline[i]=0.0f;
for (int Ichan=0; Ichan<max_num_chan; Ichan++) sum_sig_pow_test[i][Ichan]=0.0f;
counter_sum[i] = 0;
}
counter_step = -1;
}
virtual void gotoNextStep(void) {
counter_step++;
//Serial.print("AudioControlSignalTester_F32: gotoNextStep: starting step ");
//Serial.println(counter_step);
if (counter_step >= target_n_steps) {
finishTest();
return;
} else {
counter_ignore = 10; //ignore first 10 packets
counter_sum[counter_step]=0;
sum_sig_pow_baseline[counter_step]=0.0f;
for (int Ichan=0; Ichan < max_num_chan; Ichan++) sum_sig_pow_test[counter_step][Ichan]=0.0f;
updateSignalGenerator();
freq_at_each_step_Hz[counter_step]=0.0f;
}
}
virtual void updateSignalGenerator(void)
{
//if (Serial) Serial.println("AudioControlSignalTester_F32: updateSignalGenerator(): did the child version get called?");
} //override this is a child class!
virtual void finishTest(void) {
//Serial.println("AudioControlSignalTester_F32: finishTest()...");
//disable the test instrumentation
sig_gen.end();
sig_meas.end();
//let listeners know that data is available
isDataAvailable = true;
}
};
// //////////////////////////////////////////////////////////////////////////
class AudioControlTestAmpSweep_F32 : public AudioControlSignalTester_F32
{
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: ampSweepTester
public:
AudioControlTestAmpSweep_F32(AudioSettings_F32 &settings, AudioTestSignalGenerator_F32 &_sig_gen, AudioTestSignalMeasurementInterface_F32 &_sig_meas)
: AudioControlSignalTester_F32(settings, _sig_gen,_sig_meas)
{
float start_amp_dB = -100.0f, end_amp_dB = 0.0f, step_amp_dB = 2.5f;
setStepPattern(start_amp_dB, end_amp_dB, step_amp_dB);
setTargetDurPerStep_sec(0.25);
resetState();
}
void begin(void) {
//activate the instrumentation
sig_gen.begin();
sig_meas.begin(this);
//start the test
resetState();
gotoNextStep();
}
//use this to cancel the test
//void end(void) {
// finishTest();
//}
void printTableOfResults(Stream *s) {
s->println("AudioControlTestAmpSweep_F32: Start Table of Results...");
AudioControlSignalTester_F32::printTableOfResults(s);
s->println("AudioControlTestAmpSweep_F32: End Table of Results...");
}
protected:
virtual void updateSignalGenerator(void) {
float new_amp_dB = start_val + ((float)counter_step)*step_val; //start_val and step_val are in parent class
Serial.print("AudioControlTestAmpSweep_F32: updateSignalGenerator(): setting amplitude to (dBFS) ");
Serial.println(new_amp_dB);
setSignalAmplitude_dBFS(new_amp_dB);
}
void finishTest(void) {
//disable the test instrumentation
setSignalAmplitude_dBFS(-1000.0f); //some very quiet value
//do all of the common actions
AudioControlSignalTester_F32::finishTest();
//print results
printTableOfResults(&Serial);
}
//void resetState(void) {
// AudioControlSignalTester_F32::resetState();
//}
};
// //////////////////////////////////////////////////////////////////////////
class AudioControlTestFreqSweep_F32 : public AudioControlSignalTester_F32
{
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
//GUI: shortName: freqSweepTester
public:
AudioControlTestFreqSweep_F32(AudioSettings_F32 &settings, AudioTestSignalGenerator_F32 &_sig_gen, AudioTestSignalMeasurementInterface_F32 &_sig_meas)
: AudioControlSignalTester_F32(settings, _sig_gen,_sig_meas)
{
float start_freq_Hz = 125.f, end_freq_Hz = 16000.f, step_freq_octave = sqrtf(2.0);
setStepPattern(start_freq_Hz, end_freq_Hz, step_freq_octave);
setTargetDurPerStep_sec(0.25);
resetState();
}
void begin(void) {
//activate the instrumentation
sig_gen.begin();
sig_meas.begin(this);
//start the test
resetState();
recomputeTargetNumberOfSteps();
gotoNextStep();
}
//use this to cancel the test
//void end(void) {
// finishTest();
//}
void printTableOfResults(Stream *s) {
s->println("AudioControlTestFreqSweep_F32: Start Table of Results...");
AudioControlSignalTester_F32::printTableOfResults(s);
s->println("AudioControlTestFreqSweep_F32: End Table of Results...");
}
protected:
float signal_frequency_Hz = 1000.f;
float signal_amplitude_dBFS = -50.0f;
virtual int recomputeTargetNumberOfSteps(void) {
return target_n_steps = (int)(log10f(end_val/start_val)/log10f(step_val)+0.5) + 1; //round
}
virtual void updateSignalGenerator(void) {
//logarithmically step the frequency
float new_freq_Hz = start_val * powf(step_val,counter_step);
Serial.print("AudioControlTestFreqSweep_F32: updateSignalGenerator(): setting freq to ");
Serial.println(new_freq_Hz);
setSignalFrequency_Hz(new_freq_Hz);
}
void finishTest(void) {
//disable the test instrumentation
setSignalAmplitude_dBFS(-1000.0f); //some very quiet value
setSignalFrequency_Hz(1000.f);
//do all of the common actions
AudioControlSignalTester_F32::finishTest();
//print results
printTableOfResults(&Serial);
}
//void resetState(void) {
// AudioControlSignalTester_F32::resetState();
//}
};
#endif