This script will NOT work with a stream of 320kps or higher (SPIFF limitation)
This script will NOT work with MPEG-2 multichannel audio (libmad limitation). In other words, Yes: 128kb/s 44.1Khz 2Ch, MPEG Audio Version 1 Layer 3 Joint Stereo No: MPEG Audio Version 2 Layer 3 Joint Stereo / Intensity Stereo + MS Stereo
Stripped version of m5WebRadio to test buffer and source.
#include <M5StickC.h>#include <WiFi.h>#include <AudioFileSourceICYStream.h>#include <AudioFileSource.h>#include <AudioFileSourceBuffer.h>#include <AudioFileSourceSPIRAMBuffer.h>#include <AudioGeneratorAAC.h>#include <AudioGeneratorMP3.h>#include <AudioGeneratorTalkie.h>#include <AudioOutputI2S.h>#include <spiram-fast.h>//
// m5StreamTest Version 2020.12b (Source/Buffer Tester)// Board: M5StickC (esp32)// Author: tommyho510@gmail.com
// Required: Arduino library ESP8266Audio 1.60
//
// Enter your WiFi, Station, button settings here:
const char *SSID ="XXXXXXXX";const char *PASSWORD ="XXXXXXXX";const int bufferSize=128 * 1024; // buffer size in byte
const char *URLaac="http://ice4.somafm.com/christmas-32-aac";const char *URLmp3="http://ice2.somafm.com/christmas-128-mp3";const int LED=10; // GPIO LED
const int BTNA=37; // GPIO Play and Pause
const int BTNB=39; // GPIO Switch Channel / Volume
AudioGeneratorTalkie *talkie;AudioGeneratorAAC *aac;AudioGeneratorMP3 *mp3;AudioFileSourceICYStream *fileaac, *filemp3;AudioFileSourceBuffer *buffaac, *buffmp3;AudioOutputI2S *out, *outaac, *outmp3;uint32_t chipID= ESP.getEfuseMac();uint8_t spREADY[]PROGMEM={0x6A,0xB4,0xD9,0x25,0x4A,0xE5,0xDB,0xD9,0x8D,0xB1,0xB2,0x45,0x9A,0xF6,0xD8,0x9F,0xAE,0x26,0xD7,0x30,0xED,0x72,0xDA,0x9E,0xCD,0x9C,0x6D,0xC9,0x6D,0x76,0xED,0xFA,0xE1,0x93,0x8D,0xAD,0x51,0x1F,0xC7,0xD8,0x13,0x8B,0x5A,0x3F,0x99,0x4B,0x39,0x7A,0x13,0xE2,0xE8,0x3B,0xF5,0xCA,0x77,0x7E,0xC2,0xDB,0x2B,0x8A,0xC7,0xD6,0xFA,0x7F};uint8_t spPAUSE[]PROGMEM={0x00,0x00,0x00,0x00,0xFF,0x0F};void parseChip(){ Serial.printf("Chip ID: %d\n", chipID); Serial.printf("Chip Rev: %d\n", ESP.getChipRevision()); Serial.printf("CPU Freq: %d\n", ESP.getCpuFreqMHz()); Serial.printf("Flash Size: %d\n", ESP.getFlashChipSize()); Serial.printf("Flash Speed: %d\n", ESP.getFlashChipSpeed()); Serial.printf("Total heap: %d\n", ESP.getHeapSize()); Serial.printf("Free heap: %d\n", ESP.getFreeHeap()); Serial.printf("Total PSRAM: %d\n", ESP.getPsramSize()); Serial.printf("Free PSRAM: %d\n\n", ESP.getFreePsram());}void initwifi(){ WiFi.disconnect(); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); WiFi.begin(SSID, PASSWORD); // Try forever
int i=0;while(WiFi.status() != WL_CONNECTED){ Serial.print("STATUS(Connecting to WiFi) "); delay(1000);i= i + 1;if(i > 10){ ESP.restart();}} Serial.println("OK");}void talkieReady(){out= new AudioOutputI2S(0, 1); // Output to builtInDAC
out->SetOutputModeMono(true); out->SetGain(0.8);talkie= new AudioGeneratorTalkie(); talkie->begin(nullptr, out); talkie->say(spREADY, sizeof(spREADY)); talkie->say(spPAUSE, sizeof(spPAUSE));}// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc.
void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string){ const char *ptr = reinterpret_cast<const char *>(cbData);(void) isUnicode; // Punt this ball for now
// Note that the type and string may be in PROGMEM, so copy them to RAM forprintf char s1[32], s2[64]; strncpy_P(s1, type, sizeof(s1)); s1[sizeof(s1) - 1]=0; strncpy_P(s2, string, sizeof(s2)); s2[sizeof(s2) - 1]=0; Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(0, 45, 2); M5.Lcd.print(s2); M5.Lcd.print(" "); Serial.flush();}// Called when there's a warning or error (like a buffer underflow or decode hiccup)void StatusCallback(void *cbData, int code, const char *string) { const char *ptr = reinterpret_cast<const char *>(cbData); // Note that the string may be in PROGMEM, so copy it to RAM for printf char s1[64]; strncpy_P(s1, string, sizeof(s1)); s1[sizeof(s1) - 1] = 0; Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1); Serial.flush();}void playAAC() { outaac = new AudioOutputI2S(0, 1); // Output to builtInDAC outaac->SetOutputModeMono(true); outaac->SetGain(0.8); fileaac = new AudioFileSourceICYStream(URLaac); fileaac->RegisterMetadataCB(MDCallback, (void*)"ICY"); buffaac = new AudioFileSourceBuffer(fileaac, bufferSize); buffaac->RegisterStatusCB(StatusCallback, (void*)"buffer"); aac = new AudioGeneratorAAC(); aac->RegisterStatusCB(StatusCallback, (void*)"aac"); aac->begin(buffaac, outaac); Serial.printf("STATUS(URL) %s \n", URLaac); Serial.flush();}void loopAAC() { if (aac->isRunning()) { if (!aac->loop()) aac->stop(); } else { Serial.printf("Status(Stream) Stopped \n"); delay(1000); }}void playMP3() { outmp3 = new AudioOutputI2S(0, 1); // Output to builtInDAC outmp3->SetOutputModeMono(true); outmp3->SetGain(0.8); filemp3 = new AudioFileSourceICYStream(URLmp3); filemp3->RegisterMetadataCB(MDCallback, (void*)"ICY"); buffmp3 = new AudioFileSourceBuffer(filemp3, bufferSize); buffmp3->RegisterStatusCB(StatusCallback, (void*)"buffer"); mp3 = new AudioGeneratorMP3(); mp3->RegisterStatusCB(StatusCallback, (void*)"mp3"); mp3->begin(buffmp3, outmp3); Serial.printf("STATUS(URL) %s \n", URLmp3); Serial.flush();}void loopMP3() { if (mp3->isRunning()) { if (!mp3->loop()) mp3->stop(); } else { Serial.printf("Status(Stream) Stopped \n"); delay(1000); }}void setup() { Serial.begin(115200); pinMode(LED, OUTPUT); digitalWrite(LED , HIGH); pinMode(BTNA, INPUT); pinMode(BTNB, INPUT); M5.begin(); M5.Lcd.setRotation(3); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextSize(2); M5.Lcd.println("M5StickC"); M5.Lcd.println(" Stream Test"); parseChip(); initwifi(); talkieReady(); delay(500); playAAC();}void loop() { loopAAC();}
m5Core2StreamTest.ino
Arduino
*** NOT TESTED: Concept for playing MP3 stream on Core2 *** This should work with M5Stack Core2. Please note Core2 has 8Mb-PSRAM that is capable to playing 128K AAC stream
#include <M5Core2.h>#include <driver/i2s.h>#include <WiFi.h>#include <AudioFileSourceICYStream.h>#include <AudioFileSource.h>#include <AudioFileSourceBuffer.h>#include <AudioFileSourceSPIRAMBuffer.h>#include <AudioGeneratorMP3.h>#include <AudioGeneratorTalkie.h>#include <AudioOutputI2S.h>#include <spiram-fast.h>//
// m5StreamTest Version 2020.12b (Source/Buffer Tester)// Board: M5StackCore2 (esp32)// Author: tommyho510@gmail.com
// Required: Arduino library ESP8266Audio 1.60
//
// Enter your WiFi, Station, button settings here:
const char *SSID ="XXXXXXXX";const char *PASSWORD ="XXXXXXXX";const int bufferSize=128 * 1024; // buffer size in byte
const char *URLmp3="http://ice2.somafm.com/christmas-128-mp3";AudioGeneratorTalkie *talkie;AudioGeneratorMP3 *mp3;AudioFileSourceICYStream *filemp3;AudioFileSourceBuffer *buffmp3;AudioOutputI2S *out, *outmp3;uint32_t chipID= ESP.getEfuseMac();uint8_t spREADY[]PROGMEM={0x6A,0xB4,0xD9,0x25,0x4A,0xE5,0xDB,0xD9,0x8D,0xB1,0xB2,0x45,0x9A,0xF6,0xD8,0x9F,0xAE,0x26,0xD7,0x30,0xED,0x72,0xDA,0x9E,0xCD,0x9C,0x6D,0xC9,0x6D,0x76,0xED,0xFA,0xE1,0x93,0x8D,0xAD,0x51,0x1F,0xC7,0xD8,0x13,0x8B,0x5A,0x3F,0x99,0x4B,0x39,0x7A,0x13,0xE2,0xE8,0x3B,0xF5,0xCA,0x77,0x7E,0xC2,0xDB,0x2B,0x8A,0xC7,0xD6,0xFA,0x7F};uint8_t spPAUSE[]PROGMEM={0x00,0x00,0x00,0x00,0xFF,0x0F};void parseChip(){ Serial.printf("Chip ID: %d\n", chipID); Serial.printf("Chip Rev: %d\n", ESP.getChipRevision()); Serial.printf("CPU Freq: %d\n", ESP.getCpuFreqMHz()); Serial.printf("Flash Size: %d\n", ESP.getFlashChipSize()); Serial.printf("Flash Speed: %d\n", ESP.getFlashChipSpeed()); Serial.printf("Total heap: %d\n", ESP.getHeapSize()); Serial.printf("Free heap: %d\n", ESP.getFreeHeap()); Serial.printf("Total PSRAM: %d\n", ESP.getPsramSize()); Serial.printf("Free PSRAM: %d\n\n", ESP.getFreePsram());}void initwifi(){ WiFi.disconnect(); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); WiFi.begin(SSID, PASSWORD); // Try forever
int i=0;while(WiFi.status() != WL_CONNECTED){ Serial.print("STATUS(Connecting to WiFi) "); delay(1000);i= i + 1;if(i > 10){ ESP.restart();}} Serial.println("OK");}void talkieReady(){out= new AudioOutputI2S(0, 1); // Output to builtInDAC
out->SetOutputModeMono(true); out->SetGain(0.8);talkie= new AudioGeneratorTalkie(); talkie->begin(nullptr, out); talkie->say(spREADY, sizeof(spREADY)); talkie->say(spPAUSE, sizeof(spPAUSE));}// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc.
void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string){ const char *ptr = reinterpret_cast<const char *>(cbData);(void) isUnicode; // Punt this ball for now
// Note that the type and string may be in PROGMEM, so copy them to RAM forprintf char s1[32], s2[64]; strncpy_P(s1, type, sizeof(s1)); s1[sizeof(s1) - 1]=0; strncpy_P(s2, string, sizeof(s2)); s2[sizeof(s2) - 1]=0; Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(0, 45, 2); M5.Lcd.print(s2); M5.Lcd.print(" "); Serial.flush();}// Called when there's a warning or error (like a buffer underflow or decode hiccup)void StatusCallback(void *cbData, int code, const char *string) { const char *ptr = reinterpret_cast<const char *>(cbData); // Note that the string may be in PROGMEM, so copy it to RAM for printf char s1[64]; strncpy_P(s1, string, sizeof(s1)); s1[sizeof(s1) - 1] = 0; Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1); Serial.flush();}void playMP3() { outmp3 = new AudioOutputI2S(0, 1); // Output to builtInDAC outmp3->SetPinout(12, 0, 2); outmp3->SetOutputModeMono(true); outmp3->SetGain(0.2); filemp3 = new AudioFileSourceICYStream(URLmp3); filemp3->RegisterMetadataCB(MDCallback, (void*)"ICY"); buffmp3 = new AudioFileSourceBuffer(filemp3, bufferSize); buffmp3->RegisterStatusCB(StatusCallback, (void*)"buffer"); mp3 = new AudioGeneratorMP3(); mp3->RegisterStatusCB(StatusCallback, (void*)"mp3"); mp3->begin(buffmp3, outmp3); Serial.printf("STATUS(URL) %s \n", URLmp3); Serial.flush();}void loopMP3() { if (mp3->isRunning()) { if (!mp3->loop()) mp3->stop(); } else { Serial.printf("Status(Stream) Stopped \n"); delay(1000); }}void setup() { Serial.begin(115200); M5.begin(); M5.Axp.SetSpkEnable(true); M5.Lcd.setRotation(3); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextSize(2); M5.Lcd.println("M5StickCore2"); M5.Lcd.println(" Stream Test"); parseChip(); initwifi(); talkieReady(); delay(500); playMP3();}void loop() { loopMP3();}
m5WebRadio.Basic.ino
Arduino
Basic Web Radio
#include <M5StickC.h>#include <WiFi.h>#include <AudioFileSource.h>#include <AudioFileSourceBuffer.h>#include <AudioFileSourceICYStream.h>#include <AudioGeneratorMP3.h>#include <AudioOutputI2S.h>#include <AudioOutputI2SNoDAC.h>#include <spiram-fast.h>//
// m5WebRadio Version 2020.11b (Basic Edition)// Board: M5StickC (esp32)// Author: tommyho510@gmail.com
// Original Author: Milen Penev
// Required: Arduino library ESP8266Audio 1.60
//
// Enter your WiFi and Station settings here:
const char *SSID ="********";const char *PASSWORD ="*******";char * arrayURL[10]={"http://jenny.torontocast.com:8134/stream",
"http://ais-edge09-live365-dal02.cdnstream.com/a25710",
"http://188.165.212.154:8478/stream",
"https://igor.torontocast.com:1025/;.mp3",
"http://streamer.radio.co/s06b196587/listen",
"http://sj32.hnux.com/stream?type=http&nocache=3104",
"http://sl32.hnux.com/stream?type=http&nocache=1257",
"http://media-ice.musicradio.com:80/ClassicFMMP3",
"http://naxos.cdnstream.com:80/1255_128",
"http://149.56.195.94:8015/steam"};String arrayStation[10]={"Mega Shuffle",
"Orig. Top 40",
"Way Up Radio",
"Asia Dream",
"KPop Way Radio",
"Smooth Jazz",
"Smooth Lounge",
"Classic FM",
"Lite Favorites",
"MAXXED Out"};// Input and Output pins
const int LED=10;const int BTNA=37; // Play and Pause
const int BTNB=39; // Switch Channel / Volume
// Objects and variables
AudioGeneratorMP3 *mp3;AudioFileSourceICYStream *file;AudioFileSourceBuffer *buff;AudioOutputI2S *out;uint32_t LastTime=0;int playflag=0;int ledflag=0;//int btnaflag=0;//int btnbflag=0;float fgain=1.0;int sflag=0;char *URL = arrayURL[sflag];String station= arrayStation[sflag];void setup(){ Serial.begin(115200); pinMode(LED, OUTPUT); digitalWrite(LED , HIGH); pinMode(BTNA, INPUT); pinMode(BTNB, INPUT); M5.begin(); M5.Lcd.setRotation(3); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextSize(2); M5.Lcd.println("M5StickC"); M5.Lcd.println(" WebRadio"); delay(1000); M5.Lcd.println("WiFi"); M5.Lcd.println(" Connecting"); initwifi();// StartPlaying(); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextSize(2); M5.Lcd.setCursor(0, 0, 2); M5.Lcd.print("Ready"); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(0, 30, 2); M5.Lcd.print("Ch "); M5.Lcd.print(sflag + 1); M5.Lcd.print(" - "); M5.Lcd.print(station); M5.Lcd.print(" "); Serial.printf("STATUS(System) Ready \n\n");out= new AudioOutputI2S(0, 1); // Output to builtInDAC
out->SetOutputModeMono(true); out->SetGain(fgain*0.05);}void loop(){ static int lastms=0;if(playflag==0){if(digitalRead(BTNA)== LOW){ StartPlaying();playflag=1; M5.Lcd.setTextSize(2); M5.Lcd.setCursor(0, 0, 2); M5.Lcd.print("Playing");}if(digitalRead(BTNB)== LOW){sflag=(sflag + 1) % 10;URL= arrayURL[sflag];station= arrayStation[sflag]; M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(0, 30, 2); M5.Lcd.print("Ch "); M5.Lcd.print(sflag + 1); M5.Lcd.print(" - "); M5.Lcd.print(station); M5.Lcd.print(" "); delay (200);}}if(playflag==1){if(mp3->isRunning()){if(millis() - lastms > 1000){lastms= millis(); Serial.printf("STATUS(Streaming) %d ms...\n", lastms);ledflag= ledflag + 1;if(ledflag > 1){ledflag=0; digitalWrite(LED , HIGH);}else{ digitalWrite(LED , LOW);}}if(!mp3->loop()) mp3->stop();}else{ Serial.printf("MP3 done\n");playflag=0; digitalWrite(LED , HIGH); M5.Lcd.setTextSize(2); M5.Lcd.setCursor(0, 0, 2); M5.Lcd.print("Stop ");// ESP.restart();}if(digitalRead(BTNA)== LOW){ StopPlaying();playflag=0; digitalWrite(LED , HIGH); M5.Lcd.setTextSize(2); M5.Lcd.setCursor(0, 0, 2); M5.Lcd.print("Stop "); M5.Lcd.fillRect(109, 0, 160, 21, BLACK); delay(200);}if(digitalRead(BTNB)== LOW){fgain= fgain + 1.0;if(fgain > 10.0){fgain=1.0;} out->SetGain(fgain*0.05); M5.Lcd.fillRect(109, 0, 160, 21, BLACK); M5.Lcd.fillTriangle(109, 20, 109 + (5 * fgain), 20, 109 + (5 * fgain), 20 - (2 * fgain), BLUE); Serial.printf("STATUS(Gain) %f \n", fgain*0.05); delay(200);}}}void StartPlaying(){file= new AudioFileSourceICYStream(URL); file->RegisterMetadataCB(MDCallback, (void*)"ICY");buff= new AudioFileSourceBuffer(file, 2048); buff->RegisterStatusCB(StatusCallback, (void*)"buffer");out= new AudioOutputI2S(0, 1); // Output to builtInDAC
out->SetOutputModeMono(true);// out->SetGain(0.3); out->SetGain(fgain*0.05); M5.Lcd.fillTriangle(109, 20, 109 + (5 * fgain), 20, 109 + (5 * fgain), 20 - (2 * fgain), BLUE);mp3= new AudioGeneratorMP3(); mp3->RegisterStatusCB(StatusCallback, (void*)"mp3"); mp3->begin(buff, out); Serial.printf("STATUS(URL) %s \n", URL); Serial.flush();}void StopPlaying(){if(mp3){ mp3->stop(); delete mp3;mp3= NULL;}if(buff){ buff->close(); delete buff;buff= NULL;}if(file){ file->close(); delete file;file= NULL;} Serial.printf("STATUS(Stopped)\n"); Serial.flush();}void initwifi(){ WiFi.disconnect(); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_STA); WiFi.begin(SSID, PASSWORD); // Try forever
int i=0;while(WiFi.status() != WL_CONNECTED){ Serial.print("STATUS(Connecting to WiFi) "); delay(1000);i= i + 1;if(i > 10){ ESP.restart();}} Serial.println("OK");}// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc.
void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string){ const char *ptr = reinterpret_cast<const char *>(cbData);(void) isUnicode; // Punt this ball for now
// Note that the type and string may be in PROGMEM, so copy them to RAM forprintf char s1[32], s2[64]; strncpy_P(s1, type, sizeof(s1)); s1[sizeof(s1) - 1]=0; strncpy_P(s2, string, sizeof(s2)); s2[sizeof(s2) - 1]=0; Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2); M5.Lcd.setTextSize(1); M5.Lcd.setCursor(0, 45, 2); M5.Lcd.print(s2); M5.Lcd.print(" "); Serial.flush();}// Called when there's a warning or error (like a buffer underflow or decode hiccup)void StatusCallback(void *cbData, int code, const char *string) { const char *ptr = reinterpret_cast<const char *>(cbData); // Note that the string may be in PROGMEM, so copy it to RAM for printf char s1[64]; strncpy_P(s1, string, sizeof(s1)); s1[sizeof(s1) - 1] = 0; Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1); Serial.flush();}
espRadioMP3
The new version that works on many other esp32 DEV modules
Comments
Please log in or sign up to comment.