Added noise measurements (#12)
parent
16fe699111
commit
56bbb1b339
@ -0,0 +1,99 @@ |
||||
/*************************************************************************
|
||||
* This demo uses the BALibrary library to provide enhanced control of |
||||
* the TGA Pro board. |
||||
*
|
||||
* The latest copy of the BA Guitar library can be obtained from |
||||
* https://github.com/Blackaddr/BALibrary
|
||||
*
|
||||
* This demo measures the input noise of the TGA Pro. Make sure nothing is physically plugged |
||||
* into the INPUT jack when you run this program. This allows the switching-input jack to ground |
||||
* the input to zero signal. |
||||
*
|
||||
* The test will measure RMS noise and average sample value while toggling the CODEC HPF |
||||
* every few seconds. the CODEC HPF attempts to maximize headroom by modulating it's digital |
||||
* HPF filter offset. This results in near-zero low-frequncy (DC and sub-sonic) content which can |
||||
* be useful for frequency detection but is not appropriate for when sound quality is desired as |
||||
* the modulation of the filter will result in audible artifacts. |
||||
*
|
||||
*/ |
||||
#include <Wire.h> |
||||
#include <Audio.h> |
||||
#include "BALibrary.h" |
||||
#include "BAEffects.h" |
||||
|
||||
using namespace BALibrary; |
||||
using namespace BAEffects; |
||||
|
||||
#define MEASURE_CODEC_PERFORMANCE // uncomment this line to measure internal codec performance, comment the line to measure TGA analog input circuitry performance.
|
||||
|
||||
BAAudioControlWM8731 codecControl; |
||||
AudioInputI2S i2sIn; |
||||
AudioOutputI2S i2sOut; |
||||
AudioEffectRmsMeasure rmsModule; |
||||
|
||||
// Audio Connections
|
||||
AudioConnection patchInL(i2sIn,0, rmsModule, 0); // route the input to the delay
|
||||
AudioConnection patchInR(i2sIn,1, rmsModule, 1); // route the input to the delay
|
||||
|
||||
AudioConnection patchOutL(rmsModule, 0, i2sOut, 0); // connect the cab filter to the output.
|
||||
AudioConnection patchOutR(rmsModule, 0, i2sOut, 1); // connect the cab filter to the output.
|
||||
|
||||
void setup() { |
||||
|
||||
delay(5); // wait a few ms to make sure the GTA Pro is fully powered up
|
||||
AudioMemory(48); |
||||
|
||||
// If the codec was already powered up (due to reboot) power itd own first
|
||||
codecControl.disable(); |
||||
delay(100); |
||||
codecControl.enable(); |
||||
delay(100); |
||||
|
||||
#if defined(MEASURE_CODEC_PERFORMANCE) |
||||
// Measure TGA board performance with input unplugged, and 0 gain. Please set
|
||||
// the gain switch on the TGA Pro to 0 dB.
|
||||
Serial.println("Measuring CODEC internal performance"); |
||||
codecControl.setLeftInMute(true); // mute the input signal completely
|
||||
codecControl.setRightInMute(true); |
||||
codecControl.setHPFDisable(false); // Start with the HPF enabled
|
||||
#else |
||||
// Measure TGA board performance with input unplugged, and 0 gain. Please set
|
||||
// the gain switch on the TGA Pro to 0 dB.
|
||||
Serial.println("Measuring TGA Pro analog performance"); |
||||
codecControl.setLeftInputGain(23); // 23 = 10111 = 0 dB of CODEC analog gain
|
||||
codecControl.setRightInputGain(23); |
||||
codecControl.setLeftInMute(false); |
||||
codecControl.setRightInMute(false); |
||||
codecControl.setHPFDisable(false); // Start with the HPF enabled.
|
||||
#endif |
||||
|
||||
rmsModule.enable(); |
||||
rmsModule.bypass(false); |
||||
|
||||
|
||||
} |
||||
|
||||
unsigned loopCount = 0; |
||||
bool isHpfEnabled = true; |
||||
|
||||
void loop() {
|
||||
|
||||
// The audio flows automatically through the Teensy Audio Library
|
||||
|
||||
if (loopCount > 100000000) { |
||||
if (isHpfEnabled) { |
||||
Serial.println("Setting HPF disable to true"); |
||||
codecControl.setHPFDisable(true); |
||||
|
||||
isHpfEnabled = false; |
||||
} else { |
||||
Serial.println("Setting HPF disable to false"); |
||||
codecControl.setHPFDisable(false); |
||||
isHpfEnabled = true; |
||||
} |
||||
loopCount = 0; |
||||
} |
||||
|
||||
loopCount++; |
||||
|
||||
} |
@ -0,0 +1,94 @@ |
||||
/**************************************************************************//**
|
||||
* @file |
||||
* @author Steve Lascos |
||||
* @company Blackaddr Audio |
||||
* |
||||
* @brief Measure the RMS noise of a channel |
||||
* |
||||
* @copyright This program 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.* |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY__BAEFFECTS_AUDIOEFFECTDELAYEXTERNAL_H; 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*****************************************************************************/ |
||||
|
||||
#ifndef __BAEFFECTS_AUDIOEFFECTRMSMEASURE_H |
||||
#define __BAEFFECTS_AUDIOEFFECTRMSMEASURE_H |
||||
|
||||
#include <stdint.h> |
||||
#include <Audio.h> |
||||
|
||||
namespace BAEffects { |
||||
|
||||
/**************************************************************************//**
|
||||
* AudioEffectRmsMeasure |
||||
*****************************************************************************/ |
||||
class AudioEffectRmsMeasure : public AudioStream { |
||||
public: |
||||
|
||||
// *** CONSTRUCTORS ***
|
||||
/// Create the measurement object. Default is to measure and calculate over
|
||||
/// approximate 1 second when rate is roughly 44.1 KHz
|
||||
/// @param numBlockMeasurements specifies how many audio blocks to calculate the noise
|
||||
/// over.
|
||||
AudioEffectRmsMeasure(unsigned numBlockMeasurements = 345); |
||||
|
||||
virtual ~AudioEffectRmsMeasure(); ///< Destructor
|
||||
|
||||
/// Get the most recently calculated RMS value
|
||||
/// @returns the non-normalized RMS
|
||||
float getRms(void) { return m_rms; } |
||||
|
||||
/// Get the most recently calculated dBFS value
|
||||
/// @returns the RMS as dB with respecdt to dBFS
|
||||
float getDb(void) { return m_dbfs; } |
||||
|
||||
/// Bypass the effect.
|
||||
/// @param byp when true, bypass wil disable the effect, when false, effect is enabled.
|
||||
/// Note that audio still passes through when bypass is enabled.
|
||||
void bypass(bool byp) { m_bypass = byp; } |
||||
|
||||
/// Get if the effect is bypassed
|
||||
/// @returns true if bypassed, false if not bypassed
|
||||
bool isBypass() { return m_bypass; } |
||||
|
||||
/// Toggle the bypass effect
|
||||
void toggleBypass() { m_bypass = !m_bypass; } |
||||
|
||||
/// Set the output volume.
|
||||
/// @details The default is 1.0.
|
||||
/// @param vol Sets the output volume between -1.0 and +1.0
|
||||
void volume(float vol) {m_volume = vol; } |
||||
|
||||
/// Enables audio processing. Note: when not enabled, CPU load is nearly zero.
|
||||
void enable() { m_enable = true; } |
||||
|
||||
/// Disables audio process. When disabled, CPU load is nearly zero.
|
||||
void disable() { m_enable = false; } |
||||
|
||||
virtual void update(void); ///< update automatically called by the Teesny Audio Library
|
||||
|
||||
private: |
||||
audio_block_t *m_inputQueueArray[1]; |
||||
|
||||
bool m_bypass = true; |
||||
bool m_enable = false; |
||||
float m_volume = 1.0f; |
||||
unsigned m_numBlockMeasurements = 0; |
||||
unsigned m_accumulatorCount = 0; |
||||
int64_t m_sum = 0; |
||||
float m_rms = 0.0f; |
||||
float m_dbfs = 0.0f; |
||||
|
||||
}; |
||||
|
||||
} |
||||
|
||||
#endif /* __BAEFFECTS_AUDIOEFFECTRMSMEASURE_H */ |
@ -0,0 +1,102 @@ |
||||
/*
|
||||
* AudioEffectRmsMeasure.cpp |
||||
* |
||||
* Created on: March 7, 2020 |
||||
* Author: slascos |
||||
*/ |
||||
#include <arm_math.h> |
||||
#include "BALibrary.h" |
||||
#include "AudioEffectRmsMeasure.h" |
||||
|
||||
using namespace BALibrary; |
||||
|
||||
namespace BAEffects { |
||||
|
||||
AudioEffectRmsMeasure::AudioEffectRmsMeasure(unsigned numBlockMeasurements) |
||||
: AudioStream(1, m_inputQueueArray), |
||||
m_numBlockMeasurements(numBlockMeasurements), |
||||
m_accumulatorCount(0), |
||||
m_sum(0), |
||||
m_rms(0.0f), |
||||
m_dbfs(0.0f) |
||||
{ |
||||
} |
||||
|
||||
AudioEffectRmsMeasure::~AudioEffectRmsMeasure() |
||||
{ |
||||
} |
||||
|
||||
void AudioEffectRmsMeasure::update(void) |
||||
{ |
||||
audio_block_t *inputAudioBlock = receiveReadOnly(); // get the next block of input samples
|
||||
|
||||
// Check is block is disabled
|
||||
if (m_enable == false) { |
||||
// do not transmit or process any audio, return as quickly as possible.
|
||||
if (inputAudioBlock) release(inputAudioBlock); |
||||
return; |
||||
} |
||||
|
||||
// Check is block is bypassed, if so either transmit input directly or create silence
|
||||
if (m_bypass == true) { |
||||
// transmit the input directly
|
||||
if (!inputAudioBlock) { |
||||
// create silence
|
||||
inputAudioBlock = allocate(); |
||||
if (!inputAudioBlock) { return; } // failed to allocate
|
||||
else { |
||||
clearAudioBlock(inputAudioBlock); |
||||
} |
||||
} |
||||
transmit(inputAudioBlock, 0); |
||||
release(inputAudioBlock); |
||||
return; |
||||
} |
||||
|
||||
// Calculate the RMS noise over the specified number of audio blocks.
|
||||
// Once the necessary blocks have been accumulated, calculate and print the
|
||||
// RMS noise figure.
|
||||
// RMS noise = sqrt((1/N) * (x1*x1 + x2*x2 + ...) )
|
||||
|
||||
// First create the square sum of the input audio block and add it to the accumulator
|
||||
int64_t dotProduct = 0; |
||||
//arm_dot_prod_q15(inputAudioBlock->data, inputAudioBlock->data, AUDIO_BLOCK_SAMPLES, &dotProduct);
|
||||
for (int i=0; i<AUDIO_BLOCK_SAMPLES; i++) { |
||||
dotProduct += ((int64_t)inputAudioBlock->data[i] * (int64_t)inputAudioBlock->data[i]); |
||||
if (dotProduct < 0) { |
||||
Serial.println("DOT ERROR!"); |
||||
Serial.println(inputAudioBlock->data[i], HEX); |
||||
} |
||||
} |
||||
m_sum += (int64_t)(dotProduct); |
||||
|
||||
m_accumulatorCount++; |
||||
|
||||
// Check if we have enough samples accumulated.
|
||||
if (m_accumulatorCount == m_numBlockMeasurements) { |
||||
// Calculate and print the RMS figure
|
||||
float div = (float)m_sum / (float)(m_accumulatorCount * AUDIO_BLOCK_SAMPLES); |
||||
arm_sqrt_f32(div, &m_rms); |
||||
// dbfs = 20*log10(abs(rmsFigure)/32768.0f);
|
||||
m_dbfs = 20.0f * log10(m_rms/32768.0f); |
||||
|
||||
Serial.print("Accumulator: "); Serial.println((int)(m_sum >> 32), HEX); |
||||
Serial.print("RAW RMS: "); Serial.println(m_rms); |
||||
|
||||
Serial.print("AudioEffectRmsMeasure: the RMS figure is "); Serial.print(m_dbfs); |
||||
Serial.print(" dBFS over "); Serial.print(m_accumulatorCount); Serial.println(" audio blocks"); |
||||
|
||||
m_sum = 0; |
||||
m_accumulatorCount = 0; |
||||
|
||||
} |
||||
|
||||
transmit(inputAudioBlock); |
||||
release(inputAudioBlock); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
|
Loading…
Reference in new issue