<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[CORE2 as Web radio, without extra hardware ?]]></title><description><![CDATA[<p dir="auto">Can we use CORE2 as Web radio without any extra hardware ?<br />
If yes does anyone have Arduino code to share ?<br />
I just need simple code to play one station .<br />
Thx in advance for your support.</p>
]]></description><link>https://community.m5stack.com/topic/2972/core2-as-web-radio-without-extra-hardware</link><generator>RSS for Node</generator><lastBuildDate>Wed, 29 Apr 2026 00:34:53 GMT</lastBuildDate><atom:link href="https://community.m5stack.com/topic/2972.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 18 Feb 2021 15:20:35 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Thu, 20 May 2021 15:09:30 GMT]]></title><description><![CDATA[<p dir="auto">Thanks a million, works as a charm on my Core2!</p>
]]></description><link>https://community.m5stack.com/post/13826</link><guid isPermaLink="true">https://community.m5stack.com/post/13826</guid><dc:creator><![CDATA[tom8787]]></dc:creator><pubDate>Thu, 20 May 2021 15:09:30 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Sat, 27 Mar 2021 16:16:57 GMT]]></title><description><![CDATA[<p dir="auto">Sorry,  I obviously don't know what I'm doing the the 'Reply' option and I guess I made another topic.  I put new code here instead of a reply to this thread.<br />
(oops).<br />
<a href="https://forum.m5stack.com/topic/3128/updated-version-working-core2-web-radio-player-m5stack" target="_blank" rel="noopener noreferrer nofollow ugc">https://forum.m5stack.com/topic/3128/updated-version-working-core2-web-radio-player-m5stack</a></p>
]]></description><link>https://community.m5stack.com/post/13274</link><guid isPermaLink="true">https://community.m5stack.com/post/13274</guid><dc:creator><![CDATA[homeuser33]]></dc:creator><pubDate>Sat, 27 Mar 2021 16:16:57 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Thu, 25 Mar 2021 23:24:44 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/raychmond" aria-label="Profile: raychmond">@<bdi>raychmond</bdi></a></p>
<p dir="auto">Happy to help,  but all credit goes to :</p>
<p dir="auto"><a href="https://www.hackster.io/tommyho/arduino-web-radio-player-c4cb23" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.hackster.io/tommyho/arduino-web-radio-player-c4cb23</a></p>
<p dir="auto">//  m5StreamTest Version 2020.12b (Source/Buffer Tester)<br />
//  Board: M5StackCore2 (esp32)<br />
//  Author: <a href="mailto:tommyho510@gmail.com" target="_blank" rel="noopener noreferrer nofollow ugc">tommyho510@gmail.com</a><br />
//  Required: Arduino library ESP8266Audio 1.60<br />
//</p>
<p dir="auto">All I did was to work through his examples,  and a few other online examples to find the right audio settings for the Core2.</p>
<p dir="auto">Then add a few items to the GUI for battery and track information.</p>
<p dir="auto">Hopefully I'll add some of my wish list items as time permits but it seems like a fun project.</p>
]]></description><link>https://community.m5stack.com/post/13232</link><guid isPermaLink="true">https://community.m5stack.com/post/13232</guid><dc:creator><![CDATA[homeuser33]]></dc:creator><pubDate>Thu, 25 Mar 2021 23:24:44 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Thu, 25 Mar 2021 13:04:14 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/homeuser33" aria-label="Profile: homeuser33">@<bdi>homeuser33</bdi></a><br />
Thank you! I just tried your code. It works like a charm. The sound quality on CORE2 is awesome, which is much better than it's on FIRE and StickC.</p>
]]></description><link>https://community.m5stack.com/post/13228</link><guid isPermaLink="true">https://community.m5stack.com/post/13228</guid><dc:creator><![CDATA[raychmond]]></dc:creator><pubDate>Thu, 25 Mar 2021 13:04:14 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Thu, 25 Mar 2021 12:15:12 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/homeuser33" aria-label="Profile: homeuser33">@<bdi>homeuser33</bdi></a> said in <a href="/post/13219">CORE2 as Web radio, without extra hardware ?</a>:</p>
<blockquote>
<p dir="auto">//   March 23, 2021<br />
//   Made changes to the Example Core2 Web Radio Player from:<br />
//   <a href="https://www.hackster.io/tommyho/arduino-web-radio-player-c4cb23" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.hackster.io/tommyho/arduino-web-radio-player-c4cb23</a></p>
<p dir="auto">//    Wish List: (NOT DONE YET)<br />
//    Nicer Fonts<br />
//    Use 2nd CPU Core to handle GUI and button's so we keep it responsive<br />
//    Add bluetooth output to Bluetooth speakers / headest<br />
//    Get more information from the stream,  Album art, etc.<br />
//    Get track length and have a progress bar for the track<br />
//    Have an interface to select WiFi network and enter password<br />
//    -- Store password in EEPROM<br />
//    Better mehod of selecting stations<br />
//    ? Maybe web interface for setting up station lists?<br />
//<br />
//  m5StreamTest Version 2020.12b (Source/Buffer Tester)<br />
//  Board: M5StackCore2 (esp32)<br />
//  Author: <a href="mailto:tommyho510@gmail.com" target="_blank" rel="noopener noreferrer nofollow ugc">tommyho510@gmail.com</a><br />
//  Required: Arduino library ESP8266Audio 1.60<br />
//</p>
<p dir="auto">#include &lt;M5Core2.h&gt;<br />
#include &lt;driver/i2s.h&gt;<br />
#include &lt;WiFi.h&gt;<br />
#include &lt;AudioFileSourceICYStream.h&gt;<br />
#include &lt;AudioFileSource.h&gt;<br />
#include &lt;AudioFileSourceBuffer.h&gt;<br />
#include &lt;AudioFileSourceSPIRAMBuffer.h&gt;<br />
#include &lt;AudioGeneratorMP3.h&gt;<br />
#include &lt;AudioOutputI2S.h&gt;<br />
#include &lt;spiram-fast.h&gt;</p>
<p dir="auto">// Enter your WiFi, Station, button settings here:<br />
const char *SSID = "ENTER_SSID_HERE";<br />
const char *PASSWORD = "ENTER_WIFI_PASSWORD_HERE";</p>
<p dir="auto">const int bufferSize = 128 * 1024; // buffer size in byte</p>
<p dir="auto">// <a href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" target="_blank" rel="noopener noreferrer nofollow ugc">http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd</a><br />
// Charlie FM in Portland Oregon<br />
//<a href="http://24083.live.streamtheworld.com:80/KYCHFM_SC" target="_blank" rel="noopener noreferrer nofollow ugc">http://24083.live.streamtheworld.com:80/KYCHFM_SC</a><br />
//<br />
//Removed these from the list:<br />
//  {"Mega Shuffle", "<a href="http://jenny.torontocast.com:8134/stream" target="_blank" rel="noopener noreferrer nofollow ugc">http://jenny.torontocast.com:8134/stream</a>"},<br />
//  {"Way Up Radio", "<a href="http://188.165.212.154:8478/stream" target="_blank" rel="noopener noreferrer nofollow ugc">http://188.165.212.154:8478/stream</a>"},<br />
//  {"Asia Dream", "<a href="https://igor.torontocast.com:1025/;.-mp3" target="_blank" rel="noopener noreferrer nofollow ugc">https://igor.torontocast.com:1025/;.-mp3</a>"},<br />
//  {"KPop Way Radio", "<a href="http://streamer.radio.co/s06b196587/listen" target="_blank" rel="noopener noreferrer nofollow ugc">http://streamer.radio.co/s06b196587/listen</a>"},<br />
//  {"SomaFM", "<a href="http://ice2.somafm.com/christmas-128-mp3" target="_blank" rel="noopener noreferrer nofollow ugc">http://ice2.somafm.com/christmas-128-mp3</a>"}<br />
//"<a href="http://icecast.thisisdax.com/CapitalEdinburghMP3" target="_blank" rel="noopener noreferrer nofollow ugc">http://icecast.thisisdax.com/CapitalEdinburghMP3</a>",<br />
//"<a href="https://prod-34-82-94-246.wostreaming.net/ppm-jazz24mp3-ibc1" target="_blank" rel="noopener noreferrer nofollow ugc">https://prod-34-82-94-246.wostreaming.net/ppm-jazz24mp3-ibc1</a>",<br />
//"<a href="http://sj32.hnux.com/stream?type=http&amp;nocache=3104" target="_blank" rel="noopener noreferrer nofollow ugc">http://sj32.hnux.com/stream?type=http&amp;nocache=3104</a>",<br />
//"<a href="http://sl32.hnux.com/stream?type=http&amp;nocache=1257" target="_blank" rel="noopener noreferrer nofollow ugc">http://sl32.hnux.com/stream?type=http&amp;nocache=1257</a>",<br />
//"<a href="http://media-ice.musicradio.com:80/ClassicFMMP3" target="_blank" rel="noopener noreferrer nofollow ugc">http://media-ice.musicradio.com:80/ClassicFMMP3</a>",<br />
//"<a href="http://naxos.cdnstream.com:80/1255_128" target="_blank" rel="noopener noreferrer nofollow ugc">http://naxos.cdnstream.com:80/1255_128</a>",<br />
//"<a href="https://v7player.wostreaming.net/854" target="_blank" rel="noopener noreferrer nofollow ugc">https://v7player.wostreaming.net/854</a>"</p>
<p dir="auto">const int stations = 7;// Change Number here if you add feeds!<br />
char * stationList[stations][3] = {<br />
{"Charlie_FM", "<a href="http://24083.live.streamtheworld.com:80/KYCHFM_SC" target="_blank" rel="noopener noreferrer nofollow ugc">http://24083.live.streamtheworld.com:80/KYCHFM_SC</a>", "good"},<br />
{"MAXXED Out", "<a href="http://149.56.195.94:8015/steam" target="_blank" rel="noopener noreferrer nofollow ugc">http://149.56.195.94:8015/steam</a>", "good"},<br />
{"Orig. Top 40", "<a href="http://ais-edge09-live365-dal02.cdnstream.com/a25710" target="_blank" rel="noopener noreferrer nofollow ugc">http://ais-edge09-live365-dal02.cdnstream.com/a25710</a>", "good"},<br />
{"Smooth Jazz", "<a href="http://sj32.hnux.com/stream?type=http&amp;nocache=3104" target="_blank" rel="noopener noreferrer nofollow ugc">http://sj32.hnux.com/stream?type=http&amp;nocache=3104</a>", "good"},<br />
{"Smooth Lounge", "<a href="http://sl32.hnux.com/stream?type=http&amp;nocache=1257" target="_blank" rel="noopener noreferrer nofollow ugc">http://sl32.hnux.com/stream?type=http&amp;nocache=1257</a>", "good"},<br />
{"Classic FM", "<a href="http://media-ice.musicradio.com:80/ClassicFMMP3" target="_blank" rel="noopener noreferrer nofollow ugc">http://media-ice.musicradio.com:80/ClassicFMMP3</a>", "good"},<br />
{"Lite Favorites", "<a href="http://naxos.cdnstream.com:80/1255_128" target="_blank" rel="noopener noreferrer nofollow ugc">http://naxos.cdnstream.com:80/1255_128</a>", "good"}<br />
};</p>
<p dir="auto">float audioGain = 1.0;<br />
float gainfactor = 0.08;<br />
int currentStationNumber = 0;<br />
unsigned long disUpdate = millis();</p>
<p dir="auto">AudioGeneratorMP3 *mp3;<br />
AudioFileSourceICYStream *filemp3;<br />
AudioFileSourceBuffer *buffmp3;<br />
AudioOutputI2S *out, *outmp3;</p>
<p dir="auto">void displayWiFiInformation() {<br />
M5.Lcd.setCursor(0, 172, 2);<br />
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);<br />
M5.Lcd.setTextSize(1);<br />
M5.Lcd.println("WiFi Network:  " + String(SSID));<br />
M5.Lcd.print(  "IP Address   :  ");<br />
M5.Lcd.println(WiFi.localIP());<br />
}</p>
<p dir="auto">void initwifi() {<br />
WiFi.disconnect();<br />
WiFi.softAPdisconnect(true);<br />
WiFi.mode(WIFI_STA);<br />
WiFi.begin(SSID, PASSWORD);<br />
// Try forever<br />
int i = 0;<br />
while (WiFi.status() != WL_CONNECTED) {<br />
Serial.print("STATUS(Connecting to WiFi) ");<br />
delay(1000);<br />
i = i + 1;<br />
if (i &gt; 10) {<br />
ESP.restart();<br />
}<br />
}<br />
Serial.println("\nWiFi Connected!\n");<br />
}</p>
<p dir="auto">String getValue(String data, char separator, int index){<br />
int found = 0;<br />
int strIndex[] = {0,-1};<br />
int maxIndex = data.length() -1;</p>
<p dir="auto">for (int i = 0; i &lt;= maxIndex &amp;&amp; found &lt;= index; i++){<br />
if (data.charAt(i) == separator || i == maxIndex){<br />
found++;<br />
strIndex[0] = strIndex[1] + 1;<br />
strIndex[1] = (i == maxIndex) ? i+1 : i;<br />
}<br />
}<br />
return found &gt; index ? data.substring(strIndex[0], strIndex[1]) : "";<br />
}</p>
<p dir="auto">// Calculate Battery Usable range  (3.2 to 4.0 Volts)<br />
void displayBattery() {<br />
int maxVolts = 400;  // Battery Max volts * 100<br />
int minVolts = 320;  // Battery Min Volts * 100<br />
M5.Lcd.setCursor(0, 155, 2);<br />
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);<br />
M5.Lcd.setTextSize(1);<br />
M5.Lcd.printf("Battery:  %.2f  ", M5.Axp.GetBatVoltage());<br />
int batt = map(M5.Axp.GetBatVoltage()*100, minVolts, maxVolts, 0 , 10000) / 100.0;</p>
<p dir="auto">// Draw Battery bar(s) on the right side of the screen<br />
uint16_t clr = GREEN;<br />
for(int x = 9; x &gt;= 0; x--){<br />
if (x &lt; 6) clr = YELLOW;<br />
if (x &lt; 3) clr = RED;<br />
M5.Lcd.fillRoundRect(315, (216-(x<em>24)), 5, 21, 2, (batt&gt;(x</em>10))?clr:BLACK);<br />
}<br />
M5.Lcd.setCursor(180, 172, 2);<br />
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);<br />
M5.Lcd.setTextSize(1);<br />
M5.Lcd.print("WiFi Signal: ");<br />
M5.Lcd.print(WiFi.RSSI());<br />
}</p>
<p dir="auto">// Remove the Track information (While changing stations)<br />
void clearTrack() {<br />
M5.Lcd.fillRect(0,63,310,40, BLACK); // Clear the area of old data<br />
M5.Lcd.drawRect(0,64,310,37, BLUE); // Draw a box around the Track Information<br />
}</p>
<p dir="auto">// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc.<br />
void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string) {<br />
const char *ptr = reinterpret_cast&lt;const char *&gt;(cbData);<br />
(void) isUnicode; // Punt this ball for now<br />
// Note that the type and string may be in PROGMEM, so copy them to RAM for printf<br />
char s1[32], s2[64];<br />
strncpy_P(s1, type, sizeof(s1));<br />
s1[sizeof(s1) - 1] = 0;<br />
strncpy_P(s2, string, sizeof(s2));<br />
s2[sizeof(s2) - 1] = 0;</p>
<p dir="auto">String band  = getValue(s2, '-', 0);<br />
band.trim();<br />
String track = getValue(s2, '-', 1);<br />
track.trim();</p>
<p dir="auto">Serial.printf("Band: %s   Track:  %s  \n", band.c_str(), track.c_str());<br />
Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2);<br />
M5.Lcd.setTextSize(1);<br />
M5.Lcd.setCursor(5, 65, 2);<br />
clearTrack();<br />
M5.Lcd.print(band);<br />
M5.Lcd.setCursor(5, 82, 2);<br />
M5.Lcd.print(track);<br />
Serial.flush();<br />
displayBattery(); // Make sure the new song information does not overwrite the battery<br />
}</p>
<p dir="auto">// Called when there's a warning or error (like a buffer underflow or decode hiccup)<br />
void StatusCallback(void *cbData, int code, const char *string) {<br />
const char *ptr = reinterpret_cast&lt;const char *&gt;(cbData);<br />
// Note that the string may be in PROGMEM, so copy it to RAM for printf<br />
char s1[64];<br />
strncpy_P(s1, string, sizeof(s1));<br />
s1[sizeof(s1) - 1] = 0;<br />
Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1);<br />
Serial.flush();<br />
}</p>
<p dir="auto">void stopPlaying() {<br />
Serial.printf("Stopping MP3...\n");<br />
if (mp3) {<br />
mp3-&gt;stop();<br />
delete mp3;<br />
mp3 = NULL;<br />
}<br />
Serial.printf("MP3 Stopped, Stopping Buffer...\n");<br />
if (buffmp3) {<br />
buffmp3-&gt;close();<br />
delete buffmp3;<br />
buffmp3 = NULL;<br />
}<br />
Serial.printf("Buffer stopped... Stopping File ...\n");<br />
if (filemp3) {<br />
filemp3-&gt;close();<br />
delete filemp3;<br />
filemp3 = NULL;<br />
}<br />
if (outmp3) {<br />
//    filemp3-&gt;close();<br />
delete outmp3;<br />
outmp3 = NULL;<br />
}</p>
<p dir="auto">Serial.printf("STATUS(Stopped)\n");<br />
Serial.flush();<br />
}</p>
<p dir="auto">// Update the Station Label<br />
void updateStation(String message) {<br />
M5.Lcd.fillRect(0,30,315,30,BLACK); // Clear out other information on the line<br />
M5.Lcd.setCursor(0, 30, 2);<br />
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);<br />
M5.Lcd.setTextSize(2);<br />
M5.Lcd.println(message);<br />
}</p>
<p dir="auto">// Identify buttons at the bottom of screen<br />
void drawButtons() {<br />
M5.Lcd.setCursor(5, 210, 2);<br />
M5.Lcd.setTextColor(TFT_BLACK,  TFT_YELLOW);<br />
M5.Lcd.setTextSize(2);<br />
M5.Lcd.println(" Vol     Station    Mute");<br />
M5.Lcd.setTextColor(TFT_WHITE,  TFT_BLACK);<br />
M5.Lcd.setTextSize(1);<br />
}</p>
<p dir="auto">// Change to the next station<br />
void changeStation() {<br />
updateStation("Changing..Wait..");<br />
currentStationNumber++;<br />
if ( stationList[currentStationNumber][2] == "bad") currentStationNumber++; // Skip feeds marked as bad<br />
if (currentStationNumber &gt;= stations) currentStationNumber = 0;<br />
Serial.printf("\n******** Changing to channel number: %i\n", currentStationNumber);<br />
}</p>
<p dir="auto">// Change the volume level<br />
void changeVolume() {<br />
audioGain += 1.0;<br />
if (audioGain &gt; 10.0) {<br />
audioGain = 1.0;<br />
}<br />
if (audioGain &lt; 0.0) {<br />
audioGain = 0.0;<br />
}<br />
int xtPos = 260; // X Position for the Volume indication<br />
outmp3-&gt;SetGain(audioGain * gainfactor);<br />
M5.Lcd.fillRect(xtPos, 0, 320-xtPos-5, 21, BLACK);<br />
uint16_t clr = GREEN;<br />
if (audioGain &gt; 9) clr = RED;<br />
else if (audioGain &gt; 6) clr = BLUE;<br />
M5.Lcd.fillTriangle(xtPos, 20, xtPos + (5 * audioGain), 20, xtPos + (5 * audioGain), 20 - (2 * audioGain), clr);<br />
}</p>
<p dir="auto">void playMP3() {<br />
outmp3 = new AudioOutputI2S(0, 0); // Output to builtInDAC<br />
outmp3-&gt;SetPinout(12, 0, 2);<br />
outmp3-&gt;SetOutputModeMono(true);<br />
outmp3-&gt;SetGain(audioGain * gainfactor);<br />
filemp3 = new AudioFileSourceICYStream(stationList[currentStationNumber][1]);<br />
filemp3-&gt;RegisterMetadataCB(MDCallback, (void*)"ICY");<br />
buffmp3 = new AudioFileSourceBuffer(filemp3, bufferSize);<br />
buffmp3-&gt;RegisterStatusCB(StatusCallback, (void*)"buffer");<br />
mp3 = new AudioGeneratorMP3();<br />
mp3-&gt;RegisterStatusCB(StatusCallback, (void*)"mp3");<br />
mp3-&gt;begin(buffmp3, outmp3);<br />
Serial.printf("STATUS(URL) %s %s\n", stationList[currentStationNumber][0], stationList[currentStationNumber][1]);<br />
Serial.flush();<br />
updateStation(String(stationList[currentStationNumber][0]));<br />
}</p>
<p dir="auto">void loopMP3() {<br />
if (mp3 != NULL) {  // To avoid crash while changing stations<br />
if (mp3-&gt;isRunning()) {<br />
if (!mp3-&gt;loop()) mp3-&gt;stop();<br />
} else {<br />
Serial.printf("Status(Stream) Stopped \n");<br />
stationList[currentStationNumber][2] = "bad"; // Mark feed as bad if it won't play<br />
clearTrack();<br />
changeStation();<br />
//      stopPlaying();<br />
delay(1000);<br />
playMP3();<br />
}<br />
}<br />
}</p>
<p dir="auto">void setup() {<br />
Serial.begin(115200);</p>
<p dir="auto">M5.begin();<br />
M5.Axp.SetSpkEnable(true);<br />
//  M5.Lcd.setRotation(3);<br />
M5.Lcd.fillScreen(BLACK);<br />
M5.Lcd.setTextSize(2);<br />
//  M5.Lcd.setFreeFont(TT1);<br />
//  M5.Lcd.setFreeFont(FF33);<br />
M5.Lcd.setTextColor(TFT_GREEN, TFT_BLACK);<br />
M5.Lcd.println("Core2 Web Radio");<br />
M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);<br />
M5.Lcd.setTextWrap(false);</p>
<p dir="auto">initwifi();<br />
delay(500);<br />
drawButtons();<br />
playMP3();<br />
changeVolume();  // To update Volume setting and graphic<br />
displayWiFiInformation();<br />
//  Serial.printf("Battery Voltage: %f \n", M5.Axp.GetBatVoltage());<br />
}</p>
<p dir="auto">void loop() {<br />
loopMP3();<br />
M5.update();</p>
<p dir="auto">if (m5.BtnA.wasPressed()) { //Change Volume(Button A)<br />
changeVolume();<br />
}</p>
<p dir="auto">if (m5.BtnB.wasPressed()) { //Change Station(Button B)<br />
clearTrack();<br />
changeStation();<br />
stopPlaying();<br />
playMP3();<br />
}</p>
<p dir="auto">if (m5.BtnC.wasPressed()) { //Mute  (Button C)<br />
audioGain = -1.0;<br />
changeVolume();<br />
}</p>
<p dir="auto">if (disUpdate + 1000 &lt; millis()) { // Update the battery voltage<br />
disUpdate = millis();<br />
displayBattery();<br />
}<br />
}</p>
</blockquote>
<p dir="auto">Thx, will give it a try later ;-)</p>
]]></description><link>https://community.m5stack.com/post/13225</link><guid isPermaLink="true">https://community.m5stack.com/post/13225</guid><dc:creator><![CDATA[AgreeDK]]></dc:creator><pubDate>Thu, 25 Mar 2021 12:15:12 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Wed, 24 Mar 2021 21:33:13 GMT]]></title><description><![CDATA[<p dir="auto">I have worked on the webRadio for the Core2,  I have it working for me but I'm sure there are issues to iron out.  If there is allowed space here, I'll Post the code modified from the same M5WebRadio Project you are talking about.</p>
<hr />
<pre><code>

