Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Encoding and Decoding of Audio

Phil Schatzmann edited this pageSep 23, 2025 ·174 revisions

Compressed Audio

Unfortunately the available memory on Microcontrollers is quite restricted and we do not get very far bystoring a (uncompressed) WAV file e.g. in program/flesh memory, so I started to look intocompressed audio formats: The compression and decompression can be done with the help ofCodecs. Codecs are also important if you need totransmit audio data at a high sampling rate over a line with limited capacity.

On the desktop we can use theFFmpeg project which comes with a rich set of functionality. Unfortunately the situation is much more fragmented for Microcontrollers.

I started to collect the relevant libraries and in order to make things simple to use I also addeda simple C++ API on top of the available libraries:

Supported Codecs

LibraryClassIncludeFunctionFormatApplication
-DecoderL8AudioCodecs/CodecL8.hDecodingPCMAudio
-EncoderL8AudioCodecs/CodecL8.hEncodingPCMAudio
-DecoderL16AudioCodecs/CodecL16.hDecodingPCMAudio
-EncoderL16AudioCodecs/CodecL16.hEncodingPCMAudio
-DecoderFloatAudioCodecs/CodecFloat.hDecodingPCMAudio
-EncoderFloatAudioCodecs/CodecFloat.hEncodingPCMAudio
-WAVDecoderAudioCodecs/CodecWAV.hDecodingWAVAudio
-WAVEncoderAudioCodecs/CodecWAV.hEncodingWAVAudio
-WavIMADecoderAudioCodecs/CodecWavIMA.hDecodingWAV/IMAAudio
-DecoderBase64AudioCodecs/CodecBase64.hDecodingBase64
-ADTSDecoderAudioCodecs/CodecADTS.hDecodingADTSAudio
-EncoderBase64AudioCodecs/CodecBase64.hEncodingBase64
-MetaDataFilterDecoderDecodingMP3Audio
libhelixMP3DecoderHelixAudioCodecs/CodecMP3Helix.hDecodingMP3Audio
libmadMP3DecoderMADAudioCodecs/CodecMP3MAD.hDecodingMP3Audio
minimp3MP3DecoderMiniAudioCodecs/CodecMP3Mini.hDecodingMP3Audio
liblameMP3EncoderLAMEAudioCodecs/CodecMP3LAME.hEncodingMP3Audio
libhelixAACDecoderHelixAudioCodecs/CodecAACHelix.hDecodingAACAudio
libfaadAACDecoderFAADAudioCodecs/CodecAACFAAD.hDecodingAACAudio
fdk-aacAACDecoderFDKAudioCodecs/CodecAACFDK.hDecodingAACAudio
fdk-aacAACEncoderFDKAudioCodecs/CodecAACFDK.hEncodingAACAudio
libflacFLACDecoderAudioCodecs/CodecFLAC.hDecodingFLACAudio
libflacFLACEncoderAudioCodecs/CodecFLAC.hEncodingFLACAudio
libfoxenflacFLACDecoderFoxenAudioCodecs/CodecFLACFoxen.hDecodingFLACAudio
libvorbis-tremorVorbisDecoderAudioCodecs/CodecVorbis.hDecodingOGG VorbisAudio
libsbcSBCDecoderAudioCodecs/CodecSBC.hDecodingSBCAudio
libsbcSBCEncoderAudioCodecs/CodecSBC.hEncodingSBCAudio
liblc3LC3DecoderAudioCodecs/CodecLC3.hDecodingLC3Audio
liblc3LC3EncoderAudioCodecs/CodecLC3.hEncodingLC3Audio
libopenaptxAPTXDecoderAudioCodecs/CodecAPTX.hDecodingAPTXAudio
libopenaptxAPTXEncoderAudioCodecs/CodecAPTX.hEncodingAPTXAudio
codec-opusOpusAudioDecoderAudioCodecs/CodecOpus.hDecodingOpusAudio
codec-opusOpusAudioEncoderAudioCodecs/CodecOpus.hEncodingOpusAudio
codec-opusOpusOggDecoderAudioCodecs/CodecOpusOgg.hDecodingOpusAudio
codec-opusOpusOggEncoderAudioCodecs/CodecOpusOgg.hEncodingOpusAudio
adpcmADPCMDecoderAudioCodecs/CodecADPCM.hDecodingADPCMAudio
adpcmADPCMEncoderAudioCodecs/CodecADPCM.hEncodingADPCMAudio
adpcm-xqADPCMDecoderXQAudioCodecs/CodecADPCM.hDecodingADPCMAudio
adpcm-xqADPCMEncoderXQAudioCodecs/CodecADPCM.hEncodingADPCMAudio
alacEncoderALACAudioCodecs/CodecALAC.hEncodingALACAudio
alacDecoderALACAudioCodecs/CodecALAC.hEncodingALACAudio
libgsmGSMDecoderAudioCodecs/CodecGSM.hDecodingGSMSpeech
libgsmGSMEncoderAudioCodecs/CodecGSM.hEncodingGSMSpeech
libg7xxG711_ALAWDecoderAudioCodecs/CodecG7xx.hDecodingALAWSpeech
libg7xxG711_ALAWEncoderAudioCodecs/CodecG7xx.hEncodingALAWSpeech
libg7xxG711_ULAWDecoderAudioCodecs/CodecG7xx.hDecodingULAWSpeech
libg7xxG711_ULAWEncoderAudioCodecs/CodecG7xx.hEncodingULAWSpeech
libg7xxG721DecoderAudioCodecs/CodecG7xx.hDecodingG.721Speech
libg7xxG721EncoderAudioCodecs/CodecG7xx.hEncodingG.721Speech
libg722G722DecoderAudioCodecs/CodecG722.hDecodingG.722Speech
libg722G722EncoderAudioCodecs/CodecG722.hEncodingG.722Speech
libg7xxG723_24DecoderAudioCodecs/CodecG7xx.hDecodingG.723Speech
libg7xxG723_24EncoderAudioCodecs/CodecG7xx.hEncodingG.723Speech
libg7xxG723_40DecoderAudioCodecs/CodecG7xx.hDecodingG.723Speech
libg7xxG723_40EncoderAudioCodecs/CodecG7xx.hEncodingG.723Speech
codec2Codec2DecoderAudioCodecs/CodecCodec2.hDecodingCodec2Speech
codec2Codec2EncoderAudioCodecs/CodecCodec2.hEncodingCodec2Speech
codec-amrAMRNBEncoderAudioCodecs/CodecAMRNB.hEncodingAMR narrowbandSpeech
codec-amrAMRNBDecoderAudioCodecs/CodecAMRNB.hDecodingAMR narrowbandSpeech
codec-amrAMRWBEncoderAudioCodecs/CodecAMRWB.hEncodingAMR widebandSpeech
codec-amrAMRWBDecoderAudioCodecs/CodecAMRWB.hDecodingAMR widebandSpeech

