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