//   March 23, 2021
//   Made changes to the Example Core2 Web Radio Player from:
//   https://www.hackster.io/tommyho/arduino-web-radio-player-c4cb23

//    Wish List: (NOT DONE YET)
//    Nicer Fonts
//    Use 2nd CPU Core to handle GUI and button's so we keep it responsive
//    Add bluetooth output to Bluetooth speakers / headest
//    Get more information from the stream,  Album art, etc.
//    Get track length and have a progress bar for the track
//    Have an interface to select WiFi network and enter password
//    -- Store password in EEPROM
//    Better mehod of selecting stations
//    ? Maybe web interface for setting up station lists?
//
//  m5StreamTest Version 2020.12b (Source/Buffer Tester)
//  Board: M5StackCore2 (esp32)
//  Author: tommyho510@gmail.com
//  Required: Arduino library ESP8266Audio 1.60
//

#include &lt;M5Core2.h&gt;
#include &lt;driver/i2s.h&gt;
#include &lt;WiFi.h&gt;
#include &lt;AudioFileSourceICYStream.h&gt;
#include &lt;AudioFileSource.h&gt;
#include &lt;AudioFileSourceBuffer.h&gt;
#include &lt;AudioFileSourceSPIRAMBuffer.h&gt;
#include &lt;AudioGeneratorMP3.h&gt;
#include &lt;AudioOutputI2S.h&gt;
#include &lt;spiram-fast.h&gt;


