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/
GSDPlayer.cpp
- Committer:
- Goji
- Date:
- 2014-09-08
- Revision:
- 0:6fa19738f62e
File content as of revision 0:6fa19738f62e:
// -------------------------------------------------------- // 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