Container

An audio container, also known as a container format, is a file format that encapsulates audio data, along with metadata and other information.

LibraryClassIncludeFunctionFormatApplication
libopusOggContainerDecoderAudioCodecs/ContainerOgg.hDecodingOggAudio
libopusOggContainerEncoderAudioCodecs/ContainerOgg.hEncodingOggAudio
-BinaryContainerEncoderAudioCodecs/ContainerBinary.hEncoding-Audio
-BinaryContainerDecoderAudioCodecs/ContainerBinary.hDecoding-Audio
-AVIDecoderAudioCodecs/ContainerAVI.hDecodingAVIVideo
-MTSDecoderAudioCodecs/CodecMTS.hDecodingMPEG-TS (MTS)Audio
tsdemuxMTSDecoderDemuxAudioCodecs/CodecTSDemux.hDecodingvideo/mp2t MPEG-TS MTSAudio Video

Installation

If you want to use a codec, do not forget that you need toinstall the related library!

Decoding

Most decoders inherit fromAudioDecoder. I am also providing an integration into myArduino Audio Tools where you can use these libraries with theEncodedAudioStream class:

#include"AudioTools.h"#include"AudioTools/AudioCodecs/CodecMP3Helix.h"#include"BabyElephantWalk60_mp3.h"MemoryStreamdata(BabyElephantWalk60_mp3, BabyElephantWalk60_mp3_len);// MP3 data sourceI2SStream i2s;// final output of decoded streamMP3DecoderHelix mp3;// CodecEncodedAudioStreamdec(&i2s, &mp3);// Decoding streamStreamCopycopier(dec, data);// copy in to outvoidsetup(){  Serial.begin(115200);  i2s.begin();  dec.begin();}voidloop(){if (mp3) {    copier.copy();  } }

