#ifdef CONFIG_MUSIC_ENABLE #include #include "ff.h" #include "app_serv.h" #include "music_tsk.h" #include "player.h" #include "data.h" #include "datadesc.h" #include "sdcard.h" static FATFS FatFs; /* FatFs work area needed for each volume */ static FIL Fil; /* File object needed for each open file */ CPU_INT32U fat_status; CPU_INT08U music_status; CPU_INT08U music_cansel; #define FILE_BUFFER_SIZE 512 /* How many transferred bytes between collecting data. A value between 1-8 KiB is typically a good value. If REPORT_ON_SCREEN is defined, a report is given on screen each time data is collected. */ #define REPORT_INTERVAL 4096 #define REPORT_INTERVAL_MIDI 512 static u_int8 playBuf[FILE_BUFFER_SIZE]; OS_STK MusicTaskStk[MUSIC_TASK_STK_SIZE]; OS_EVENT *MusicQuery = NULL; void *MusicQueryTbl[MUSIC_QUERY_LEN]; /// int IsMusicPlaying(void) { if (music_status == MUSIC_STATUS_PLAYING) return 1; return 0; } /// void MusicCanselPlay(void) { music_cansel = 1; } /// int GetMusicEvent(int* event) { CPU_INT08U err = 0; int evt = (int)OSQPend(MusicQuery, 1, &err); if (err != 0) return 0; *event = evt; return 1; } /// void PostMusicEvent(int event) { OSQPost(MusicQuery, (void *)event); } enum AudioFormat { afUnknown, afRiff, afOggVorbis, afMp1, afMp2, afMp3, afAacMp4, afAacAdts, afAacAdif, afFlac, afWma, afMidi, } audioFormat = afUnknown; const char *afName[] = { "unknown", "RIFF", "Ogg", "MP1", "MP2", "MP3", "AAC MP4", "AAC ADTS", "AAC ADIF", "FLAC", "WMA", "MIDI", }; enum PlayerStates { psPlayback = 0, psUserRequestedCancel, psCancelSentToVS10xx, psStopped } playerState; int playFile(FIL *readFp, uint16_t volume) { UINT bytesInBuffer; // How many bytes in buffer left u_int32 pos=0; // File position int endFillByte = 0; // What byte value to send after file int endFillBytes = 2050; // How many of those to send long nextReportPos=0; // File pointer where to next collect/report int i; playerState = psPlayback; // Set state to normal playback WriteSci(SCI_DECODE_TIME, 0); // Reset DECODE_TIME // volume = 0..255 WriteSci(SCI_VOL, volume*0x101); // Main playback loop while ((f_read(readFp, playBuf, FILE_BUFFER_SIZE, &bytesInBuffer) == FR_OK) && (bytesInBuffer > 0) && (playerState != psStopped)) { u_int8 *bufP = playBuf; while (bytesInBuffer && (playerState != psStopped)) { int t = min(SDI_MAX_TRANSFER_SIZE, bytesInBuffer); // This is the heart of the algorithm: on the following line // actual audio data gets sent to VS10xx. if (WriteSdi(bufP, t) != 0) return -1; bufP += t; bytesInBuffer -= t; pos += t; // If the user has requested cancel, set VS10xx SM_CANCEL bit if (playerState == psUserRequestedCancel) { unsigned short oldMode; playerState = psCancelSentToVS10xx; oldMode = ReadSci(SCI_MODE); WriteSci(SCI_MODE, oldMode | SM_CANCEL); } // If VS10xx SM_CANCEL bit has been set, see if it has gone // through. If it is, it is time to stop playback. if (playerState == psCancelSentToVS10xx) { unsigned short mode = ReadSci(SCI_MODE); if (!(mode & SM_CANCEL)) { playerState = psStopped; } } // If playback is going on as normal, see if we need to collect and // possibly report if (playerState == psPlayback && pos >= nextReportPos) { nextReportPos += (audioFormat == afMidi || audioFormat == afUnknown) ? REPORT_INTERVAL_MIDI : REPORT_INTERVAL; /* It is important to collect endFillByte while still in normal playback. If we need to later cancel playback or run into any trouble with e.g. a broken file, we need to be able to repeatedly send this byte until the decoder has been able to exit. */ endFillByte = ReadVS10xxMem(PAR_END_FILL_BYTE); } } // if (playerState == psPlayback && pos >= nextReportPos) if ((music_cansel) &&(playerState == psPlayback)) { playerState = psUserRequestedCancel; } } // while ((bytesInBuffer = fread(...)) > 0 && playerState != psStopped) // Earlier we collected endFillByte. Now, just in case the file was // broken, or if a cancel playback command has been given, write // lots of endFillBytes. memset(playBuf, endFillByte, sizeof(playBuf)); for (i=0; i= MUSIC_EVENT_PLAY_FILE) { music_cansel = 0; if (!player_connected()) player_init(); if (player_connected()) { char filepath[12 + 1]; if (find_file("/audio", event - MUSIC_EVENT_PLAY_FILE, filepath) == FR_OK) { if (f_chdir("/audio") == FR_OK) { music_status = MUSIC_STATUS_PLAYING; if (f_open(&Fil, filepath, FA_READ | FA_OPEN_EXISTING) == FR_OK) { CPU_INT32U volume100; uint16_t volume; GetData(&SoundVolumeDesc, &volume100, 0, DATA_FLAG_SYSTEM_INDEX); volume = (255 * (100 - volume100)) / 100; playFile(&Fil, volume); f_close(&Fil); } f_chdir("/"); music_status = MUSIC_STATUS_STOPPED; } } } file_menu_cmd = 0; } } else { if (OSTimeGet() - time_stamp > 10000) { time_stamp = OSTimeGet(); if (f_open(&Fil, "fstab.tmp", FA_READ | FA_OPEN_EXISTING) == FR_OK) { UINT rbytes; if ((f_read(&Fil, playBuf, 10, &rbytes) == FR_OK) && (rbytes == 10)) { f_close(&Fil); } else { f_close(&Fil); fat_status = FAT_STATUS_EMPTY; f_unmount(""); } } else { fat_status = FAT_STATUS_EMPTY; f_unmount(""); } } OSTimeDly(10); } } else { while (GetMusicEvent(&event)); // события пропускаем if (OSTimeGet() - time_stamp > 10000) { time_stamp = OSTimeGet(); sd_init(); if (f_mount(&FatFs, "", 1) == FR_OK) { UINT rbytes; if (f_open(&Fil, "fstab.tmp", FA_READ | FA_OPEN_EXISTING) == FR_OK) { if ((f_read(&Fil, playBuf, 10, &rbytes) == FR_OK) && (rbytes == 10)) { if (f_close(&Fil) == FR_OK) { fat_status = FAT_STATUS_OK; } } } if (fat_status != FAT_STATUS_OK) { if (f_open(&Fil, "fstab.tmp", FA_WRITE | FA_CREATE_NEW) == FR_OK) { if ((f_read(&Fil, playBuf, 10, &rbytes) == FR_OK) && (rbytes == 10)) { if (f_close(&Fil) == FR_OK) { fat_status = FAT_STATUS_OK; } } else { UINT wbytes; if ((f_write(&Fil, playBuf, 10, &wbytes) == FR_OK) && (wbytes == 10)) { if (f_close(&Fil) == FR_OK) { fat_status = FAT_STATUS_OK; } } else { f_close(&Fil); } } } else { f_unmount(""); } } } else { fat_status = FAT_STATUS_EMPTY; } } else { OSTimeDly(10); } } } } /// void InitMusicTask(void) { if (MusicQuery == NULL) { MusicQuery = OSQCreate(&MusicQueryTbl[0], MUSIC_QUERY_LEN); } fat_status = FAT_STATUS_NOCONN; music_status = MUSIC_STATUS_STOPPED; OSTaskCreate(MusicTask, (void *)0, (OS_STK *)&MusicTaskStk[MUSIC_TASK_STK_SIZE-1], MUSIC_TASK_PRIO); } #endif