// Enter your WiFi, Station, button settings here:
const char *SSID = "ENTER_SSID_HERE";
const char *PASSWORD = "ENTER_WIFI_PASSWORD_HERE";

const int bufferSize = 128 * 1024; // buffer size in byte


// http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd
// Charlie FM in Portland Oregon
//http://24083.live.streamtheworld.com:80/KYCHFM_SC
//
//Removed these from the list:
//  {"Mega Shuffle", "http://jenny.torontocast.com:8134/stream"},
//  {"Way Up Radio", "http://188.165.212.154:8478/stream"},
//  {"Asia Dream", "https://igor.torontocast.com:1025/;.-mp3"},
//  {"KPop Way Radio", "http://streamer.radio.co/s06b196587/listen"},
//  {"SomaFM", "http://ice2.somafm.com/christmas-128-mp3"}
//"http://icecast.thisisdax.com/CapitalEdinburghMP3",
//"https://prod-34-82-94-246.wostreaming.net/ppm-jazz24mp3-ibc1",
//"http://sj32.hnux.com/stream?type=http&amp;nocache=3104",
//"http://sl32.hnux.com/stream?type=http&amp;nocache=1257",
//"http://media-ice.musicradio.com:80/ClassicFMMP3",
//"http://naxos.cdnstream.com:80/1255_128",
//"https://v7player.wostreaming.net/854"

