
Originally Posted by
Werkstatt Kreuzberg
So what can i do? Using an interval timer like Subfanatic did??
And here comes the answer. I have tried different types of timers with no success. All kinds of calling the AudioPlayQueue from an interrupt are leading to problems.
So i decided to link the PlayQueue to a RecordQueue to get the right timing for the audio library. Every time the RecordQueue receives a new audio packet it triggers the PlayQueue.
And this looks very good to me.
Sample played from EXTMEM:
Code:
*AudioPlayQueue Test*
AudioBlockSamples: 128 AudioMem: 10 BufSize: 32768 Bytes SampleT: 371 mS FCPU: 600 MHz EXTMEM TestInterval: 500 mS
1 PlayQueueCalls 0 LastTxIntervals Min 0 Avg 0 Max 0 uS AudioMemUsed 0 Loops/S 1
2 PlayQueueCalls 173 LastTxIntervals Min 0 Avg 0 Max 0 uS AudioMemUsed 2 Loops/S 6813184
3 PlayQueueCalls 172 LastTxIntervals Min 2896 Avg 2901 Max 2907 uS AudioMemUsed 2 Loops/S 6832277
4 PlayQueueCalls 173 LastTxIntervals Min 2898 Avg 2902 Max 2908 uS AudioMemUsed 2 Loops/S 6832345
5 PlayQueueCalls 173 LastTxIntervals Min 2895 Avg 2902 Max 2907 uS AudioMemUsed 2 Loops/S 6832297
6 PlayQueueCalls 172 LastTxIntervals Min 2896 Avg 2901 Max 2910 uS AudioMemUsed 2 Loops/S 6832990
7 PlayQueueCalls 173 LastTxIntervals Min 2897 Avg 2901 Max 2907 uS AudioMemUsed 2 Loops/S 6832443
8 PlayQueueCalls 172 LastTxIntervals Min 2894 Avg 2901 Max 2909 uS AudioMemUsed 2 Loops/S 6832742
9 PlayQueueCalls 173 LastTxIntervals Min 2895 Avg 2902 Max 2908 uS AudioMemUsed 2 Loops/S 6832591
10 PlayQueueCalls 173 LastTxIntervals Min 2895 Avg 2901 Max 2909 uS AudioMemUsed 2 Loops/S 6832639
MaxAudioCpu Used: 0 ElapsedTime: 5 Seconds TxIntervals Min: 2894 Avg: 2901 Max: 2910 uS
Sample played from DMAMEM:
Code:
*AudioPlayQueue Test*
AudioBlockSamples: 128 AudioMem: 10 BufSize: 32768 Bytes SampleT: 371 mS FCPU: 600 MHz DMAMEM TestInterval: 500 mS
1 PlayQueueCalls 0 LastTxIntervals Min 0 Avg 0 Max 0 uS AudioMemUsed 0 Loops/S 1
2 PlayQueueCalls 173 LastTxIntervals Min 0 Avg 0 Max 0 uS AudioMemUsed 2 Loops/S 6828643
3 PlayQueueCalls 172 LastTxIntervals Min 2900 Avg 2901 Max 2903 uS AudioMemUsed 2 Loops/S 6834204
4 PlayQueueCalls 173 LastTxIntervals Min 2901 Avg 2902 Max 2903 uS AudioMemUsed 2 Loops/S 6833840
5 PlayQueueCalls 173 LastTxIntervals Min 2901 Avg 2902 Max 2903 uS AudioMemUsed 2 Loops/S 6833998
6 PlayQueueCalls 172 LastTxIntervals Min 2901 Avg 2902 Max 2903 uS AudioMemUsed 2 Loops/S 6834184
7 PlayQueueCalls 173 LastTxIntervals Min 2901 Avg 2902 Max 2903 uS AudioMemUsed 2 Loops/S 6834008
8 PlayQueueCalls 172 LastTxIntervals Min 2901 Avg 2902 Max 2903 uS AudioMemUsed 2 Loops/S 6834233
9 PlayQueueCalls 173 LastTxIntervals Min 2900 Avg 2901 Max 2903 uS AudioMemUsed 2 Loops/S 6834066
10 PlayQueueCalls 173 LastTxIntervals Min 2900 Avg 2901 Max 2903 uS AudioMemUsed 2 Loops/S 6834120
MaxAudioCpu Used: 0 ElapsedTime: 5 Seconds TxIntervals Min: 2900 Avg: 2901 Max: 2903 uS
No crackle, no problems 
Code:
/* Teensy 4.1, Arduino 1.8.5, Teensyduino 1.53 */
#include <Audio.h>
AudioSynthWaveformDc dcSynth;
AudioRecordQueue recordQueue;
AudioPlayQueue playQueue;
AudioOutputSPDIF3 spdif3Output;
AudioOutputUSB usbOutput;
AudioConnection patchCord1(dcSynth, 0, recordQueue, 0);
AudioConnection patchCord2(playQueue, 0, spdif3Output, 0);
AudioConnection patchCord3(playQueue, 0, usbOutput, 0);
AudioConnection patchCord4(playQueue, 0, usbOutput, 1);
uint32_t blinkLedTicks = 0;
uint32_t serialTerminalOutMillis = 0;
uint32_t serialTerminalOutRuns = 0;
uint32_t serialTerminalRowCnt = 0;
uint32_t transmitAudioBlockIntervalMicros = 0;
uint32_t elapsedTime = 0;
#define MEM_TO_USE 2
const int32_t SAMPLES = AUDIO_BLOCK_SAMPLES * 128;
#if MEM_TO_USE == 1
EXTMEM int16_t sampleBuffer[SAMPLES];
char* memText = "EXTMEM";
#elif MEM_TO_USE == 2
DMAMEM int16_t sampleBuffer[SAMPLES];
char* memText = "DMAMEM";
#elif MEM_TO_USE == 3
int16_t sampleBuffer[SAMPLES];
char* memText = "RAM";
#endif
uint32_t bufferPosition = 0;
int16_t *queueTransmitBuffer;
uint32_t audioMemUsed;
uint32_t maxAudioMemUsed;
uint32_t audioCpuUsed;
uint32_t maxAudioCpuUsed;
uint32_t triggerPlayQueueCnt = 0;
uint32_t playQueueCalls = 0;
uint32_t playQueueCallsSum = 0;
uint32_t loopCnt = 0;
uint32_t avgLoopsPerSecond = 0;
uint32_t testState = 0;
bool buildNewSineWave = true;
uint32_t sineWaveFrequency = 1000;
uint32_t sineWaveFrequencyDirection = 0;
#define SINE_WAVE_MIN_FREQUENCY 100
#define SINE_WAVE_MAX_FREQUENCY 1000
#define SINE_WAVE_FREQUENCY_CHANGE 100
#define AUDIO_MEMORY_BLOCKS 10
#define SERIAL_TERMINAL_OUT_INTERVAL 500 // In mS
#define MAX_SERIAL_TERMINAL_OUT_RUNS 10 // Max rows for the test. If it's Zero the test runs until Loops/S drops.
const uint32_t CLOCK_CYCLES_PER_MICROSECOND = F_CPU / 1000000;
uint32_t lastTxAudioBlockIntervalCycCnt = 0;
uint32_t txAudioBlockIntervalCycleCountMicros = 0;
uint32_t txAudioBlockIntervalCycleCountMicrosSum = 0;
uint32_t txAudioBlockIntervalCycleCountMicrosSumSum = 0;
uint32_t lastMinTxAudioBlockIntervalCycleCountMicros = 0;
uint32_t lastMaxTxAudioBlockIntervalCycleCountMicros = 0;
uint32_t overallMinTxAudioBlockIntervalCycleCountMicros = 9999;
uint32_t overallMaxTxAudioBlockIntervalCycleCountMicros = 0;
void setup() {
/* Enable Clock Cycle Counter */
ARM_DEMCR |= ARM_DEMCR_TRCENA;
ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA;
Serial.begin(115200);
delay(500);
AudioMemory(AUDIO_MEMORY_BLOCKS);
Serial.printf("\n*AudioPlayQueue Test*\n\n");
Serial.printf("AudioBlockSamples: %d AudioMem: %d BufSize: %d Bytes SampleT: %d mS FCPU: %d MHz %s TestInterval: %d mS\n\n", AUDIO_BLOCK_SAMPLES, AUDIO_MEMORY_BLOCKS, SAMPLES * 2, SAMPLES * 1000 / 44100, F_CPU/1000000, memText, SERIAL_TERMINAL_OUT_INTERVAL);
pinMode(13, OUTPUT);
BuildSineWave();
recordQueue.begin();
elapsedTime = millis();
}
void loop() {
loopCnt++;
CheckRecordQueue();
PlayQueue();
//BuildSineWave(); // Generate a new sine wave each buffer end
SerialTerminalOut();
BlinkLed();
}
void CheckRecordQueue() {
if (recordQueue.available()) {
recordQueue.readBuffer();
recordQueue.freeBuffer();
triggerPlayQueueCnt++;
}
}
void PlayQueue() {
if (triggerPlayQueueCnt > 0) {
triggerPlayQueueCnt--;
queueTransmitBuffer = playQueue.getBuffer();
memcpy(queueTransmitBuffer, sampleBuffer + bufferPosition, AUDIO_BLOCK_SAMPLES * 2);
playQueue.playBuffer();
if (lastTxAudioBlockIntervalCycCnt) txAudioBlockIntervalCycleCountMicros = (ARM_DWT_CYCCNT - lastTxAudioBlockIntervalCycCnt) / CLOCK_CYCLES_PER_MICROSECOND;
lastTxAudioBlockIntervalCycCnt = ARM_DWT_CYCCNT;
if (serialTerminalRowCnt > 1) {
txAudioBlockIntervalCycleCountMicrosSum = txAudioBlockIntervalCycleCountMicrosSum + txAudioBlockIntervalCycleCountMicros;
txAudioBlockIntervalCycleCountMicrosSumSum = txAudioBlockIntervalCycleCountMicrosSumSum + txAudioBlockIntervalCycleCountMicros;
if (txAudioBlockIntervalCycleCountMicros < lastMinTxAudioBlockIntervalCycleCountMicros || lastMinTxAudioBlockIntervalCycleCountMicros == 0) lastMinTxAudioBlockIntervalCycleCountMicros = txAudioBlockIntervalCycleCountMicros;
if (txAudioBlockIntervalCycleCountMicros > lastMaxTxAudioBlockIntervalCycleCountMicros) lastMaxTxAudioBlockIntervalCycleCountMicros = txAudioBlockIntervalCycleCountMicros;
playQueueCallsSum++;
}
playQueueCalls++;
bufferPosition = bufferPosition + AUDIO_BLOCK_SAMPLES;
if (bufferPosition == SAMPLES) {
bufferPosition = 0;
buildNewSineWave = true;
}
}
}
void SerialTerminalOut() {
if (MAX_SERIAL_TERMINAL_OUT_RUNS == 0) { serialTerminalOutRuns = 0; }
if (testState < 3) {
if (millis() - serialTerminalOutMillis > SERIAL_TERMINAL_OUT_INTERVAL) {
uint32_t loopspersecond = float(loopCnt * (1000.0f / (millis() - serialTerminalOutMillis)));
serialTerminalOutMillis = millis();
avgLoopsPerSecond = (avgLoopsPerSecond + loopspersecond) / 2;
loopCnt = 0;
audioMemUsed = AudioMemoryUsage();
audioCpuUsed = AudioProcessorUsage();
if (audioMemUsed > maxAudioMemUsed) maxAudioMemUsed = audioMemUsed;
if (audioCpuUsed > maxAudioCpuUsed) maxAudioCpuUsed = audioCpuUsed;
Serial.printf("%3d PlayQueueCalls %3d LastTxIntervals Min%5d Avg%5d Max%6d uS AudioMemUsed %2d Loops/S %7d\n", ++serialTerminalRowCnt, playQueueCalls, lastMinTxAudioBlockIntervalCycleCountMicros, txAudioBlockIntervalCycleCountMicrosSum / playQueueCalls, lastMaxTxAudioBlockIntervalCycleCountMicros, audioMemUsed, loopspersecond);
if (serialTerminalRowCnt > 1) {
if (lastMinTxAudioBlockIntervalCycleCountMicros < overallMinTxAudioBlockIntervalCycleCountMicros || overallMinTxAudioBlockIntervalCycleCountMicros == 0) overallMinTxAudioBlockIntervalCycleCountMicros = lastMinTxAudioBlockIntervalCycleCountMicros;
if (lastMaxTxAudioBlockIntervalCycleCountMicros > overallMaxTxAudioBlockIntervalCycleCountMicros) overallMaxTxAudioBlockIntervalCycleCountMicros = lastMaxTxAudioBlockIntervalCycleCountMicros;
lastMinTxAudioBlockIntervalCycleCountMicros = 9999;
lastMaxTxAudioBlockIntervalCycleCountMicros = 0;
txAudioBlockIntervalCycleCountMicrosSum = 0;
}
playQueueCalls = 0;
if (playQueueCallsSum > 1 && loopspersecond < avgLoopsPerSecond / 4) { testState++; } // Loops/S droped? Stop the test.
if (serialTerminalOutRuns++ +1 == MAX_SERIAL_TERMINAL_OUT_RUNS) { testState = 3; } // Max runs reached? Stop the test.
}
}
if (testState == 3) {
Serial.printf("\nMaxAudioCpu Used: %2d ElapsedTime: %d Seconds TxIntervals Min: %4d Avg: %4d Max: %4d uS\n", maxAudioCpuUsed, (millis() - elapsedTime + SERIAL_TERMINAL_OUT_INTERVAL) / 1000, overallMinTxAudioBlockIntervalCycleCountMicros, txAudioBlockIntervalCycleCountMicrosSumSum / playQueueCallsSum, overallMaxTxAudioBlockIntervalCycleCountMicros);
testState++;
}
}
void BlinkLed() {
blinkLedTicks++;
if (blinkLedTicks > 100) {
blinkLedTicks = 0;
digitalWriteFast(13, !digitalReadFast(13));
}
}
void BuildSineWave() {
if (buildNewSineWave == true) {
buildNewSineWave = false;
if (sineWaveFrequencyDirection == 0) {
sineWaveFrequency = sineWaveFrequency - SINE_WAVE_FREQUENCY_CHANGE;
if (sineWaveFrequency <= SINE_WAVE_MIN_FREQUENCY) {
sineWaveFrequencyDirection = 1;
}
}
else if (sineWaveFrequencyDirection == 1) {
sineWaveFrequency = sineWaveFrequency + SINE_WAVE_FREQUENCY_CHANGE;
if (sineWaveFrequency >= SINE_WAVE_MAX_FREQUENCY) {
sineWaveFrequencyDirection = 0;
}
}
uint32_t cycles = (((SAMPLES-1) * sineWaveFrequency) / 44100);
for (uint32_t i = 0; i < SAMPLES; i++) {
sampleBuffer[i] = int16_t((7000 * (sin((i * (2 * PI * cycles)) / SAMPLES))) / 2);
}
}
}