The above stream is implementing the following flow:mp3 MemoryStream -copy-> EncodedAudioStream -> I2SStreamThis method is used bymost codecs.

The MultiDecoder

I have added theMultiDecoder class to support the decoding of multiple data formats. The actual decoder is only opened at it's first use: The relevant decoder is determined dynamically at the first write from thedetermined mime type. You can add your own custom mime type determination logic.

When you change the data source to provide a new format you need to call end() on the EncodedAudioStream, to let the decoder know that it needs to determine a new format.

#include"AudioTools.h"#include"AudioTools/AudioCodecs/CodecMP3Helix.h"#include"AudioTools/AudioCodecs/CodecAACHelix.h"#include"AudioTools/AudioLibs/AudioBoardStream.h"#include"AudioTools/Communication/AudioHttp.h"URLStreamurl("ssid","password");I2SStream i2s;MultiDecoder multi;MP3DecoderHelix mp3;AACDecoderHelix aac;WAVDecoder wav;EncodedAudioStreamdec(&i2s, &multi);// Decoding streamStreamCopycopier(dec, url);// copy url to decodervoidsetup(){  Serial.begin(115200);  AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);// register supported codecs with their mime type  multi.addDecoder(mp3,"audio/mpeg");  multi.addDecoder(aac,"audio/aac");  multi.addDecoder(wav,"audio/vnd.wave");// setup i2sauto config = i2s.defaultConfig(TX_MODE);// you could define e.g your pins and change other settings//config.pin_ws = 10;//config.pin_bck = 11;//config.pin_data = 12;//config.mode = I2S_STD_FORMAT;  i2s.begin(config);// setup I2S based on sampling rate provided by decoder  dec.begin();// mp3 radio  url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128","audio/mpeg");}voidloop(){  copier.copy();}

Please note:

  • The distinction between mp3 and aac just from their content is difficult and can't be 100% reliable. Files are more reliable because mp3 usually starts with some metadata.
  • You can provide the URLStream object in the constructor of the MultiDecoder, so that the system can look up the mime type from the http response.
  • TheMimeDetector contains different alternatives predefined implementations that you can use when youadd a decoder.
  • If you don't want to rely on the automatic determination you can select the decoder by calling theselectDecoder method.

Decoding on the Input Side

You can also decode on the input side, which is less efficient, but sometimes more convenient.This is implementing the following flow:mp3 MemoryStream -> EncodedAudioStream -copy-> I2SStream

#include"AudioTools.h"#include"AudioTools/AudioCodecs/CodecMP3Helix.h"#include"BabyElephantWalk60_mp3.h"MemoryStreamdata(BabyElephantWalk60_mp3, BabyElephantWalk60_mp3_len);// MP3 data sourceMP3DecoderHelix mp3;EncodedAudioStreamdec(&data, &mp3);// Decoding streamI2SStream i2s;// final output of decoded streamStreamCopycopier(i2s, dec);// copy dec to outvoidsetup(){  Serial.begin(115200);  i2s.begin();  dec.addNotifyAudioChange(i2s);//dec.resizeReadResultQueue(1024 * 10);  dec.begin();}voidloop(){  copier.copy();}
  • Please note that the read functionality is implemented by reading the data from the indicated source and calling the write functionality on the decoder to store the result in a queue. Calling readBytes() is then providing the data from this queue.
  • The MP3 decoder provides the PCM data in big arrays (e.g. 4608 bytes). The default decoding queue might not be big enough to store this result, so you might need to specify the queue size yourself. You can do this by setting it to a fixed size by calling dec.resizeReadResultQueue(1024 * 10);.

Because of this complexity I do not recommend this functionality for beginners and only use it if you have a good understanding of the result sizes provided by the involved functionality.

Streaming Decoding

Ogg (FLACDecoder) and Vorbis VorbisDecoder are using an alternative method which is pulling the data directly from an input stream:

In this case aStreamingDecoder is used.

#include"AudioTools.h"#include"AudioTools/AudioCodecs/CodecVorbis.h"constchar* ssid ="ssid";constchar* pwd ="password";URLStreamurl(ssid, pwd);VorbisDecoder dec;I2SStream i2s;voidsetup() {  Serial.begin(115200);AudioLogger::instance().begin(Serial, AudioLogger::Info);    i2s.begin(i2s.defaultConfig(TX_MODE));  url.begin("http://marmalade.scenesat.com:8086/bitjam.ogg","application/ogg");// setup decoder  dec.setInputStream(url);  dec.setOutputStream(i2s);  dec.begin();}voidloop() {  dec.copy();}