const int stations = 7;// Change Number here if you add feeds!
char * stationList[stations][3] = {
  {"Charlie_FM", "http://24083.live.streamtheworld.com:80/KYCHFM_SC", "good"},
  {"MAXXED Out", "http://149.56.195.94:8015/steam", "good"},
  {"Orig. Top 40", "http://ais-edge09-live365-dal02.cdnstream.com/a25710", "good"},
  {"Smooth Jazz", "http://sj32.hnux.com/stream?type=http&amp;nocache=3104", "good"},
  {"Smooth Lounge", "http://sl32.hnux.com/stream?type=http&amp;nocache=1257", "good"},
  {"Classic FM", "http://media-ice.musicradio.com:80/ClassicFMMP3", "good"},
  {"Lite Favorites", "http://naxos.cdnstream.com:80/1255_128", "good"}
};

float audioGain = 1.0;
float gainfactor = 0.08;
int currentStationNumber = 0;
unsigned long disUpdate = millis();

AudioGeneratorMP3 *mp3;
AudioFileSourceICYStream *filemp3;
AudioFileSourceBuffer *buffmp3;
AudioOutputI2S *out, *outmp3;


void displayWiFiInformation() {
  M5.Lcd.setCursor(0, 172, 2);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.println("WiFi Network:  " + String(SSID));
  M5.Lcd.print(  "IP Address   :  ");
  M5.Lcd.println(WiFi.localIP());
}

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 &gt; 10) {
      ESP.restart();
    }
  }
  Serial.println("\nWiFi Connected!\n");
}


