|
|
本帖最后由 dash1982 于 2013-8-24 08:18 编辑
在《基于VS1003和SD卡的MP3播放器》中已经完成了MP3播放器的雏形。然而该播放器只是简单的顺序播放,无法实现随机播放/切歌/音量调节/音质调节等功能。本帖将实现这些需求。
本帖实现的MP3读取并解析从串口的命令,执行相应的工作。
主要功能如下:
[n] to jump to next Song // 播放下一首
[+ or -] to change volume // +, 增加音量;- 减少音量
retrieve current audio information (partial list) // i 获得当前播放音频信息
[p] to pause. //暂停,恢复
[r] resumes play from 2s from begin of file // 重放
[R] Resets and initializes VS10xx chip. //重启VS1003板
[M] Toggle between Mono and Stereo Output. //切换立体声模式
[g] Skip to a predetermined offset of ms in current track. // 越过相应时间播放
[k] Skip a predetermined number of ms in current track. //越过特定时间
[O} turns OFF the VS10xx into low power reset. //重启VS1003
[o} turns ON the VS10xx out of low power reset. //启动VS1003
[D] to toggle SM_DIFF between inphase and differential output // 切换DIFF模式
[h] this help // 打印此帮助菜单
先决条件:
需要用到Sparkfun mp3 Shield的库,sparkfun的mp3板也是基于VS1003的,直接把它拿来用就是了。
介绍:
www.billporter.info/2012/01/28/sparkfun-mp3-shield-arduino-library/
库下载地址:
https://github.com/madsci1016/Sparkfun-MP3-Player-Shield-Arduino-Library
下载完后,解压缩,而后将目录下的SFEMP3Shield整个目录拷贝到你的arduino安装目录的libraries下。SFEMP3Shield包括了SdFat等,但是我们已经在第一个帖子中用到过SdFat库,就不需要重复操作了。从github下载来的档案中同时也含有vs1003的Dsp设置文件,都放置在plugin目录中,这些都不需要。
拷贝完毕后你的ardino安装目录下libraries看起来应该和下面差不多(ArchLinux为例), pwd返回当前工作目录,tree则显示出当前目录树结构:
$ pwd
/media/y/arduino/1.0.5/libraries/SFEMP3Shield
$ tree
.
|-- Examples
| |-- FilePlayer
| | `-- FilePlayer.ino
| |-- MP3Shield_Library_Demo
| | `-- MP3Shield_Library_Demo.ino
| `-- WebPlayer
| `-- WebPlayer.ino
|-- keywords.txt
|-- SFEMP3ShieldConfig.h
|-- SFEMP3Shield.cpp
|-- SFEMP3Shield.h
`-- SFEMP3Shieldmainpage.h
4 directories, 8 files
接下来需要对SFEMP3Shield.h进行一些参数上的修改,我直接定义了一个宏,用于标识自己使用的MP3模块的接线图:
修改:
- #if ( SEEEDUINO == 1 )
- #define MP3_XCS A3 //Control Chip Select Pin (for accessing SPI Control/Status registers)
- #define MP3_XDCS A2 //Data Chip Select / BSYNC Pin
- #define MP3_DREQ A1 //Data Request Pin: Player asks for more data
- //#define MP3_DREQINT 0 // There is no IRQ used on Seeduino
- #define MP3_RESET A0 //Reset is active low
- #define SD_SEL 10 //select pin for SD card
- #else // otherwise use pinout of typical Sparkfun MP3 Player Shield.
- #define MP3_XCS 6 //Control Chip Select Pin (for accessing SPI Control/Status registers)
- #define MP3_XDCS 7 //Data Chip Select / BSYNC Pin
- #define MP3_DREQ 2 //Data Request Pin: Player asks for more data
- #if defined(__AVR_ATmega32U4__)
- #define MP3_DREQINT 1 //Corresponding INTx for DREQ pin
- #else // swapped between Uno and Leonardo.
- #define MP3_DREQINT 0 //Corresponding INTx for DREQ pin
- #endif
- #define MP3_RESET 8 //Reset is active low
- #if ( GRAVITECH == 1 )
- #define SD_SEL 4 //select pin for SD card
- #else
- #define SD_SEL 9 //select pin for SD card
- #endif // GRAVITECH
- #endif // none SEEEDUINO
复制代码
为:
- #if ( SEEEDUINO == 1 )
- #define MP3_XCS A3 //Control Chip Select Pin (for accessing SPI Control/Status registers)
- #define MP3_XDCS A2 //Data Chip Select / BSYNC Pin
- #define MP3_DREQ A1 //Data Request Pin: Player asks for more data
- //#define MP3_DREQINT 0 // There is no IRQ used on Seeduino
- #define MP3_RESET A0 //Reset is active low
- #define SD_SEL 10 //select pin for SD card
- #elif (TAOBAO == 1)
- #define MP3_XCS 9 //Control Chip Select Pin ( For accessing SPI Control/Status registers )
- #define MP3_XDCS 6 // Data Chip Select / BSYNC Pin
- #define MP3_DREQ 2 // Data Request Pin: Player ask for more data
- #define MP3_RESET 8 // Reset is active low
- #define SD_SEL 4 // SD Card Selection
- #define MP3_DREQINT 0 //Corresponding INTx for DREQ pin
- #else // otherwise use pinout of typical Sparkfun MP3 Player Shield.
- #define MP3_XCS 6 //Control Chip Select Pin (for accessing SPI Control/Status registers)
- #define MP3_XDCS 7 //Data Chip Select / BSYNC Pin
- #define MP3_DREQ 2 //Data Request Pin: Player asks for more data
- #if defined(__AVR_ATmega32U4__)
- #define MP3_DREQINT 1 //Corresponding INTx for DREQ pin
- #else // swapped between Uno and Leonardo.
- #define MP3_DREQINT 0 //Corresponding INTx for DREQ pin
- #endif
- #define MP3_RESET 8 //Reset is active low
- #if ( GRAVITECH == 1 )
- #define SD_SEL 4 //select pin for SD card
- #else
- #define SD_SEL 9 //select pin for SD card
- #endif // GRAVITECH
- #endif // none SEEEDUINO
复制代码
这个改动很简单,就是单纯的加入从淘宝上买回来的MP3模块的接线而已。于是我们需要在SFEMP3Shield.h的开头定义一下TAOBAO这个变量,比如我就直接在原有文件里加了行:
- #define GRAVITECH 0 // uncomment if using the Gravitech's MP3-4NANO shield
- #define TAOBAO 1 // uncomment if you using the shield bought from taobao.
复制代码
按照《基于VS1003和SD卡的MP3播放器》里的接线图亦需要做一个改动,我们需要把MP3模块的DREQ口接到arduino nano的D2口上。因为我们修改了如下定义:
- #define MP3_DREQ 2 // Data Request Pin: Player ask for more data
复制代码
与上篇帖子不同的是:本帖中的实现方案,使用arduino板的中断来实时更新需要发送给VS1003的数据。查数据手册可知,arduino nano上使用了D2口为中断0, 而我们Fill vs1003数据段使用了中断0的方式,因而需要把DREQ从以前的D7换到D2。
SFEMP3Shield.cpp亦需要做少许改动:
Ln 217,
- if(MP3Mode != (SM_LINE1 | SM_SDINEW)) return 4;
复制代码
改为:
- if(MP3Mode != (SM_SDINEW )) return 4;
复制代码
再注释掉Ln 235:
- if(VSLoadUserCode("patches.053")) return 6;
复制代码
为:
- // if(VSLoadUserCode("patches.053")) return 6;
复制代码
做这些改动是因为从淘宝上购得的板子输入不是走SM_LINE1, 且不需要加载默认的patches文件给DSP即可工作。
优点
1. 中断方式喂(feed) vs1003,效率比上个版本更高,384KBPS支持无压力。
2. 串口交互实现功能控制,高阶功能均可衍生开发之。
、
局限
1. 文件尺寸可以把nano的Flash撑到25,254 bytes (of a 30,720 byte maximum), 后续需要添加功能(液晶显示,控制按钮等)就得很小心了。
2. 默认进入随机播放状态。顺序播放状态支持是不难的事,设置个全局变量记录下当前播放曲目而已,将在下个版本中加以修正。
3. 'n'可进入下一首,然而上一首功能暂时无法实现 ,因为随机播放每次产生的数值都是随机数。顺序播放时很容易记住当前曲目并前进/后退到相应曲目,随机播放则是无法预知,故暂不支持’上一首‘播放。。
代码
打开arduino IDE界面,输入以下代码,编译运行即可, 在打开的串口监视器窗口中,输入对应的命令即可实现对应的功能:
- /*
- * This sketch will list all files in the root directory and
- * then do a recursive list of all directories on the SD card.
- * Only the mp3 files will be listed in the original playlist.
- * Then we use original Playlist to generate the actual Playlist.
- * Then feeding VS1003 with the bytes read from the mp3 file.
- *
- */
- #include <SdFat.h>
- #include <SdFatUtil.h>
- #include <SdFile.h>
- #include <SPI.h>
- // MP3 Shield Library
- #include <SFEMP3Shield.h>
- // SD FileSystem Object
- SdFat sd;
- SdFile file; // General Operating file
- /* Object instancing the SFEMP3Shield library
- * object for handling all the atrributes, members and functions of the library .
- */
- SFEMP3Shield MP3player;
- short songnumbers = 0; // songs in SD Card
- short open_count = 0; // open_count is for holding the opencounts in genOrigListFile()
- short totalsongs = 0; // totalsongs in playlist.
- // Variable for holding the latest timestamp
- uint16_t latestWriteTime = 0;
- uint16_t latestWriteDate = 0;
- ///////////////////////////////////////////////////////////////////////////
- // SD Operations
- ///////////////////////////////////////////////////////////////////////////
- /* This function is for generating the original mp3 list */
- /* mp3 list file will use the latest timestamp in SD Card */
- short genOrigListFile(const char *f, SdBaseFile * dir, int numTabs) {
- // entry is for recording the file information
- SdFile entry;
- // length is 8(filename)+1(.)+3(suffix)+1(NUL) == 13
- char filename[13];
- /* Create file from "f" for recording the result */
- open_count++;
- if(!file.isOpen())
- {
- /* Create one */
- if(!file.open(f, O_CREAT | O_TRUNC | O_WRITE))
- {
- /* Create failed will return 3 */
- return 3;
- }
- }
- // Set the file's current position to zero
- dir->rewind();
- // open Next item, until the end of the world.
- while(entry.openNext(dir, O_READ)) {
- // If this entry is a sub-directory, Print itself and sub-entries
- if(entry.isSubDir())
- {
- // Use spaces for indicating the directory layers.
- for(uint8_t i=0; i < numTabs; i++) {
- //Serial.print(" ");
- file.write(" ");
- }
- memset(filename, '\0', 13);
- entry.getFilename(filename);
- uint8_t lastchar = strlen(filename);
- filename[lastchar]='/';
- file.write(filename);
- file.write("\r\n");
- dir_t dir_time;
- entry.dirEntry(&dir_time);
- if((dir_time.lastWriteDate > latestWriteDate))
- {
- latestWriteDate = dir_time.lastWriteDate;
- latestWriteTime = dir_time.lastWriteTime;
- }
- if((dir_time.lastWriteDate == latestWriteDate))
- {
- if(dir_time.lastWriteTime > latestWriteTime)
- {
- latestWriteTime = dir_time.lastWriteTime;
- }
- }
- // Get the current index, use this index for recursively print the sub-directories
- uint16_t index = dir->curPosition()/32 -1;
- SdBaseFile s;
- if(s.open(dir, index, O_READ))
- {
- if(numTabs <=2 )
- {
- genOrigListFile(f, &s, numTabs + 1);
- }
- }
- entry.close();
- }
- // Common files will directly be displayed.
- else
- {
- // Calculate how many MP3 exists in SD card.
- memset(filename, '\0', 13);
- entry.getFilename(filename);
- if((filename[strlen(filename)-3] == 'M') &&
- (filename[strlen(filename)-2] == 'P') &&
- (filename[strlen(filename)-1] == '3'))
- {
- // Use spaces for indicating the directory layers.
- for(uint8_t i=0; i < numTabs; i++) {
- file.write(" ");
- }
- file.write(filename);
- file.write("\r\n");
- dir_t dir_time;
- entry.dirEntry(&dir_time);
- if((dir_time.lastWriteDate > latestWriteDate))
- {
- latestWriteDate = dir_time.lastWriteDate;
- latestWriteTime = dir_time.lastWriteTime;
- }
- if((dir_time.lastWriteDate == latestWriteDate))
- {
- if(dir_time.lastWriteTime > latestWriteTime)
- {
- latestWriteTime = dir_time.lastWriteTime;
- }
- }
- }
- entry.close();
- }
- }
- // open_count will decrease for avoiding open it several times.
- open_count--;
- // Close opened file at the end of all routine, failed if we received 4.
- if(open_count == 0)
- {
- // update the timestamp.
- dir_t dir_play;
- file.dirEntry(&dir_play);
- // Update the timestamp for generated file. later we will use this timestamp for updating.
- if (!file.timestamp(T_WRITE, (1980+(latestWriteDate>>9)), ((latestWriteDate>>5)&0XF), (latestWriteDate & 0X1F), (latestWriteTime >> 11), ((latestWriteTime >> 5) & 0X3F), ((latestWriteTime & 0X1F)*2)))
- {
- //Serial.println("set Write time Failed");
- }
- file.sync();
- if(!file.close())
- {
- return 4;
- }
- }
- return 0;
- }
- /* This function will get raw file list from Original file
- * then output with the full name to the dest file */
- short genPlayList(const char *src, const char *dest)
- {
- char *str = NULL;
- short n=0;
- short SpaceCounts, i, j, k;
- char *dirname[4] = {
- 0 };
- // 10 layers means (8+1)*10layer+13(file)
- char *prefix = NULL; //(char *)malloc(9*4 + 13);
- file.open(src, O_READ);
- if(!file.isOpen())
- {
- return 1;
- }
- // pl == PlayList file
- SdFile plfile(dest, O_CREAT | O_TRUNC | O_WRITE);
- if(!plfile.isOpen())
- {
- return 2;
- }
- for( j = 0; j < 4; j++)
- {
- // malloc size is 8(dir name) + 1("/") + 1(NULL) = 10
- dirname[j] = (char *)malloc(10);
- }
- str = (char *)malloc(100);
- prefix = (char *)malloc(9*4 + 13);
- while((n = file.fgets(str, sizeof(str))) > 0)
- {
- // Change the '\r' to the NUL, means the end of the string.
- short len = strlen(str) -1;
- if(str[len] == '\n')
- {
- str[len] = 0;
- }
- if(str[len -1] == '\r')
- {
- str[len - 1] = 0;
- }
- SpaceCounts = 0;
- for( i = 0; i < strlen(str); i++)
- {
- if(str[i] == ' ')
- {
- SpaceCounts++;
- }
- }
- // Directly print the MP3 files under the root directory
- if((!strncmp(str+strlen(str)-3, "MP3", 4)) && (SpaceCounts == 0))
- {
- plfile.write(str);
- plfile.write("\r\n");
- }
- // Processing directory entries
- if(str[strlen(str) - 1] == '/')
- {
- // Remove the SpaceCounts and copy the rest of the name into string array dirname[]
- strcpy(dirname[(SpaceCounts/2)], (char *)(str+SpaceCounts));
- }
- // Print the MP3 which locates in sub-directories
- if((SpaceCounts >= 2) && (str[strlen(str) - 1] != '/'))
- {
- memset(prefix, '\0', 9*4 + 13);
- for( k = 0; k <= (SpaceCounts/2); k++ )
- {
- strcat(prefix, dirname[k]);
- }
- strcat(prefix, str+SpaceCounts);
- plfile.write(prefix, strlen(prefix));
- plfile.write("\r\n");
- delay(10);
- }
- } // end of while()
- for(j = 0; j < 4; j++)
- {
- free(dirname[j]);
- }
- free(str);
- free(prefix);
- // Generate the real player file.
- if(!file.close())
- {
- return 5;
- }
- if(!plfile.close())
- {
- return 6;
- }
- return 0;
- }
- /* This function is for scanning all of the directories and sub-items
- * to fetch the latest timestamp, we will use the latest timestamp for
- * judging update playlist or not
- */
- void getLatestStamp(SdBaseFile * dir, short numTabs) {
- // entry is for recording the file information
- SdFile entry;
- // length is 8(filename)+1(.)+3(suffix)+1(NUL) == 13
- char filename[13];
- // open Next item, until the end of the world.
- while(entry.openNext(dir, O_READ)) {
- // If this entry is a sub-directory, Print itself and sub-entries
- if(entry.isSubDir())
- {
- // Get the latest timestamp of the directory.
- dir_t dir_time;
- entry.dirEntry(&dir_time);
- if((dir_time.lastWriteDate > latestWriteDate))
- {
- latestWriteDate = dir_time.lastWriteDate;
- latestWriteTime = dir_time.lastWriteTime;
- }
- if((dir_time.lastWriteDate == latestWriteDate))
- {
- if(dir_time.lastWriteTime > latestWriteTime)
- {
- latestWriteTime = dir_time.lastWriteTime;
- }
- }
- // Get the current index, use this index for recursively print the sub-directories
- uint16_t index = dir->curPosition()/32 -1;
- SdBaseFile s;
- if(s.open(dir, index, O_READ))
- {
- if(numTabs <=2) getLatestStamp(&s, numTabs + 1);
- }
- entry.close();
- }
- // Common files goes here.
- else
- {
- // Calculate how many MP3 exists in SD card.
- entry.getFilename(filename);
- if((filename[strlen(filename)-3] == 'M') &&
- (filename[strlen(filename)-2] == 'P') &&
- (filename[strlen(filename)-1] == '3'))
- {
- // Get the latest timestamp of the directory.
- dir_t dir_time;
- entry.dirEntry(&dir_time);
- if((dir_time.lastWriteDate > latestWriteDate))
- {
- latestWriteDate = dir_time.lastWriteDate;
- latestWriteTime = dir_time.lastWriteTime;
- }
- if((dir_time.lastWriteDate == latestWriteDate))
- {
- if(dir_time.lastWriteTime > latestWriteTime)
- {
- latestWriteTime = dir_time.lastWriteTime;
- }
- }
- }
- entry.close();
- }
- }
- }
- /* This function will get the file's timestamp, we want to
- * fetch the orginal playlist's timestamp, use it to judging update
- * playlist or not.
- */
- short getfileStamp(const char *f, uint16_t *date, uint16_t *time)
- {
- SdFile localfile(f, O_READ);
- if(!localfile.isOpen())
- {
- //Serial.println("Open Local File Failed!");
- return 2;
- }
- // Get the latest timestamp of the directory.
- dir_t dir_time;
- localfile.dirEntry(&dir_time);
- *date = dir_time.lastWriteDate;
- *time = dir_time.lastWriteTime;
- if(!localfile.close())
- {
- return 4;
- }
- return 0;
- }
- /* This function is for getting the numbers in PlayList */
- short getListLength(char *playlistfile)
- {
- short tmpnum = 0;
- char line[25];
- int n;
- delay(100);
- // Read Items from the Playlist file.
- // open PlayList file
- SdFile rdfile(playlistfile, O_READ);
- if (!rdfile.isOpen())
- {
- //Serial.println("Open PlayList Failed!");
- /* Actually 9999 is not good */
- return 9999;
- }
- // read lines from the file
- while ((n = rdfile.fgets(line, sizeof(line))) > 0)
- {
- if (line[n - 1] == '\n')
- {
- tmpnum++;
- }
- else
- {
- ;
- }
- }
- rdfile.close();
- return tmpnum;
- }
- void selectSong(char *playlistfile, char *song, short select_number)
- {
- short tmpnum = select_number;
- char line[50];
- int n;
- delay(100);
- // Read Items from the Playlist file.
- // open PlayList file
- SdFile rdfile(playlistfile, O_READ);
- if (!rdfile.isOpen())
- {
- Serial.println("Open PlayList Failed!");
- return;
- }
- // read lines from the file
- while ((n = rdfile.fgets(line, sizeof(line))) > 0)
- {
- if (line[n - 1] == '\n')
- {
- tmpnum--;
- //songs_in_list++;
- }
- else
- {
- ;
- }
- if(tmpnum == 0)
- {
- strncpy(song, line, strlen(line)-1);
- song[strlen(line)-1]='\0';
- }
- }
- rdfile.close();
- }
- //------------------------------------------------------------------------------
- /**
- * \brief Decode the Menu.
- *
- * Parses through the characters of the users input, executing corresponding
- * MP3player library functions and features then displaying a brief menu and
- * prompting for next input command.
- */
- void parse_menu(byte key_command) {
- uint8_t result; // result code from some function as to be tested at later time.
- // Note these buffer may be desired to exist globably.
- // but do take much space if only needed temporarily, hence they are here.
- char title[30]; // buffer to contain the extract the Title from the current filehandles
- char artist[30]; // buffer to contain the extract the artist name from the current filehandles
- char album[30]; // buffer to contain the extract the album name from the current filehandles
- Serial.print(F("Received command: "));
- Serial.write(key_command);
- Serial.println(F(" "));
- if(key_command == 'n')
- {
- /* Since random, this next won't go back to previous playlist */
- // First stop the current playing.
- Serial.println(F("Stopping"));
- MP3player.stopTrack();
- // Then select a new song.
- char song[50];
- //randomSeed(analogRead(4));
- selectSong("PLT.TXT", song, random(1, totalsongs));
- Serial.println(song);
- // Play the selected song.
- MP3player.playMP3(song, 0);
- }
- else if((key_command == '-') || (key_command == '+')) {
- union twobyte mp3_vol; // create key_command existing variable that can be both word and double byte of left and right.
- mp3_vol.word = MP3player.getVolume(); // returns a double uint8_t of Left and Right packed into int16_t
- if(key_command == '-') { // note dB is negative
- // assume equal balance and use byte[1] for math
- if(mp3_vol.byte[1] >= 254) { // range check
- mp3_vol.byte[1] = 254;
- }
- else {
- mp3_vol.byte[1] += 2; // keep it simpler with whole dB's
- }
- }
- else {
- if(mp3_vol.byte[1] <= 2) { // range check
- mp3_vol.byte[1] = 2;
- }
- else {
- mp3_vol.byte[1] -= 2;
- }
- }
- // push byte[1] into both left and right assuming equal balance.
- MP3player.setVolume(mp3_vol.byte[1], mp3_vol.byte[1]); // commit new volume
- Serial.print(F("Volume changed to -"));
- Serial.print(mp3_vol.byte[1]>>1, 1);
- Serial.println(F("[dB]"));
- }
- else if(key_command == 'i') {
- MP3player.getAudioInfo();
- }
- else if(key_command == 'p') {
- if( MP3player.getState() == playback) {
- MP3player.pauseMusic();
- Serial.println(F("Pausing"));
- }
- else if( MP3player.getState() == paused_playback) {
- MP3player.resumeMusic();
- Serial.println(F("Resuming"));
- }
- else {
- Serial.println(F("Not Playing!"));
- }
- }
- else if(key_command == 'R') {
- MP3player.stopTrack();
- MP3player.vs_init();
- Serial.println(F("Reseting VS10xx chip"));
- }
- else if(key_command == 'M') {
- uint16_t monostate = MP3player.getMonoMode();
- Serial.print(F("Mono Mode "));
- if(monostate == 0) {
- MP3player.setMonoMode(1);
- Serial.println(F("Enabled."));
- }
- else {
- MP3player.setMonoMode(0);
- Serial.println(F("Disabled."));
- }
- }
- else if(key_command == 'g') {
- int32_t offset_ms = 20000; // Note this is just an example, try your own number.
- Serial.print(F("jumping to "));
- Serial.print(offset_ms, DEC);
- Serial.println(F("[milliseconds]"));
- result = MP3player.skipTo(offset_ms);
- if(result != 0) {
- Serial.print(F("Error code: "));
- Serial.print(result);
- Serial.println(F(" when trying to skip track"));
- }
- }
- else if(key_command == 'k') {
- int32_t offset_ms = -1000; // Note this is just an example, try your own number.
- Serial.print(F("moving = "));
- Serial.print(offset_ms, DEC);
- Serial.println(F("[milliseconds]"));
- result = MP3player.skip(offset_ms);
- if(result != 0) {
- Serial.print(F("Error code: "));
- Serial.print(result);
- Serial.println(F(" when trying to skip track"));
- }
- }
- else if(key_command == 'O') {
- MP3player.end();
- Serial.println(F("VS10xx placed into low power reset mode."));
- }
- else if(key_command == 'o') {
- MP3player.begin();
- Serial.println(F("VS10xx restored from low power reset mode."));
- }
- else if(key_command == 'D') {
- uint16_t diff_state = MP3player.getDifferentialOutput();
- Serial.print(F("Differential Mode "));
- if(diff_state == 0) {
- MP3player.setDifferentialOutput(1);
- Serial.println(F("Enabled."));
- }
- else {
- MP3player.setDifferentialOutput(0);
- Serial.println(F("Disabled."));
- }
- }
- else if(key_command == 'h') {
- help();
- }
- // print prompt after key stroke has been processed.
- Serial.println(F("Enter n,+,-,i,p,r,R,M,g,k,h,O,o,D,S :"));
- }
- //------------------------------------------------------------------------------
- /**
- * \brief Print Help Menu.
- *
- * Prints a full menu of the commands available along with descriptions.
- */
- void help() {
- Serial.println(F("Arduino SFEMP3Shield Library Example:"));
- Serial.println(F(" courtesy of Bill Porter & Michael P. Flaga"));
- Serial.println(F("COMMANDS:"));
- Serial.println(F(" [n] to jump to next Song"));
- Serial.println(F(" [+ or -] to change volume"));
- Serial.println(F(" [i] retrieve current audio information (partial list)"));
- Serial.println(F(" [p] to pause."));
- Serial.println(F(" [r] resumes play from 2s from begin of file"));
- Serial.println(F(" [R] Resets and initializes VS10xx chip."));
- Serial.println(F(" [M] Toggle between Mono and Stereo Output."));
- Serial.println(F(" [g] Skip to a predetermined offset of ms in current track."));
- Serial.println(F(" [k] Skip a predetermined number of ms in current track."));
- Serial.println(F(" [O} turns OFF the VS10xx into low power reset."));
- Serial.println(F(" [o} turns ON the VS10xx out of low power reset."));
- Serial.println(F(" [D] to toggle SM_DIFF between inphase and differential output"));
- Serial.println(F(" [h] this help"));
- }
- void setup()
- {
- bool updateflag = 0;
- delay(10);
- Serial.begin(9600);
- // See Free RAM
- PgmPrint("Free RAM: ");
- Serial.println(FreeRam());
- // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
- // breadboards. use SPI_FULL_SPEED for better performance.
- digitalWrite(9,HIGH);
- delay(2000);
- if (!sd.begin(4, SPI_HALF_SPEED)) sd.initErrorHalt();
- if(!sd.chdir("/")) sd.errorHalt("sd.chdir");
- //Initialize the MP3 Player Shield
- uint8_t result = MP3player.begin();
- //check result, see readme for error codes.
- if(result != 0) {
- Serial.print(F("Error code: "));
- Serial.print(result);
- Serial.println(F(" when trying to start MP3 player"));
- if( result == 6 ) {
- Serial.println(F("Warning: patch file not found, skipping.")); // can be removed for space, if needed.
- Serial.println(F("Use the "d" command to verify SdCard can be read")); // can be removed for space, if needed.
- }
- }
- // Start at beginning of the root directory.
- // rewind is used for set current position to zero.
- sd.vwd()->rewind();
- // 1. If no playlist file exists, scan the whole SD to generate one
- // 2. Else Check the timestamp of the playlist to see if update is needed
- // 3. If update is needed, generate playlist again.
- sd.vwd()->rewind();
- if(!sd.exists("PL_OK.TXT")) // Condition 1
- {
- Serial.println("No PL_OK.TXT found!");
- updateflag = 1;
- }
- else // Condition 2
- {
- Serial.println("PL_OK has been created, need to check its timestamp!");
- // Set global Variables to 0 for avoiding potential mis-using
- latestWriteTime = 0;
- latestWriteDate = 0;
- sd.vwd()->rewind();
- getLatestStamp(sd.vwd(), 0);
- // Get the PlayList File's timestamp, for comparing.
- uint16_t ldate = 0;
- uint16_t ltime = 0;
- short rvalue = getfileStamp("PL_OK.TXT", &ldate,<ime);
- if( (ldate == latestWriteDate) && ( ltime == latestWriteTime) )
- {
- Serial.println("PlayList is the newest version, update not needed!");
- }
- else
- {
- Serial.println("Need Update PlayList!");
- updateflag = 1;
- }
- }
- sd.vwd()->rewind();
- if(updateflag) // Condition 3, update playlist or not
- {
- // Call genOrigListFile() to fetch all of the MP3 and directory layer information
- short error_reason = genOrigListFile("PL_OK.TXT", sd.vwd(), 0);
- if(error_reason != 0)
- {
- Serial.print("genOrigListFile error number is ");
- Serial.println(error_reason);
- }
- // Call genPlayList() to generate the actual PlayList file
- error_reason = genPlayList("PL_OK.TXT", "PLT.TXT");
- if(error_reason != 0)
- {
- Serial.print("genPlayList error number is ");
- Serial.println(error_reason);
- }
- Serial.println("Generate OrigiList and PlayList Done!");
- }
- else
- {
- Serial.println("No Update!");
- }
- /* For saving space */
- totalsongs = getListLength("PLT.TXT");
- /* Generate random seed , a0 will be a random variable*/
- randomSeed(analogRead(0));
- Serial.println("Done setup()");
- }
- void loop() {
- //Serial.println(MP3player.getState());
- if((MP3player.getState() == initialized) | (MP3player.getState() == ready))
- {
- char song[50];
- selectSong("PLT.TXT", song, random(1, totalsongs));
- Serial.println(song);
- MP3player.playMP3(song, 0);
- Serial.println(F("Enter n,+,-,i,p,r,R,M,g,k,h,O,o,D,S :"));
- }
- else
- {
- if(Serial.available()) {
- parse_menu(Serial.read()); // get command from serial input
- }
- delay(100);
- }
- }
复制代码
|
|