main
This commit is contained in:
@ -0,0 +1,156 @@
|
||||
// found this sketch on https://www.mikrocontroller.net/topic/474383
|
||||
// thanks to Michael U. (amiga)
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "WiFi.h"
|
||||
#include "SPI.h"
|
||||
#include "SD.h"
|
||||
#include "FS.h"
|
||||
#include "Wire.h"
|
||||
#include "AC101.h" //https://github.com/schreibfaul1/AC101
|
||||
// #include "ES8388.h" // https://github.com/maditnerd/es8388
|
||||
#include "Audio.h" //https://github.com/schreibfaul1/ESP32-audioI2S
|
||||
|
||||
|
||||
// SPI GPIOs
|
||||
#define SD_CS 13
|
||||
#define SPI_MOSI 15
|
||||
#define SPI_MISO 2
|
||||
#define SPI_SCK 14
|
||||
|
||||
// I2S GPIOs, the names refer on AC101, AS1 Audio Kit V2.2 2379
|
||||
#define I2S_DSIN 25
|
||||
#define I2S_BCLK 27
|
||||
#define I2S_LRC 26
|
||||
#define I2S_MCLK 0
|
||||
#define I2S_DOUT 35
|
||||
|
||||
// I2S GPIOs, the names refer on ES8388, AS1 Audio Kit V2.2 3378
|
||||
//#define I2S_DSIN 35
|
||||
//#define I2S_BCLK 27
|
||||
//#define I2S_LRC 25
|
||||
//#define I2S_MCLK 0
|
||||
//#define I2S_DOUT 26
|
||||
|
||||
// I2C GPIOs
|
||||
#define IIC_CLK 32
|
||||
#define IIC_DATA 33
|
||||
|
||||
// buttons
|
||||
// #define BUTTON_2_PIN 13 // shared mit SPI_CS
|
||||
#define BUTTON_3_PIN 19
|
||||
#define BUTTON_4_PIN 23
|
||||
#define BUTTON_5_PIN 18 // Stop
|
||||
#define BUTTON_6_PIN 5 // Play
|
||||
|
||||
// amplifier enable
|
||||
#define GPIO_PA_EN 21
|
||||
|
||||
//Switch S1: 1-OFF, 2-ON, 3-ON, 4-OFF, 5-OFF
|
||||
|
||||
String ssid = "xxxxxxxxx";
|
||||
String password = "xxxxxxxxx";
|
||||
|
||||
static AC101 dac; // AC101
|
||||
// ES8388 dac; // ES8388 (new board)
|
||||
int volume = 40; // 0...100
|
||||
|
||||
Audio audio;
|
||||
|
||||
//#####################################################################
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("\r\nReset");
|
||||
Serial.printf_P(PSTR("Free mem=%d\n"), ESP.getFreeHeap());
|
||||
|
||||
pinMode(SD_CS, OUTPUT);
|
||||
digitalWrite(SD_CS, HIGH);
|
||||
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
SPI.setFrequency(1000000);
|
||||
|
||||
SD.begin(SD_CS);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid.c_str(), password.c_str());
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
Serial.print(".");
|
||||
delay(100);
|
||||
}
|
||||
|
||||
Serial.printf_P(PSTR("Connected\r\nRSSI: "));
|
||||
Serial.print(WiFi.RSSI());
|
||||
Serial.print(" IP: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
Serial.printf("Connect to DAC codec... ");
|
||||
while (not dac.begin(IIC_DATA, IIC_CLK))
|
||||
{
|
||||
Serial.printf("Failed!\n");
|
||||
delay(1000);
|
||||
}
|
||||
Serial.printf("OK\n");
|
||||
|
||||
dac.SetVolumeSpeaker(volume);
|
||||
dac.SetVolumeHeadphone(volume);
|
||||
// ac.DumpRegisters();
|
||||
|
||||
// Enable amplifier
|
||||
pinMode(GPIO_PA_EN, OUTPUT);
|
||||
digitalWrite(GPIO_PA_EN, HIGH);
|
||||
|
||||
// set I2S_MasterClock
|
||||
audio.i2s_mclk_pin_select(I2S_MCLK);
|
||||
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DSIN);
|
||||
audio.setVolume(10); // 0...21
|
||||
|
||||
audio.connecttoFS(SD, "/320k_test.mp3");
|
||||
// audio.connecttoSD("/Banana Boat Song - Harry Belafonte.mp3");
|
||||
// audio.connecttohost("http://mp3channels.webradio.antenne.de:80/oldies-but-goldies");
|
||||
// audio.connecttohost("http://dg-rbb-http-dus-dtag-cdn.cast.addradio.de/rbb/antennebrandenburg/live/mp3/128/stream.mp3");
|
||||
// audio.connecttospeech("Wenn die Hunde schlafen, kann der Wolf gut Schafe stehlen.", "de");
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
void loop()
|
||||
{
|
||||
audio.loop();
|
||||
}
|
||||
|
||||
// optional
|
||||
void audio_info(const char *info){
|
||||
Serial.print("info "); Serial.println(info);
|
||||
}
|
||||
void audio_id3data(const char *info){ //id3 metadata
|
||||
Serial.print("id3data ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_mp3(const char *info){ //end of file
|
||||
Serial.print("eof_mp3 ");Serial.println(info);
|
||||
}
|
||||
void audio_showstation(const char *info){
|
||||
Serial.print("station ");Serial.println(info);
|
||||
}
|
||||
void audio_showstreamtitle(const char *info){
|
||||
Serial.print("streamtitle ");Serial.println(info);
|
||||
}
|
||||
void audio_bitrate(const char *info){
|
||||
Serial.print("bitrate ");Serial.println(info);
|
||||
}
|
||||
void audio_commercial(const char *info){ //duration in sec
|
||||
Serial.print("commercial ");Serial.println(info);
|
||||
}
|
||||
void audio_icyurl(const char *info){ //homepage
|
||||
Serial.print("icyurl ");Serial.println(info);
|
||||
}
|
||||
void audio_lasthost(const char *info){ //stream URL played
|
||||
Serial.print("lasthost ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_speech(const char *info){
|
||||
Serial.print("eof_speech ");Serial.println(info);
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
// the pin assignment matches the Olimex ADF board
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "WiFi.h"
|
||||
#include "SPI.h"
|
||||
#include "SD.h"
|
||||
#include "FS.h"
|
||||
#include "Wire.h"
|
||||
#include "ES8388.h" // https://github.com/maditnerd/es8388
|
||||
#include "Audio.h" // https://github.com/schreibfaul1/ESP32-audioI2S
|
||||
|
||||
|
||||
#define SD_CS 21
|
||||
|
||||
// GPIOs for SPI
|
||||
#define SPI_MOSI 13
|
||||
#define SPI_MISO 12
|
||||
#define SPI_SCK 14
|
||||
|
||||
// I2S GPIOs
|
||||
#define I2S_SDOUT 26
|
||||
#define I2S_BCLK 5
|
||||
#define I2S_LRCK 25
|
||||
#define I2S_MCLK 0
|
||||
|
||||
// I2C GPIOs
|
||||
#define IIC_CLK 23
|
||||
#define IIC_DATA 18
|
||||
|
||||
// Amplifier enable
|
||||
#define GPIO_PA_EN 19
|
||||
|
||||
char ssid[] = "xxxxxxxxx";
|
||||
char password[] = "xxxxxxxxx";
|
||||
|
||||
|
||||
int volume = 80; // 0...100
|
||||
|
||||
ES8388 es;
|
||||
Audio audio;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("\r\nReset");
|
||||
Serial.printf_P(PSTR("Free mem=%d\n"), ESP.getFreeHeap());
|
||||
|
||||
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
SPI.setFrequency(1000000);
|
||||
|
||||
SD.begin(SD_CS);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
|
||||
while(WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(100);
|
||||
}
|
||||
|
||||
Serial.printf_P(PSTR("Connected\r\nRSSI: "));
|
||||
Serial.print(WiFi.RSSI());
|
||||
Serial.print(" IP: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
|
||||
Serial.printf("Connect to ES8388 codec... ");
|
||||
while (not es.begin(IIC_DATA, IIC_CLK))
|
||||
{
|
||||
Serial.printf("Failed!\n");
|
||||
delay(1000);
|
||||
}
|
||||
Serial.printf("OK\n");
|
||||
|
||||
es.volume(ES8388::ES_MAIN, volume);
|
||||
es.volume(ES8388::ES_OUT1, volume);
|
||||
es.volume(ES8388::ES_OUT2, volume);
|
||||
es.mute(ES8388::ES_OUT1, false);
|
||||
es.mute(ES8388::ES_OUT2, false);
|
||||
es.mute(ES8388::ES_MAIN, false);
|
||||
|
||||
// Enable amplifier
|
||||
pinMode(GPIO_PA_EN, OUTPUT);
|
||||
digitalWrite(GPIO_PA_EN, HIGH);
|
||||
|
||||
audio.setPinout(I2S_BCLK, I2S_LRCK, I2S_SDOUT);
|
||||
audio.i2s_mclk_pin_select(I2S_MCLK);
|
||||
audio.setVolume(21); // 0...21
|
||||
|
||||
audio.connecttohost("http://mp3channels.webradio.antenne.de:80/oldies-but-goldies");
|
||||
// audio.connecttoFS(SD, "320k_test.mp3");
|
||||
// audio.connecttospeech("Wenn die Hunde schlafen, kann der Wolf gut Schafe stehlen.", "de");
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void loop()
|
||||
{
|
||||
audio.loop();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// optional
|
||||
void audio_info(const char *info){
|
||||
Serial.print("info "); Serial.println(info);
|
||||
}
|
||||
void audio_id3data(const char *info){ //id3 metadata
|
||||
Serial.print("id3data ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_mp3(const char *info){ //end of file
|
||||
Serial.print("eof_mp3 ");Serial.println(info);
|
||||
}
|
||||
void audio_showstation(const char *info){
|
||||
Serial.print("station ");Serial.println(info);
|
||||
}
|
||||
void audio_showstreaminfo(const char *info){
|
||||
Serial.print("streaminfo ");Serial.println(info);
|
||||
}
|
||||
void audio_showstreamtitle(const char *info){
|
||||
Serial.print("streamtitle ");Serial.println(info);
|
||||
}
|
||||
void audio_bitrate(const char *info){
|
||||
Serial.print("bitrate ");Serial.println(info);
|
||||
}
|
||||
void audio_commercial(const char *info){ //duration in sec
|
||||
Serial.print("commercial ");Serial.println(info);
|
||||
}
|
||||
void audio_icyurl(const char *info){ //homepage
|
||||
Serial.print("icyurl ");Serial.println(info);
|
||||
}
|
||||
void audio_lasthost(const char *info){ //stream URL played
|
||||
Serial.print("lasthost ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_speech(const char *info){
|
||||
Serial.print("eof_speech ");Serial.println(info);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
//**********************************************************************************************************
|
||||
//* audioI2S-- I2S audiodecoder for ESP32, *
|
||||
//**********************************************************************************************************
|
||||
//
|
||||
// first release on 11/2018
|
||||
// Version 3 , Jul.02/2020
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT.
|
||||
// FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR
|
||||
// OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
|
||||
//
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "WiFiMulti.h"
|
||||
#include "Audio.h"
|
||||
#include "SPI.h"
|
||||
#include "SD.h"
|
||||
#include "FS.h"
|
||||
|
||||
// Digital I/O used
|
||||
#define SD_CS 5
|
||||
#define SPI_MOSI 23
|
||||
#define SPI_MISO 19
|
||||
#define SPI_SCK 18
|
||||
#define I2S_DOUT 25
|
||||
#define I2S_BCLK 27
|
||||
#define I2S_LRC 26
|
||||
|
||||
Audio audio;
|
||||
WiFiMulti wifiMulti;
|
||||
String ssid = "xxxxx";
|
||||
String password = "xxxxx";
|
||||
|
||||
|
||||
void setup() {
|
||||
pinMode(SD_CS, OUTPUT); digitalWrite(SD_CS, HIGH);
|
||||
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
SPI.setFrequency(1000000);
|
||||
Serial.begin(115200);
|
||||
SD.begin(SD_CS);
|
||||
WiFi.mode(WIFI_STA);
|
||||
wifiMulti.addAP(ssid.c_str(), password.c_str());
|
||||
wifiMulti.run();
|
||||
if(WiFi.status() != WL_CONNECTED){
|
||||
WiFi.disconnect(true);
|
||||
wifiMulti.run();
|
||||
}
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
audio.setVolume(12); // 0...21
|
||||
|
||||
// audio.connecttoFS(SD, "/320k_test.mp3");
|
||||
// audio.connecttoFS(SD, "test.wav");
|
||||
// audio.connecttohost("http://www.wdr.de/wdrlive/media/einslive.m3u");
|
||||
// audio.connecttohost("http://macslons-irish-pub-radio.com/media.asx");
|
||||
// audio.connecttohost("http://mp3.ffh.de/radioffh/hqlivestream.aac"); // 128k aac
|
||||
audio.connecttohost("http://mp3.ffh.de/radioffh/hqlivestream.mp3"); // 128k mp3
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
audio.loop();
|
||||
if(Serial.available()){ // put streamURL in serial monitor
|
||||
audio.stopSong();
|
||||
String r=Serial.readString(); r.trim();
|
||||
if(r.length()>5) audio.connecttohost(r.c_str());
|
||||
log_i("free heap=%i", ESP.getFreeHeap());
|
||||
}
|
||||
}
|
||||
|
||||
// optional
|
||||
void audio_info(const char *info){
|
||||
Serial.print("info "); Serial.println(info);
|
||||
}
|
||||
void audio_id3data(const char *info){ //id3 metadata
|
||||
Serial.print("id3data ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_mp3(const char *info){ //end of file
|
||||
Serial.print("eof_mp3 ");Serial.println(info);
|
||||
}
|
||||
void audio_showstation(const char *info){
|
||||
Serial.print("station ");Serial.println(info);
|
||||
}
|
||||
void audio_showstreamtitle(const char *info){
|
||||
Serial.print("streamtitle ");Serial.println(info);
|
||||
}
|
||||
void audio_bitrate(const char *info){
|
||||
Serial.print("bitrate ");Serial.println(info);
|
||||
}
|
||||
void audio_commercial(const char *info){ //duration in sec
|
||||
Serial.print("commercial ");Serial.println(info);
|
||||
}
|
||||
void audio_icyurl(const char *info){ //homepage
|
||||
Serial.print("icyurl ");Serial.println(info);
|
||||
}
|
||||
void audio_lasthost(const char *info){ //stream URL played
|
||||
Serial.print("lasthost ");Serial.println(info);
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
//**********************************************************************************************************
|
||||
//* audioI2S-- I2S audiodecoder for M5Stack Core2 *
|
||||
//**********************************************************************************************************
|
||||
//
|
||||
// first release on May.12/2021
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT.
|
||||
// FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR
|
||||
// OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
|
||||
//
|
||||
|
||||
#include <M5Core2.h>
|
||||
#include "Audio.h"
|
||||
|
||||
// Digital I/O used
|
||||
#define SD_CS 4
|
||||
#define SD_MOSI 23
|
||||
#define SD_MISO 38
|
||||
#define SD_SCK 18
|
||||
#define I2S_DOUT 2
|
||||
#define I2S_BCLK 12
|
||||
#define I2S_LRC 0
|
||||
|
||||
Audio audio;
|
||||
String ssid = "xxxxxx";
|
||||
String password = "xxxxxx";
|
||||
|
||||
|
||||
void setup() {
|
||||
M5.begin(true, true, true, true);
|
||||
M5.Axp.SetSpkEnable(true);
|
||||
M5.Lcd.fillScreen(BLACK);
|
||||
M5.Lcd.setTextColor(WHITE);
|
||||
M5.Lcd.setTextSize(2);
|
||||
|
||||
pinMode(SD_CS, OUTPUT);
|
||||
digitalWrite(SD_CS, HIGH);
|
||||
SPI.begin(SD_SCK, SD_MISO, SD_MOSI);
|
||||
SPI.setFrequency(1000000);
|
||||
SD.begin(SD_CS);
|
||||
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
audio.setVolume(15); // 0...21
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid.c_str(), password.c_str());
|
||||
while (!WiFi.isConnected()) {
|
||||
delay(10);
|
||||
}
|
||||
ESP_LOGI(TAG, "Connected");
|
||||
ESP_LOGI(TAG, "Starting MP3...\n");
|
||||
|
||||
// audio.connecttoFS(SD, "/320k_test.mp3");
|
||||
// audio.connecttoFS(SD, "test.wav");
|
||||
audio.connecttohost("http://air.ofr.fm:8008/jazz/mp3/128");
|
||||
// audio.connecttospeech("Миска вареників з картоплею та шкварками, змащених салом!", "uk-UA");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
audio.loop();
|
||||
if(Serial.available()){ // put streamURL in serial monitor
|
||||
audio.stopSong();
|
||||
String r=Serial.readString();
|
||||
r.trim();
|
||||
if(r.length()>5) audio.connecttohost(r.c_str());
|
||||
log_i("free heap=%i", ESP.getFreeHeap());
|
||||
}
|
||||
}
|
||||
|
||||
// optional
|
||||
void audio_info(const char *info){
|
||||
Serial.print("info "); Serial.println(info);
|
||||
}
|
||||
void audio_id3data(const char *info){ //id3 metadata
|
||||
Serial.print("id3data ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_mp3(const char *info){ //end of file
|
||||
Serial.print("eof_mp3 ");Serial.println(info);
|
||||
}
|
||||
void audio_showstation(const char *info){
|
||||
Serial.print("station ");Serial.println(info);
|
||||
}
|
||||
void audio_showstreamtitle(const char *info){
|
||||
Serial.print("streamtitle ");Serial.println(info);
|
||||
}
|
||||
void audio_bitrate(const char *info){
|
||||
Serial.print("bitrate ");Serial.println(info);
|
||||
}
|
||||
void audio_commercial(const char *info){ //duration in sec
|
||||
Serial.print("commercial ");Serial.println(info);
|
||||
}
|
||||
void audio_icyurl(const char *info){ //homepage
|
||||
Serial.print("icyurl ");Serial.println(info);
|
||||
}
|
||||
void audio_lasthost(const char *info){ //stream URL played
|
||||
Serial.print("lasthost ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_speech(const char *info){
|
||||
Serial.print("eof_speech ");Serial.println(info);
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
|
||||
// M5Stack Node support
|
||||
// thanks to Cellie - issue #35 25.Apr.2020
|
||||
// M5Stack board with Node base also need a MCLK signal on GPIO0.
|
||||
|
||||
#include <wm8978.h> /* https://github.com/CelliesProjects/wm8978-esp32 */
|
||||
#include <Audio.h> /* https://github.com/schreibfaul1/ESP32-audioI2S */
|
||||
|
||||
/* M5Stack Node WM8978 I2C pins */
|
||||
#define I2C_SDA 21
|
||||
#define I2C_SCL 22
|
||||
|
||||
/* M5Stack Node I2S pins */
|
||||
#define I2S_BCK 5
|
||||
#define I2S_WS 13
|
||||
#define I2S_DOUT 2
|
||||
#define I2S_DIN 34
|
||||
|
||||
/* M5Stack WM8978 MCLK gpio number */
|
||||
#define I2S_MCLKPIN 0
|
||||
|
||||
WM8978 dac;
|
||||
Audio audio;
|
||||
|
||||
void setup() {
|
||||
/* Setup wm8978 I2C interface */
|
||||
if (!dac.begin(I2C_SDA, I2C_SCL)) {
|
||||
ESP_LOGE(TAG, "Error setting up dac. System halted");
|
||||
while (1) delay(100);
|
||||
}
|
||||
|
||||
/* Setup wm8978 I2S interface */
|
||||
audio.setPinout(I2S_BCK, I2S_WS, I2S_DOUT, I2S_DIN);
|
||||
|
||||
/* Setup wm8978 MCLK - for example M5Stack Node needs MCLK on GPIO 0 */
|
||||
audio.i2s_mclk_pin_select(I2S_MCLKPIN);
|
||||
|
||||
WiFi.begin("xxx", "xxx");
|
||||
while (!WiFi.isConnected()) {
|
||||
delay(10);
|
||||
}
|
||||
ESP_LOGI(TAG, "Connected");
|
||||
|
||||
ESP_LOGI(TAG, "Starting MP3...\n");
|
||||
audio.connecttohost("http://icecast.omroep.nl/3fm-bb-mp3");
|
||||
|
||||
dac.setSPKvol(40); /* max 63 */
|
||||
dac.setHPvol(32, 32);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
audio.loop();
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
//**********************************************************************************************************
|
||||
//* audioI2S-- I2S audiodecoder for M5StickC Plus and SPK HAT *
|
||||
//**********************************************************************************************************
|
||||
//
|
||||
// first release on May.12/2021
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT.
|
||||
// FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR
|
||||
// OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
|
||||
//
|
||||
|
||||
#include <M5StickCPlus.h>
|
||||
#include "Audio.h"
|
||||
|
||||
Audio audio = Audio(true);
|
||||
|
||||
String ssid = "xxxxxxxx";
|
||||
String password = "xxxxxxxx";
|
||||
|
||||
|
||||
void setup() {
|
||||
M5.begin(false); //Lcd disabled to reduce noise
|
||||
M5.Axp.ScreenBreath(1); //Lower Lcd backlight
|
||||
pinMode(36, INPUT);
|
||||
gpio_pulldown_dis(GPIO_NUM_25);
|
||||
gpio_pullup_dis(GPIO_NUM_25);
|
||||
M5.Beep.tone(44100); //Built-in buzzer tone
|
||||
M5.Beep.end(); //disabled
|
||||
|
||||
audio.setVolume(15); // 0...21
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid.c_str(), password.c_str());
|
||||
while (!WiFi.isConnected()) {
|
||||
delay(10);
|
||||
}
|
||||
ESP_LOGI(TAG, "Connected");
|
||||
ESP_LOGI(TAG, "Starting MP3...\n");
|
||||
|
||||
audio.connecttohost("http://air.ofr.fm:8008/jazz/mp3/128");
|
||||
// audio.connecttospeech("Миска вареників з картоплею та шкварками, змащених салом!", "uk-UA");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
audio.loop();
|
||||
if(Serial.available()){ // put streamURL in serial monitor
|
||||
audio.stopSong();
|
||||
String r=Serial.readString();
|
||||
r.trim();
|
||||
if(r.length()>5) audio.connecttohost(r.c_str());
|
||||
log_i("free heap=%i", ESP.getFreeHeap());
|
||||
}
|
||||
}
|
||||
|
||||
// optional
|
||||
void audio_info(const char *info){
|
||||
Serial.print("info "); Serial.println(info);
|
||||
}
|
||||
void audio_id3data(const char *info){ //id3 metadata
|
||||
Serial.print("id3data ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_mp3(const char *info){ //end of file
|
||||
Serial.print("eof_mp3 ");Serial.println(info);
|
||||
}
|
||||
void audio_showstation(const char *info){
|
||||
Serial.print("station ");Serial.println(info);
|
||||
}
|
||||
void audio_showstreamtitle(const char *info){
|
||||
Serial.print("streamtitle ");Serial.println(info);
|
||||
}
|
||||
void audio_bitrate(const char *info){
|
||||
Serial.print("bitrate ");Serial.println(info);
|
||||
}
|
||||
void audio_commercial(const char *info){ //duration in sec
|
||||
Serial.print("commercial ");Serial.println(info);
|
||||
}
|
||||
void audio_icyurl(const char *info){ //homepage
|
||||
Serial.print("icyurl ");Serial.println(info);
|
||||
}
|
||||
void audio_lasthost(const char *info){ //stream URL played
|
||||
Serial.print("lasthost ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_speech(const char *info){
|
||||
Serial.print("eof_speech ");Serial.println(info);
|
||||
}
|
||||
@ -0,0 +1,158 @@
|
||||
#include "Arduino.h"
|
||||
#include "WiFi.h"
|
||||
#include "Audio.h"
|
||||
|
||||
// Digital I/O used
|
||||
#define I2S_DOUT 25
|
||||
#define I2S_BCLK 27
|
||||
#define I2S_LRC 26
|
||||
|
||||
Audio audio;
|
||||
|
||||
String ssid = "******";
|
||||
String password = "******";
|
||||
|
||||
//****************************************************************************************
|
||||
// A U D I O _ T A S K *
|
||||
//****************************************************************************************
|
||||
|
||||
struct audioMessage{
|
||||
uint8_t cmd;
|
||||
const char* txt;
|
||||
uint32_t value;
|
||||
uint32_t ret;
|
||||
} audioTxMessage, audioRxMessage;
|
||||
|
||||
enum : uint8_t { SET_VOLUME, GET_VOLUME, CONNECTTOHOST, CONNECTTOSD };
|
||||
|
||||
QueueHandle_t audioSetQueue = NULL;
|
||||
QueueHandle_t audioGetQueue = NULL;
|
||||
|
||||
void CreateQueues(){
|
||||
audioSetQueue = xQueueCreate(10, sizeof(struct audioMessage));
|
||||
audioGetQueue = xQueueCreate(10, sizeof(struct audioMessage));
|
||||
}
|
||||
|
||||
void audioTask(void *parameter) {
|
||||
CreateQueues();
|
||||
if(!audioSetQueue || !audioGetQueue){
|
||||
log_e("queues are not initialized");
|
||||
while(true){;} // endless loop
|
||||
}
|
||||
|
||||
struct audioMessage audioRxTaskMessage;
|
||||
struct audioMessage audioTxTaskMessage;
|
||||
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
audio.setVolume(15); // 0...21
|
||||
|
||||
while(true){
|
||||
if(xQueueReceive(audioSetQueue, &audioRxTaskMessage, 1) == pdPASS) {
|
||||
if(audioRxTaskMessage.cmd == SET_VOLUME){
|
||||
audioTxTaskMessage.cmd = SET_VOLUME;
|
||||
audio.setVolume(audioRxTaskMessage.value);
|
||||
audioTxTaskMessage.ret = 1;
|
||||
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
|
||||
}
|
||||
else if(audioRxTaskMessage.cmd == CONNECTTOHOST){
|
||||
audioTxTaskMessage.cmd = CONNECTTOHOST;
|
||||
audioTxTaskMessage.ret = audio.connecttohost(audioRxTaskMessage.txt);
|
||||
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
|
||||
}
|
||||
else if(audioRxTaskMessage.cmd == CONNECTTOSD){
|
||||
audioTxTaskMessage.cmd = CONNECTTOSD;
|
||||
audioTxTaskMessage.ret = audio.connecttoSD(audioRxTaskMessage.txt);
|
||||
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
|
||||
}
|
||||
else if(audioRxTaskMessage.cmd == GET_VOLUME){
|
||||
audioTxTaskMessage.cmd = GET_VOLUME;
|
||||
audioTxTaskMessage.ret = audio.getVolume();
|
||||
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
|
||||
}
|
||||
else{
|
||||
log_i("error");
|
||||
}
|
||||
}
|
||||
audio.loop();
|
||||
}
|
||||
}
|
||||
|
||||
void audioInit() {
|
||||
xTaskCreatePinnedToCore(
|
||||
audioTask, /* Function to implement the task */
|
||||
"audioplay", /* Name of the task */
|
||||
5000, /* Stack size in words */
|
||||
NULL, /* Task input parameter */
|
||||
2 | portPRIVILEGE_BIT, /* Priority of the task */
|
||||
NULL, /* Task handle. */
|
||||
1 /* Core where the task should run */
|
||||
);
|
||||
}
|
||||
|
||||
audioMessage transmitReceive(audioMessage msg){
|
||||
xQueueSend(audioSetQueue, &msg, portMAX_DELAY);
|
||||
if(xQueueReceive(audioGetQueue, &audioRxMessage, portMAX_DELAY) == pdPASS){
|
||||
if(msg.cmd != audioRxMessage.cmd){
|
||||
log_e("wrong reply from message queue");
|
||||
}
|
||||
}
|
||||
return audioRxMessage;
|
||||
}
|
||||
|
||||
void audioSetVolume(uint8_t vol){
|
||||
audioTxMessage.cmd = SET_VOLUME;
|
||||
audioTxMessage.value = vol;
|
||||
audioMessage RX = transmitReceive(audioTxMessage);
|
||||
}
|
||||
|
||||
uint8_t audioGetVolume(){
|
||||
audioTxMessage.cmd = GET_VOLUME;
|
||||
audioMessage RX = transmitReceive(audioTxMessage);
|
||||
return RX.ret;
|
||||
}
|
||||
|
||||
bool audioConnecttohost(const char* host){
|
||||
audioTxMessage.cmd = CONNECTTOHOST;
|
||||
audioTxMessage.txt = host;
|
||||
audioMessage RX = transmitReceive(audioTxMessage);
|
||||
return RX.ret;
|
||||
}
|
||||
|
||||
bool audioConnecttoSD(const char* filename){
|
||||
audioTxMessage.cmd = CONNECTTOSD;
|
||||
audioTxMessage.txt = filename;
|
||||
audioMessage RX = transmitReceive(audioTxMessage);
|
||||
return RX.ret;
|
||||
}
|
||||
|
||||
//****************************************************************************************
|
||||
// S E T U P *
|
||||
//****************************************************************************************
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
WiFi.begin(ssid.c_str(), password.c_str());
|
||||
while (WiFi.status() != WL_CONNECTED) delay(1500);
|
||||
|
||||
audioInit();
|
||||
|
||||
audioConnecttohost("http://mp3.ffh.de/radioffh/hqlivestream.mp3");
|
||||
audioSetVolume(15);
|
||||
log_i("current volume is: %d", audioGetVolume());
|
||||
}
|
||||
|
||||
//****************************************************************************************
|
||||
// L O O P *
|
||||
//****************************************************************************************
|
||||
|
||||
void loop(){
|
||||
// your own code here
|
||||
}
|
||||
//*****************************************************************************************
|
||||
// E V E N T S *
|
||||
//*****************************************************************************************
|
||||
|
||||
void audio_info(const char *info){
|
||||
Serial.print("info "); Serial.println(info);
|
||||
}
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
//**********************************************************************************************************
|
||||
//* audioI2S-- I2S audiodecoder for ESP32, SdFat example *
|
||||
//**********************************************************************************************************
|
||||
//
|
||||
// first release on 05/2020
|
||||
// updated on Sep. 27, 2021
|
||||
/*
|
||||
|
||||
⒈ install SdFat V2 from https://github.com/greiman/SdFat
|
||||
⒉ activate "SDFATFS_USED" in Audio.h
|
||||
⒊ activate "#define USE_UTF8_LONG_NAMES 1" in SdFatConfig.h
|
||||
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Audio.h"
|
||||
#include "SPI.h"
|
||||
|
||||
// Digital I/O used
|
||||
#define SD_CS 5
|
||||
#define SPI_MOSI 23
|
||||
#define SPI_MISO 19
|
||||
#define SPI_SCK 18
|
||||
#define I2S_DOUT 25
|
||||
#define I2S_BCLK 27
|
||||
#define I2S_LRC 26
|
||||
|
||||
Audio audio;
|
||||
|
||||
void setup() {
|
||||
pinMode(SD_CS, OUTPUT); digitalWrite(SD_CS, HIGH);
|
||||
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
SPI.setFrequency(1000000);
|
||||
Serial.begin(115200);
|
||||
SD.begin(SD_CS);
|
||||
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
audio.setVolume(12); // 0...21
|
||||
|
||||
// audio.connecttoFS(SD, "test.mp3");
|
||||
audio.connecttoFS(SD, "良い一日私の友達.mp3");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
audio.loop();
|
||||
}
|
||||
|
||||
// optional
|
||||
void audio_info(const char *info){
|
||||
Serial.print("info "); Serial.println(info);
|
||||
}
|
||||
void audio_id3data(const char *info){ //id3 metadata
|
||||
Serial.print("id3data ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_mp3(const char *info){ //end of file
|
||||
Serial.print("eof_mp3 ");Serial.println(info);
|
||||
}
|
||||
@ -0,0 +1,224 @@
|
||||
#include <Arduino.h>
|
||||
#include <Preferences.h>
|
||||
#include <SPI.h>
|
||||
#include <WiFi.h>
|
||||
#include "tft.h" //see my repository at github "https://github.com/schreibfaul1/ESP32-TFT-Library-ILI9486"
|
||||
#include "Audio.h" //see my repository at github "https://github.com/schreibfaul1/ESP32-audioI2S"
|
||||
|
||||
#define TFT_CS 22
|
||||
#define TFT_DC 21
|
||||
#define TP_CS 14 //16
|
||||
#define TP_IRQ 39
|
||||
#define SPI_MOSI 23
|
||||
#define SPI_MISO 19
|
||||
#define SPI_SCK 18
|
||||
#define I2S_DOUT 25
|
||||
#define I2S_BCLK 27
|
||||
#define I2S_LRC 26
|
||||
|
||||
Preferences pref;
|
||||
TFT tft;
|
||||
TP tp(TP_CS, TP_IRQ);
|
||||
Audio audio;
|
||||
|
||||
String ssid = "*****";
|
||||
String password = "*****";
|
||||
|
||||
String stations[] ={
|
||||
"0n-80s.radionetz.de:8000/0n-70s.mp3",
|
||||
"mediaserv30.live-streams.nl:8000/stream",
|
||||
"www.surfmusic.de/m3u/100-5-das-hitradio,4529.m3u",
|
||||
"stream.1a-webradio.de/deutsch/mp3-128/vtuner-1a",
|
||||
"mp3.ffh.de/radioffh/hqlivestream.aac", // 128k aac
|
||||
"www.antenne.de/webradio/antenne.m3u",
|
||||
"listen.rusongs.ru/ru-mp3-128",
|
||||
"edge.audio.3qsdn.com/senderkw-mp3",
|
||||
"macslons-irish-pub-radio.com/media.asx",
|
||||
};
|
||||
|
||||
//some global variables
|
||||
|
||||
uint8_t max_volume = 21;
|
||||
uint8_t max_stations = 0; //will be set later
|
||||
uint8_t cur_station = 0; //current station(nr), will be set later
|
||||
uint8_t cur_volume = 0; //will be set from stored preferences
|
||||
int8_t cur_btn =-1; //current button (, -1 means idle)
|
||||
|
||||
enum action{VOLUME_UP=0, VOLUME_DOWN=1, STATION_UP=2, STATION_DOWN=3};
|
||||
enum staus {RELEASED=0, PRESSED=1};
|
||||
|
||||
struct _btns{
|
||||
uint16_t x; //PosX
|
||||
uint16_t y; //PosY
|
||||
uint16_t w; //Width
|
||||
uint16_t h; //Hight
|
||||
uint8_t a; //Action
|
||||
uint8_t s; //Status
|
||||
};
|
||||
typedef _btns btns;
|
||||
|
||||
btns btn[4];
|
||||
|
||||
//**************************************************************************************************
|
||||
// G U I *
|
||||
//**************************************************************************************************
|
||||
void draw_button(btns b){
|
||||
uint16_t color=TFT_BLACK;
|
||||
uint8_t r=4, o=r*3;
|
||||
if(b.s==RELEASED) color=TFT_GOLD;
|
||||
if(b.s==PRESSED) color=TFT_DEEPSKYBLUE;
|
||||
tft.drawRoundRect(b.x, b.y, b.w, b.h, r, color);
|
||||
switch(b.a){
|
||||
case VOLUME_UP:
|
||||
tft.fillTriangle(b.x+b.w/2, b.y+o, b.x+o, b.y+b.h-o, b.x+b.w-o, b.y+b.h-o, color); break;
|
||||
case VOLUME_DOWN:
|
||||
tft.fillTriangle(b.x+o, b.y+o, b.x+b.w/2, b.y+b.h-o, b.x+b.w-o, b.y+o, color); break;
|
||||
case STATION_UP:
|
||||
tft.fillTriangle(b.x+o, b.y+o, b.x+o, b.y+b.h-o, b.x+b.w-o, b.y+b.h/2, color); break;
|
||||
case STATION_DOWN:
|
||||
tft.fillTriangle(b.x+b.w-o, b.y+o, b.x+o, b.y+b.h/2, b.x+b.w-o, b.y+b.h-o, color); break;
|
||||
}
|
||||
}
|
||||
void write_stationNr(uint8_t nr){
|
||||
tft.fillRect(80, 250, 80, 60, TFT_BLACK);
|
||||
String snr = String(nr);
|
||||
if(snr.length()<2) snr = "0"+snr;
|
||||
tft.setCursor(98, 255);
|
||||
tft.setFont(Times_New_Roman66x53);
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
tft.print(snr);
|
||||
}
|
||||
void write_volume(uint8_t vol){
|
||||
tft.fillRect(320, 250, 80, 60, TFT_BLACK);
|
||||
String svol = String(vol);
|
||||
if(svol.length()<2) svol = "0"+svol;
|
||||
tft.setCursor(338, 255);
|
||||
tft.setFont(Times_New_Roman66x53);
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
tft.print(svol);
|
||||
}
|
||||
void write_stationName(String sName){
|
||||
tft.fillRect(0, 0, 480, 100, TFT_BLACK);
|
||||
tft.setFont(Times_New_Roman43x35);
|
||||
tft.setTextColor(TFT_CORNSILK);
|
||||
tft.setCursor(20, 20);
|
||||
tft.print(sName);
|
||||
}
|
||||
void write_streamTitle(String sTitle){
|
||||
tft.fillRect(0, 100, 480, 150, TFT_BLACK);
|
||||
tft.setFont(Times_New_Roman43x35);
|
||||
tft.setTextColor(TFT_LIGHTBLUE);
|
||||
tft.setCursor(20, 100);
|
||||
int l = tft.writeText((const uint8_t*) sTitle.c_str(), 100 + 150); // do not write under y=250
|
||||
if(l < sTitle.length()){
|
||||
// sTitle has been shortened, is too long for the display
|
||||
}
|
||||
}
|
||||
//**************************************************************************************************
|
||||
// S E T U P *
|
||||
//**************************************************************************************************
|
||||
void setup() {
|
||||
btn[0].x= 20; btn[0].y=250; btn[0].w=60; btn[0].h=60; btn[0].a=STATION_DOWN; btn[0].s=RELEASED;
|
||||
btn[1].x=160; btn[1].y=250; btn[1].w=60; btn[1].h=60; btn[1].a=STATION_UP; btn[1].s=RELEASED;
|
||||
btn[2].x=260; btn[2].y=250; btn[2].w=60; btn[2].h=60; btn[2].a=VOLUME_UP; btn[2].s=RELEASED;
|
||||
btn[3].x=400; btn[3].y=250; btn[3].w=60; btn[3].h=60; btn[3].a=VOLUME_DOWN; btn[3].s=RELEASED;
|
||||
max_stations= sizeof(stations)/sizeof(stations[0]); log_i("max stations %i", max_stations);
|
||||
Serial.begin(115200);
|
||||
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
pref.begin("WebRadio", false); // instance of preferences for defaults (station, volume ...)
|
||||
if(pref.getShort("volume", 1000) == 1000){ // if that: pref was never been initialized
|
||||
pref.putShort("volume", 10);
|
||||
pref.putShort("station", 0);
|
||||
}
|
||||
else{ // get the stored values
|
||||
cur_station = pref.getShort("station");
|
||||
cur_volume = pref.getShort("volume");
|
||||
}
|
||||
|
||||
WiFi.begin(ssid.c_str(), password.c_str());
|
||||
while (WiFi.status() != WL_CONNECTED){
|
||||
delay(2000);
|
||||
Serial.print(".");
|
||||
}
|
||||
log_i("Connect to %s", WiFi.SSID().c_str());
|
||||
tft.begin(TFT_CS, TFT_DC, SPI_MOSI, SPI_MISO, SPI_SCK);
|
||||
tft.setRotation(3);
|
||||
tp.setRotation(3);
|
||||
tft.setFont(Times_New_Roman43x35);
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
audio.setVolume(cur_volume); // 0...21
|
||||
audio.connecttohost(stations[cur_station].c_str());
|
||||
for(uint8_t i=0; i<(sizeof(btn)/sizeof(*btn)); i++) draw_button(btn[i]);
|
||||
write_volume(cur_volume);
|
||||
write_stationNr(cur_station);
|
||||
}
|
||||
//**************************************************************************************************
|
||||
// L O O P *
|
||||
//**************************************************************************************************
|
||||
void loop()
|
||||
{
|
||||
audio.loop();
|
||||
tp.loop();
|
||||
}
|
||||
//**************************************************************************************************
|
||||
// E V E N T S *
|
||||
//**************************************************************************************************
|
||||
void audio_info(const char *info){
|
||||
Serial.print("audio_info: "); Serial.println(info);
|
||||
}
|
||||
void audio_showstation(const char *info){
|
||||
write_stationName(String(info));
|
||||
}
|
||||
void audio_showstreamtitle(const char *info){
|
||||
String sinfo=String(info);
|
||||
sinfo.replace("|", "\n");
|
||||
write_streamTitle(sinfo);
|
||||
}
|
||||
|
||||
void tp_pressed(uint16_t x, uint16_t y){
|
||||
for(uint8_t i=0; i<(sizeof(btn)/sizeof(*btn)); i++){
|
||||
if(x>btn[i].x && (x<btn[i].x+btn[i].w)){
|
||||
if(y>btn[i].y && (y<btn[i].y+btn[i].h)){
|
||||
cur_btn=i;
|
||||
btn[cur_btn].s=PRESSED;
|
||||
draw_button(btn[cur_btn]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void tp_released(){
|
||||
if(cur_btn !=-1){
|
||||
btn[cur_btn].s=RELEASED;
|
||||
draw_button(btn[cur_btn]);
|
||||
switch(btn[cur_btn].a){
|
||||
case VOLUME_UP: if(cur_volume<max_volume){
|
||||
cur_volume++;
|
||||
write_volume(cur_volume);
|
||||
audio.setVolume(cur_volume);
|
||||
pref.putShort("volume", cur_volume);} // store the current volume in nvs
|
||||
break;
|
||||
case VOLUME_DOWN: if(cur_volume>0){
|
||||
cur_volume-- ;
|
||||
write_volume(cur_volume);
|
||||
audio.setVolume(cur_volume);
|
||||
pref.putShort("volume", cur_volume);} // store the current volume in nvs
|
||||
break;
|
||||
case STATION_UP: if(cur_station<max_stations-1){
|
||||
cur_station++;
|
||||
write_stationNr(cur_station);
|
||||
tft.fillRect(0, 0, 480, 250, TFT_BLACK);
|
||||
audio.connecttohost(stations[cur_station].c_str());
|
||||
pref.putShort("station", cur_station);} // store the current station in nvs
|
||||
break;
|
||||
case STATION_DOWN:if(cur_station>0){
|
||||
cur_station--;
|
||||
write_stationNr(cur_station);
|
||||
tft.fillRect(0, 0, 480, 250, TFT_BLACK);
|
||||
audio.connecttohost(stations[cur_station].c_str());
|
||||
pref.putShort("station", cur_station);} // store the current station in nvs
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur_btn=-1;
|
||||
}
|
||||
@ -0,0 +1,269 @@
|
||||
// this is the same example as Webradio_I2S.ino only with an IR remote control
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Preferences.h>
|
||||
#include <SPI.h>
|
||||
#include <WiFi.h>
|
||||
#include "tft.h" //see my repository at github "https://github.com/schreibfaul1/ESP32-TFT-Library-ILI9486"
|
||||
#include "Audio.h" //see my repository at github "https://github.com/schreibfaul1/ESP32-audioI2S"
|
||||
#include "IR.h" //see my repository at github "ESP32-IR-Remote-Control"
|
||||
|
||||
|
||||
#define TFT_CS 22
|
||||
#define TFT_DC 21
|
||||
#define TP_CS 16
|
||||
#define TP_IRQ 39
|
||||
#define SPI_MOSI 23
|
||||
#define SPI_MISO 19
|
||||
#define SPI_SCK 18
|
||||
#define I2S_DOUT 25
|
||||
#define I2S_BCLK 27
|
||||
#define I2S_LRC 26
|
||||
#define IR_PIN 34
|
||||
|
||||
Preferences pref;
|
||||
TFT tft; // @suppress("Abstract class cannot be instantiated")
|
||||
TP tp(TP_CS, TP_IRQ);
|
||||
Audio audio;
|
||||
IR ir(IR_PIN); // do not change the objectname, it must be "ir"
|
||||
|
||||
String ssid = "*********";
|
||||
String password = "*********";
|
||||
|
||||
String stations[] ={
|
||||
"0n-80s.radionetz.de:8000/0n-70s.mp3",
|
||||
"mediaserv30.live-streams.nl:8000/stream",
|
||||
"www.surfmusic.de/m3u/100-5-das-hitradio,4529.m3u",
|
||||
"stream.1a-webradio.de/deutsch/mp3-128/vtuner-1a",
|
||||
"mp3.ffh.de/radioffh/hqlivestream.aac", // 128k aac
|
||||
"www.antenne.de/webradio/antenne.m3u",
|
||||
"listen.rusongs.ru/ru-mp3-128",
|
||||
"edge.audio.3qsdn.com/senderkw-mp3",
|
||||
"macslons-irish-pub-radio.com/media.asx",
|
||||
};
|
||||
|
||||
//some global variables
|
||||
|
||||
uint8_t max_volume = 21;
|
||||
uint8_t max_stations = 0; //will be set later
|
||||
uint8_t cur_station = 0; //current station(nr), will be set later
|
||||
uint8_t cur_volume = 0; //will be set from stored preferences
|
||||
int8_t cur_btn =-1; //current button (, -1 means idle)
|
||||
|
||||
enum action{VOLUME_UP=0, VOLUME_DOWN=1, STATION_UP=2, STATION_DOWN=3};
|
||||
enum staus {RELEASED=0, PRESSED=1};
|
||||
|
||||
struct _btns{
|
||||
uint16_t x; //PosX
|
||||
uint16_t y; //PosY
|
||||
uint16_t w; //Width
|
||||
uint16_t h; //Hight
|
||||
uint8_t a; //Action
|
||||
uint8_t s; //Status
|
||||
};
|
||||
typedef _btns btns;
|
||||
|
||||
btns btn[4];
|
||||
|
||||
//**************************************************************************************************
|
||||
// G U I *
|
||||
//**************************************************************************************************
|
||||
void draw_button(btns b){
|
||||
uint16_t color=TFT_BLACK;
|
||||
uint8_t r=4, o=r*3;
|
||||
if(b.s==RELEASED) color=TFT_GOLD;
|
||||
if(b.s==PRESSED) color=TFT_DEEPSKYBLUE;
|
||||
tft.drawRoundRect(b.x, b.y, b.w, b.h, r, color);
|
||||
switch(b.a){
|
||||
case VOLUME_UP:
|
||||
tft.fillTriangle(b.x+b.w/2, b.y+o, b.x+o, b.y+b.h-o, b.x+b.w-o, b.y+b.h-o, color); break;
|
||||
case VOLUME_DOWN:
|
||||
tft.fillTriangle(b.x+o, b.y+o, b.x+b.w/2, b.y+b.h-o, b.x+b.w-o, b.y+o, color); break;
|
||||
case STATION_UP:
|
||||
tft.fillTriangle(b.x+o, b.y+o, b.x+o, b.y+b.h-o, b.x+b.w-o, b.y+b.h/2, color); break;
|
||||
case STATION_DOWN:
|
||||
tft.fillTriangle(b.x+b.w-o, b.y+o, b.x+o, b.y+b.h/2, b.x+b.w-o, b.y+b.h-o, color); break;
|
||||
}
|
||||
}
|
||||
void write_stationNr(uint8_t nr){
|
||||
tft.fillRect(80, 250, 80, 60, TFT_BLACK);
|
||||
String snr = String(nr);
|
||||
if(snr.length()<2) snr = "0"+snr;
|
||||
tft.setCursor(98, 255);
|
||||
tft.setFont(Times_New_Roman66x53);
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
tft.print(snr);
|
||||
}
|
||||
void write_volume(uint8_t vol){
|
||||
tft.fillRect(320, 250, 80, 60, TFT_BLACK);
|
||||
String svol = String(vol);
|
||||
if(svol.length()<2) svol = "0"+svol;
|
||||
tft.setCursor(338, 255);
|
||||
tft.setFont(Times_New_Roman66x53);
|
||||
tft.setTextColor(TFT_YELLOW);
|
||||
tft.print(svol);
|
||||
}
|
||||
void write_stationName(String sName){
|
||||
tft.fillRect(0, 0, 480, 100, TFT_BLACK);
|
||||
tft.setFont(Times_New_Roman43x35);
|
||||
tft.setTextColor(TFT_CORNSILK);
|
||||
tft.setCursor(20, 20);
|
||||
tft.print(sName);
|
||||
}
|
||||
void write_streamTitle(String sTitle){
|
||||
tft.fillRect(0, 100, 480, 150, TFT_BLACK);
|
||||
tft.setFont(Times_New_Roman43x35);
|
||||
tft.setTextColor(TFT_LIGHTBLUE);
|
||||
tft.setCursor(20, 100);
|
||||
tft.print(sTitle);
|
||||
}
|
||||
void volume_up(){
|
||||
if(cur_volume < max_volume){
|
||||
cur_volume++;
|
||||
write_volume(cur_volume);
|
||||
audio.setVolume(cur_volume);
|
||||
pref.putShort("volume", cur_volume);} // store the current volume in nvs
|
||||
}
|
||||
void volume_down(){
|
||||
if(cur_volume>0){
|
||||
cur_volume-- ;
|
||||
write_volume(cur_volume);
|
||||
audio.setVolume(cur_volume);
|
||||
pref.putShort("volume", cur_volume);} // store the current volume in nvs
|
||||
}
|
||||
void station_up(){
|
||||
if(cur_station < max_stations-1){
|
||||
cur_station++;
|
||||
write_stationNr(cur_station);
|
||||
tft.fillRect(0, 0, 480, 250, TFT_BLACK);
|
||||
audio.connecttohost(stations[cur_station].c_str());
|
||||
pref.putShort("station", cur_station);} // store the current station in nvs
|
||||
}
|
||||
void station_down(){
|
||||
if(cur_station > 0){
|
||||
cur_station--;
|
||||
write_stationNr(cur_station);
|
||||
tft.fillRect(0, 0, 480, 250, TFT_BLACK);
|
||||
audio.connecttohost(stations[cur_station].c_str());
|
||||
pref.putShort("station", cur_station);} // store the current station in nvs
|
||||
}
|
||||
|
||||
|
||||
//**************************************************************************************************
|
||||
// S E T U P *
|
||||
//**************************************************************************************************
|
||||
void setup() {
|
||||
btn[0].x= 20; btn[0].y=250; btn[0].w=60; btn[0].h=60; btn[0].a=STATION_DOWN; btn[0].s=RELEASED;
|
||||
btn[1].x=160; btn[1].y=250; btn[1].w=60; btn[1].h=60; btn[1].a=STATION_UP; btn[1].s=RELEASED;
|
||||
btn[2].x=260; btn[2].y=250; btn[2].w=60; btn[2].h=60; btn[2].a=VOLUME_UP; btn[2].s=RELEASED;
|
||||
btn[3].x=400; btn[3].y=250; btn[3].w=60; btn[3].h=60; btn[3].a=VOLUME_DOWN; btn[3].s=RELEASED;
|
||||
max_stations= sizeof(stations)/sizeof(stations[0]); log_i("max stations %i", max_stations);
|
||||
Serial.begin(115200);
|
||||
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
pref.begin("WebRadio", false); // instance of preferences for defaults (station, volume ...)
|
||||
if(pref.getShort("volume", 1000) == 1000){ // if that: pref was never been initialized
|
||||
pref.putShort("volume", 10);
|
||||
pref.putShort("station", 0);
|
||||
}
|
||||
else{ // get the stored values
|
||||
cur_station = pref.getShort("station");
|
||||
cur_volume = pref.getShort("volume");
|
||||
}
|
||||
WiFi.disconnect();
|
||||
WiFi.begin(ssid.c_str(), password.c_str());
|
||||
while (WiFi.status() != WL_CONNECTED) {delay(1500); Serial.print(".");}
|
||||
log_i("Connected to %s", WiFi.SSID().c_str());
|
||||
tft.begin(TFT_CS, TFT_DC, SPI_MOSI, SPI_MISO, SPI_SCK);
|
||||
tft.setFrequency(20000000);
|
||||
tft.setRotation(3);
|
||||
tp.setRotation(3);
|
||||
tft.setFont(Times_New_Roman43x35);
|
||||
tft.fillScreen(TFT_BLACK);
|
||||
ir.begin(); // Init InfraredDecoder
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
audio.setVolume(cur_volume); // 0...21
|
||||
audio.connecttohost(stations[cur_station].c_str());
|
||||
for(uint8_t i=0; i<(sizeof(btn)/sizeof(*btn)); i++) draw_button(btn[i]);
|
||||
write_volume(cur_volume);
|
||||
write_stationNr(cur_station);
|
||||
}
|
||||
//**************************************************************************************************
|
||||
// L O O P *
|
||||
//**************************************************************************************************
|
||||
void loop()
|
||||
{
|
||||
audio.loop();
|
||||
tp.loop();
|
||||
ir.loop();
|
||||
}
|
||||
//**************************************************************************************************
|
||||
// E V E N T S *
|
||||
//**************************************************************************************************
|
||||
void audio_info(const char *info){
|
||||
Serial.print("audio_info: "); Serial.println(info);
|
||||
}
|
||||
void audio_showstation(const char *info){
|
||||
write_stationName(String(info));
|
||||
}
|
||||
void audio_showstreamtitle(const char *info){
|
||||
String sinfo=String(info);
|
||||
sinfo.replace("|", "\n");
|
||||
write_streamTitle(sinfo);
|
||||
}
|
||||
|
||||
void tp_pressed(uint16_t x, uint16_t y){
|
||||
for(uint8_t i=0; i<(sizeof(btn)/sizeof(*btn)); i++){
|
||||
if(x>btn[i].x && (x<btn[i].x+btn[i].w)){
|
||||
if(y>btn[i].y && (y<btn[i].y+btn[i].h)){
|
||||
cur_btn=i;
|
||||
btn[cur_btn].s=PRESSED;
|
||||
draw_button(btn[cur_btn]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void tp_released(){
|
||||
if(cur_btn !=-1){
|
||||
btn[cur_btn].s=RELEASED;
|
||||
draw_button(btn[cur_btn]);
|
||||
switch(btn[cur_btn].a){
|
||||
case VOLUME_UP: volume_up(); break;
|
||||
case VOLUME_DOWN: volume_down(); break;
|
||||
case STATION_UP: station_up(); break;
|
||||
case STATION_DOWN: station_down(); break;
|
||||
}
|
||||
}
|
||||
cur_btn=-1;
|
||||
}
|
||||
// Events from IR Library
|
||||
void ir_res(uint32_t res){
|
||||
if(res < max_stations){
|
||||
cur_station = res;
|
||||
write_stationNr(cur_station);
|
||||
tft.fillRect(0, 0, 480, 250, TFT_BLACK);
|
||||
audio.connecttohost(stations[cur_station].c_str());
|
||||
pref.putShort("station", cur_station);} // store the current station in nvs
|
||||
else{
|
||||
tft.fillRect(0, 0, 480, 250, TFT_BLACK);
|
||||
audio.connecttohost(stations[cur_station].c_str());
|
||||
}
|
||||
}
|
||||
void ir_number(const char* num){
|
||||
tft.fillRect(0, 0, 480, 250, TFT_BLACK);
|
||||
tft.setTextSize(7);
|
||||
tft.setTextColor(TFT_CORNSILK);
|
||||
tft.setCursor(50, 70);
|
||||
tft.print(num);
|
||||
}
|
||||
void ir_key(const char* key){
|
||||
switch(key[0]){
|
||||
case 'k': break; // OK
|
||||
case 'r': volume_up(); break; // right
|
||||
case 'l': volume_down(); break; // left
|
||||
case 'u': station_up(); break; // up
|
||||
case 'd': station_down(); break; // down
|
||||
case '#': break; // #
|
||||
case '*': break; // *
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
// Copied from https://github.com/LilyGO/TTGO-TAudio/issues/12
|
||||
|
||||
|
||||
// Required Libraries (Download zips and add to the Arduino IDE library).
|
||||
#include "Arduino.h"
|
||||
#include <WM8978.h> // https://github.com/CelliesProjects/wm8978-esp32
|
||||
#include <Audio.h> // https://github.com/schreibfaul1/ESP32-audioI2S
|
||||
|
||||
// T-Audio 1.6 WM8978 I2C pins.
|
||||
#define I2C_SDA 19
|
||||
#define I2C_SCL 18
|
||||
|
||||
// T-Audio 1.6 WM8978 I2S pins.
|
||||
#define I2S_BCK 33
|
||||
#define I2S_WS 25
|
||||
#define I2S_DOUT 26
|
||||
|
||||
// T-Audio 1.6 WM8978 MCLK gpio number
|
||||
#define I2S_MCLKPIN 0
|
||||
|
||||
Audio audio;
|
||||
WM8978 dac;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Setup wm8978 I2C interface.
|
||||
if (!dac.begin(I2C_SDA, I2C_SCL)) {
|
||||
ESP_LOGE(TAG, "Error setting up dac: System halted.");
|
||||
while (1) delay(100);
|
||||
}
|
||||
|
||||
// Select I2S pins
|
||||
audio.setPinout(I2S_BCK, I2S_WS, I2S_DOUT);
|
||||
audio.i2s_mclk_pin_select(I2S_MCLKPIN);
|
||||
|
||||
// WiFi Settings here.
|
||||
WiFi.begin("EnterSSIDHere", "EnterPasswordHere");
|
||||
while (!WiFi.isConnected()) {
|
||||
delay(10);
|
||||
}
|
||||
ESP_LOGI(TAG, "Connected. Starting MP3...");
|
||||
// Enter your Icecast station URL here.
|
||||
audio.setVolume(21);
|
||||
audio.connecttohost("http://hestia2.cdnstream.com/1458_128");
|
||||
// Volume control.
|
||||
dac.setSPKvol(63); // Change volume here for board speaker output (Max 63).
|
||||
dac.setHPvol(63, 63); // Change volume here for headphone jack left, right channel.
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Start the stream.
|
||||
audio.loop();
|
||||
}
|
||||
|
||||
// optional
|
||||
void audio_info(const char *info){
|
||||
Serial.print("info "); Serial.println(info);
|
||||
}
|
||||
void audio_id3data(const char *info){ //id3 metadata
|
||||
Serial.print("id3data ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_mp3(const char *info){ //end of file
|
||||
Serial.print("eof_mp3 ");Serial.println(info);
|
||||
}
|
||||
void audio_showstation(const char *info){
|
||||
Serial.print("station ");Serial.println(info);
|
||||
}
|
||||
void audio_showstreamtitle(const char *info){
|
||||
Serial.print("streamtitle ");Serial.println(info);
|
||||
}
|
||||
void audio_bitrate(const char *info){
|
||||
Serial.print("bitrate ");Serial.println(info);
|
||||
}
|
||||
void audio_commercial(const char *info){ //duration in sec
|
||||
Serial.print("commercial ");Serial.println(info);
|
||||
}
|
||||
void audio_icyurl(const char *info){ //homepage
|
||||
Serial.print("icyurl ");Serial.println(info);
|
||||
}
|
||||
void audio_lasthost(const char *info){ //stream URL played
|
||||
Serial.print("lasthost ");Serial.println(info);
|
||||
}
|
||||
void audio_eof_speech(const char *info){
|
||||
Serial.print("eof_speech ");Serial.println(info);
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
#include "Arduino.h"
|
||||
#include "Audio.h"
|
||||
#include "SD.h"
|
||||
#include "SPI.h"
|
||||
#include "FS.h"
|
||||
#include "Ticker.h"
|
||||
|
||||
// Digital I/O used
|
||||
#define SD_CS 5
|
||||
#define SPI_MOSI 23
|
||||
#define SPI_MISO 19
|
||||
#define SPI_SCK 18
|
||||
#define I2S_DOUT 25
|
||||
#define I2S_BCLK 27
|
||||
#define I2S_LRC 26
|
||||
|
||||
Audio audio;
|
||||
Ticker ticker;
|
||||
struct tm timeinfo;
|
||||
time_t now;
|
||||
|
||||
uint8_t hour = 6;
|
||||
uint8_t minute = 59;
|
||||
uint8_t sec = 45;
|
||||
|
||||
bool f_time = false;
|
||||
int8_t timefile = -1;
|
||||
char chbuf[100];
|
||||
|
||||
void tckr1s(){
|
||||
sec++;
|
||||
if(sec > 59) {sec = 0; minute++;}
|
||||
if(minute > 59){minute = 0; hour++;}
|
||||
if(hour > 23) {hour = 0;}
|
||||
if(minute == 59 && sec == 50) f_time = true; // flag will be set 10s before full hour
|
||||
Serial.printf("%02d:%02d:%02d\n", hour, minute, sec);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
|
||||
SD.begin(SD_CS);
|
||||
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
|
||||
audio.setVolume(10); // 0...21
|
||||
ticker.attach(1, tckr1s);
|
||||
}
|
||||
|
||||
void loop(){
|
||||
audio.loop();
|
||||
if(f_time == true){
|
||||
f_time = false;
|
||||
timefile = 3;
|
||||
uint8_t next_hour = hour + 1;
|
||||
if(next_hour == 25) next_hour = 1;
|
||||
sprintf(chbuf, "/voice_time/%03d.mp3", next_hour);
|
||||
audio.connecttoFS(SD, chbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void audio_eof_mp3(const char *info){ //end of file
|
||||
//Serial.printf("file :%s\n", info);
|
||||
if(timefile>0){
|
||||
if(timefile==1){audio.connecttoFS(SD, "/voice_time/080.mp3"); timefile--;} // stroke
|
||||
if(timefile==2){audio.connecttoFS(SD, "/voice_time/200.mp3"); timefile--;} // precisely
|
||||
if(timefile==3){audio.connecttoFS(SD, "/voice_time/O'clock.mp3"); timefile--;}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user