forked from KolibriOS/kolibrios
1634ac97c2
git-svn-id: svn://kolibrios.org@165 a494cfbc-eb01-0410-851d-a64ba20cac60
719 lines
16 KiB
C
719 lines
16 KiB
C
//
|
|
// 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");
|
|
|
|
|
|
|