Skip to content

Audio Metadata

Phil Schatzmann edited this page Mar 11, 2024 · 18 revisions

Music metadata is the identifying data embedded in a music file, comprised of text-based meta tags that are attached via metadata containers (ID3v1 and ID3v2 being by far the most widespread), providing information like the artist’s name and the song’s title, associated genres.

This library supports ID3 and Icecast Metadata.

ID3 Metadata

ID3 is the metadata container which is most often used in conjunction with the MP3 audio file format. It allows information such as the title, artist, album, track number, and other information about the file to be stored in the file itself.

Both versions of ID3 (ID3v1 and ID3v2) are supported. I currently however only provide the information that is available in both which is:

  • Artist
  • Album
  • Title
  • Genre

The MetaDataOutput class is used as stream output destination and you register your callback method with setCallback():

#include "AudioTools.h"
#include "sample-12s.h"

MemoryStream mp3(sample_12s_mp3, sample_12s_mp3_len);
MetaDataOutput out;
StreamCopy copier(out, mp3); // copy in to out

// callback for meta data
void printMetaData(MetaDataType type, const char* str, int len){
  Serial.print("==> ");
  Serial.print(toStr(type));
  Serial.print(": ");
  Serial.println(str);
}

void setup(){
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Info);  

  mp3.begin();

  out.setCallback(printMetaData);
  out.begin();
}

void loop(){
    copier.copy();
}

The complete example is available on Github.

In your final application you will most likely use a MultiOutput, so that you can also send the MP3 data stream to a decoder, in order to play the related audio: here is the related example.

Icecast

The MetaDataOutput also supports Icecast Metadata, however you need to configure this in the begin method, e.g. by calling out.begin(true);

#include "AudioTools.h"
#include "AudioCodecs/CodecMP3Helix.h"


ICYStream url("Phil Schatzmann","sabrina01");
MetaDataOutput out; // final output of decoded stream
StreamCopy copier(out, url); // copy url to decoder

// callback for meta data
void printMetaData(MetaDataType type, const char* str, int len){
  Serial.print("==> ");
  Serial.print(toStr(type));
  Serial.print(": ");
  Serial.println(str);
}

void setup(){
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Info);  

// mp3 radio
  url.httpRequest().header().put("Icy-MetaData","1");
  url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");

  out.setCallback(printMetaData);
  out.begin(url.httpRequest()); // determine of ICE metadata
}

void loop(){
  copier.copy();
}

The Icecast protocol is also directly providing metadata: In this case you can just use an IcyStream and add the callback method to it.

#include "AudioTools.h"
#include "AudioCodecs/CodecAACHelix.h"
#include "AudioLibs/AudioBoardStream.h"


ICYStream url("ssid","password");  
I2SStream i2s; // final output of decoded stream
EncodedAudioStream dec(&i2s, new AACDecoderHelix()); // Decoding stream
StreamCopy copier(dec, url); // copy url to decoder

// callback for meta data
void printMetaData(MetaDataType type, const char* str, int len){
  Serial.print("==> ");
  Serial.print(MetaDataTypeStr[type]);
  Serial.print(": ");
  Serial.println(str);
}

void setup(){
  Serial.begin(115200);
  AudioLogger::instance().begin(Serial, AudioLogger::Info);  

  // setup i2s
  auto config = i2s.defaultConfig(TX_MODE);
  i2s.begin(config);

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

  // aac radio
  url.setMetadataCallback(printMetaData);
  url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mp3");

}

void loop(){
  copier.copy();
}