// // This file is part of the AC97 mp3 player. // (C) copyright Serge 2006 // email: infinity_sound@mail.ru // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. #include "kolibri.h" #include "stdio.h" #include "string.h" #include "ac97wav.h" #include "mp3dec/mp3dec.h" void thread_proc(); void touch(char *buf, int size); extern char *__argv; //extern char __path; /***** for debug output only char formats[37][12] = { "PCM_ALL", "PCM_2_16_48","PCM_1_16_48","PCM_2_16_44","PCM_1_16_44", "PCM_2_16_32","PCM_1_16_32","PCM_2_16_24","PCM_1_16_24", "PCM_2_16_22","PCM_1_16_22","PCM_2_16_16","PCM_1_16_16", "PCM_2_16_12","PCM_1_16_12","PCM_2_16_11","PCM_1_16_11", "PCM_2_16_8","PCM_1_16_8","PCM_2_8_48","PCM_1_8_48", "PCM_2_8_44","PCM_1_8_44","PCM_2_8_32","PCM_1_8_32", "PCM_2_8_24","PCM_1_8_24","PCM_2_8_22","PCM_1_8_22", "PCM_2_8_16","PCM_1_8_16","PCM_2_8_12","PCM_1_8_12", "PCM_2_8_11","PCM_1_8_11","PCM_2_8_8","PCM_1_8_8" }; *******/ DWORD hDrv; DWORD hSound; DWORD hBuff; DWORD event[2]; CTRL_INFO info; FILEINFO fileinfo; int m_vol; DWORD status; DWORD offset; DWORD first_sync; char *testbuff; char *outbuf; char *inpbuf; int inpsize; int outsize; char srv_name[] = "INFINITY"; char srv_intel[] = "SOUND"; char header[] = "AC97 MP3 player"; char buttons_text[]=" Play Stop << >> Vol- Vol+"; MPEG_DECODE_INFO mpginfo; MPEG_DECODE_PARAM param; void (*snd_play)(); void draw_window() { BeginDraw(); DrawWindow(100,100,299,72,0x404040,3,0,0,0); make_button(7,24,45,13, 0x10|BT_NORMAL,0x808080); make_button(56,24,45,13, 0x11|BT_NORMAL,0x808080); make_button(104,24,45,13, 0x12|BT_NORMAL,0x808080); make_button(152,24,45,13, 0x13|BT_NORMAL,0x808080); make_button(200,24,45,13, 0x14|BT_NORMAL,0x808080); make_button(248,24,45,13, 0x15|BT_NORMAL,0x808080); make_button(7,41,286,11, 0x30|BT_HIDE|BT_NOFRAME,0x404040); draw_bar(7,41,286,11,0x404040); draw_bar(7,55,286,11,0x404040); write_text(12,58,0x004000|FONT0, __argv, strlen(__argv)); write_text(11,57,0x00FF20|FONT0, __argv, strlen(__argv)); write_text(8,8,0xFFFFFF|FONT0, header, strlen(header)); write_text(12,28,0x404040|FONT0,buttons_text,strlen(buttons_text)); write_text(11,27,0xA0FFA0|FONT0,buttons_text,strlen(buttons_text)); EndDraw(); }; void draw_progress_bar() { DWORD x; x = 286.0f * (float)offset/(float)fileinfo.size; if(x==0) return; draw_bar(7,41,x,11,0xA0A0A0); draw_bar(x+7,41,286-x,11,0x404040); }; void debug_out_str(char* str) { while (*str != 0) { debug_out(*str); str++; } } int main() //int argc, char *argv[]) { DWORD fmt; char *thread_stack; DWORD r_bytes; int retval; InitHeap(1024*1024); if(get_fileinfo(__argv, &fileinfo)==FILE_NOT_FOUND) return 0; if((hDrv=GetService(srv_intel))==0) return 0; if ((hSound=GetService(srv_name))==0) return 0; GetDevInfo(hDrv, &info); m_vol = GetMasterVol(hDrv,&m_vol); if (m_vol > 85) { m_vol = 85; SetMasterVol(hDrv,m_vol); }; _asm {fninit}; mp3DecodeInit(); testbuff = UserAlloc(4096); get_fileinfo(__argv, &fileinfo); offset = 0; retval=read_file (__argv,testbuff,0,2048,&r_bytes); if (retval) return 0; fmt = test_wav((WAVEHEADER*)testbuff); if (fmt != 0) { snd_play = &play_wave; outbuf = UserAlloc(32*1024); touch(outbuf, 32768); offset = 44; } else { fmt = test_mp3(testbuff); if(fmt ==0) return 0; snd_play = &play_mp3; inpsize = mpginfo.maxInputSize*30; inpbuf = UserAlloc(inpsize); touch(inpbuf, inpsize); outsize = mpginfo.outputSize*30+0x10000; outbuf = UserAlloc(outsize); touch(outbuf, outsize); first_sync = offset; }; status = ST_PLAY; hBuff = CreateBuffer(hSound,fmt); if (hBuff == 0) return 0; thread_stack = UserAlloc(4096); thread_stack+=4092; CreateThread(thread_proc, thread_stack); while(1) { delay(10); switch(status) { case ST_PLAY: snd_play(); continue; case ST_STOP: StopBuffer(hSound, hBuff); status = ST_DONE; continue; case ST_EXIT: StopBuffer(hSound, hBuff); DestroyBuffer(hSound, hBuff); return 0; }; }; return 0; }; void touch(char *buf, int size) { int i; for ( i = 0;i < size; i+=4096) buf[i] = 0; }; DWORD test_mp3(char *buf) { int retval; int sync; WAVEHEADER whdr; DWORD r_bytes=2048; for (;;) { if (!mp3FindSync(buf, 2048, &sync)) offset+= 2048; else break; if (offset >= fileinfo.size || offset >= 102400) return 0; retval = read_file (__argv,buf,offset,2048,&r_bytes); if(retval != 0) return 0; }; offset+=sync; retval = read_file (__argv,buf,offset,2048,&r_bytes); if(retval != 0) return 0; mp3GetDecodeInfo(buf, r_bytes, &mpginfo, 1); whdr.riff_id = 0x46464952; whdr.riff_format = 0x45564157; whdr.wFormatTag = 0x01; whdr.nSamplesPerSec = mpginfo.frequency; whdr.nChannels = mpginfo.channels; whdr.wBitsPerSample = mpginfo.bitsPerSample; return test_wav(&whdr); }; void wave_out(char* buff) { DWORD ev[2]; GetNotify(&ev[0]); SetBuffer(hSound,hBuff,buff,ev[1],0x8000); } void play_mp3() { int retval; DWORD r_bytes; char *inpPtr; char *outPtr; int inpBytes; int totalout; offset = first_sync; retval = read_file (__argv,inpbuf,offset,inpsize,&r_bytes); if(retval != 0) { status = ST_STOP; return ; }; offset+=inpsize; mp3DecodeStart(inpbuf, inpsize); inpPtr = inpbuf+mpginfo.skipSize; inpBytes = inpsize-mpginfo.skipSize; outPtr = outbuf; totalout=0; memset(outbuf,0,0x10000); SetBuffer(hSound,hBuff,outbuf,0,0x10000); PlayBuffer(hSound, hBuff); _asm { fninit } while(1) { if(status!=ST_PLAY) break; for(;;) { param.inputBuf = inpPtr; param.inputSize = inpBytes; param.outputBuf = outPtr; if(!mp3DecodeFrame(¶m)) if( mp3GetLastError()== MP3_ERROR_OUT_OF_BUFFER) break; inpPtr += param.inputSize; inpBytes -= param.inputSize; outPtr+=param.outputSize; totalout+=param.outputSize; }; memmove(inpbuf, inpPtr, inpBytes); retval = read_file(__argv, &inpbuf[inpBytes],offset, inpsize-inpBytes, &r_bytes); offset+=r_bytes; if (r_bytes== 0) break; inpPtr = inpbuf; inpBytes += r_bytes; if(totalout < 32768) continue; outPtr = outbuf; while (totalout > 32768) { wave_out(outPtr); totalout-=0x8000; outPtr+=0x8000; }; memmove(outbuf,outPtr, totalout); outPtr = outbuf+totalout; }; if(status != ST_EXIT) status = ST_STOP; }; void play_wave() { int retval; int remain; int i; offset = 44; read_file (__argv,outbuf,offset,32*1024,0); offset+=32*1024; SetBuffer(hSound,hBuff,outbuf,0,0x8000); read_file (__argv,outbuf,offset,32*1024,0); offset+=32*1024; SetBuffer(hSound,hBuff,outbuf,0x8000,0x8000); PlayBuffer(hSound, hBuff); retval = 0; while(1) { if(status!=ST_PLAY) break; GetNotify(&event[0]); if(retval == FILE_EOF) break; remain = fileinfo.size-offset; if(remain >=32768) { retval = read_file (__argv,outbuf,offset,32*1024,0); offset+=32*1024; SetBuffer(hSound,hBuff,outbuf,event[1],0x8000); continue; }; if(remain == 0) { retval = FILE_EOF; continue; }; read_file (__argv,outbuf,offset,remain,0); for(i=remain;i<32768;i++) outbuf[i] = 0; SetBuffer(hSound,hBuff,outbuf,event[1],0x8000); retval= FILE_EOF; }; if(status != ST_EXIT) status = ST_STOP; }; void snd_stop() { StopBuffer(hSound, hBuff); }; void thread_proc() { int evnt; int pos; int key; _asm { fninit }; draw_window(); while(1) { if(status==ST_PLAY) { draw_progress_bar(); evnt = wait_for_event(80); // debug_out_str("BIG ERROR...\x0D\x0A\x00"); } else evnt = wait_for_event_infinite(); switch(evnt) { case EV_REDRAW: draw_window(); break; case EV_KEY: key = get_key(); if(key==27) { status = ST_EXIT; exit(); }; if((key==45)||key==54) { if(m_vol > 0) { m_vol--; SetMasterVol(hDrv,m_vol); }; break; }; if((key==61)||key==56) { if(m_vol < 90) { m_vol++; SetMasterVol(hDrv,m_vol); }; }; break; case EV_BUTTON: switch(get_button_id()) { case 1: status = ST_EXIT; exit(); break; case 0x10: status = ST_PLAY; continue; case 0x11: status = ST_STOP; break; // case 0x12: // case 0x13: case 0x14: if(m_vol > 0) { m_vol--; SetMasterVol(hDrv,m_vol); }; break; case 0x15: if(m_vol < 90) { m_vol++; SetMasterVol(hDrv,m_vol); }; break; case 0x30: if(status==ST_DONE) break; if(snd_play == play_mp3) continue; pos = (GetMousePos(REL_WINDOW)>>16)-7; offset = ((fileinfo.size-44)/286*pos+44)&0xFFFFFFFC; draw_progress_bar(); break; }; }; }; }; DWORD test_wav(WAVEHEADER *hdr) { if(hdr->riff_id != 0x46464952) return 0; if(hdr->riff_format != 0x45564157) return 0; if (hdr->wFormatTag != 0x01) return 0; switch(hdr->nSamplesPerSec) { case 48000: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_48; else return PCM_1_8_48; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_48; else return PCM_2_8_48; }; case 44100: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_44; else return PCM_1_8_44; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_44; else return PCM_2_8_44; }; case 32000: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_32; else return PCM_1_8_32; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_32; else return PCM_2_8_32; }; case 24000: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_24; else return PCM_1_8_24; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_24; else return PCM_2_8_24; }; case 22050: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_22; else return PCM_1_8_22; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_22; else return PCM_2_8_22; }; case 16000: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_16; else return PCM_1_8_16; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_16; else return PCM_2_8_16; }; case 12000: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_12; else return PCM_1_8_12; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_12; else return PCM_2_8_12; }; case 11025: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_11; else return PCM_1_8_11; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_11; else return PCM_2_8_11; }; case 8000: switch (hdr->nChannels) { case 1: if(hdr->wBitsPerSample == 16) return PCM_1_16_8; else return PCM_1_8_8; case 2: if(hdr->wBitsPerSample == 16) return PCM_2_16_8; else return PCM_2_8_8; }; default: return 0; }; }; void delay (int val) { _asm { mov eax,5 mov ebx, [val] int 0x40 }; } int wait_for_event(int time) { int retval; _asm { mov eax,23 mov ebx,[time] int 0x40 mov [retval], eax }; return retval; }; int wait_for_event_infinite() { int retval; _asm { mov eax,10 int 0x40 mov [retval], eax }; return retval; }; void BeginDraw() {_asm { mov eax,12 mov ebx, 1 int 0x40 }; }; void EndDraw() { _asm { mov eax,12 mov ebx, 2 int 0x40 }; }; void * __cdecl memmove ( void * dst, const void * src, size_t count) { void * ret = dst; if (dst <= src || (char *)dst >= ((char *)src + count)) { while (count--) { *(char *)dst = *(char *)src; dst = (char *)dst + 1; src = (char *)src + 1; } } else { dst = (char *)dst + count - 1; src = (char *)src + count - 1; while (count--) { *(char *)dst = *(char *)src; dst = (char *)dst - 1; src = (char *)src - 1; } } return(ret); }; // debug_out_str(formats[fmt]); // debug_out_str("\x0D\x0A\x00"); // debug_out_str("pci cmd: "); // debug_out_hex(info.pci_cmd); // debug_out_str("\x0D\x0A\x00"); // debug_out_str("irq line: "); // debug_out_hex(info.irq); // debug_out_str("\x0D\x0A\x00"); // debug_out_str("global control: "); // debug_out_hex(info.glob_cntrl); // debug_out_str("\x0D\x0A\x00"); // debug_out_str("global status: "); // debug_out_hex(info.glob_sta); // debug_out_str("\x0D\x0A\x00"); // call _print_volume // debug_out_hex(whdr.nChannels); // debug_out_str("\x0D\x0A\x00"); // debug_out_hex(whdr.nSamplesPerSec); // debug_out_str("\x0D\x0A\x00"); // debug_out_hex(fmt); // debug_out_str("\x0D\x0A\x00");