├── examples ├── record_ogg │ ├── v44k1q05.img │ └── record_ogg.ino ├── player_gpiotest │ └── player_gpiotest.ino ├── feather_midi │ └── feather_midi.ino ├── player_miditest │ └── player_miditest.ino ├── player_interrupts │ └── player_interrupts.ino ├── player_simple │ └── player_simple.ino └── feather_player │ └── feather_player.ino ├── library.properties ├── README.md ├── .github ├── workflows │ └── githubci.yml ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── Adafruit_VS1053.h └── Adafruit_VS1053.cpp /examples/record_ogg/v44k1q05.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_VS1053_Library/HEAD/examples/record_ogg/v44k1q05.img -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Adafruit VS1053 Library 2 | version=1.4.4 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=This is a library for the Adafruit VS1053 Codec Breakout and Music Maker Shields 6 | paragraph=This is a library for the Adafruit VS1053 Codec Breakout and Music Maker Shields 7 | category=Device Control 8 | url=https://github.com/adafruit/Adafruit_VS1053_Library 9 | architectures=* 10 | depends=SD, Adafruit BusIO 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adafruit VS1053 Breakout [![Build Status](https://github.com/adafruit/Adafruit_VS1053_Library/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_VS1053_Library/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_VS1053_Library/html/index.html) 2 | 3 | This is a library for the Adafruit VS1053 Codec Breakout 4 | 5 | Designed specifically to work with the Adafruit VS1053 Codec Breakout 6 | ----> https://www.adafruit.com/products/1381 7 | 8 | Adafruit invests time and resources providing this open source code, 9 | please support Adafruit and open-source hardware by purchasing 10 | products from Adafruit! 11 | 12 | Written by Limor Fried/Ladyada for Adafruit Industries. 13 | BSD license, all text above must be included in any redistribution 14 | -------------------------------------------------------------------------------- /.github/workflows/githubci.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Library CI 2 | 3 | on: [pull_request, push, repository_dispatch] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/setup-python@v4 11 | with: 12 | python-version: '3.x' 13 | - uses: actions/checkout@v3 14 | - uses: actions/checkout@v3 15 | with: 16 | repository: adafruit/ci-arduino 17 | path: ci 18 | 19 | - name: pre-install 20 | run: bash ci/actions_install.sh 21 | 22 | - name: test platforms 23 | run: python3 ci/build_platform.py main_platforms 24 | 25 | - name: clang 26 | run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . 27 | 28 | - name: doxygen 29 | env: 30 | GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} 31 | PRETTYNAME : "Adafruit VS1053 Arduino Library" 32 | run: bash ci/doxy_gen_and_deploy.sh 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Arduino library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Arduino projects check these very common issues to ensure they don't apply**: 17 | 18 | - For uploading sketches or communicating with the board make sure you're using 19 | a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes 20 | very hard to tell the difference between a data and charge cable! Try using the 21 | cable with other devices or swapping to another cable to confirm it is not 22 | the problem. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and plug in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | - **Ensure you are using an official Arduino or Adafruit board.** We can't 33 | guarantee a clone board will have the same functionality and work as expected 34 | with this code and don't support them. 35 | 36 | If you're sure this issue is a defect in the code and checked the steps above 37 | please fill in the following fields to provide enough troubleshooting information. 38 | You may delete the guideline and text above to just leave the following details: 39 | 40 | - Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** 41 | 42 | - Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO 43 | VERSION HERE** 44 | 45 | - List the steps to reproduce the problem below (if possible attach a sketch or 46 | copy the sketch code in too): **LIST REPRO STEPS BELOW** 47 | -------------------------------------------------------------------------------- /examples/player_gpiotest/player_gpiotest.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for the Adafruit VS1053 Codec Breakout 3 | 4 | Designed specifically to work with the Adafruit VS1053 Codec Breakout 5 | ----> https://www.adafruit.com/products/1381 6 | 7 | Adafruit invests time and resources providing this open source code, 8 | please support Adafruit and open-source hardware by purchasing 9 | products from Adafruit! 10 | 11 | Written by Limor Fried/Ladyada for Adafruit Industries. 12 | BSD license, all text above must be included in any redistribution 13 | ****************************************************/ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | // These are the pins used for the breakout example 20 | #define BREAKOUT_RESET 9 // VS1053 reset pin (output) 21 | #define BREAKOUT_CS 10 // VS1053 chip select pin (output) 22 | #define BREAKOUT_DCS 8 // VS1053 Data/command select pin (output) 23 | // These are the pins used for the music maker shield 24 | #define SHIELD_RESET -1 // VS1053 reset pin (unused!) 25 | #define SHIELD_CS 7 // VS1053 chip select pin (output) 26 | #define SHIELD_DCS 6 // VS1053 Data/command select pin (output) 27 | 28 | // These are common pins between breakout and shield 29 | #define CARDCS 4 // Card chip select pin 30 | // DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt 31 | #define DREQ 3 // VS1053 Data request, ideally an Interrupt pin 32 | 33 | Adafruit_VS1053_FilePlayer musicPlayer = 34 | // create breakout-example object! 35 | Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS); 36 | // create shield-example object! 37 | //Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS); 38 | 39 | void setup() { 40 | Serial.begin(9600); 41 | Serial.println("VS1053 GPIO test"); 42 | 43 | // disable the card (we won't be using it) 44 | pinMode(CARDCS, OUTPUT); 45 | digitalWrite(CARDCS, HIGH); 46 | 47 | // initialise the music player 48 | if (!musicPlayer.begin()) { 49 | Serial.println("VS1053 not found"); 50 | while (1); // don't do anything more 51 | } 52 | 53 | musicPlayer.sineTest(0x44, 500); // Make a tone to indicate VS1053 is working 54 | } 55 | 56 | void loop() { 57 | for (uint8_t i=0; i<8; i++) { 58 | musicPlayer.GPIO_pinMode(i, OUTPUT); 59 | 60 | musicPlayer.GPIO_digitalWrite(i, HIGH); 61 | Serial.print("GPIO: "); Serial.println(musicPlayer.GPIO_digitalRead(i)); 62 | musicPlayer.GPIO_digitalWrite(i, LOW); 63 | Serial.print("GPIO: "); Serial.println(musicPlayer.GPIO_digitalRead(i)); 64 | 65 | musicPlayer.GPIO_pinMode(i, INPUT); 66 | 67 | delay(100); 68 | } 69 | } -------------------------------------------------------------------------------- /examples/feather_midi/feather_midi.ino: -------------------------------------------------------------------------------- 1 | 2 | // Solder closed jumper on bottom! 3 | 4 | // See http://www.vlsi.fi/fileadmin/datasheets/vs1053.pdf Pg 31 5 | #define VS1053_BANK_DEFAULT 0x00 6 | #define VS1053_BANK_DRUMS1 0x78 7 | #define VS1053_BANK_DRUMS2 0x7F 8 | #define VS1053_BANK_MELODY 0x79 9 | 10 | // See http://www.vlsi.fi/fileadmin/datasheets/vs1053.pdf Pg 32 for more! 11 | #define VS1053_GM1_OCARINA 80 12 | 13 | #define MIDI_NOTE_ON 0x90 14 | #define MIDI_NOTE_OFF 0x80 15 | #define MIDI_CHAN_MSG 0xB0 16 | #define MIDI_CHAN_BANK 0x00 17 | #define MIDI_CHAN_VOLUME 0x07 18 | #define MIDI_CHAN_PROGRAM 0xC0 19 | 20 | 21 | #if defined(ESP8266) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) 22 | #define VS1053_MIDI Serial 23 | #else 24 | // anything else? use the hardware serial1 port 25 | #define VS1053_MIDI Serial1 26 | #endif 27 | 28 | void setup() { 29 | delay(1000); 30 | 31 | Serial.begin(115200); 32 | 33 | Serial.println("VS1053 MIDI test"); 34 | 35 | VS1053_MIDI.begin(31250); // MIDI uses a 'strange baud rate' 36 | 37 | midiSetChannelBank(0, VS1053_BANK_MELODY); 38 | 39 | midiSetChannelVolume(0, 127); 40 | 41 | midiSetInstrument(0, VS1053_GM1_OCARINA); 42 | } 43 | 44 | void loop() { 45 | for (uint8_t i=60; i<69; i++) { 46 | midiNoteOn(0, i, 127); 47 | delay(100); 48 | midiNoteOff(0, i, 127); 49 | } 50 | 51 | delay(1000); 52 | } 53 | 54 | void midiSetInstrument(uint8_t chan, uint8_t inst) { 55 | if (chan > 15) return; 56 | inst --; // page 32 has instruments starting with 1 not 0 :( 57 | if (inst > 127) return; 58 | 59 | VS1053_MIDI.write(MIDI_CHAN_PROGRAM | chan); 60 | delay(10); 61 | VS1053_MIDI.write(inst); 62 | delay(10); 63 | } 64 | 65 | 66 | void midiSetChannelVolume(uint8_t chan, uint8_t vol) { 67 | if (chan > 15) return; 68 | if (vol > 127) return; 69 | 70 | VS1053_MIDI.write(MIDI_CHAN_MSG | chan); 71 | VS1053_MIDI.write(MIDI_CHAN_VOLUME); 72 | VS1053_MIDI.write(vol); 73 | } 74 | 75 | void midiSetChannelBank(uint8_t chan, uint8_t bank) { 76 | if (chan > 15) return; 77 | if (bank > 127) return; 78 | 79 | VS1053_MIDI.write(MIDI_CHAN_MSG | chan); 80 | VS1053_MIDI.write((uint8_t)MIDI_CHAN_BANK); 81 | VS1053_MIDI.write(bank); 82 | } 83 | 84 | void midiNoteOn(uint8_t chan, uint8_t n, uint8_t vel) { 85 | if (chan > 15) return; 86 | if (n > 127) return; 87 | if (vel > 127) return; 88 | 89 | VS1053_MIDI.write(MIDI_NOTE_ON | chan); 90 | VS1053_MIDI.write(n); 91 | VS1053_MIDI.write(vel); 92 | } 93 | 94 | void midiNoteOff(uint8_t chan, uint8_t n, uint8_t vel) { 95 | if (chan > 15) return; 96 | if (n > 127) return; 97 | if (vel > 127) return; 98 | 99 | VS1053_MIDI.write(MIDI_NOTE_OFF | chan); 100 | VS1053_MIDI.write(n); 101 | VS1053_MIDI.write(vel); 102 | } -------------------------------------------------------------------------------- /examples/player_miditest/player_miditest.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for the Adafruit VS1053 Codec Breakout 3 | 4 | Designed specifically to work with the Adafruit VS1053 Codec Breakout 5 | ----> https://www.adafruit.com/products/1381 6 | 7 | Adafruit invests time and resources providing this open source code, 8 | please support Adafruit and open-source hardware by purchasing 9 | products from Adafruit! 10 | 11 | Written by Limor Fried/Ladyada for Adafruit Industries. 12 | BSD license, all text above must be included in any redistribution 13 | ****************************************************/ 14 | 15 | // define the pins used 16 | #define VS1053_RX 2 // This is the pin that connects to the RX pin on VS1053 17 | 18 | #define VS1053_RESET 9 // This is the pin that connects to the RESET pin on VS1053 19 | // If you have the Music Maker shield, you don't need to connect the RESET pin! 20 | 21 | // If you're using the VS1053 breakout: 22 | // Don't forget to connect the GPIO #0 to GROUND and GPIO #1 pin to 3.3V 23 | // If you're using the Music Maker shield: 24 | // Don't forget to connect the GPIO #1 pin to 3.3V and the RX pin to digital #2 25 | 26 | // See http://www.vlsi.fi/fileadmin/datasheets/vs1053.pdf Pg 31 27 | #define VS1053_BANK_DEFAULT 0x00 28 | #define VS1053_BANK_DRUMS1 0x78 29 | #define VS1053_BANK_DRUMS2 0x7F 30 | #define VS1053_BANK_MELODY 0x79 31 | 32 | // See http://www.vlsi.fi/fileadmin/datasheets/vs1053.pdf Pg 32 for more! 33 | #define VS1053_GM1_OCARINA 80 34 | 35 | #define MIDI_NOTE_ON 0x90 36 | #define MIDI_NOTE_OFF 0x80 37 | #define MIDI_CHAN_MSG 0xB0 38 | #define MIDI_CHAN_BANK 0x00 39 | #define MIDI_CHAN_VOLUME 0x07 40 | #define MIDI_CHAN_PROGRAM 0xC0 41 | 42 | #if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) 43 | #include 44 | SoftwareSerial VS1053_MIDI(0, 2); // TX only, do not use the 'rx' side 45 | #else 46 | // on a Mega/Leonardo you may have to change the pin to one that 47 | // software serial support uses OR use a hardware serial port! 48 | #define VS1053_MIDI Serial1 49 | #endif 50 | 51 | 52 | 53 | void setup() { 54 | Serial.begin(9600); 55 | Serial.println("VS1053 MIDI test"); 56 | 57 | VS1053_MIDI.begin(31250); // MIDI uses a 'strange baud rate' 58 | 59 | pinMode(VS1053_RESET, OUTPUT); 60 | digitalWrite(VS1053_RESET, LOW); 61 | delay(10); 62 | digitalWrite(VS1053_RESET, HIGH); 63 | delay(10); 64 | 65 | midiSetChannelBank(0, VS1053_BANK_MELODY); 66 | midiSetInstrument(0, VS1053_GM1_OCARINA); 67 | midiSetChannelVolume(0, 127); 68 | } 69 | 70 | void loop() { 71 | for (uint8_t i=60; i<69; i++) { 72 | midiNoteOn(0, i, 127); 73 | delay(100); 74 | midiNoteOff(0, i, 127); 75 | } 76 | 77 | delay(1000); 78 | } 79 | 80 | void midiSetInstrument(uint8_t chan, uint8_t inst) { 81 | if (chan > 15) return; 82 | inst --; // page 32 has instruments starting with 1 not 0 :( 83 | if (inst > 127) return; 84 | 85 | VS1053_MIDI.write(MIDI_CHAN_PROGRAM | chan); 86 | VS1053_MIDI.write(inst); 87 | } 88 | 89 | 90 | void midiSetChannelVolume(uint8_t chan, uint8_t vol) { 91 | if (chan > 15) return; 92 | if (vol > 127) return; 93 | 94 | VS1053_MIDI.write(MIDI_CHAN_MSG | chan); 95 | VS1053_MIDI.write(MIDI_CHAN_VOLUME); 96 | VS1053_MIDI.write(vol); 97 | } 98 | 99 | void midiSetChannelBank(uint8_t chan, uint8_t bank) { 100 | if (chan > 15) return; 101 | if (bank > 127) return; 102 | 103 | VS1053_MIDI.write(MIDI_CHAN_MSG | chan); 104 | VS1053_MIDI.write((uint8_t)MIDI_CHAN_BANK); 105 | VS1053_MIDI.write(bank); 106 | } 107 | 108 | void midiNoteOn(uint8_t chan, uint8_t n, uint8_t vel) { 109 | if (chan > 15) return; 110 | if (n > 127) return; 111 | if (vel > 127) return; 112 | 113 | VS1053_MIDI.write(MIDI_NOTE_ON | chan); 114 | VS1053_MIDI.write(n); 115 | VS1053_MIDI.write(vel); 116 | } 117 | 118 | void midiNoteOff(uint8_t chan, uint8_t n, uint8_t vel) { 119 | if (chan > 15) return; 120 | if (n > 127) return; 121 | if (vel > 127) return; 122 | 123 | VS1053_MIDI.write(MIDI_NOTE_OFF | chan); 124 | VS1053_MIDI.write(n); 125 | VS1053_MIDI.write(vel); 126 | } -------------------------------------------------------------------------------- /examples/player_interrupts/player_interrupts.ino: -------------------------------------------------------------------------------- 1 | /*************************************************** 2 | This is an example for the Adafruit VS1053 Codec Breakout 3 | 4 | Designed specifically to work with the Adafruit VS1053 Codec Breakout 5 | ----> https://www.adafruit.com/products/1381 6 | 7 | Adafruit invests time and resources providing this open source code, 8 | please support Adafruit and open-source hardware by purchasing 9 | products from Adafruit! 10 | 11 | Written by Limor Fried/Ladyada for Adafruit Industries. 12 | BSD license, all text above must be included in any redistribution 13 | ****************************************************/ 14 | 15 | // include SPI, MP3 and SD libraries 16 | #include 17 | #include 18 | #include 19 | 20 | // These are the pins used for the breakout example 21 | #define BREAKOUT_RESET 9 // VS1053 reset pin (output) 22 | #define BREAKOUT_CS 10 // VS1053 chip select pin (output) 23 | #define BREAKOUT_DCS 8 // VS1053 Data/command select pin (output) 24 | // These are the pins used for the music maker shield 25 | #define SHIELD_RESET -1 // VS1053 reset pin (unused!) 26 | #define SHIELD_CS 7 // VS1053 chip select pin (output) 27 | #define SHIELD_DCS 6 // VS1053 Data/command select pin (output) 28 | 29 | // These are common pins between breakout and shield 30 | #define CARDCS 4 // Card chip select pin 31 | // DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt 32 | #define DREQ 3 // VS1053 Data request, ideally an Interrupt pin 33 | 34 | Adafruit_VS1053_FilePlayer musicPlayer = 35 | // create breakout-example object! 36 | //Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS); 37 | // create shield-example object! 38 | Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS); 39 | 40 | 41 | //// 42 | 43 | void setup() { 44 | Serial.begin(9600); 45 | Serial.println("Adafruit VS1053 Library Test"); 46 | 47 | // initialise the music player 48 | if (! musicPlayer.begin()) { // initialise the music player 49 | Serial.println(F("Couldn't find VS1053, do you have the right pins defined?")); 50 | while (1); 51 | } 52 | Serial.println(F("VS1053 found")); 53 | 54 | musicPlayer.sineTest(0x44, 500); // Make a tone to indicate VS1053 is working 55 | 56 | if (!SD.begin(CARDCS)) { 57 | Serial.println(F("SD failed, or not present")); 58 | while (1); // don't do anything more 59 | } 60 | Serial.println("SD OK!"); 61 | 62 | // list files 63 | printDirectory(SD.open("/"), 0); 64 | 65 | // Set volume for left, right channels. lower numbers == louder volume! 66 | musicPlayer.setVolume(20,20); 67 | 68 | /***** Two interrupt options! *******/ 69 | // This option uses timer0, this means timer1 & t2 are not required 70 | // (so you can use 'em for Servos, etc) BUT millis() can lose time 71 | // since we're hitchhiking on top of the millis() tracker 72 | //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT); 73 | 74 | // This option uses a pin interrupt. No timers required! But DREQ 75 | // must be on an interrupt pin. For Uno/Duemilanove/Diecimilla 76 | // that's Digital #2 or #3 77 | // See http://arduino.cc/en/Reference/attachInterrupt for other pins 78 | // *** This method is preferred 79 | if (! musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT)) 80 | Serial.println(F("DREQ pin is not an interrupt pin")); 81 | } 82 | 83 | void loop() { 84 | // Alternately, we can just play an entire file at once 85 | // This doesn't happen in the background, instead, the entire 86 | // file is played and the program will continue when it's done! 87 | musicPlayer.playFullFile("track001.ogg"); 88 | 89 | // Start playing a file, then we can do stuff while waiting for it to finish 90 | if (! musicPlayer.startPlayingFile("/track001.mp3")) { 91 | Serial.println("Could not open file track001.mp3"); 92 | while (1); 93 | } 94 | Serial.println(F("Started playing")); 95 | 96 | while (musicPlayer.playingMusic) { 97 | // file is now playing in the 'background' so now's a good time 98 | // to do something else like handling LEDs or buttons :) 99 | Serial.print("."); 100 | delay(1000); 101 | } 102 | Serial.println("Done playing music"); 103 | } 104 | 105 | 106 | /// File listing helper 107 | void printDirectory(File dir, int numTabs) { 108 | while(true) { 109 | 110 | File entry = dir.openNextFile(); 111 | if (! entry) { 112 | // no more files 113 | //Serial.println("**nomorefiles**"); 114 | break; 115 | } 116 | for (uint8_t i=0; i https://www.adafruit.com/products/1381 6 | 7 | Adafruit invests time and resources providing this open source code, 8 | please support Adafruit and open-source hardware by purchasing 9 | products from Adafruit! 10 | 11 | Written by Limor Fried/Ladyada for Adafruit Industries. 12 | BSD license, all text above must be included in any redistribution 13 | ****************************************************/ 14 | 15 | // include SPI, MP3 and SD libraries 16 | #include 17 | #include 18 | #include 19 | 20 | // define the pins used 21 | //#define CLK 13 // SPI Clock, shared with SD card 22 | //#define MISO 12 // Input data, from VS1053/SD card 23 | //#define MOSI 11 // Output data, to VS1053/SD card 24 | // Connect CLK, MISO and MOSI to hardware SPI pins. 25 | // See http://arduino.cc/en/Reference/SPI "Connections" 26 | 27 | // These are the pins used for the breakout example 28 | #define BREAKOUT_RESET 9 // VS1053 reset pin (output) 29 | #define BREAKOUT_CS 10 // VS1053 chip select pin (output) 30 | #define BREAKOUT_DCS 8 // VS1053 Data/command select pin (output) 31 | // These are the pins used for the music maker shield 32 | #define SHIELD_RESET -1 // VS1053 reset pin (unused!) 33 | #define SHIELD_CS 7 // VS1053 chip select pin (output) 34 | #define SHIELD_DCS 6 // VS1053 Data/command select pin (output) 35 | 36 | // These are common pins between breakout and shield 37 | #define CARDCS 4 // Card chip select pin 38 | // DREQ should be an Int pin, see http://arduino.cc/en/Reference/attachInterrupt 39 | #define DREQ 3 // VS1053 Data request, ideally an Interrupt pin 40 | 41 | Adafruit_VS1053_FilePlayer musicPlayer = 42 | // create breakout-example object! 43 | Adafruit_VS1053_FilePlayer(BREAKOUT_RESET, BREAKOUT_CS, BREAKOUT_DCS, DREQ, CARDCS); 44 | // create shield-example object! 45 | //Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS); 46 | 47 | void setup() { 48 | Serial.begin(9600); 49 | Serial.println("Adafruit VS1053 Simple Test"); 50 | 51 | if (! musicPlayer.begin()) { // initialise the music player 52 | Serial.println(F("Couldn't find VS1053, do you have the right pins defined?")); 53 | while (1); 54 | } 55 | Serial.println(F("VS1053 found")); 56 | 57 | if (!SD.begin(CARDCS)) { 58 | Serial.println(F("SD failed, or not present")); 59 | while (1); // don't do anything more 60 | } 61 | 62 | // list files 63 | printDirectory(SD.open("/"), 0); 64 | 65 | // Set volume for left, right channels. lower numbers == louder volume! 66 | musicPlayer.setVolume(20,20); 67 | 68 | // Timer interrupts are not suggested, better to use DREQ interrupt! 69 | //musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT); // timer int 70 | 71 | // If DREQ is on an interrupt pin (on uno, #2 or #3) we can do background 72 | // audio playing 73 | musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int 74 | 75 | // Play one file, don't return until complete 76 | Serial.println(F("Playing track 001")); 77 | musicPlayer.playFullFile("/track001.mp3"); 78 | // Play another file in the background, REQUIRES interrupts! 79 | Serial.println(F("Playing track 002")); 80 | musicPlayer.startPlayingFile("/track002.mp3"); 81 | } 82 | 83 | void loop() { 84 | // File is playing in the background 85 | if (musicPlayer.stopped()) { 86 | Serial.println("Done playing music"); 87 | while (1) { 88 | delay(10); // we're done! do nothing... 89 | } 90 | } 91 | if (Serial.available()) { 92 | char c = Serial.read(); 93 | 94 | // if we get an 's' on the serial console, stop! 95 | if (c == 's') { 96 | musicPlayer.stopPlaying(); 97 | } 98 | 99 | // if we get an 'p' on the serial console, pause/unpause! 100 | if (c == 'p') { 101 | if (! musicPlayer.paused()) { 102 | Serial.println("Paused"); 103 | musicPlayer.pausePlaying(true); 104 | } else { 105 | Serial.println("Resumed"); 106 | musicPlayer.pausePlaying(false); 107 | } 108 | } 109 | } 110 | 111 | delay(100); 112 | } 113 | 114 | 115 | /// File listing helper 116 | void printDirectory(File dir, int numTabs) { 117 | while(true) { 118 | 119 | File entry = dir.openNextFile(); 120 | if (! entry) { 121 | // no more files 122 | //Serial.println("**nomorefiles**"); 123 | break; 124 | } 125 | for (uint8_t i=0; i https://www.adafruit.com/products/1381 6 | 7 | Adafruit invests time and resources providing this open source code, 8 | please support Adafruit and open-source hardware by purchasing 9 | products from Adafruit! 10 | 11 | Written by Limor Fried/Ladyada for Adafruit Industries. 12 | BSD license, all text above must be included in any redistribution 13 | ****************************************************/ 14 | 15 | // This is a very beta demo of Ogg Vorbis recording. It works... 16 | // Connect a button to digital 7 on the Arduino and use that to 17 | // start and stop recording. 18 | 19 | // A mic or line-in connection is required. See page 13 of the 20 | // datasheet for wiring 21 | 22 | // Don't forget to copy the v44k1q05.img patch to your micro SD 23 | // card before running this example! 24 | 25 | 26 | // include SPI, MP3 and SD libraries 27 | #include 28 | #include 29 | #include 30 | 31 | // define the pins used 32 | #define RESET 9 // VS1053 reset pin (output) 33 | #define CS 10 // VS1053 chip select pin (output) 34 | #define DCS 8 // VS1053 Data/command select pin (output) 35 | #define CARDCS A0 // Card chip select pin 36 | #define DREQ 3 // VS1053 Data request, ideally an Interrupt pin 37 | 38 | #define REC_BUTTON 7 39 | 40 | Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(RESET, CS, DCS, DREQ, CARDCS); 41 | 42 | File recording; // the file we will save our recording to 43 | #define RECBUFFSIZE 128 // 64 or 128 bytes. 44 | uint8_t recording_buffer[RECBUFFSIZE]; 45 | 46 | void setup() { 47 | Serial.begin(9600); 48 | Serial.println("Adafruit VS1053 Ogg Recording Test"); 49 | 50 | // initialise the music player 51 | if (!musicPlayer.begin()) { 52 | Serial.println("VS1053 not found"); 53 | while (1); // don't do anything more 54 | } 55 | 56 | musicPlayer.sineTest(0x44, 500); // Make a tone to indicate VS1053 is working 57 | 58 | if (!SD.begin(CARDCS)) { 59 | Serial.println("SD failed, or not present"); 60 | while (1); // don't do anything more 61 | } 62 | Serial.println("SD OK!"); 63 | 64 | // Set volume for left, right channels. lower numbers == louder volume! 65 | musicPlayer.setVolume(10,10); 66 | 67 | // when the button is pressed, record! 68 | pinMode(REC_BUTTON, INPUT); 69 | digitalWrite(REC_BUTTON, HIGH); 70 | 71 | // load plugin from SD card! We'll use mono 44.1KHz, high quality 72 | if (! musicPlayer.prepareRecordOgg("v44k1q05.img")) { 73 | Serial.println("Couldn't load plugin!"); 74 | while (1); 75 | } 76 | } 77 | 78 | uint8_t isRecording = false; 79 | 80 | void loop() { 81 | if (!isRecording && !digitalRead(REC_BUTTON)) { 82 | Serial.println("Begin recording"); 83 | isRecording = true; 84 | 85 | // Check if the file exists already 86 | char filename[15]; 87 | strcpy(filename, "RECORD00.OGG"); 88 | for (uint8_t i = 0; i < 100; i++) { 89 | filename[6] = '0' + i/10; 90 | filename[7] = '0' + i%10; 91 | // create if does not exist, do not open existing, write, sync after write 92 | if (! SD.exists(filename)) { 93 | break; 94 | } 95 | } 96 | Serial.print("Recording to "); Serial.println(filename); 97 | recording = SD.open(filename, FILE_WRITE); 98 | if (! recording) { 99 | Serial.println("Couldn't open file to record!"); 100 | while (1); 101 | } 102 | musicPlayer.startRecordOgg(true); // use microphone (for linein, pass in 'false') 103 | } 104 | if (isRecording) 105 | saveRecordedData(isRecording); 106 | if (isRecording && digitalRead(REC_BUTTON)) { 107 | Serial.println("End recording"); 108 | musicPlayer.stopRecordOgg(); 109 | isRecording = false; 110 | // flush all the data! 111 | saveRecordedData(isRecording); 112 | // close it up 113 | recording.close(); 114 | delay(1000); 115 | } 116 | } 117 | 118 | uint16_t saveRecordedData(boolean isrecord) { 119 | uint16_t written = 0; 120 | 121 | // read how many words are waiting for us 122 | uint16_t wordswaiting = musicPlayer.recordedWordsWaiting(); 123 | 124 | // try to process 256 words (512 bytes) at a time, for best speed 125 | while (wordswaiting > 256) { 126 | //Serial.print("Waiting: "); Serial.println(wordswaiting); 127 | // for example 128 bytes x 4 loops = 512 bytes 128 | for (int x=0; x < 512/RECBUFFSIZE; x++) { 129 | // fill the buffer! 130 | for (uint16_t addr=0; addr < RECBUFFSIZE; addr+=2) { 131 | uint16_t t = musicPlayer.recordedReadWord(); 132 | //Serial.println(t, HEX); 133 | recording_buffer[addr] = t >> 8; 134 | recording_buffer[addr+1] = t; 135 | } 136 | if (! recording.write(recording_buffer, RECBUFFSIZE)) { 137 | Serial.print("Couldn't write "); Serial.println(RECBUFFSIZE); 138 | while (1); 139 | } 140 | } 141 | // flush 512 bytes at a time 142 | recording.flush(); 143 | written += 256; 144 | wordswaiting -= 256; 145 | } 146 | 147 | wordswaiting = musicPlayer.recordedWordsWaiting(); 148 | if (!isrecord) { 149 | Serial.print(wordswaiting); Serial.println(" remaining"); 150 | // wrapping up the recording! 151 | uint16_t addr = 0; 152 | for (int x=0; x < wordswaiting-1; x++) { 153 | // fill the buffer! 154 | uint16_t t = musicPlayer.recordedReadWord(); 155 | recording_buffer[addr] = t >> 8; 156 | recording_buffer[addr+1] = t; 157 | if (addr > RECBUFFSIZE) { 158 | if (! recording.write(recording_buffer, RECBUFFSIZE)) { 159 | Serial.println("Couldn't write!"); 160 | while (1); 161 | } 162 | recording.flush(); 163 | addr = 0; 164 | } 165 | } 166 | if (addr != 0) { 167 | if (!recording.write(recording_buffer, addr)) { 168 | Serial.println("Couldn't write!"); while (1); 169 | } 170 | written += addr; 171 | } 172 | musicPlayer.sciRead(VS1053_SCI_AICTRL3); 173 | if (! (musicPlayer.sciRead(VS1053_SCI_AICTRL3) & (1 << 2))) { 174 | recording.write(musicPlayer.recordedReadWord() & 0xFF); 175 | written++; 176 | } 177 | recording.flush(); 178 | } 179 | 180 | return written; 181 | } 182 | -------------------------------------------------------------------------------- /examples/feather_player/feather_player.ino: -------------------------------------------------------------------------------- 1 | // Specifically for use with the Adafruit Feather, the pins are pre-set here! 2 | 3 | // include SPI, MP3 and SD libraries 4 | #include 5 | #include 6 | #include 7 | 8 | // These are the pins used 9 | #define VS1053_RESET -1 // VS1053 reset pin (not used!) 10 | 11 | // Feather ESP8266 12 | #if defined(ESP8266) 13 | #define VS1053_CS 16 // VS1053 chip select pin (output) 14 | #define VS1053_DCS 15 // VS1053 Data/command select pin (output) 15 | #define CARDCS 2 // Card chip select pin 16 | #define VS1053_DREQ 0 // VS1053 Data request, ideally an Interrupt pin 17 | 18 | // Feather ESP32-C6 19 | #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32C6) 20 | #define VS1053_CS 6 // VS1053 chip select pin (output) 21 | #define VS1053_DCS 8 // VS1053 Data/command select pin (output) 22 | #define CARDCS 5 // Card chip select pin 23 | #define VS1053_DREQ 7 // VS1053 Data request, ideally an Interrupt pin 24 | 25 | // Feather ESP32-S2 and ESP32-S3 (all variants) 26 | #elif defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) || \ 27 | defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2_REVTFT) || \ 28 | defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2_TFT) || \ 29 | defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3) || \ 30 | defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3_NOPSRAM)|| \ 31 | defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3_REVTFT) || \ 32 | defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S3_TFT) 33 | #define VS1053_CS 6 // VS1053 chip select pin (output) 34 | #define VS1053_DCS 10 // VS1053 Data/command select pin (output) 35 | #define CARDCS 5 // Card chip select pin 36 | #define VS1053_DREQ 9 // VS1053 Data request, ideally an Interrupt pin 37 | 38 | // Feather ESP32 39 | #elif defined(ESP32) && !defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) 40 | #define VS1053_CS 32 // VS1053 chip select pin (output) 41 | #define VS1053_DCS 33 // VS1053 Data/command select pin (output) 42 | #define CARDCS 14 // Card chip select pin 43 | #define VS1053_DREQ 15 // VS1053 Data request, ideally an Interrupt pin 44 | 45 | // Feather Teensy3 46 | #elif defined(TEENSYDUINO) 47 | #define VS1053_CS 3 // VS1053 chip select pin (output) 48 | #define VS1053_DCS 10 // VS1053 Data/command select pin (output) 49 | #define CARDCS 8 // Card chip select pin 50 | #define VS1053_DREQ 4 // VS1053 Data request, ideally an Interrupt pin 51 | 52 | // WICED feather 53 | #elif defined(ARDUINO_STM32_FEATHER) 54 | #define VS1053_CS PC7 // VS1053 chip select pin (output) 55 | #define VS1053_DCS PB4 // VS1053 Data/command select pin (output) 56 | #define CARDCS PC5 // Card chip select pin 57 | #define VS1053_DREQ PA15 // VS1053 Data request, ideally an Interrupt pin 58 | 59 | #elif defined(ARDUINO_NRF52832_FEATHER ) 60 | #define VS1053_CS 30 // VS1053 chip select pin (output) 61 | #define VS1053_DCS 11 // VS1053 Data/command select pin (output) 62 | #define CARDCS 27 // Card chip select pin 63 | #define VS1053_DREQ 31 // VS1053 Data request, ideally an Interrupt pin 64 | 65 | // Feather RP2040 66 | #elif defined(ARDUINO_ADAFRUIT_FEATHER_RP2040) 67 | #define VS1053_CS 8 // VS1053 chip select pin (output) 68 | #define VS1053_DCS 10 // VS1053 Data/command select pin (output) 69 | #define CARDCS 7 // Card chip select pin 70 | #define VS1053_DREQ 9 // VS1053 Data request, ideally an Interrupt pin 71 | 72 | // Feather M4, M0, 328, ESP32S2, nRF52840 or 32u4 73 | #else 74 | #define VS1053_CS 6 // VS1053 chip select pin (output) 75 | #define VS1053_DCS 10 // VS1053 Data/command select pin (output) 76 | #define CARDCS 5 // Card chip select pin 77 | // DREQ should be an Int pin *if possible* (not possible on 32u4) 78 | #define VS1053_DREQ 9 // VS1053 Data request, ideally an Interrupt pin 79 | 80 | #endif 81 | 82 | 83 | Adafruit_VS1053_FilePlayer musicPlayer = 84 | Adafruit_VS1053_FilePlayer(VS1053_RESET, VS1053_CS, VS1053_DCS, VS1053_DREQ, CARDCS); 85 | 86 | void setup() { 87 | Serial.begin(115200); 88 | 89 | // if you're using Bluefruit or LoRa/RFM Feather, disable the radio module 90 | //pinMode(8, INPUT_PULLUP); 91 | 92 | // Wait for serial port to be opened, remove this line for 'standalone' operation 93 | while (!Serial) { delay(1); } 94 | delay(500); 95 | Serial.println("\n\nAdafruit VS1053 Feather Test"); 96 | 97 | if (! musicPlayer.begin()) { // initialise the music player 98 | Serial.println(F("Couldn't find VS1053, do you have the right pins defined?")); 99 | while (1); 100 | } 101 | 102 | Serial.println(F("VS1053 found")); 103 | 104 | musicPlayer.sineTest(0x44, 500); // Make a tone to indicate VS1053 is working 105 | 106 | if (!SD.begin(CARDCS)) { 107 | Serial.println(F("SD failed, or not present")); 108 | while (1); // don't do anything more 109 | } 110 | Serial.println("SD OK!"); 111 | 112 | // list files 113 | printDirectory(SD.open("/"), 0); 114 | 115 | // Set volume for left, right channels. lower numbers == louder volume! 116 | musicPlayer.setVolume(10,10); 117 | 118 | #if defined(__AVR_ATmega32U4__) 119 | // Timer interrupts are not suggested, better to use DREQ interrupt! 120 | // but we don't have them on the 32u4 feather... 121 | musicPlayer.useInterrupt(VS1053_FILEPLAYER_TIMER0_INT); // timer int 122 | #else 123 | // If DREQ is on an interrupt pin we can do background 124 | // audio playing 125 | musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT); // DREQ int 126 | #endif 127 | 128 | // Play a file in the background, REQUIRES interrupts! 129 | Serial.println(F("Playing full track 001")); 130 | musicPlayer.playFullFile("/track001.mp3"); 131 | 132 | Serial.println(F("Playing track 002")); 133 | musicPlayer.startPlayingFile("/track002.mp3"); 134 | } 135 | 136 | void loop() { 137 | Serial.print("."); 138 | // File is playing in the background 139 | if (musicPlayer.stopped()) { 140 | Serial.println("Done playing music"); 141 | while (1) { 142 | delay(10); // we're done! do nothing... 143 | } 144 | } 145 | if (Serial.available()) { 146 | char c = Serial.read(); 147 | 148 | // if we get an 's' on the serial console, stop! 149 | if (c == 's') { 150 | musicPlayer.stopPlaying(); 151 | } 152 | 153 | // if we get an 'p' on the serial console, pause/unpause! 154 | if (c == 'p') { 155 | if (! musicPlayer.paused()) { 156 | Serial.println("Paused"); 157 | musicPlayer.pausePlaying(true); 158 | } else { 159 | Serial.println("Resumed"); 160 | musicPlayer.pausePlaying(false); 161 | } 162 | } 163 | } 164 | delay(100); 165 | } 166 | 167 | 168 | 169 | /// File listing helper 170 | void printDirectory(File dir, int numTabs) { 171 | while(true) { 172 | 173 | File entry = dir.openNextFile(); 174 | if (! entry) { 175 | // no more files 176 | //Serial.println("**nomorefiles**"); 177 | break; 178 | } 179 | for (uint8_t i=0; i= 100) 9 | #include 10 | #else 11 | #include 12 | #include 13 | #endif 14 | 15 | #if !defined(ARDUINO_STM32_FEATHER) && !defined(ARDUINO_UNOR4_WIFI) && \ 16 | !defined(ARDUINO_UNOR4_MINIMA) 17 | #include "pins_arduino.h" 18 | #include "wiring_private.h" 19 | #endif 20 | 21 | #include 22 | 23 | #if defined(PREFER_SDFAT_LIBRARY) 24 | #include 25 | extern SdFat SD; 26 | #else 27 | #include 28 | #endif 29 | 30 | // define here the size of a register! 31 | #if defined(ARDUINO_STM32_FEATHER) 32 | typedef volatile uint32 RwReg; 33 | typedef uint32_t PortMask; 34 | #elif defined(ARDUINO_ARCH_AVR) 35 | typedef volatile uint8_t RwReg; 36 | typedef uint8_t PortMask; 37 | #elif defined(__arm__) 38 | #if defined(TEENSYDUINO) 39 | typedef volatile uint8_t RwReg; 40 | typedef uint8_t PortMask; 41 | #else 42 | typedef volatile uint32_t RwReg; 43 | typedef uint32_t PortMask; 44 | #endif 45 | #elif defined(ESP8266) || defined(ESP32) 46 | typedef volatile uint32_t RwReg; 47 | typedef uint32_t PortMask; 48 | #elif defined(__ARDUINO_ARC__) 49 | typedef volatile uint32_t RwReg; 50 | typedef uint32_t PortMask; 51 | #else 52 | typedef volatile uint8_t RwReg; //!< 1-byte read-write register 53 | typedef uint8_t PortMask; //!< Type definition for a bitmask that is used to 54 | //!< specify the bit width 55 | #endif 56 | 57 | typedef volatile RwReg PortReg; //!< Type definition/alias used to specify the 58 | //!< port register that a pin is in 59 | 60 | #define VS1053_FILEPLAYER_TIMER0_INT \ 61 | 255 //!< Allows useInterrupt to accept pins 0 to 254 62 | #define VS1053_FILEPLAYER_PIN_INT \ 63 | 5 //!< Allows useInterrupt to accept pins 0 to 4 64 | 65 | #define VS1053_SCI_READ 0x03 //!< Serial read address 66 | #define VS1053_SCI_WRITE 0x02 //!< Serial write address 67 | 68 | #define VS1053_REG_MODE 0x00 //!< Mode control 69 | #define VS1053_REG_STATUS 0x01 //!< Status of VS1053b 70 | #define VS1053_REG_BASS 0x02 //!< Built-in bass/treble control 71 | #define VS1053_REG_CLOCKF 0x03 //!< Clock frequency + multiplier 72 | #define VS1053_REG_DECODETIME 0x04 //!< Decode time in seconds 73 | #define VS1053_REG_AUDATA 0x05 //!< Misc. audio data 74 | #define VS1053_REG_WRAM 0x06 //!< RAM write/read 75 | #define VS1053_REG_WRAMADDR 0x07 //!< Base address for RAM write/read 76 | #define VS1053_REG_HDAT0 0x08 //!< Stream header data 0 77 | #define VS1053_REG_HDAT1 0x09 //!< Stream header data 1 78 | #define VS1053_REG_VOLUME 0x0B //!< Volume control 79 | 80 | #define VS1053_GPIO_DDR 0xC017 //!< Direction 81 | #define VS1053_GPIO_IDATA 0xC018 //!< Values read from pins 82 | #define VS1053_GPIO_ODATA 0xC019 //!< Values set to the pins 83 | 84 | #define VS1053_INT_ENABLE 0xC01A //!< Interrupt enable 85 | 86 | #define VS1053_MODE_SM_DIFF \ 87 | 0x0001 //!< Differential, 0: normal in-phase audio, 1: left channel inverted 88 | #define VS1053_MODE_SM_LAYER12 0x0002 //!< Allow MPEG layers I & II 89 | #define VS1053_MODE_SM_RESET 0x0004 //!< Soft reset 90 | #define VS1053_MODE_SM_CANCEL 0x0008 //!< Cancel decoding current file 91 | #define VS1053_MODE_SM_EARSPKLO 0x0010 //!< EarSpeaker low setting 92 | #define VS1053_MODE_SM_TESTS 0x0020 //!< Allow SDI tests 93 | #define VS1053_MODE_SM_STREAM 0x0040 //!< Stream mode 94 | #define VS1053_MODE_SM_SDINEW 0x0800 //!< VS1002 native SPI modes 95 | #define VS1053_MODE_SM_ADPCM 0x1000 //!< PCM/ADPCM recording active 96 | #define VS1053_MODE_SM_LINE1 0x4000 //!< MIC/LINE1 selector, 0: MICP, 1: LINE1 97 | #define VS1053_MODE_SM_CLKRANGE \ 98 | 0x8000 //!< Input clock range, 0: 12..13 MHz, 1: 24..26 MHz 99 | 100 | #define VS1053_SCI_AIADDR \ 101 | 0x0A //!< Indicates the start address of the application code written earlier 102 | //!< with SCI_WRAMADDR and SCI_WRAM registers. 103 | #define VS1053_SCI_AICTRL0 \ 104 | 0x0C //!< SCI_AICTRL register 0. Used to access the user's application program 105 | #define VS1053_SCI_AICTRL1 \ 106 | 0x0D //!< SCI_AICTRL register 1. Used to access the user's application program 107 | #define VS1053_SCI_AICTRL2 \ 108 | 0x0E //!< SCI_AICTRL register 2. Used to access the user's application program 109 | #define VS1053_SCI_AICTRL3 \ 110 | 0x0F //!< SCI_AICTRL register 3. Used to access the user's application program 111 | #define VS1053_SCI_WRAM 0x06 //!< RAM write/read 112 | #define VS1053_SCI_WRAMADDR 0x07 //!< Base address for RAM write/read 113 | 114 | #define VS1053_PARA_PLAYSPEED 0x1E04 //!< 0,1 = normal speed, 2 = 2x, 3 = 3x etc 115 | 116 | #define VS1053_DATABUFFERLEN 32 //!< Length of the data buffer 117 | 118 | /*! 119 | * Driver for the Adafruit VS1053 120 | */ 121 | class Adafruit_VS1053 { 122 | public: 123 | /*! 124 | * @brief Software SPI constructor - must specify all pins 125 | * @param mosi MOSI (Microcontroller Out Serial In) pin 126 | * @param miso MISO (Microcontroller In Serial Out) pin 127 | * @param clk Clock pin 128 | * @param rst Reset pin 129 | * @param cs SCI Chip Select pin 130 | * @param dcs SDI Chip Select pin 131 | * @param dreq Data Request pin 132 | */ 133 | Adafruit_VS1053(int8_t mosi, int8_t miso, int8_t clk, int8_t rst, int8_t cs, 134 | int8_t dcs, int8_t dreq); 135 | /*! 136 | * @brief Hardware SPI constructor - assumes hardware SPI pins 137 | * @param rst Reset pin 138 | * @param cs SCI Chip Select pin 139 | * @param dcs SDI Chip Select pin 140 | * @param dreq Data Request pin 141 | */ 142 | Adafruit_VS1053(int8_t rst, int8_t cs, int8_t dcs, int8_t dreq); 143 | /*! 144 | * @brief Initialize communication and (hard) reset the chip. 145 | * @return Returns true if a VS1053 is found 146 | */ 147 | uint8_t begin(void); 148 | /*! 149 | * @brief Performs a hard reset of the chip 150 | */ 151 | void reset(void); 152 | /*! 153 | * @brief Attempts a soft reset of the chip 154 | */ 155 | void softReset(void); 156 | /*! 157 | * @brief Reads from the specified register on the chip 158 | * @param addr Register address to read from 159 | * @return Retuns the 16-bit data corresponding to the received address 160 | */ 161 | uint16_t sciRead(uint8_t addr); 162 | /*! 163 | * @brief Writes to the specified register on the chip 164 | * @param addr Register address to write to 165 | * @param data Data to write 166 | */ 167 | void sciWrite(uint8_t addr, uint16_t data); 168 | /*! 169 | * @brief Generate a sine-wave test signal 170 | * @param n Defines the sine test to use 171 | * @param ms Delay (in ms) 172 | */ 173 | void sineTest(uint8_t n, uint16_t ms); 174 | /*! 175 | * @brief Reads the DECODETIME register from the chip 176 | * @return Returns the decode time as an unsigned 16-bit integer 177 | */ 178 | uint16_t decodeTime(void); 179 | /*! 180 | * @brief Set the output volume for the chip 181 | * @param left Desired left channel volume 182 | * @param right Desired right channel volume 183 | */ 184 | void setVolume(uint8_t left, uint8_t right); 185 | /*! 186 | * @brief Prints the contents of the MODE, STATUS, CLOCKF and VOLUME registers 187 | */ 188 | void dumpRegs(void); 189 | 190 | /*! 191 | * @brief Decode and play the contents of the supplied buffer 192 | * @param buffer Buffer to decode and play 193 | * @param buffsiz Size to decode and play 194 | */ 195 | void playData(uint8_t *buffer, uint8_t buffsiz); 196 | /*! 197 | * @brief Test if ready for more data 198 | * @return Returns true if it is ready for data 199 | */ 200 | boolean readyForData(void); 201 | /*! 202 | * @brief Apply a code patch 203 | * @param patch Patch to apply 204 | * @param patchsize Patch size 205 | */ 206 | void applyPatch(const uint16_t *patch, uint16_t patchsize); 207 | /*! 208 | * @brief Load the specified plug-in 209 | * @param fn Plug-in to load 210 | * @return Either returns 0xFFFF if there is an error, or the address of the 211 | * plugin that was loaded 212 | */ 213 | uint16_t loadPlugin(char *fn); 214 | 215 | /*! 216 | * @brief Write to a GPIO pin 217 | * @param i GPIO pin to write to 218 | * @param val Value to write 219 | */ 220 | void GPIO_digitalWrite(uint8_t i, uint8_t val); 221 | /*! 222 | * @brief Write to all 8 GPIO pins at once 223 | * @param i Value to write 224 | */ 225 | void GPIO_digitalWrite(uint8_t i); 226 | /*! 227 | * @brief Read all 8 GPIO pins at once 228 | * @return Returns a 2 byte value with the reads from the 8 pins 229 | */ 230 | uint16_t GPIO_digitalRead(void); 231 | /*! 232 | * @brief Read a single GPIO pin 233 | * @param i pin to read 234 | * @return Returns the state of the specified GPIO pin 235 | */ 236 | boolean GPIO_digitalRead(uint8_t i); 237 | /*! 238 | * @brief Set the Pin Mode (INPUT/OUTPUT) for a GPIO pin. 239 | * @param i Pin to set the mode for 240 | * @param dir Mode to set 241 | */ 242 | void GPIO_pinMode(uint8_t i, uint8_t dir); 243 | 244 | /*! 245 | * @brief Initialize chip for OGG recording 246 | * @param plugin Binary file of the plugin to use 247 | * @return Returns true if the device is ready to record 248 | */ 249 | boolean prepareRecordOgg(char *plugin); 250 | /*! 251 | * @brief Start recording 252 | * @param mic mic=true for microphone input 253 | */ 254 | void startRecordOgg(boolean mic); 255 | /*! 256 | * @brief Stop the recording 257 | */ 258 | void stopRecordOgg(void); 259 | /*! 260 | * @brief Returns the number of words recorded 261 | * @return 2-byte unsigned int with the number of words 262 | */ 263 | uint16_t recordedWordsWaiting(void); 264 | /*! 265 | * @brief Reads the next word from the buffer of recorded words 266 | * @return Returns the 16-bit data corresponding to the received address 267 | */ 268 | uint16_t recordedReadWord(void); 269 | 270 | uint8_t mp3buffer[VS1053_DATABUFFERLEN]; //!< mp3 buffer that gets sent to the 271 | //!< device 272 | 273 | #ifdef ARDUINO_ARCH_SAMD 274 | protected: 275 | uint32_t _dreq; //!< Data request pin 276 | boolean usingInterrupts = false; //!< True if using interrupts 277 | 278 | private: 279 | Adafruit_SPIDevice *spi_dev_ctrl = NULL; ///< Pointer to SPI dev for control 280 | Adafruit_SPIDevice *spi_dev_data = NULL; ///< Pointer to SPI dev for data 281 | int32_t _mosi, _miso, _clk, _reset, _cs, _dcs; 282 | boolean useHardwareSPI; 283 | #else 284 | protected: 285 | uint8_t _dreq; //!< Data request pin 286 | boolean usingInterrupts = false; //!< True if using interrupts 287 | 288 | private: 289 | Adafruit_SPIDevice *spi_dev_ctrl = NULL; ///< Pointer to SPI dev for control 290 | Adafruit_SPIDevice *spi_dev_data = NULL; ///< Pointer to SPI dev for data 291 | int8_t _mosi, _miso, _clk, _reset, _cs, _dcs; 292 | boolean useHardwareSPI; 293 | #endif 294 | }; 295 | 296 | /*! 297 | * @brief File player for the Adafruit VS1053 298 | */ 299 | class Adafruit_VS1053_FilePlayer : public Adafruit_VS1053 { 300 | public: 301 | /*! 302 | * @brief Software SPI constructor. Uses Software SPI, so you must specify all 303 | * SPI pins 304 | * @param mosi MOSI (Microcontroller Out Serial In) pin 305 | * @param miso MISO (Microcontroller In Serial Out) pin 306 | * @param clk Clock pin 307 | * @param rst Reset pin 308 | * @param cs SCI Chip Select pin 309 | * @param dcs SDI Chip Select pin 310 | * @param dreq Data Request pin 311 | * @param cardCS CS pin for the SD card on the SPI bus 312 | */ 313 | Adafruit_VS1053_FilePlayer(int8_t mosi, int8_t miso, int8_t clk, int8_t rst, 314 | int8_t cs, int8_t dcs, int8_t dreq, int8_t cardCS); 315 | /*! 316 | * @brief Hardware SPI constructor. Uses Hardware SPI and assumes the default 317 | * SPI pins 318 | * @param rst Reset pin 319 | * @param cs SCI Chip Select pin 320 | * @param dcs SDI Chip Select pin 321 | * @param dreq Data Request pin 322 | * @param cardCS CS pin for the SD card on the SPI bus 323 | */ 324 | Adafruit_VS1053_FilePlayer(int8_t rst, int8_t cs, int8_t dcs, int8_t dreq, 325 | int8_t cardCS); 326 | 327 | /*! 328 | * @brief Hardware SPI constructor. Uses Hardware SPI and assumes the default 329 | * SPI pins 330 | * @param cs SCI Chip Select pin 331 | * @param dcs SDI Chip Select pin 332 | * @param dreq Data Request pin 333 | * @param cardCS CS pin for the SD card on the SPI bus 334 | */ 335 | Adafruit_VS1053_FilePlayer(int8_t cs, int8_t dcs, int8_t dreq, int8_t cardCS); 336 | 337 | /*! 338 | * @brief Initialize communication and reset the chip. 339 | * @return Returns true if a VS1053 is found 340 | */ 341 | boolean begin(void); 342 | /*! 343 | * @brief Specifies the argument to use for interrupt-driven playback 344 | * @param type interrupt to use. Valid arguments are 345 | * VS1053_FILEPLAYER_TIMER0_INT and VS1053_FILEPLAYER_PIN_INT 346 | * @return Returs true/false for success/failure 347 | */ 348 | boolean useInterrupt(uint8_t type); 349 | File currentTrack; //!< File that is currently playing 350 | volatile boolean playingMusic; //!< Whether or not music is playing 351 | /*! 352 | * @brief Feeds the buffer. Reads mp3 file data from the SD card and file and 353 | * puts it into the buffer that the decoder reads from to play a file 354 | */ 355 | void feedBuffer(void); 356 | /*! 357 | * @brief Checks if the inputted filename is an mp3 358 | * @param fileName File to check 359 | * @return Returns true or false 360 | */ 361 | static boolean isMP3File(const char *fileName); 362 | /*! 363 | * @brief Checks for an ID3 tag at the beginning of the file. 364 | * @param mp3 File to read 365 | * @return returns the seek position within the file where the mp3 data starts 366 | */ 367 | unsigned long mp3_ID3Jumper(File mp3); 368 | /*! 369 | * @brief Begin playing the specified file from the SD card using 370 | * interrupt-drive playback. 371 | * @param *trackname File to play 372 | * @return Returns true when file starts playing 373 | */ 374 | boolean startPlayingFile(const char *trackname); 375 | /*! 376 | * @brief Play the complete file. This function will not return until the 377 | * playback is complete 378 | * @param *trackname File to play 379 | * @return Returns true when file starts playing 380 | */ 381 | boolean playFullFile(const char *trackname); 382 | void stopPlaying(void); //!< Stop playback 383 | /*! 384 | * @brief If playback is paused 385 | * @return Returns true if playback is paused 386 | */ 387 | boolean paused(void); 388 | /*! 389 | * @brief If playback is stopped 390 | * @return Returns true if playback is stopped 391 | */ 392 | boolean stopped(void); 393 | /*! 394 | * @brief Pause playback 395 | * @param pause whether or not to pause playback 396 | */ 397 | void pausePlaying(boolean pause); 398 | /*! 399 | * @brief Set state for playback looping 400 | * @param loopState Sets playback loop state (Note: Only use with 401 | * startPlayingFile, if used with playFullFile no subsequent code in the 402 | * sketch executes) 403 | */ 404 | void playbackLoop(boolean loopState); 405 | /*! 406 | * @brief Retrieve playback loop state 407 | * @return Returns true when looped playback is enabled 408 | */ 409 | boolean playbackLooped(); 410 | /*! 411 | * @brief Determine current playback speed 412 | * @return Returns playback speed, i.e. 1 for 1x, 2 for 2x, 3 for 3x 413 | */ 414 | uint16_t getPlaySpeed(); 415 | /*! 416 | * @brief Set playback speed 417 | * @param speed Set playback speed, i.e. 1 for 1x, 2 for 2x, 3 for 3x 418 | */ 419 | void setPlaySpeed(uint16_t speed); 420 | 421 | private: 422 | void feedBuffer_noLock(void); 423 | 424 | uint8_t _cardCS; 425 | }; 426 | 427 | #endif // ADAFRUIT_VS1053_H 428 | -------------------------------------------------------------------------------- /Adafruit_VS1053.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_VS1053.cpp 3 | * 4 | * @mainpage Adafruit VS1053 Library 5 | * 6 | * @section intro_sec Introduction 7 | * 8 | * This is a library for the Adafruit VS1053 Codec Breakout 9 | * 10 | * Designed specifically to work with the Adafruit VS1053 Codec Breakout 11 | * ----> https://www.adafruit.com/products/1381 12 | * 13 | * Adafruit invests time and resources providing this open source code, 14 | * please support Adafruit and open-source hardware by purchasing 15 | * products from Adafruit! 16 | * 17 | * @section author Author 18 | * 19 | * Written by Limor Fried/Ladyada for Adafruit Industries. 20 | * 21 | * @section license License 22 | * 23 | * BSD license, all text above must be included in any redistribution 24 | */ 25 | 26 | #include 27 | 28 | #if defined(ARDUINO_STM32_FEATHER) 29 | #define digitalPinToInterrupt(x) x 30 | #endif 31 | 32 | static Adafruit_VS1053_FilePlayer *myself; 33 | 34 | #ifndef _BV 35 | #define _BV(x) (1 << (x)) //!< Macro that returns the "value" of a bit 36 | #endif 37 | 38 | #if defined(ARDUINO_ARCH_AVR) 39 | SIGNAL(TIMER0_COMPA_vect) { myself->feedBuffer(); } 40 | #endif 41 | 42 | volatile boolean feedBufferLock = false; //!< Locks feeding the buffer 43 | boolean _loopPlayback; //!< internal variable, used to control playback looping 44 | 45 | #if defined(ESP8266) 46 | ICACHE_RAM_ATTR 47 | #endif 48 | static void feeder(void) { myself->feedBuffer(); } 49 | 50 | boolean Adafruit_VS1053_FilePlayer::useInterrupt(uint8_t type) { 51 | myself = this; // oy vey 52 | 53 | usingInterrupts = true; 54 | 55 | if (type == VS1053_FILEPLAYER_TIMER0_INT) { 56 | #if defined(ARDUINO_ARCH_AVR) 57 | OCR0A = 0xAF; 58 | TIMSK0 |= _BV(OCIE0A); 59 | return true; 60 | #elif defined(__arm__) && defined(CORE_TEENSY) 61 | IntervalTimer *t = new IntervalTimer(); 62 | return (t && t->begin(feeder, 1024)) ? true : false; 63 | #elif defined(ARDUINO_STM32_FEATHER) 64 | HardwareTimer timer(3); 65 | // Pause the timer while we're configuring it 66 | timer.pause(); 67 | 68 | // Set up period 69 | timer.setPeriod(25000); // in microseconds 70 | 71 | // Set up an interrupt on channel 1 72 | timer.setChannel1Mode(TIMER_OUTPUT_COMPARE); 73 | timer.setCompare(TIMER_CH1, 1); // Interrupt 1 count after each update 74 | timer.attachCompare1Interrupt(feeder); 75 | 76 | // Refresh the timer's count, prescale, and overflow 77 | timer.refresh(); 78 | 79 | // Start the timer counting 80 | timer.resume(); 81 | 82 | #else 83 | usingInterrupts = false; 84 | return false; 85 | #endif 86 | } 87 | if (type == VS1053_FILEPLAYER_PIN_INT) { 88 | int8_t irq = digitalPinToInterrupt(_dreq); 89 | // Serial.print("Using IRQ "); Serial.println(irq); 90 | if (irq == -1) 91 | return false; 92 | #if defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) && !defined(ESP32) && \ 93 | !defined(ARDUINO_STM32_FEATHER) 94 | SPI.usingInterrupt(irq); 95 | #endif 96 | attachInterrupt(irq, feeder, CHANGE); 97 | return true; 98 | } 99 | usingInterrupts = false; 100 | return false; 101 | } 102 | 103 | Adafruit_VS1053_FilePlayer::Adafruit_VS1053_FilePlayer(int8_t rst, int8_t cs, 104 | int8_t dcs, int8_t dreq, 105 | int8_t cardcs) 106 | : Adafruit_VS1053(rst, cs, dcs, dreq) { 107 | 108 | playingMusic = false; 109 | _cardCS = cardcs; 110 | _loopPlayback = false; 111 | } 112 | 113 | Adafruit_VS1053_FilePlayer::Adafruit_VS1053_FilePlayer(int8_t cs, int8_t dcs, 114 | int8_t dreq, 115 | int8_t cardcs) 116 | : Adafruit_VS1053(-1, cs, dcs, dreq) { 117 | 118 | playingMusic = false; 119 | _cardCS = cardcs; 120 | _loopPlayback = false; 121 | } 122 | 123 | Adafruit_VS1053_FilePlayer::Adafruit_VS1053_FilePlayer(int8_t mosi, int8_t miso, 124 | int8_t clk, int8_t rst, 125 | int8_t cs, int8_t dcs, 126 | int8_t dreq, 127 | int8_t cardcs) 128 | : Adafruit_VS1053(mosi, miso, clk, rst, cs, dcs, dreq) { 129 | 130 | playingMusic = false; 131 | _cardCS = cardcs; 132 | _loopPlayback = false; 133 | } 134 | 135 | boolean Adafruit_VS1053_FilePlayer::begin(void) { 136 | // Set the card to be disabled while we get the VS1053 up 137 | pinMode(_cardCS, OUTPUT); 138 | digitalWrite(_cardCS, HIGH); 139 | 140 | uint8_t v = Adafruit_VS1053::begin(); 141 | 142 | // dumpRegs(); 143 | // Serial.print("Version = "); Serial.println(v); 144 | return (v == 4); 145 | } 146 | 147 | boolean Adafruit_VS1053_FilePlayer::playFullFile(const char *trackname) { 148 | if (!startPlayingFile(trackname)) 149 | return false; 150 | 151 | while (playingMusic) { 152 | // twiddle thumbs 153 | feedBuffer(); 154 | delay(5); // give IRQs a chance 155 | } 156 | // music file finished! 157 | return true; 158 | } 159 | 160 | void Adafruit_VS1053_FilePlayer::stopPlaying(void) { 161 | // cancel all playback 162 | sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_LINE1 | VS1053_MODE_SM_SDINEW | 163 | VS1053_MODE_SM_CANCEL); 164 | 165 | // wrap it up! 166 | playingMusic = false; 167 | currentTrack.close(); 168 | } 169 | 170 | void Adafruit_VS1053_FilePlayer::pausePlaying(boolean pause) { 171 | playingMusic = (!pause && currentTrack); 172 | if (playingMusic) { 173 | feedBuffer(); 174 | } 175 | } 176 | 177 | boolean Adafruit_VS1053_FilePlayer::paused(void) { 178 | return (!playingMusic && currentTrack); 179 | } 180 | 181 | boolean Adafruit_VS1053_FilePlayer::stopped(void) { 182 | return (!playingMusic && !currentTrack); 183 | } 184 | 185 | void Adafruit_VS1053_FilePlayer::playbackLoop(boolean loopState) { 186 | _loopPlayback = loopState; 187 | } 188 | 189 | boolean Adafruit_VS1053_FilePlayer::playbackLooped() { return _loopPlayback; } 190 | 191 | // Just checks to see if the name ends in ".mp3" 192 | boolean Adafruit_VS1053_FilePlayer::isMP3File(const char *fileName) { 193 | return (strlen(fileName) > 4) && 194 | !strcasecmp(fileName + strlen(fileName) - 4, ".mp3"); 195 | } 196 | 197 | unsigned long Adafruit_VS1053_FilePlayer::mp3_ID3Jumper(File mp3) { 198 | 199 | char tag[4]; 200 | uint32_t start; 201 | unsigned long current; 202 | 203 | start = 0; 204 | if (mp3) { 205 | current = mp3.position(); 206 | if (mp3.seek(0)) { 207 | if (mp3.read((uint8_t *)tag, 3)) { 208 | tag[3] = '\0'; 209 | if (!strcmp(tag, "ID3")) { 210 | if (mp3.seek(6)) { 211 | start = 0ul; 212 | for (byte i = 0; i < 4; i++) { 213 | start <<= 7; 214 | start |= (0x7F & mp3.read()); 215 | } 216 | } else { 217 | // Serial.println("Second seek failed?"); 218 | } 219 | } else { 220 | // Serial.println("It wasn't the damn TAG."); 221 | } 222 | } else { 223 | // Serial.println("Read for the tag failed"); 224 | } 225 | } else { 226 | // Serial.println("Seek failed? How can seek fail?"); 227 | } 228 | mp3.seek(current); // Put you things away like you found 'em. 229 | } else { 230 | // Serial.println("They handed us a NULL file!"); 231 | } 232 | // Serial.print("Jumper returning: "); Serial.println(start); 233 | return start; 234 | } 235 | 236 | boolean Adafruit_VS1053_FilePlayer::startPlayingFile(const char *trackname) { 237 | // reset playback 238 | sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_LINE1 | VS1053_MODE_SM_SDINEW | 239 | VS1053_MODE_SM_LAYER12); 240 | // resync 241 | sciWrite(VS1053_REG_WRAMADDR, 0x1e29); 242 | sciWrite(VS1053_REG_WRAM, 0); 243 | 244 | currentTrack = SD.open(trackname); 245 | if (!currentTrack) { 246 | return false; 247 | } 248 | 249 | // We know we have a valid file. Check if .mp3 250 | // If so, check for ID3 tag and jump it if present. 251 | if (isMP3File(trackname)) { 252 | currentTrack.seek(mp3_ID3Jumper(currentTrack)); 253 | } 254 | 255 | // don't let the IRQ get triggered by accident here 256 | if (usingInterrupts) 257 | noInterrupts(); 258 | 259 | // As explained in datasheet, set twice 0 in REG_DECODETIME to set time back 260 | // to 0 261 | sciWrite(VS1053_REG_DECODETIME, 0x00); 262 | sciWrite(VS1053_REG_DECODETIME, 0x00); 263 | 264 | playingMusic = true; 265 | 266 | // wait till its ready for data 267 | while (!readyForData()) { 268 | delay(1); 269 | #if defined(ESP8266) 270 | ESP.wdtFeed(); 271 | #endif 272 | } 273 | 274 | // fill it up! 275 | while (playingMusic && readyForData()) { 276 | feedBuffer(); 277 | } 278 | 279 | // ok going forward, we can use the IRQ 280 | interrupts(); 281 | 282 | return true; 283 | } 284 | 285 | void Adafruit_VS1053_FilePlayer::feedBuffer(void) { 286 | if (usingInterrupts) 287 | noInterrupts(); 288 | // dont run twice in case interrupts collided 289 | // This isn't a perfect lock as it may lose one feedBuffer request if 290 | // an interrupt occurs before feedBufferLock is reset to false. This 291 | // may cause a glitch in the audio but at least it will not corrupt 292 | // state. 293 | if (feedBufferLock) { 294 | interrupts(); 295 | return; 296 | } 297 | feedBufferLock = true; 298 | interrupts(); 299 | 300 | feedBuffer_noLock(); 301 | 302 | feedBufferLock = false; 303 | } 304 | 305 | void Adafruit_VS1053_FilePlayer::feedBuffer_noLock(void) { 306 | if ((!playingMusic) // paused or stopped 307 | || (!currentTrack) || (!readyForData())) { 308 | return; // paused or stopped 309 | } 310 | 311 | // Feed the hungry buffer! :) 312 | while (readyForData()) { 313 | // Read some audio data from the SD card file 314 | int bytesread = currentTrack.read(mp3buffer, VS1053_DATABUFFERLEN); 315 | 316 | if (bytesread == 0) { 317 | // must be at the end of the file 318 | if (_loopPlayback) { 319 | // play in loop 320 | if (isMP3File(currentTrack.name())) { 321 | currentTrack.seek(mp3_ID3Jumper(currentTrack)); 322 | } else { 323 | currentTrack.seek(0); 324 | } 325 | } else { 326 | // wrap it up! 327 | playingMusic = false; 328 | currentTrack.close(); 329 | break; 330 | } 331 | } 332 | 333 | playData(mp3buffer, bytesread); 334 | } 335 | } 336 | 337 | // get current playback speed. 0 or 1 indicates normal speed 338 | uint16_t Adafruit_VS1053_FilePlayer::getPlaySpeed() { 339 | if (usingInterrupts) 340 | noInterrupts(); 341 | sciWrite(VS1053_SCI_WRAMADDR, VS1053_PARA_PLAYSPEED); 342 | uint16_t speed = sciRead(VS1053_SCI_WRAM); 343 | interrupts(); 344 | return speed; 345 | } 346 | 347 | // set playback speed: 0 or 1 for normal speed, 2 for 2x, 3 for 3x, etc. 348 | void Adafruit_VS1053_FilePlayer::setPlaySpeed(uint16_t speed) { 349 | if (usingInterrupts) 350 | noInterrupts(); 351 | sciWrite(VS1053_SCI_WRAMADDR, VS1053_PARA_PLAYSPEED); 352 | sciWrite(VS1053_SCI_WRAM, speed); 353 | interrupts(); 354 | } 355 | 356 | /***************************************************************/ 357 | 358 | /* VS1053 'low level' interface */ 359 | 360 | Adafruit_VS1053::Adafruit_VS1053(int8_t mosi, int8_t miso, int8_t clk, 361 | int8_t rst, int8_t cs, int8_t dcs, 362 | int8_t dreq) { 363 | _mosi = mosi; 364 | _miso = miso; 365 | _clk = clk; 366 | _reset = rst; 367 | _cs = cs; 368 | _dcs = dcs; 369 | _dreq = dreq; 370 | 371 | useHardwareSPI = false; 372 | } 373 | 374 | Adafruit_VS1053::Adafruit_VS1053(int8_t rst, int8_t cs, int8_t dcs, 375 | int8_t dreq) { 376 | _mosi = 0; 377 | _miso = 0; 378 | _clk = 0; 379 | useHardwareSPI = true; 380 | _reset = rst; 381 | _cs = cs; 382 | _dcs = dcs; 383 | _dreq = dreq; 384 | } 385 | 386 | void Adafruit_VS1053::applyPatch(const uint16_t *patch, uint16_t patchsize) { 387 | uint16_t i = 0; 388 | 389 | // Serial.print("Patch size: "); Serial.println(patchsize); 390 | while (i < patchsize) { 391 | uint16_t addr, n, val; 392 | 393 | addr = pgm_read_word(patch++); 394 | n = pgm_read_word(patch++); 395 | i += 2; 396 | 397 | // Serial.println(addr, HEX); 398 | if (n & 0x8000U) { // RLE run, replicate n samples 399 | n &= 0x7FFF; 400 | val = pgm_read_word(patch++); 401 | i++; 402 | while (n--) { 403 | sciWrite(addr, val); 404 | } 405 | } else { // Copy run, copy n samples 406 | while (n--) { 407 | val = pgm_read_word(patch++); 408 | i++; 409 | sciWrite(addr, val); 410 | } 411 | } 412 | } 413 | } 414 | 415 | uint16_t Adafruit_VS1053::loadPlugin(char *plugname) { 416 | 417 | File plugin = SD.open(plugname); 418 | if (!plugin) { 419 | Serial.println("Couldn't open the plugin file"); 420 | Serial.println(plugin); 421 | return 0xFFFF; 422 | } 423 | 424 | if ((plugin.read() != 'P') || (plugin.read() != '&') || 425 | (plugin.read() != 'H')) 426 | return 0xFFFF; 427 | 428 | uint16_t type; 429 | 430 | // Serial.print("Patch size: "); Serial.println(patchsize); 431 | while ((type = plugin.read()) >= 0) { 432 | uint16_t offsets[] = {0x8000UL, 0x0, 0x4000UL}; 433 | uint16_t addr, len; 434 | 435 | // Serial.print("type: "); Serial.println(type, HEX); 436 | 437 | if (type >= 4) { 438 | plugin.close(); 439 | return 0xFFFF; 440 | } 441 | 442 | len = plugin.read(); 443 | len <<= 8; 444 | len |= plugin.read() & ~1; 445 | addr = plugin.read(); 446 | addr <<= 8; 447 | addr |= plugin.read(); 448 | // Serial.print("len: "); Serial.print(len); 449 | // Serial.print(" addr: $"); Serial.println(addr, HEX); 450 | 451 | if (type == 3) { 452 | // execute rec! 453 | plugin.close(); 454 | return addr; 455 | } 456 | 457 | // set address 458 | sciWrite(VS1053_REG_WRAMADDR, addr + offsets[type]); 459 | // write data 460 | do { 461 | uint16_t data; 462 | data = plugin.read(); 463 | data <<= 8; 464 | data |= plugin.read(); 465 | sciWrite(VS1053_REG_WRAM, data); 466 | } while ((len -= 2)); 467 | } 468 | 469 | plugin.close(); 470 | return 0xFFFF; 471 | } 472 | 473 | boolean Adafruit_VS1053::readyForData(void) { return digitalRead(_dreq); } 474 | 475 | void Adafruit_VS1053::playData(uint8_t *buffer, uint8_t buffsiz) { 476 | spi_dev_data->write(buffer, buffsiz); 477 | } 478 | 479 | void Adafruit_VS1053::setVolume(uint8_t left, uint8_t right) { 480 | // accepts values between 0 and 255 for left and right. 481 | uint16_t v; 482 | v = left; 483 | v <<= 8; 484 | v |= right; 485 | 486 | if (usingInterrupts) 487 | noInterrupts(); // cli(); 488 | 489 | sciWrite(VS1053_REG_VOLUME, v); 490 | 491 | interrupts(); // sei(); 492 | } 493 | 494 | uint16_t Adafruit_VS1053::decodeTime() { 495 | if (usingInterrupts) 496 | noInterrupts(); 497 | uint16_t t = sciRead(VS1053_REG_DECODETIME); 498 | interrupts(); // sei(); 499 | return t; 500 | } 501 | 502 | void Adafruit_VS1053::softReset(void) { 503 | sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_SDINEW | VS1053_MODE_SM_RESET); 504 | delay(100); 505 | } 506 | 507 | void Adafruit_VS1053::reset() { 508 | // TODO: 509 | // http://www.vlsi.fi/player_vs1011_1002_1003/modularplayer/vs10xx_8c.html#a3 510 | // hardware reset 511 | if (_reset >= 0) { 512 | digitalWrite(_reset, LOW); 513 | delay(100); 514 | digitalWrite(_reset, HIGH); 515 | } 516 | 517 | delay(100); 518 | softReset(); 519 | delay(100); 520 | 521 | sciWrite(VS1053_REG_CLOCKF, 0x6000); 522 | 523 | setVolume(40, 40); 524 | } 525 | 526 | uint8_t Adafruit_VS1053::begin(void) { 527 | if (_reset >= 0) { 528 | pinMode(_reset, OUTPUT); 529 | digitalWrite(_reset, LOW); 530 | } 531 | 532 | pinMode(_dreq, INPUT); 533 | 534 | if (useHardwareSPI) { 535 | spi_dev_ctrl = new Adafruit_SPIDevice(_cs, 250000, SPI_BITORDER_MSBFIRST, 536 | SPI_MODE0, &SPI); 537 | spi_dev_data = new Adafruit_SPIDevice(_dcs, 8000000, SPI_BITORDER_MSBFIRST, 538 | SPI_MODE0, &SPI); 539 | } else { 540 | spi_dev_ctrl = new Adafruit_SPIDevice(_cs, _clk, _miso, _mosi, 250000, 541 | SPI_BITORDER_MSBFIRST, SPI_MODE0); 542 | spi_dev_data = new Adafruit_SPIDevice(_dcs, _clk, _miso, _mosi, 8000000, 543 | SPI_BITORDER_MSBFIRST, SPI_MODE0); 544 | } 545 | spi_dev_ctrl->begin(); 546 | spi_dev_data->begin(); 547 | 548 | reset(); 549 | 550 | return (sciRead(VS1053_REG_STATUS) >> 4) & 0x0F; 551 | } 552 | 553 | void Adafruit_VS1053::dumpRegs(void) { 554 | Serial.print("Mode = 0x"); 555 | Serial.println(sciRead(VS1053_REG_MODE), HEX); 556 | Serial.print("Stat = 0x"); 557 | Serial.println(sciRead(VS1053_REG_STATUS), HEX); 558 | Serial.print("ClkF = 0x"); 559 | Serial.println(sciRead(VS1053_REG_CLOCKF), HEX); 560 | Serial.print("Vol. = 0x"); 561 | Serial.println(sciRead(VS1053_REG_VOLUME), HEX); 562 | } 563 | 564 | uint16_t Adafruit_VS1053::recordedWordsWaiting(void) { 565 | return sciRead(VS1053_REG_HDAT1); 566 | } 567 | 568 | uint16_t Adafruit_VS1053::recordedReadWord(void) { 569 | return sciRead(VS1053_REG_HDAT0); 570 | } 571 | 572 | boolean Adafruit_VS1053::prepareRecordOgg(char *plugname) { 573 | sciWrite(VS1053_REG_CLOCKF, 0xC000); // set max clock 574 | delay(1); 575 | while (!readyForData()) 576 | ; 577 | 578 | sciWrite(VS1053_REG_BASS, 0); // clear Bass 579 | 580 | softReset(); 581 | delay(1); 582 | while (!readyForData()) 583 | ; 584 | 585 | sciWrite(VS1053_SCI_AIADDR, 0); 586 | // disable all interrupts except SCI 587 | sciWrite(VS1053_REG_WRAMADDR, VS1053_INT_ENABLE); 588 | sciWrite(VS1053_REG_WRAM, 0x02); 589 | 590 | int pluginStartAddr = loadPlugin(plugname); 591 | if (pluginStartAddr == 0xFFFF) 592 | return false; 593 | Serial.print("Plugin at $"); 594 | Serial.println(pluginStartAddr, HEX); 595 | if (pluginStartAddr != 0x34) 596 | return false; 597 | 598 | return true; 599 | } 600 | 601 | void Adafruit_VS1053::stopRecordOgg(void) { sciWrite(VS1053_SCI_AICTRL3, 1); } 602 | 603 | void Adafruit_VS1053::startRecordOgg(boolean mic) { 604 | /* Set VS1053 mode bits as instructed in the VS1053b Ogg Vorbis Encoder 605 | manual. Note: for microphone input, leave SMF_LINE1 unset! */ 606 | if (mic) { 607 | sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_ADPCM | VS1053_MODE_SM_SDINEW); 608 | } else { 609 | sciWrite(VS1053_REG_MODE, VS1053_MODE_SM_LINE1 | VS1053_MODE_SM_ADPCM | 610 | VS1053_MODE_SM_SDINEW); 611 | } 612 | sciWrite(VS1053_SCI_AICTRL0, 1024); 613 | /* Rec level: 1024 = 1. If 0, use AGC */ 614 | sciWrite(VS1053_SCI_AICTRL1, 1024); 615 | /* Maximum AGC level: 1024 = 1. Only used if SCI_AICTRL1 is set to 0. */ 616 | sciWrite(VS1053_SCI_AICTRL2, 0); 617 | /* Miscellaneous bits that also must be set before recording. */ 618 | sciWrite(VS1053_SCI_AICTRL3, 0); 619 | 620 | sciWrite(VS1053_SCI_AIADDR, 0x34); 621 | delay(1); 622 | while (!readyForData()) 623 | ; 624 | } 625 | 626 | void Adafruit_VS1053::GPIO_pinMode(uint8_t i, uint8_t dir) { 627 | if (i > 7) 628 | return; 629 | 630 | sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_DDR); 631 | uint16_t ddr = sciRead(VS1053_REG_WRAM); 632 | 633 | if (dir == INPUT) 634 | ddr &= ~_BV(i); 635 | if (dir == OUTPUT) 636 | ddr |= _BV(i); 637 | 638 | sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_DDR); 639 | sciWrite(VS1053_REG_WRAM, ddr); 640 | } 641 | 642 | void Adafruit_VS1053::GPIO_digitalWrite(uint8_t val) { 643 | sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_ODATA); 644 | sciWrite(VS1053_REG_WRAM, val); 645 | } 646 | 647 | void Adafruit_VS1053::GPIO_digitalWrite(uint8_t i, uint8_t val) { 648 | if (i > 7) 649 | return; 650 | 651 | sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_ODATA); 652 | uint16_t pins = sciRead(VS1053_REG_WRAM); 653 | 654 | if (val == LOW) 655 | pins &= ~_BV(i); 656 | if (val == HIGH) 657 | pins |= _BV(i); 658 | 659 | sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_ODATA); 660 | sciWrite(VS1053_REG_WRAM, pins); 661 | } 662 | 663 | uint16_t Adafruit_VS1053::GPIO_digitalRead(void) { 664 | sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_IDATA); 665 | return sciRead(VS1053_REG_WRAM) & 0xFF; 666 | } 667 | 668 | boolean Adafruit_VS1053::GPIO_digitalRead(uint8_t i) { 669 | if (i > 7) 670 | return 0; 671 | 672 | sciWrite(VS1053_REG_WRAMADDR, VS1053_GPIO_IDATA); 673 | uint16_t val = sciRead(VS1053_REG_WRAM); 674 | if (val & _BV(i)) 675 | return true; 676 | return false; 677 | } 678 | 679 | uint16_t Adafruit_VS1053::sciRead(uint8_t addr) { 680 | uint8_t buffer[2] = {VS1053_SCI_READ, addr}; 681 | spi_dev_ctrl->write_then_read(buffer, 2, buffer, 2); 682 | return (uint16_t(buffer[0]) << 8) | uint16_t(buffer[1]); 683 | } 684 | 685 | void Adafruit_VS1053::sciWrite(uint8_t addr, uint16_t data) { 686 | uint8_t buffer[4] = {VS1053_SCI_WRITE, addr, uint8_t(data >> 8), 687 | uint8_t(data & 0xFF)}; 688 | spi_dev_ctrl->write(buffer, 4); 689 | } 690 | 691 | void Adafruit_VS1053::sineTest(uint8_t n, uint16_t ms) { 692 | reset(); 693 | 694 | uint16_t mode = sciRead(VS1053_REG_MODE); 695 | mode |= 0x0020; 696 | sciWrite(VS1053_REG_MODE, mode); 697 | 698 | while (!digitalRead(_dreq)) 699 | ; 700 | // delay(10); 701 | 702 | uint8_t sine_start[8] = {0x53, 0xEF, 0x6E, n, 0x00, 0x00, 0x00, 0x00}; 703 | uint8_t sine_stop[8] = {0x45, 0x78, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00}; 704 | 705 | spi_dev_data->write(sine_start, 8); 706 | delay(ms); 707 | spi_dev_data->write(sine_stop, 8); 708 | } 709 | --------------------------------------------------------------------------------