String getValue(String data, char separator, int index){
  int found = 0;
  int strIndex[] = {0,-1};
  int maxIndex = data.length() -1;

  for (int i = 0; i &lt;= maxIndex &amp;&amp; found &lt;= index; i++){
    if (data.charAt(i) == separator || i == maxIndex){
      found++;
      strIndex[0] = strIndex[1] + 1;
      strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }
  return found &gt; index ? data.substring(strIndex[0], strIndex[1]) : "";
}


// Calculate Battery Usable range  (3.2 to 4.0 Volts)
void displayBattery() {
  int maxVolts = 400;  // Battery Max volts * 100
  int minVolts = 320;  // Battery Min Volts * 100
  M5.Lcd.setCursor(0, 155, 2);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.printf("Battery:  %.2f  ", M5.Axp.GetBatVoltage());
  int batt = map(M5.Axp.GetBatVoltage()*100, minVolts, maxVolts, 0 , 10000) / 100.0;

  // Draw Battery bar(s) on the right side of the screen
  uint16_t clr = GREEN;  
  for(int x = 9; x &gt;= 0; x--){
    if (x &lt; 6) clr = YELLOW;
    if (x &lt; 3) clr = RED;
    M5.Lcd.fillRoundRect(315, (216-(x*24)), 5, 21, 2, (batt&gt;(x*10))?clr:BLACK);  
  }
  M5.Lcd.setCursor(180, 172, 2);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Lcd.setTextSize(1);
  M5.Lcd.print("WiFi Signal: ");
  M5.Lcd.print(WiFi.RSSI());
}


// Remove the Track information (While changing stations)
void clearTrack() {
  M5.Lcd.fillRect(0,63,310,40, BLACK); // Clear the area of old data 
  M5.Lcd.drawRect(0,64,310,37, BLUE); // Draw a box around the Track Information
}


// 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&lt;const char *&gt;(cbData);
  (void) isUnicode; // Punt this ball for now
  // Note that the type and string may be in PROGMEM, so copy them to RAM for printf
  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;

  String band  = getValue(s2, '-', 0);
  band.trim();
  String track = getValue(s2, '-', 1);
  track.trim();
   
  Serial.printf("Band: %s   Track:  %s  \n", band.c_str(), track.c_str());
  Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2);
  M5.Lcd.setTextSize(1);
  M5.Lcd.setCursor(5, 65, 2);
  clearTrack();
  M5.Lcd.print(band);
  M5.Lcd.setCursor(5, 82, 2);
  M5.Lcd.print(track);
  Serial.flush();
  displayBattery(); // Make sure the new song information does not overwrite the battery
}


