This program checks that audio and analog I/O work properly. You should physically connect each audio and analog output back to its respective input.
#include <cmath>
#include <Gpio.h>
float ANALOG_OUT_LOW;
float ANALOG_OUT_HIGH;
float ANALOG_IN_LOW;
float ANALOG_IN_HIGH;
enum {
kStateTestingAudioLeft = 0,
kStateTestingAudioRight,
kStateTestingAudioDone,
kStateTestingAnalog,
kStateTestingAnalogDone,
kStateTestingNone
};
uint64_t gLastErrorFrame = 0;
uint32_t gEnvelopeSampleCount = 0;
float gEnvelopeValueL = 0.5, gEnvelopeValueR = 0.5;
float gEnvelopeDecayRate = 0.9995;
int gEnvelopeLastChannel = 0;
float gPositivePeakLevels[2] = {0, 0};
float gNegativePeakLevels[2] = {0, 0};
float gPeakLevelDecayRate = 0.999;
int gAnalogTestSuccessCounter = 0;
const float gPeakLevelLowThreshold = 0.02;
const float gPeakLevelHighThreshold = 0.2;
const float gDCOffsetThreshold = 0.1;
int gAudioTestState = kStateTestingNone;
int gAudioTestStateSampleCount = 0;
int gAudioTestSuccessCounter = 0;
const int gAudioTestSuccessCounterThreshold = 64;
const int gAudioTestStateSampleThreshold = 16384;
{
printf("To prepare for this test you should physically connect each audio and analog output back to its respective input\n");
{
printf("On Bela Mini, feed back the line out L to audio in L and analogs 0, 2, 4, 6, and a feed the line out R to audio in L and analogs 1, 3, 5 ,7\n");
ANALOG_OUT_LOW = -1;
ANALOG_OUT_HIGH = 1;
ANALOG_IN_LOW = 0.15;
ANALOG_IN_HIGH = 0.5;
led1->
open(87, Gpio::OUTPUT);
led2->
open(89, Gpio::OUTPUT);
} else {
ANALOG_OUT_LOW = 0;
ANALOG_OUT_HIGH = 50000.0 / 65536.0;
ANALOG_IN_LOW = 2048.0 / 65536.0;
ANALOG_IN_HIGH = 50000.0 / 65536.0;
}
return true;
}
{
static float phase = 0.0;
static int sampleCounter = 0;
static int invertChannel = 0;
float frequency = 0;
if(gAudioTestState == kStateTestingNone){
gAudioTestState = kStateTestingAudioLeft;
rt_printf("Testing audio left\n");
}
if(gAudioTestState == kStateTestingAudioDone)
{
gAudioTestState = kStateTestingAnalog;
rt_printf("Testing analog\n");
}
for(
unsigned int n = 0; n < context->
audioFrames; n++) {
if(value > gPositivePeakLevels[ch])
gPositivePeakLevels[ch] = value;
gPositivePeakLevels[ch] += 0.1f;
gPositivePeakLevels[ch] *= gPeakLevelDecayRate;
gPositivePeakLevels[ch] -= 0.1f;
if(value < gNegativePeakLevels[ch])
gNegativePeakLevels[ch] = value;
gNegativePeakLevels[ch] -= 0.1f;
gNegativePeakLevels[ch] *= gPeakLevelDecayRate;
gNegativePeakLevels[ch] += 0.1f;
}
int enabledChannel;
int disabledChannel;
const char* enabledChannelLabel;
const char* disabledChannelLabel;
if(gAudioTestState == kStateTestingAudioLeft) {
enabledChannel = 0;
disabledChannel = 1;
enabledChannelLabel = "Left";
disabledChannelLabel = "Right";
} else if (gAudioTestState == kStateTestingAudioRight) {
enabledChannel = 1;
disabledChannel = 0;
enabledChannelLabel = "Right";
disabledChannelLabel = "Left";
}
if(gAudioTestState == kStateTestingAudioLeft || gAudioTestState == kStateTestingAudioRight)
{
audioWrite(context, n, enabledChannel, 0.2f * sinf(phase));
frequency = 3000.0;
if(phase >= M_PI)
phase -= 2.0f * (float)M_PI;
gAudioTestStateSampleCount++;
if(gAudioTestStateSampleCount >= gAudioTestStateSampleThreshold) {
if((gPositivePeakLevels[enabledChannel] - gNegativePeakLevels[enabledChannel]) >= gPeakLevelHighThreshold
&& (gPositivePeakLevels[disabledChannel] - gNegativePeakLevels[disabledChannel]) <= gPeakLevelLowThreshold &&
fabsf(gPositivePeakLevels[disabledChannel]) < gDCOffsetThreshold &&
fabsf(gNegativePeakLevels[disabledChannel]) < gDCOffsetThreshold) {
gAudioTestSuccessCounter++;
if(gAudioTestSuccessCounter >= gAudioTestSuccessCounterThreshold) {
rt_printf("Audio %s test successful\n", enabledChannelLabel);
if(gAudioTestState == kStateTestingAudioLeft)
{
gAudioTestState = kStateTestingAudioRight;
rt_printf("Testing audio Right\n");
} else if(gAudioTestState == kStateTestingAudioRight)
{
gAudioTestState = kStateTestingAudioDone;
}
gAudioTestStateSampleCount = 0;
gAudioTestSuccessCounter = 0;
}
}
else {
if((gPositivePeakLevels[enabledChannel] - gNegativePeakLevels[enabledChannel]) < gPeakLevelHighThreshold)
rt_printf("%s Audio In FAIL: insufficient signal: %f\n", enabledChannelLabel,
gPositivePeakLevels[enabledChannel] - gNegativePeakLevels[enabledChannel]);
else if(gPositivePeakLevels[disabledChannel] - gNegativePeakLevels[disabledChannel] > gPeakLevelLowThreshold)
rt_printf("%s Audio In FAIL: signal present when it should not be: %f\n", disabledChannelLabel,
gPositivePeakLevels[disabledChannel] - gNegativePeakLevels[disabledChannel]);
else if(fabsf(gPositivePeakLevels[disabledChannel]) >= gDCOffsetThreshold ||
fabsf(gNegativePeakLevels[disabledChannel]) >= gDCOffsetThreshold)
rt_printf("%s Audio In FAIL: DC offset: (%f, %f)\n", disabledChannelLabel,
gPositivePeakLevels[disabledChannel], gNegativePeakLevels[disabledChannel]);
}
gAudioTestSuccessCounter--;
if(gAudioTestSuccessCounter <= 0)
gAudioTestSuccessCounter = 0;
}
}
}
if(
gAudioTestState == kStateTestingAnalogDone ||
)
{
audioWrite(context, n, 0, gEnvelopeValueL * sinf(phase));
audioWrite(context, n, 1, gEnvelopeValueR * sinf(phase));
{
gEnvelopeValueL *= gEnvelopeDecayRate;
gEnvelopeValueR *= gEnvelopeDecayRate;
gEnvelopeSampleCount++;
if(gEnvelopeSampleCount > 22050) {
if(gEnvelopeLastChannel == 0)
gEnvelopeValueR = 0.5;
else
gEnvelopeValueL = 0.5;
gEnvelopeLastChannel = !gEnvelopeLastChannel;
gEnvelopeSampleCount = 0;
}
frequency = 880.0;
if(led1)
{
led1->
write(gEnvelopeValueL > 0.2);
}
if(led2)
{
led2->
write(gEnvelopeValueR > 0.2);
}
} else {
gEnvelopeValueL = gEnvelopeValueR = 0.5;
gEnvelopeLastChannel = 0;
frequency = 220.0;
}
if(phase >= M_PI)
phase -= 2.0f * (float)M_PI;
}
}
if(gAudioTestState == kStateTestingAnalog)
{
for(unsigned int n = 0; n < outFrames; n++) {
for(unsigned int k = 0; k < outChannels; k++) {
float outValue;
if((k % outChannels) == (invertChannel % outChannels))
outValue = sampleCounter < 512 ? ANALOG_OUT_HIGH : ANALOG_OUT_LOW;
else
outValue = sampleCounter < 512 ? ANALOG_OUT_LOW : ANALOG_OUT_HIGH;
else
}
}
if(sampleCounter == 256 || sampleCounter == 768) {
bool inverted = ((k % outChannels) == (invertChannel % outChannels));
if(
(
inverted &&
(
(sampleCounter == 256 && inValue < ANALOG_IN_HIGH) ||
(sampleCounter == 768 && inValue > ANALOG_IN_LOW)
)
) || (
!inverted &&
(
(sampleCounter == 256 && inValue > ANALOG_IN_LOW) ||
(sampleCounter == 768 && inValue < ANALOG_IN_HIGH)
)
)
)
{
rt_printf("Analog FAIL [output %d, input %d] -- output %s input %f %s\n",
k % outChannels,
k,
(sampleCounter == 256 && inverted) || (sampleCounter == 768 && !inverted) ? "HIGH" : "LOW",
inValue,
inverted ? "(inverted channel)" : "");
gAnalogTestSuccessCounter = 0;
} else {
++gAnalogTestSuccessCounter;
}
}
}
if(++sampleCounter >= 1024) {
sampleCounter = 0;
invertChannel++;
if(invertChannel >= 8)
invertChannel = 0;
}
if(gAnalogTestSuccessCounter >= 500) {
static bool notified = false;
if(!notified)
{
rt_printf("Analog test successful\n");
gAudioTestState = kStateTestingAnalogDone;
}
notified = true;
}
}
}
}
{
delete led1;
delete led2;
}