You can transform any AudioDecoder into a StreamingDecoder with the help of aStreamingDecoderAdapter.

MultiStreamingDecoder

TheMultiStreamingDecoder class is able to handle multiple decoders: It supports bothStreamingDecoders and regularAudioDecoders efficiently.The mime type is determined internally with the help of the MimeDetector class. Alternatively you can specify the mime source: This is helpfull if you want to determine the mime e.g. from an URLStream.

#include"AudioTools.h"#include"AudioTools/AudioCodecs/CodecMP3Helix.h"#include"AudioTools/AudioCodecs/CodecAACHelix.h"#include"AudioTools/AudioCodecs/CodecVorbis.h"#include"AudioTools/AudioLibs/AudioBoardStream.h"URLStreamurl("Phil Schatzmann","sabrina01"); AudioBoardStreami2s(AudioKitEs8388V1);// final output of decoded streamMP3DecoderHelix mp3;AACDecoderHelix aac;VorbisDecoder ogg;MultiStreamingDecoder multi;voidsetup(){  Serial.begin(115200);  AudioToolsLogger.begin(Serial, AudioToolsLogLevel::Info);// setup i2sauto config = i2s.defaultConfig(TX_MODE);  i2s.begin(config);// register supported codecs with their mime type  multi.addDecoder(mp3,"audio/mpeg");  multi.addDecoder(aac,"audio/aac");  multi.addDecoder(ogg,"audio/ogg; codec=vorbis");// from mime detector  multi.addDecoder(ogg,"application/ogg");// from url// setup I2S based on sampling rate provided by decoder  multi.setInput(url);  multi.setOutput(i2s);  multi.setMimeSource(url);// get mime from url  multi.begin();// select a urls//url.begin("http://stream.srg-ssr.ch/m/rsj/mp3_128");//url.begin("https://audio.wavefarm.org/pondstation.mp3");  url.begin("https://locus.creacast.com:9443/santander_bay.ogg");}voidloop(){  multi.copy();}

Encoding

The encoding of audio data to a different format is also done with the help of theEncodedAudioStream class. The only difference (to the decoding examples) is that we pass anEncoder as argument.

Here is the related Arduino sketch:

#include"AudioTools.h"#include"SdFat.h"AudioInfoinfo(44100,2,16);// The stream will have 2 channelsWhiteNoiseGenerator<int16_t>noise(32000);// subclass of SoundGenerator with max amplitude of 32000GeneratedSoundStream<int16_t>in_stream(noise);// Stream generated from sine waveSdFat SD;File audioFile;// final output streamWAVEncoder encoder;EncodedAudioStreamout_stream(&audioFile, &encoder);// encode as wav fileStreamCopycopier(out_stream, in_stream);// copies sound to outvoidsetup(){  Serial.begin(115200);AudioLogger::instance().begin(Serial, AudioLogger::Info);auto cfg = noise.defaultConfig();  cfg.copyFrom(info);  noise.begin(info);  in_stream.begin();// we need to provide the audio information to the encoder    out_stream.begin(info);// open the output file  SD.begin(SdSpiConfig(PIN_CS, DEDICATED_SPI,SD_SCK_MHZ(2)));  audioFile = SD.open("/test/002.wav", O_WRITE | O_CREAT);}voidloop(){    copier.copy();// audioFile.flush(); // force write down of data}

We create an input stream which is based on some sound generator. In the out_stream we indicate the final output stream (which is a file in the example) and the encoder that is used when the data is written:GeneratedSoundStream -copy-> EncodedAudioStream -> File

Please note the following:

  • you need to make sure that the file content is written to the file by callingaudioFile.close() at the end - or by flushing the individual writes.
  • callout_stream.begin() before you write to anew file, this makes sure that the header is written to the file if necessary (e.g. for WAV files).
  • Before you start to write to a file,delete the file or move to the beginning. Otherwise the content is just appended!
  • This example is using the sdfat library, but you can useany other Arduino file library implementation.
  • MP3 and AAC are quire popular audio format, but they require a lot of memory and are at the edge what a Microcontroller can do. I recommend to avoid them and toprefer a lean format like ADPCM.

Further Information

Clone this wiki locally


[8]ページ先頭

©2009-2025 Movatter.jp