// 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&lt;const char *&gt;(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 stopPlaying() {
  Serial.printf("Stopping MP3...\n");
  if (mp3) {
    mp3-&gt;stop();
    delete mp3;
    mp3 = NULL;
  }
  Serial.printf("MP3 Stopped, Stopping Buffer...\n");
  if (buffmp3) {
    buffmp3-&gt;close();
    delete buffmp3;
    buffmp3 = NULL;
  }
  Serial.printf("Buffer stopped... Stopping File ...\n");
  if (filemp3) {
    filemp3-&gt;close();
    delete filemp3;
    filemp3 = NULL;
  }
  if (outmp3) {
    //    filemp3-&gt;close();
    delete outmp3;
    outmp3 = NULL;
  }

  Serial.printf("STATUS(Stopped)\n");
  Serial.flush();
}


// Update the Station Label
void updateStation(String message) {
  M5.Lcd.fillRect(0,30,315,30,BLACK); // Clear out other information on the line
  M5.Lcd.setCursor(0, 30, 2);
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Lcd.setTextSize(2);
  M5.Lcd.println(message);
}


// Identify buttons at the bottom of screen
void drawButtons() {
  M5.Lcd.setCursor(5, 210, 2);
  M5.Lcd.setTextColor(TFT_BLACK,  TFT_YELLOW);
  M5.Lcd.setTextSize(2);
  M5.Lcd.println(" Vol     Station    Mute");
  M5.Lcd.setTextColor(TFT_WHITE,  TFT_BLACK);
  M5.Lcd.setTextSize(1);
}


