Music Player for ARCH-PRO
Dependencies: GT20L16J1Y_font TinyJpgDec mbed
SeeedStudio Arch Pro + aitendo TFT-LCD w/Touch panel => .wav File Player
LPC1768 + aitendo TFT-LCD w/Touch panel => .wav File Player
http://goji2100.com/
Diff: GSDPlayer.cpp
- Revision:
- 0:6fa19738f62e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GSDPlayer.cpp Mon Sep 08 16:07:05 2014 +0000 @@ -0,0 +1,746 @@ +// -------------------------------------------------------- +// GSDPlayer (c) CopYright 2013-2014 Goji. goji2100.com +// -------------------------------------------------------- + +#include "mbed.h" +#include "mainconf.h" + +#include "SDFileSystem.h" +#include "TinyJpgDec.h" + +#include "mGTFT.h" +#include "mGTP.h" +#include "GT20L16J1Y_font.h" + + +/* SDFileSystem.cpp change + ----------------------------------------------------------------------- +144: _spi.frequency(16000000); +210: _spi.frequency(24000000); // Set to 1MHz for data transfer +*/ + + +//#define Level_Indicator 4000 // for Level Indicator +//#define Test // for Simple Player + +#define FILESYS "sd" +#if defined(_ARCH_PRO) + SDFileSystem sd(P0_9, P0_8, P0_7, P0_6, FILESYS); // Arch Pro SPI1SD + #define BUFF_SIZE (512 * 4) // WAV file buffer size + #define LLow 1 + #define LHigh 0 + PwmOut Line_R(P2_0), Line_L(P2_1); // PWM_1, PWM_2 + BusOut TFTBus(D8, D9, D2, D3, D4, D5, D6, D7); +#else +#endif + +Serial pc(USBTX, USBRX); +DigitalOut statLED1(LED1), statLED2(LED2), statLED3(LED3), statLED4(LED4); + +#define PWM_CLKMHZ 24 // 24MHz +Ticker Tick_Timer; + +volatile uint16_t ps_stat = 0; // Player status +uint16_t tp_stat = 0, tp_statN = 0; +#define PS_PLAY BIT1(15) +#define PS_PAUSE BIT1(14) +#define PS_FFR BIT1(13) +#define PS_FFF BIT1(12) +#define PS_SEEK BIT1(11) +#define PS_FR BIT1(10) +#define PS_FF BIT1( 9) +#define PS_VDOWN BIT1( 8) +#define PS_VUP BIT1( 7) +#define PS_EOR BIT1( 6) // End of Root +#define PS_EOD BIT1( 5) // End of DIR +#define PS_EOF BIT1( 4) // Eod of File + +#define SWBuff() { if (buffNX==0) { buffNW=0,buffNX=1; } else { buffNW=1,buffNX=0; } buffLN[buffNX]=buffGP=0; } +volatile int32_t buffNW, buffNX, buffLN[2], buffGP; +unsigned char Wave_buff[2][BUFF_SIZE]; +#define _WS16(n,v) *(short* )&Wave_buff[n][v] +#define _WU16(n,v) *(unsigned short*)&Wave_buff[n][v] +#define _WU32(n,v) *(unsigned long* )&Wave_buff[n][v] +uint8_t Wave_CHs, Wave_Bits; +uint32_t Wave_BPS, Wave_Size, Wave_Rlen, Wave_Play, Wave_FPos; +uint16_t Wave_Prid; + +volatile uint16_t Pwm_Ratio, Line_Vols = 16, Line_Vol = 160; + +#if defined(Level_Indicator) +volatile uint32_t Pwm_cnt = 0; +volatile uint16_t Pwm_aveL = 0, Pwm_aveR = 0; +#endif + +void PwmLR_Out16(int16_t lv, int16_t rv) +{ + int16_t lw = ((lv + 32768) / Pwm_Ratio); + int16_t rw = ((rv + 32768) / Pwm_Ratio); +// if (lw >= LPC_PWM1->MR0) lw = LPC_PWM1->MR0; +// if (rw >= LPC_PWM1->MR0) rw = LPC_PWM1->MR0; + #if defined(_ARCH_PRO) + LPC_PWM1->MR1 = lw; + LPC_PWM1->MR2 = rw; + if (Line_Vols) + LPC_PWM1->LER |= ((1 << 1) | (1 << 2)); + #else + LPC_PWM1->MR6 = lw; + LPC_PWM1->MR5 = rw; + if (Line_Vols) + LPC_PWM1->LER |= ((1 << 6) | (1 << 5)); + #endif + #if defined(Level_Indicator) + Pwm_cnt++; + Pwm_aveL = (Pwm_aveL + ((uint16_t)(lv) + 32768) >> 8) / 2; + Pwm_aveR = (Pwm_aveR + ((uint16_t)(rv) + 32768) >> 8) / 2; + #endif +} + + +void ISR_Tick(void) +{ + if (!(ps_stat & PS_PAUSE) && (buffGP < buffLN[buffNW])) { + statLED2 = LHigh; + PwmLR_Out16(_WS16(buffNW, buffGP), _WS16(buffNW, buffGP + 2)); + buffGP += 4; + if ((buffGP >= buffLN[buffNW]) && (buffNX != -1)) SWBuff(); + statLED2 = LLow; + } +} + + +extern TFT_INFO TFT_info; +int32_t Last_Err; + +GT20L16J1Y_FONT font(p11, p12, p13, P0_16); +void draw_kanji(int x1, int y1, uint16_t c1, uint16_t c2) +{ + for (int x = 0; x < 32; x++) + for (int y = 0, m = 0x01; y < 8; y++, m <<= 1) + TFT_setPixel(x1 + x%16, y1 + y + (8 * (x >> 4)), ((font.bitmap[x] & m) ? c1 : c2)); +} + + +uint16_t bmpXsize, bmpYsize; + +void BMP24Bits(int16_t x1, int16_t y1, char *fn) +{ + uint8_t rbuff[64]; + + FILE *fp = fopen(fn, "rb"); + if (!fp) { + pc.printf("open error\n"); + return; + } + + fread(rbuff, 1, (14 + 40), fp); + bmpXsize = *(uint16_t*)&rbuff[18]; + bmpYsize = *(uint16_t*)&rbuff[22]; + + if ((bmpXsize > TFT_MAX_X) || + (bmpYsize > TFT_MAX_Y) || + (rbuff[28] != 24)) { + pc.printf("format error\n"); + return; + } + + int dummy = (bmpXsize * 3) % 4; + for (int z = 0, y = y1; z < bmpYsize; z++, y--) { + TFT_setXY(x1, y); + for (int i = 0; i < bmpXsize; i++) { + fread(rbuff, 1, 3, fp); + TFT_wr_data((uint16_t)( + ((rbuff[2] & 0xF8) << 8) | // R + ((rbuff[1] & 0xFC) << 3) | // G + ((rbuff[0] ) >> 3) )); // B + } + if (dummy) fread(rbuff, 1, dummy, fp); + } + fclose(fp); +} + + +FILE *jfp; +UINT jpeg_input(JDEC *jd, BYTE *buff, UINT ndata) +{ + if (buff) { + int n = fread(buff, 1, ndata, jfp); + return(n == -1 ? 0 : n); + } + return(fseek(jfp, ndata, SEEK_CUR) == -1 ? 0 : ndata); +} + +int16_t Cover_tlx, Cover_tly; + +UINT jpeg_output(JDEC *jd, void *bitmap, JRECT *rect) +{ + WORD *src = (WORD *)bitmap; + + int x0 = rect->left; + int x1 = rect->right; + int y0 = rect->top; + int y1 = rect->bottom; + int w = x1 - x0 + 1; + + if (x0 >= TFT_MAX_X || y0 >= TFT_MAX_Y) return 1; + if (x1 >= TFT_MAX_X) x1 = TFT_MAX_X - 1; + if (y1 >= TFT_MAX_Y) y1 = TFT_MAX_Y - 1; + + for (int y = y0; y <= y1; y++) { + TFT_setXY(Cover_tlx + x0, Cover_tly + y); + WORD *p = src + w * (y - y0); + for (int x = x0; x <= x1; x++) + TFT_wr_data(*p++); + } + return 1; +} + + +#define MM_TLX 0 +#define MM_TLY (TFT_MAX_Y - bmpYsize) +#define MM_YH bmpYsize + +#define MM_FR 80 +#define MM_PLAY (MM_FR + 50) +#define MM_FF (MM_PLAY + 54) +#define MM_FFE (MM_FF + 50) +#define MM_VUPD (TFT_MAX_X - 58) + +#define MM_VUP (TFT_MAX_Y - bmpYsize) +#define MM_VDWN (TFT_MAX_Y - (bmpYsize / 2)) + +uint16_t tp_menu() +{ + int16_t wposX, wposY; + + if (TPC_getXY(&wposX, &wposY) == 2) { + if (wposY < MM_TLY) return(PS_SEEK); + if (wposX < MM_FR ) return(0); + if (wposX < MM_PLAY) return(PS_FFR); + else if (wposX < MM_FF ) return(PS_PAUSE); + else if (wposX < MM_FFE ) return(PS_FFF); + else if (wposY < MM_VDWN) return(PS_VUP); + else if (wposY > MM_VDWN) return(PS_VDOWN); + } + return(0); +} + +//#define SEEK_Dump() +#define SEEK_Dump() pc.printf("%d - (%8d - %d = %8d) = %8d(%8d)\n", Wave_Size,Wave_FPos,Wave_Play,Wave_FPos-Wave_Play,Wave_Rlen,Wave_Rlen-(Wave_Size-(Wave_FPos-Wave_Play))) + +uint16_t event_chk() +{ + static uint16_t stepS = 0, timep, barp, bcp; + static int16_t tp_cnt = 0; + + int16_t px, py; + uint16_t statN = 0, tw, barl, bc; + char times[8]; + + while (1) { + switch (stepS) { + case 0: + case 50: + tw = (Wave_FPos - Wave_Play) / (Wave_BPS * 4); // (Wave_FPos * 8) / (Wave_BPS * 16 * 4) + if (tw != timep) { + timep = tw; + sprintf(times, "%02d:%02d", (timep / 60), (timep % 60)); + TFT_drawText( 28, (TFT_MAX_Y - 1) - 6 - (bmpYsize / 2), (uint8_t*)times, WHITE, BLACK); + barp = 0; + } + stepS += 10; + break; + + case 10: + case 60: + barl = (((Wave_FPos - Wave_Play) / 1000) * TFT_MAX_X) / (Wave_Size / 1000); + bc = (ps_stat & PS_PAUSE) ? YELLOW : BLUE; + if ((stepS >= 50) || (barp != barl) || (bcp != bc)) { + TFT_fillRectangle( 0, (TFT_MAX_Y - 1) - bmpYsize - 2, barl, (TFT_MAX_Y - 1) - bmpYsize, bc, bc); + if (barl < (TFT_MAX_X - 1)) + TFT_fillRectangle(barl, (TFT_MAX_Y - 1) - bmpYsize - 2, (TFT_MAX_X - 1), (TFT_MAX_Y - 1) - bmpYsize, BLACK, BLACK); + barp = barl; + bcp = bc; + } + if (stepS > 50) stepS += 10; + else stepS = 20; + break; + + case 70: + if (TPC_getXY(&px, &py) == 2) { + if (px < ((320 * 1) / 10)) px = ((320 * 1) / 10); + if (px > ((320 * 9) / 10)) px = ((320 * 9) / 10); + if (px < ((320 * 1) / 7)) { + if (Wave_FPos < (Wave_BPS * 2 * 2 * 2)) { + SEEK_Dump(); + statN = PS_FFR; + tp_cnt = 0; + stepS = 0; + break; + } + Wave_FPos = Wave_Play; + Wave_Rlen = Wave_Size; + } else if (px >= ((320 * 9) / 10)) { + Wave_FPos = Wave_Play + Wave_Size; + Wave_Rlen = 0; + } else { + uint64_t pr = (px - ((320 * 1) / 10)) * 1000 / (((320 * 8) / 10)); + Wave_FPos = ((Wave_Size * pr) / 1000); + if (Wave_FPos > (Wave_Play + Wave_Size)) Wave_FPos = Wave_Size + Wave_Play; + if (Wave_FPos < Wave_Play) Wave_FPos = Wave_Play; + Wave_Rlen = Wave_Size - (Wave_FPos - Wave_Play); + } + } else { + tp_cnt++; + if (tp_cnt > 100) { + if (Wave_FPos < Wave_Size + Wave_Play) { + Wave_FPos &= (uint64_t)-BUFF_SIZE; + if (Wave_FPos < Wave_Play) Wave_FPos = Wave_Play; + Wave_Rlen = Wave_Size - (Wave_FPos - Wave_Play); + } + SEEK_Dump(); + statN = PS_SEEK; + tp_cnt = 0; + stepS = 0; + break; + } + } + stepS = 50; + break; + + case 20: + if (tp_stat != 0) { + stepS = 22; + break; + } + tp_stat = tp_menu(); + tp_cnt = 0; + if (tp_stat & PS_SEEK) { + ps_stat |= PS_PAUSE; + stepS = 50; + SEEK_Dump(); + break; + } + if (tp_stat == 0) stepS = 0; + else stepS = 22; + break; + + case 22: + tp_statN = tp_menu(); + if (tp_statN == 0) { + tp_cnt = 0; + tp_stat = 0; + stepS = 0; + break; + } + if (tp_stat == tp_statN) { + if (tp_cnt != -1) tp_cnt++; + stepS = 24; + break; + } + tp_cnt = 0; + tp_stat = tp_statN; + stepS = 22; + break; + + case 24: + if (tp_cnt > 1) { + if (tp_stat & PS_VUP) { + if (tp_cnt == 3) statN = tp_stat; + if (tp_cnt >= 5) tp_cnt = 0; + } else if (tp_stat & PS_VDOWN) { + if (tp_cnt == 2) statN = tp_stat; + if (tp_cnt >= 3) tp_cnt = 0; + } else { + statN = tp_stat; + tp_cnt = -1; + } + } + stepS = 0; + break; + + default: + stepS = 0; + break; + } + if (stepS < 50) break; + } + return(statN); +} + + +void poll() +{ + uint16_t statN; + char stext[8]; + + if ((statN = event_chk()) == 0) return; + if (statN & PS_PAUSE) { ps_stat ^= PS_PAUSE; return; } + if (statN & (PS_FFR | PS_FFF | PS_SEEK)) { ps_stat |= statN; return; } + if (statN & (PS_VUP | PS_VDOWN)) { + if (statN & PS_VUP) { + if (Line_Vols < 32) { Line_Vol -= (Line_Vols >= 16 ? 10 : 40); Line_Vols++; } + } else { + if (Line_Vols > 0) { Line_Vol += (Line_Vols > 16 ? 10 : 40); Line_Vols--; } + } + sprintf(stext, "%2d", Line_Vols); + TFT_drawText((TFT_MAX_X - 76), (TFT_MAX_Y - 1) - 6 - (bmpYsize / 2), (uint8_t*)stext, WHITE, BLACK); + Pwm_Ratio = ((65536 / PWM_CLKMHZ) / Wave_Prid) + Line_Vol; + } + return; +} + + +DIR *dp; +FILE *fp; +struct dirent *p; + +int Open_Wave(char *path) +{ + fp = fopen(path, "rb"); + if (fp == NULL) return (Last_Err = -3); // can't open + + buffLN[0] = fread(Wave_buff[0], 1, BUFF_SIZE, fp); + if (buffLN[0] < 46) return (Last_Err = -4); // invalid file + + // "RIFF", (long)File size, "WAVE" + if ((_WU32(0, 0) != 0x46464952) || + (_WU32(0, 8) != 0x45564157)) + return (Last_Err = -5); // invalid file + + buffGP = 12; + while (buffGP < BUFF_SIZE) { + unsigned long tagn = _WU32(0, buffGP); + unsigned long tagl = _WU32(0, buffGP + 4); + buffGP += 8; + + if (tagn == 0x20746D66) { // "fmt " + Wave_CHs = _WU16(0, buffGP + 2); + Wave_BPS = _WU32(0, buffGP + 4); + Wave_Bits = _WU32(0, buffGP +14); + Wave_Prid = 2000000 / Wave_BPS; + if (Wave_Prid & 1) Wave_Prid++; + Wave_Prid >>= 1; + } + + // "fact" 0x74636166) + // "LIST" 0x74636166) + if (tagn != 0x61746164) { // !"data" + buffGP += tagl; + continue; + } + + if ((Wave_BPS == 24000) || + (Wave_BPS == 32000) || + (Wave_BPS == 44100) || + (Wave_BPS == 48000)) { + Wave_Size = tagl; + return 0; + } + break; + } + return (Last_Err = -6); // invalid file +} + + +int music_nw, music_nx; + +int Play_Wave() +{ + int32_t getln; + + if (((buffNX != -1) && (buffLN[buffNX] == 0)) ||(ps_stat & (PS_SEEK | PS_FFR))) { + statLED1 = LHigh; + if (ps_stat & (PS_SEEK | PS_FFR)) { + if (fseek(fp, Wave_FPos, SEEK_SET) == -1) { + ps_stat |= PS_EOF; + buffNX = -1; + return (Last_Err = -7); // read error + } + Wave_Rlen = Wave_Size - (Wave_FPos - Wave_Play); + ps_stat &= ~PS_FFR; + } + + if (Wave_FPos <= Wave_Play) + getln = ((BUFF_SIZE - Wave_Play) > Wave_Rlen) ? Wave_Rlen : (BUFF_SIZE - Wave_Play); + else + getln = (Wave_Rlen > BUFF_SIZE) ? BUFF_SIZE : Wave_Rlen; + if (getln && (buffNX != -1)) { + if (fread(Wave_buff[buffNX], 1, getln, fp) != getln) { + ps_stat |= PS_EOF; + buffNX = -1; + return (Last_Err = -7); // read error + } + buffLN[buffNX] = getln & -4; + Wave_FPos += getln; + if (Wave_Rlen > getln) Wave_Rlen -= getln; else Wave_Rlen = 0; + + if (ps_stat & PS_SEEK) { + buffLN[buffNW] = buffLN[buffNX]; + SWBuff(); + ps_stat &= ~(PS_SEEK | PS_PAUSE); + } + } + statLED1 = LLow; + + if (Wave_Rlen == 0) { + buffNX = -1; + ps_stat |= PS_EOF; + wait_ms(50); + return(0); + } + return getln; + } + + if (ps_stat & PS_PAUSE) return(1); + return 0; +} + + +#if defined(Test) +int main() +{ + if (Open_Wave("/" FILESYS "/music/01.wav")) error("open error\n"); + + Pwm_Ratio = ((65535 / PWM_CLKMHZ) / Wave_Prid) + Line_Vol; + buffNW = 0, buffNX = 1; + buffLN[buffNX] = 0; + + Line_R.period_us(Wave_Prid); + Line_L.period_us(Wave_Prid); + Tick_Timer.attach_us(&ISR_Tick, Wave_Prid); + + pc.printf("start\n"); + while (1) { + if (buffLN[buffNX] == 0) { + if (fread(Wave_buff[buffNX], 1, BUFF_SIZE, fp) != BUFF_SIZE) break; + if (Wave_Size >= BUFF_SIZE) Wave_Size -= BUFF_SIZE; else break; + buffLN[buffNX] = BUFF_SIZE; + } + } + Tick_Timer.detach(); + fclose(fp); + pc.printf("stop\n"); +} + +#else + +int main() +{ + char path[256], msc_file[256], stext[20]; + + pc.baud(115200); + TFT_init(); + TPC_Init(); + TFT_clearScreen(GRAY); + + while (1) { + + // Open Music Directory + // --------------------- + if (sd.disk_initialize()) return -1; + + BMP24Bits(0, (TFT_MAX_Y - 1), "/" FILESYS "/images/Play.bmp"); + dp = 0, music_nw = 1, music_nx = 1; + + while (1) { + + // Get Music file(.wav) + // --------------------- + { + int i; + + if (music_nw >= music_nx) { + if (dp) closedir(dp); + dp = opendir("/" FILESYS "/music"); + if (dp == NULL) { + pc.printf("\n" "/" FILESYS "/music/ open error.\n"); + return 0; + } + music_nw = 0; + } + + if ((p = readdir(dp)) == NULL) break; + for (i = 0; p->d_name[i]; i++) + msc_file[i] = p->d_name[i]; + msc_file[i] = '\0'; + + if (msc_file[i - 4] == '.') msc_file[i - 4] = '\0'; + if (strcmp(p->d_name + (i - 3), "wav") != 0) { + pc.printf("Skip - music/%s\n", p->d_name); + continue; + } + + if (++music_nw < music_nx) continue; + music_nx++; + } + + // View Navigate(Play time, Sound volume) + // --------------------------------------- + { + snprintf(path, sizeof path, "/" FILESYS "/music/%s", msc_file); + pc.printf("Play - %s\n", path); + + TFT_fillRectangle( 0, 0, 319, 239 - bmpYsize, GRAY, GRAY); + TFT_drawText( 28, 239 - 6 - (bmpYsize / 2), (uint8_t*)"00:00", WHITE, BLACK); + sprintf(stext, "%2d", Line_Vols); + TFT_drawText(244, 239 - 6 - (bmpYsize / 2), (uint8_t*)stext, WHITE, BLACK); + TFT_fillRectangle( 0, 239 - bmpYsize - 2, 319, 239 - bmpYsize, BLACK, BLACK); + } + + // View Image + // ----------- + { + JDEC jdec; + WORD work[4000/sizeof(WORD)]; + + snprintf(path, sizeof path, "/" FILESYS "/music/%s" ".jpg", msc_file); + pc.printf("jpg - %s\n", path); + jfp = fopen(path, "rb"); + if (!jfp) jfp = fopen("/" FILESYS "/images/NoImage.jpg", "rb"); + if (jfp) { + JRESULT r = jd_prepare(&jdec, jpeg_input, work, sizeof(work), jfp); + if (r == JDR_OK) { + uint16_t ww = jdec.width & 0x3FF; // struct jdec ??? + uint16_t wh = jdec.width >> 16; // .. + Cover_tlx = (ww < 170) ? ((176 - ww) / 2) : 4; + Cover_tly = (wh < 180) ? ((188 - wh) / 2) : 4; + r = jd_decomp(&jdec, jpeg_output, 0); + #if (0) + TFT_drawLine(Cover_tlx + 1, Cover_tly + wh, Cover_tlx + ww, Cover_tly + wh, WHITE); + TFT_drawLine(Cover_tlx + ww, Cover_tly + 1, Cover_tlx + ww, Cover_tly + wh, WHITE); + #endif + } + fclose(jfp); + } + } + + // View Song title + // ---------------- + { + int l = 0; + char msc_Text[256]; + + snprintf(path, sizeof path, "/" FILESYS "/music/%s" ".txt", msc_file); + pc.printf("txt - %s\n", path); + + fp = fopen(path, "r"); + if (fp) { + l = fread(msc_Text, 1, 256, fp); + fclose(fp); + } + + if (l > 4) + msc_Text[l] = '\0'; + else snprintf(msc_Text, sizeof(msc_Text), "||%s||", msc_file); + pc.printf("%02d - %s\n\n", music_nw, msc_Text); + + int ps, pl = 0; + int px = 176, py = Cover_tly + 2; + uint8_t ws[2]; + ws[1] = '\0'; + + for (ps = 0; ps < 256; ps++) { + if (msc_Text[ps] == '|') { + if (++pl > 2) break; + py += 20; + px = 176; + continue; + } + if (msc_Text[ps] & 0x80) { // KANJI ? + font.read((msc_Text[ps] << 8)| msc_Text[ps + 1]); + draw_kanji(px, py, ((pl == 2) ? WHITE : DWHITE), GRAY); + px += 16; + ps++; + } else { + ws[0] = msc_Text[ps]; + TFT_drawText(px, py + 2, ws, ((pl == 2) ? WHITE : DWHITE), GRAY); + px += 8; + } + } + } + + // Play Music + // ----------- + { + snprintf(path, sizeof path, "/" FILESYS "/music/%s" ".wav", msc_file); + int rc = Open_Wave(path); + if (rc) { + if (fp != NULL) fclose(fp); + pc.printf(" rc=%d, Last_Err=%d\n", rc, Last_Err); + Last_Err = 0; + continue; + } + + uint16_t tw = Wave_Size / (Wave_BPS * 4); + sprintf(stext, "%02d %2dks %02d:%02d", music_nw, (Wave_BPS / 1000), (tw / 60), (tw % 60)); + TFT_drawText(214, (222 - bmpYsize), (uint8_t*)stext, BLACK, GRAY); + + Wave_Play = buffGP; + Wave_FPos = BUFF_SIZE; + Wave_Rlen = Wave_Size - (Wave_FPos - Wave_Play); + buffNW = 0, buffNX = 1; + buffLN[buffNX] = 0; + + Last_Err = 0; + ps_stat = PS_PLAY; + + Pwm_Ratio = ((65535 / PWM_CLKMHZ) / Wave_Prid) + Line_Vol; + Line_R.period_us(Wave_Prid); + Line_L.period_us(Wave_Prid); + Tick_Timer.attach_us(&ISR_Tick, Wave_Prid); // Play! + + while (!(ps_stat & PS_EOF) && (ps_stat & PS_PLAY) && (Last_Err == 0)) { + + #if defined(Level_Indicator) + uint16_t yl0 = 0, yr0 = 0, yl, yr; + if (Pwm_cnt > Level_Indicator) { + yl = 238 - (((Pwm_aveL - 64) * (bmpYsize - 2)) / 200); + yr = 238 - (((Pwm_aveR - 64) * (bmpYsize - 2)) / 200); + Pwm_cnt = 0; + if (yl > 237) yl = 238; + if (yr > 237) yr = 238; + yl0 = (yl > yl0) ? yl : ((yl0 + yl) / 2); + yr0 = (yr > yr0) ? yr : ((yr0 + yl) / 2); + TFT_fillRectangle(MM_VUPD + 5, MM_VUP + 1, MM_VUPD + 7, yl0, BLACK, BLACK); + TFT_fillRectangle(MM_VUPD + 9, MM_VUP + 1, MM_VUPD + 11, yr0, BLACK, BLACK); + if (yl0 < 238) TFT_fillRectangle(MM_VUPD + 5, yl0, MM_VUPD + 7, 238, YELLOW, YELLOW); + if (yr0 < 238) TFT_fillRectangle(MM_VUPD + 9, yr0, MM_VUPD + 11, 238, YELLOW, YELLOW); + } + #endif + + if (Play_Wave()) { + + statLED4 = LHigh; + if (ps_stat & PS_PAUSE) wait_ms(5); + poll(); + statLED4 = LLow; + + if (ps_stat & PS_FFF) { + buffNX = -1; + break; + } + + if (ps_stat & PS_FFR) { + if (Wave_FPos < (Wave_BPS * 2 * 2 * 2)) { + buffNX = -1; + if (music_nx > music_nw) + music_nx = (music_nw > 1) ? music_nw - 1 : 1; + break; + } else + Wave_FPos = Wave_Play; + } + } + } + + Tick_Timer.detach(); + fclose(fp); + pc.printf("Close stat=%04X, %d - %d\n", ps_stat, Wave_Rlen, Last_Err); + ps_stat = 0; + Last_Err = 0; + } + } + closedir(dp); + } +} +#endif \ No newline at end of file