Skip to content

Measuring the Data Thruput

Phil Schatzmann edited this page Jan 30, 2025 · 24 revisions

You can measure the data thruput with the help of the MeauringStream class. This class can be used as final output or in a chain both on the input or output side!

This information is critical to check if the selected hardware can provide the data fast enough and to determine the maximum sample rate, channels and bits per sample.

By default the result is reported in bytes per second if the frame size is not known and in frames per second if it is defined.

If you know the total (e.g. file) size, this class can also be used to estimate the total or open processing time based on the actual progress.

As Final Output

The thruput speed (in frames per second) is logged to serial after every 10 reads or writes to io:

AudioInfo info(44100, 2, 16)
MeasuringStream io(10, Serial);

void setup() {
  io.begin(info);
}

Just write or copy the data to io!

In a Processing Chain

The thruput speed (in frames per second) is logged to serial after every 10 reads or writes to io. The final data output goes to the File if you write data or the intput comes from the file if you read data from io.

AudioInfo info(44100, 2, 16)
File file
MeasuringStream io(file, 10, Serial);

void setup() {
  io.begin(info);
}

Estimating Times

You can calculate the exact runtime for a WAV file quite easily from it's size and it's audio information in it's header.

For MP3 this is much more difficult, but an easy approach (that works for all cases) is to estimate the total and open times while we are doing the processing. We can use the MeasuringStream to do this estimates. All we need to know is the total (file) size:

#include <SPI.h>
#include <SD.h>
#include "AudioTools.h"
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"

const int chipSelect = 15;
I2SStream i2s; // final output of decoded stream
MP3DecoderHelix mp3; // decoder
EncodedAudioStream decoder(&i2s, &mp3); // Decoding stream
MeasuringStream measure(decoder);
File audioFile;
StreamCopy copier(measure, audioFile); 

void setup(){
  Serial.begin(115200);
  AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);  

  // setup i2s!
  i2s.begin(defaultConfig(TX_MODE));

  // setup file
  SD.begin(chipSelect);
  audioFile = SD.open("/ZZ Top/Unknown Album/Lowrider.mp3");

  // setup I2S based on sampling rate provided by decoder
  decoder.begin();

  // start measuring
  measure.begin();

}

void printInfo() {
  Serial.print("Bytes since begin: ");
  Serial.println(measure.bytesSinceBegin());

  Serial.print("Time since begin sec: ");
  Serial.println(measure.timeSinceBegin()/1000);

  Serial.print("File size: ");
  Serial.println(audioFile.size());

  Serial.print("Estimated total sec: ");
  Serial.println(measure.estimatedTotalTimeFor(audioFile.size())/1000);

  int sec =  measure.estimatedOpenTimeFor(audioFile.size()) / 1000;
  Serial.print("open sec: ");
  Serial.println(sec);

}

void loop(){
  if (!copier.copy()) {
    stop();
  }

  printInfo();
}

This example assumes that you use the MeasuingStream in the processing chain. However you can still use it outside of the processing chain, if you feed it with the actually processed data by using the setProcessedBytes() method. If you use a file you can just provide it the actual file position!

Clone this wiki locally