// Change to the next station
void changeStation() {
  updateStation("Changing..Wait..");
  currentStationNumber++;
  if ( stationList[currentStationNumber][2] == "bad") currentStationNumber++; // Skip feeds marked as bad
  if (currentStationNumber &gt;= stations) currentStationNumber = 0;
  Serial.printf("\n******** Changing to channel number: %i\n", currentStationNumber);
}


// Change the volume level
void changeVolume() {
  audioGain += 1.0;
  if (audioGain &gt; 10.0) {
    audioGain = 1.0;
  }
  if (audioGain &lt; 0.0) {
    audioGain = 0.0;
  }
  int xtPos = 260; // X Position for the Volume indication
  outmp3-&gt;SetGain(audioGain * gainfactor);
  M5.Lcd.fillRect(xtPos, 0, 320-xtPos-5, 21, BLACK);
  uint16_t clr = GREEN;
  if (audioGain &gt; 9) clr = RED;
  else if (audioGain &gt; 6) clr = BLUE;
  M5.Lcd.fillTriangle(xtPos, 20, xtPos + (5 * audioGain), 20, xtPos + (5 * audioGain), 20 - (2 * audioGain), clr);
}


void playMP3() {
  outmp3 = new AudioOutputI2S(0, 0); // Output to builtInDAC
  outmp3-&gt;SetPinout(12, 0, 2);
  outmp3-&gt;SetOutputModeMono(true);
  outmp3-&gt;SetGain(audioGain * gainfactor);
  filemp3 = new AudioFileSourceICYStream(stationList[currentStationNumber][1]);
  filemp3-&gt;RegisterMetadataCB(MDCallback, (void*)"ICY");
  buffmp3 = new AudioFileSourceBuffer(filemp3, bufferSize);
  buffmp3-&gt;RegisterStatusCB(StatusCallback, (void*)"buffer");
  mp3 = new AudioGeneratorMP3();
  mp3-&gt;RegisterStatusCB(StatusCallback, (void*)"mp3");
  mp3-&gt;begin(buffmp3, outmp3);
  Serial.printf("STATUS(URL) %s %s\n", stationList[currentStationNumber][0], stationList[currentStationNumber][1]);
  Serial.flush();
  updateStation(String(stationList[currentStationNumber][0]));
}


void loopMP3() {
  if (mp3 != NULL) {  // To avoid crash while changing stations
    if (mp3-&gt;isRunning()) {
      if (!mp3-&gt;loop()) mp3-&gt;stop();
    } else {
      Serial.printf("Status(Stream) Stopped \n");
      stationList[currentStationNumber][2] = "bad"; // Mark feed as bad if it won't play
      clearTrack();
      changeStation();
      //      stopPlaying();
      delay(1000);
      playMP3();
    }
  }
}


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.setFreeFont(TT1);       
//  M5.Lcd.setFreeFont(FF33);
  M5.Lcd.setTextColor(TFT_GREEN, TFT_BLACK);
  M5.Lcd.println("Core2 Web Radio");
  M5.Lcd.setTextColor(TFT_WHITE, TFT_BLACK);
  M5.Lcd.setTextWrap(false);
  
  initwifi();
  delay(500);
  drawButtons();
  playMP3();
  changeVolume();  // To update Volume setting and graphic
  displayWiFiInformation();
