diff --git a/audioooo/.gitignore b/audioooo/.gitignore new file mode 100644 index 0000000..03f4a3c --- /dev/null +++ b/audioooo/.gitignore @@ -0,0 +1 @@ +.pio diff --git a/audioooo/include/README b/audioooo/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/audioooo/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/audioooo/lib/ESP32-audioI2S b/audioooo/lib/ESP32-audioI2S new file mode 160000 index 0000000..e5e7497 --- /dev/null +++ b/audioooo/lib/ESP32-audioI2S @@ -0,0 +1 @@ +Subproject commit e5e7497cc468cb1814e490a721c6d32384561b88 diff --git a/audioooo/lib/README b/audioooo/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/audioooo/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/audioooo/platformio.ini b/audioooo/platformio.ini new file mode 100644 index 0000000..0d75a1c --- /dev/null +++ b/audioooo/platformio.ini @@ -0,0 +1,17 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +lib_deps = + adafruit/Adafruit SSD1306@^2.4.5 + adafruit/Adafruit BusIO@^1.7.3 diff --git a/audioooo/src/main.ino b/audioooo/src/main.ino new file mode 100644 index 0000000..0183fba --- /dev/null +++ b/audioooo/src/main.ino @@ -0,0 +1,434 @@ +#include "Arduino.h" +//#include "WiFiMulti.h" +#include "Audio.h" +#include "SPI.h" +#include "SD.h" +#include "FS.h" +#include +#include + +//SD Card +#define SD_CS 22 +#define SPI_MOSI 23 +#define SPI_MISO 19 +#define SPI_SCK 18 + +//Digital I/O used //Makerfabs Audio V2.0 +#define I2S_DOUT 27 +#define I2S_BCLK 26 +#define I2S_LRC 25 + +//SSD1306 +#define MAKEPYTHON_ESP32_SDA 4 +#define MAKEPYTHON_ESP32_SCL 5 +#define SCREEN_WIDTH 128 // OLED display width, in pixels +#define SCREEN_HEIGHT 64 // OLED display height, in pixels +#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) + +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); + +//Button +const int Pin_vol_up = 39; +const int Pin_vol_down = 36; +const int Pin_mute = 35; + +const int Pin_previous = 15; +const int Pin_pause = 33; +const int Pin_next = 2; + +Audio audio; + +/* + WiFiMulti wifiMulti; + String ssid = "Makerfabs"; + String password = "20160704"; + */ + +struct Music_info +{ + String name; + int length; + int runtime; + int volume; + int status; + int mute_volume; +} music_info = {"", 0, 0, 0, 0, 0}; + +String file_list[20]; +int file_num = 0; +int file_index = 0; + +int get_music_list(fs::FS &fs, const char *dirname, uint8_t levels, String wavlist[30]); + +void setup() +{ + //IO mode init + pinMode(Pin_vol_up, INPUT_PULLUP); + pinMode(Pin_vol_down, INPUT_PULLUP); + pinMode(Pin_mute, INPUT_PULLUP); + pinMode(Pin_previous, INPUT_PULLUP); + pinMode(Pin_pause, INPUT_PULLUP); + pinMode(Pin_next, INPUT_PULLUP); + + //Serial + Serial.begin(115200); + + //LCD + Wire.begin(MAKEPYTHON_ESP32_SDA, MAKEPYTHON_ESP32_SCL); + // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally + if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) + { // Address 0x3C for 128x32 + Serial.println(F("SSD1306 allocation failed")); + for (;;) + ; // Don't proceed, loop forever + } + display.clearDisplay(); + logoshow(); + + //SD(SPI) + pinMode(SD_CS, OUTPUT); + digitalWrite(SD_CS, HIGH); + SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI); + SPI.setFrequency(1000000); + if (!SD.begin(SD_CS, SPI)) + { + Serial.println("Card Mount Failed"); + lcd_text("SD ERR"); + while (1) + ; + } + else + { + lcd_text("SD OK"); + } + + //Read SD + file_num = get_music_list(SD, "/", 0, file_list); + Serial.print("Music file count:"); + Serial.println(file_num); + Serial.println("All music:"); + for (int i = 0; i < file_num; i++) + { + Serial.println(file_list[i]); + } + + //WiFi + /* + 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(I2S) + audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT); + audio.setVolume(21); // 0...21 + + //audio.connecttoFS(SD, "/MoonlightBay.mp3"); //ChildhoodMemory.mp3 //MoonRiver.mp3 //320k_test.mp3 + //file_list[0] = "MoonlightBay.mp3"; + open_new_song(file_list[file_index]); + print_song_time(); +} + +uint run_time = 0; +uint button_time = 0; + +void loop() +{ + audio.loop(); + if (millis() - run_time > 1000) + { + run_time = millis(); + print_song_time(); + display_music(); + } + + if (millis() - button_time > 300) + { + //Button logic + if (digitalRead(Pin_next) == 0) + { + Serial.println("Pin_next"); + if (file_index < file_num - 1) + file_index++; + else + file_index = 0; + open_new_song(file_list[file_index]); + print_song_time(); + button_time = millis(); + } + if (digitalRead(Pin_previous) == 0) + { + Serial.println("Pin_previous"); + if (file_index > 0) + file_index--; + else + file_index = file_num - 1; + open_new_song(file_list[file_index]); + print_song_time(); + button_time = millis(); + } + if (digitalRead(Pin_vol_up) == 0) + { + Serial.println("Pin_vol_up"); + if (music_info.volume < 21) + music_info.volume++; + audio.setVolume(music_info.volume); + button_time = millis(); + } + if (digitalRead(Pin_vol_down) == 0) + { + Serial.println("Pin_vol_down"); + if (music_info.volume > 0) + music_info.volume--; + audio.setVolume(music_info.volume); + button_time = millis(); + } + if (digitalRead(Pin_mute) == 0) + { + Serial.println("Pin_mute"); + if (music_info.volume != 0) + { + music_info.mute_volume = music_info.volume; + music_info.volume = 0; + } + else + { + music_info.volume = music_info.mute_volume; + } + audio.setVolume(music_info.volume); + button_time = millis(); + } + if (digitalRead(Pin_pause) == 0) + { + Serial.println("Pin_pause"); + audio.pauseResume(); + button_time = millis(); + } + } + + //串口控制切歌,音量 + if (Serial.available()) + { + String r = Serial.readString(); + r.trim(); + if (r.length() > 5) + { + audio.stopSong(); + open_new_song(file_list[0]); + print_song_info(); + } + else + { + audio.setVolume(r.toInt()); + } + } +} + +void open_new_song(String filename) +{ + //去掉文件名的根目录"/"和文件后缀".mp3",".wav" + music_info.name = filename.substring(1, filename.indexOf(".")); + audio.connecttoFS(SD, filename.c_str()); + music_info.runtime = audio.getAudioCurrentTime(); + music_info.length = audio.getAudioFileDuration(); + music_info.volume = audio.getVolume(); + music_info.status = 1; + Serial.println("**********start a new sound************"); +} + +void display_music() +{ + int line_step = 24; + int line = 0; + char buff[20]; + ; + sprintf(buff, "%d:%d", music_info.runtime, music_info.length); + + display.clearDisplay(); + + display.setTextSize(2); // Normal 1:1 pixel scale + display.setTextColor(SSD1306_WHITE); // Draw white text + + display.setCursor(0, line); // Start at top-left corner + display.println(music_info.name); + line += line_step; + + display.setCursor(0, line); + display.println(buff); + line += line_step; + + sprintf(buff, "V:%d",music_info.volume); + + display.setCursor(0, line); + display.println(buff); + line += line_step; + + display.setCursor(0, line); + display.println(music_info.status); + line += line_step; + + display.display(); +} + +void logoshow(void) +{ + display.clearDisplay(); + + display.setTextSize(2); // Normal 1:1 pixel scale + display.setTextColor(SSD1306_WHITE); // Draw white text + display.setCursor(0, 0); // Start at top-left corner + display.println(F("MakePython")); + display.setCursor(0, 20); // Start at top-left corner + display.println(F("MUSIC")); + display.setCursor(0, 40); // Start at top-left corner + display.println(F("PLAYER V2")); + display.display(); + delay(2000); +} + +void lcd_text(String text) +{ + display.clearDisplay(); + + display.setTextSize(2); // Normal 1:1 pixel scale + display.setTextColor(SSD1306_WHITE); // Draw white text + display.setCursor(0, 0); // Start at top-left corner + display.println(text); + display.display(); + delay(500); +} + +void print_song_info() +{ + Serial.println("***********************************"); + Serial.println(audio.getFileSize()); + Serial.println(audio.getFilePos()); + Serial.println(audio.getSampleRate()); + Serial.println(audio.getBitsPerSample()); + Serial.println(audio.getChannels()); + Serial.println(audio.getVolume()); + Serial.println("***********************************"); +} + +//刷新歌曲时间 +void print_song_time() +{ + //Serial.println(audio.getAudioCurrentTime()); + //Serial.println(audio.getAudioFileDuration()); + music_info.runtime = audio.getAudioCurrentTime(); + music_info.length = audio.getAudioFileDuration(); + music_info.volume = audio.getVolume(); +} + +int get_music_list(fs::FS &fs, const char *dirname, uint8_t levels, String wavlist[30]) +{ + Serial.printf("Listing directory: %s\n", dirname); + int i = 0; + + File root = fs.open(dirname); + if (!root) + { + Serial.println("Failed to open directory"); + return i; + } + if (!root.isDirectory()) + { + Serial.println("Not a directory"); + return i; + } + + File file = root.openNextFile(); + while (file) + { + if (file.isDirectory()) + { + } + else + { + String temp = file.name(); + if (temp.endsWith(".wav")) + { + wavlist[i] = temp; + i++; + } + else if (temp.endsWith(".mp3")) + { + wavlist[i] = temp; + i++; + } + } + file = root.openNextFile(); + } + return i; +} + +//********************************************** +// 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); + file_index++; + if (file_index >= file_num) + { + file_index = 0; + } + open_new_song(file_list[file_index]); +} +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); +} diff --git a/audioooo/test/README b/audioooo/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/audioooo/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html