//  Serial.printf("Battery Voltage: %f \n", M5.Axp.GetBatVoltage());
}


void loop() {
  loopMP3();
  M5.update();

  if (m5.BtnA.wasPressed()) { //Change Volume(Button A)
    changeVolume();
  }

  if (m5.BtnB.wasPressed()) { //Change Station(Button B)
    clearTrack();
    changeStation();
    stopPlaying();
    playMP3();
  }

  if (m5.BtnC.wasPressed()) { //Mute  (Button C)
    audioGain = -1.0;
    changeVolume();
  }
  
  if (disUpdate + 1000 &lt; millis()) { // Update the battery voltage
    disUpdate = millis();
    displayBattery();
  }
}

</code></pre>
]]></description><link>https://community.m5stack.com/post/13219</link><guid isPermaLink="true">https://community.m5stack.com/post/13219</guid><dc:creator><![CDATA[homeuser33]]></dc:creator><pubDate>Wed, 24 Mar 2021 21:33:13 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Sat, 20 Mar 2021 12:35:18 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/agreedk" aria-label="Profile: agreedk">@<bdi>agreedk</bdi></a><br />
Thank you!<br />
I did the same thing. The code works on M5StickC, but not on Cores2. The author did post the Core2 code, but he said it’s not tested. The fact is it’s not working.<br />
I hope you can move to Core2 soon.<br />
Thank you!</p>
]]></description><link>https://community.m5stack.com/post/13159</link><guid isPermaLink="true">https://community.m5stack.com/post/13159</guid><dc:creator><![CDATA[raychmond]]></dc:creator><pubDate>Sat, 20 Mar 2021 12:35:18 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Sat, 20 Mar 2021 08:20:50 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/raychmond" aria-label="Profile: raychmond">@<bdi>raychmond</bdi></a> I did get it to work, but the quality is very bad - had not have time to work more on it , but I have manage to get better sound out with a M5 StickC &amp; Speaker HAT, so next step for me will be to try move that code to core2.</p>
]]></description><link>https://community.m5stack.com/post/13158</link><guid isPermaLink="true">https://community.m5stack.com/post/13158</guid><dc:creator><![CDATA[AgreeDK]]></dc:creator><pubDate>Sat, 20 Mar 2021 08:20:50 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Fri, 19 Mar 2021 17:50:05 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/agreedk" aria-label="Profile: agreedk">@<bdi>agreedk</bdi></a><br />
Hi, were you able to play stream or mp3 on Core2?<br />
The only program I can make the sound is the Core2 example speak.ino. I'm trying to combine the example with the web ratio program that you mentioned. It gives me error due to decode problem.<br />
Then I turned to another tutorial that plays mp3 on SD card. But it doesn't output the sound either. I don't know what the problem is. So I hope you did successfully and can shed some light on this issue.</p>
<p dir="auto">Thank you,</p>
]]></description><link>https://community.m5stack.com/post/13141</link><guid isPermaLink="true">https://community.m5stack.com/post/13141</guid><dc:creator><![CDATA[raychmond]]></dc:creator><pubDate>Fri, 19 Mar 2021 17:50:05 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Thu, 18 Feb 2021 20:49:08 GMT]]></title><description><![CDATA[<p dir="auto">Hi <a class="plugin-mentions-user plugin-mentions-a" href="/user/felmue" aria-label="Profile: felmue">@<bdi>felmue</bdi></a><br />
Thanks, using your link, I mange to find an untestet example using the library here<br />
<a href="https://www.hackster.io/tommyho/arduino-web-radio-player-c4cb23" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.hackster.io/tommyho/arduino-web-radio-player-c4cb23</a></p>
<p dir="auto">but first when I added code to enable the I2S Speaker (using code from the example 'speak.ino' I manage to get something out of the speaker on CORE2, but the quality make it useless - it might get better turning the code, so will try do some test on that.</p>
]]></description><link>https://community.m5stack.com/post/12555</link><guid isPermaLink="true">https://community.m5stack.com/post/12555</guid><dc:creator><![CDATA[AgreeDK]]></dc:creator><pubDate>Thu, 18 Feb 2021 20:49:08 GMT</pubDate></item><item><title><![CDATA[Reply to CORE2 as Web radio, without extra hardware ? on Thu, 18 Feb 2021 19:02:21 GMT]]></title><description><![CDATA[<p dir="auto">Hello <a class="plugin-mentions-user plugin-mentions-a" href="/user/agreedk" aria-label="Profile: AgreeDK">@<bdi>AgreeDK</bdi></a></p>
<p dir="auto">have you had a look at this <a href="https://github.com/earlephilhower/ESP8266Audio" target="_blank" rel="noopener noreferrer nofollow ugc">repository</a> - lots of examples too.</p>
<p dir="auto">Good luck!<br />
Felix</p>
]]></description><link>https://community.m5stack.com/post/12554</link><guid isPermaLink="true">https://community.m5stack.com/post/12554</guid><dc:creator><![CDATA[felmue]]></dc:creator><pubDate>Thu, 18 Feb 2021 19:02:21 GMT</pubDate></item></channel></rss>