e080f21757
git-svn-id: svn://kolibrios.org@801 a494cfbc-eb01-0410-851d-a64ba20cac60
671 lines
16 KiB
C
671 lines
16 KiB
C
//
|
|
// This file is part of the AC97 mp3 player.
|
|
// (C) copyright Serge 2006-2007 infinity_sound@mail.ru
|
|
// (C) copyright Quantum 2007 ufmod@users.sf.net
|
|
//
|
|
// 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 "string.h"
|
|
#include "ac97wav.h"
|
|
#include "../mpg/mpg123.h"
|
|
#include "../sound.h"
|
|
#include "../ufmod-codec.h" /* uFMOD integration */
|
|
void exit(); /* uFMOD integration */
|
|
|
|
#define MP3_ERROR_OUT_OF_BUFFER 5
|
|
int m_last_error;
|
|
|
|
void _stdcall thread_proc(void *param);
|
|
void _stdcall create_thread(void *proc, void *param, int stack_size);
|
|
void _stdcall send_ipc(int dst, DWORD code);
|
|
|
|
void touch(char *buf, int size);
|
|
int mp3FindSync(byte* buf, int size, int* sync);
|
|
int stream_read_raw(struct reader *rd,unsigned char *buf, int size);
|
|
|
|
int __cdecl _stricmp (const char * dst, const char * src);
|
|
char *__cdecl strrchr (const char * string,int ch);
|
|
|
|
char *fname;
|
|
|
|
struct reader rd;
|
|
struct frame fr;
|
|
|
|
DWORD hDrv;
|
|
DWORD hSound;
|
|
SNDBUF hBuff;
|
|
|
|
CTRL_INFO info;
|
|
|
|
FILEINFO fileinfo;
|
|
const char *filename;
|
|
const char *fileext;
|
|
|
|
int m_vol;
|
|
int l_vol=-700; //-7db
|
|
int r_vol=-700;
|
|
int pan =0;
|
|
|
|
DWORD status;
|
|
DWORD first_sync;
|
|
|
|
unsigned char *testbuff;
|
|
unsigned char *outbuf;
|
|
unsigned char *inpbuf;
|
|
unsigned char *outPtr;
|
|
|
|
int inpsize;
|
|
int outsize;
|
|
int outremain;
|
|
int totalout;
|
|
int done;
|
|
|
|
char header[] = "AC97 MP3 player";
|
|
char buttons_xm[] = " Play Stop Vol- Vol+"; /* uFMOD integration */
|
|
char buttons_wav[] = " Play Stop << >> Vol- Vol+"; /* uFMOD integration */
|
|
char *buttons_text = buttons_wav; /* uFMOD integration */
|
|
|
|
void play_xm(); /* uFMOD integration */
|
|
void (*snd_play)();
|
|
|
|
void draw_window()
|
|
{
|
|
int len; /* uFMOD integration */
|
|
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);
|
|
len = strlen(filename); /* uFMOD integration */
|
|
if(len > 47) len = 47; /* uFMOD integration */
|
|
write_text(11,57,0x00FF20|FONT0, filename, len); /* uFMOD integration */
|
|
|
|
write_text(8,8,FONT0, header, sizeof(header)-1); /* uFMOD integration */
|
|
write_text(12,28,0x404040|FONT0,buttons_text,sizeof(buttons_wav)-1); /* uFMOD integration */
|
|
write_text(11,27,0xA0FFA0|FONT0,buttons_text,sizeof(buttons_wav)-1); /* uFMOD integration */
|
|
|
|
EndDraw();
|
|
};
|
|
|
|
void draw_progress_bar()
|
|
{ DWORD x;
|
|
x = (DWORD)(287.0f * (float)(rd.filepos-rd.strremain)/(float)fileinfo.size); /* uFMOD integration */
|
|
if(x==0) return;
|
|
draw_bar(7,41,x,11,0xA0A0A0);
|
|
draw_bar(x+7,41,287-x,11,0x404040);
|
|
};
|
|
|
|
void debug_out_str(char* str)
|
|
{
|
|
while (*str != 0)
|
|
{
|
|
debug_out(*str);
|
|
str++;
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[]) //int argc, char *argv[])
|
|
{
|
|
DWORD fmt;
|
|
DWORD r_bytes;
|
|
int retval;
|
|
int err;
|
|
int ver;
|
|
unsigned char *ttl, *cur; /* uFMOD integration */
|
|
|
|
fname = argv[1];
|
|
debug_out_str("\n\rPlay file ");
|
|
debug_out_str(fname);
|
|
debug_out_str("\n\r");
|
|
|
|
InitHeap(1024*1024);
|
|
if(get_fileinfo(fname, &fileinfo)==FILE_NOT_FOUND)
|
|
{ debug_out_str("\n\rfile not found\n\r");
|
|
return 0;
|
|
};
|
|
|
|
if(err = InitSound(&ver))
|
|
{
|
|
debug_out_str("Sound service not installed\n\r");
|
|
return 0;
|
|
}
|
|
|
|
if( (SOUND_VERSION>(ver&0xFFFF)) ||
|
|
(SOUND_VERSION<(ver >> 16)))
|
|
{
|
|
debug_out_str("Sound service version mismatch\n\r");
|
|
return 0;
|
|
}
|
|
|
|
testbuff = UserAlloc(4096);
|
|
|
|
get_fileinfo(fname, &fileinfo);
|
|
r_bytes=0;
|
|
retval=read_file (fname,testbuff,0,2048,&r_bytes);
|
|
if ( retval && (r_bytes==0))
|
|
return 0;
|
|
|
|
inpbuf = UserAlloc(0x10000);
|
|
touch(inpbuf, 0x10000);
|
|
|
|
create_reader(&rd, inpbuf, 0x10000);
|
|
init_reader(&rd,fname);
|
|
|
|
filename = strrchr(fname,'/')+1;
|
|
if( !(fileext = strrchr(filename,'.')))
|
|
return 0;
|
|
|
|
if(!_stricmp(fileext,".mp3"))
|
|
{
|
|
fmt = test_mp3(testbuff);
|
|
if(!fmt)
|
|
{
|
|
debug_out_str("\n\rInvalid MP3 file");
|
|
return 0;
|
|
};
|
|
snd_play = &play_mp3;
|
|
outremain = 0x40000;
|
|
outbuf = UserAlloc(outremain);
|
|
touch(outbuf, outremain);
|
|
make_decode_tables(32767);
|
|
init_layer2();
|
|
init_layer3(32);
|
|
fr.single = -1;
|
|
goto play;
|
|
};
|
|
|
|
if(!_stricmp(fileext,".xm"))
|
|
{
|
|
if(uFMOD_LoadSong(fname))
|
|
{
|
|
buttons_text = buttons_xm; /* uFMOD integration */
|
|
fmt = PCM_2_16_48; /* uFMOD integration */
|
|
snd_play = &play_xm; /* uFMOD integration */
|
|
ttl = uFMOD_GetTitle(); /* uFMOD integration */
|
|
cur = ttl; /* uFMOD integration */
|
|
err = 0; /* uFMOD integration */
|
|
while(*cur && *cur++ != ' ') err++; /* uFMOD integration */
|
|
if(err){ /* uFMOD integration */
|
|
cur = fname; /* uFMOD integration */
|
|
while(*cur) cur++; /* uFMOD integration */
|
|
*cur++ = ' '; /* uFMOD integration */
|
|
*cur++ = '|'; /* uFMOD integration */
|
|
*cur++ = ' '; /* uFMOD integration */
|
|
while(*ttl) *cur++ = *ttl++; /* uFMOD integration */
|
|
}
|
|
goto play;
|
|
}
|
|
debug_out_str("\n\rInvalid XM file");
|
|
return 0;
|
|
};
|
|
|
|
if(!_stricmp(fileext, ".wav"))
|
|
{
|
|
fmt = test_wav((WAVEHEADER*)testbuff);
|
|
if(fmt)
|
|
{
|
|
snd_play = &play_wave;
|
|
set_reader(&rd, 44);
|
|
outbuf = UserAlloc(32*1024);
|
|
touch(outbuf, 32768);
|
|
goto play;
|
|
}
|
|
debug_out_str("\n\rInvalid WAV file");
|
|
return 0;
|
|
};
|
|
|
|
debug_out_str("\n\rUsupported file");
|
|
return 0;
|
|
|
|
play:
|
|
|
|
status = ST_PLAY;
|
|
|
|
if (err = CreateBuffer(fmt,0, &hBuff))
|
|
{
|
|
debug_out_str("create buffer return error\n\r");
|
|
; return 0;
|
|
}
|
|
|
|
SetVolume(hBuff,l_vol,r_vol);
|
|
GetVolume(hBuff,&l_vol,&r_vol);
|
|
|
|
create_thread(thread_proc, 0, 4096);
|
|
|
|
while(1)
|
|
{ delay(10);
|
|
switch(status)
|
|
{ case ST_PLAY:
|
|
snd_play();
|
|
continue;
|
|
|
|
case ST_STOP:
|
|
StopBuffer(hBuff);
|
|
status = ST_DONE;
|
|
continue;
|
|
|
|
case ST_EXIT:
|
|
uFMOD_StopSong(); /* uFMOD integration */
|
|
StopBuffer(hBuff);
|
|
DestroyBuffer(hBuff);
|
|
return 0;
|
|
};
|
|
};
|
|
return 0;
|
|
};
|
|
|
|
void touch(char *buf, int size)
|
|
{ int i;
|
|
char a;
|
|
for ( i = 0;i < size; i+=4096) //alloc all pages
|
|
a = buf[i];
|
|
};
|
|
|
|
DWORD test_mp3(char *buf)
|
|
{ unsigned long hdr;
|
|
WAVEHEADER whdr;
|
|
|
|
while (1)
|
|
{ if(rd.filepos > 102400)
|
|
return 0;
|
|
if(!rd.head_read(&rd,&hdr))
|
|
return 0;
|
|
if(!decode_header(&fr,hdr))
|
|
{
|
|
if((hdr & 0xffffff00) == 0x49443300)
|
|
{
|
|
int id3length = 0;
|
|
id3length = parse_new_id3(&rd, hdr);
|
|
continue;
|
|
};
|
|
rd.strpos-=3;
|
|
rd.stream-=3;
|
|
rd.strremain+=3;
|
|
continue;
|
|
};
|
|
break;
|
|
};
|
|
|
|
first_sync = rd.filepos-rd.strremain-4;
|
|
|
|
whdr.riff_id = 0x46464952;
|
|
whdr.riff_format = 0x45564157;
|
|
whdr.wFormatTag = 0x01;
|
|
whdr.nSamplesPerSec = freqs[fr.sampling_frequency];
|
|
whdr.nChannels = 2;
|
|
whdr.wBitsPerSample = 16;
|
|
|
|
return test_wav(&whdr);
|
|
};
|
|
|
|
|
|
void play_mp3()
|
|
{ char *outPtr;
|
|
int totalout;
|
|
int outcount;
|
|
|
|
// memset(&fr,0,sizeof(fr));
|
|
fr.down_sample_sblimit = 32;
|
|
fr.single = -1;
|
|
reset_mpg();
|
|
|
|
outPtr = outbuf;
|
|
totalout=0;
|
|
done = 0;
|
|
outremain=0x40000;
|
|
|
|
memset(outbuf,0,0x40000);
|
|
set_reader(&rd, 0); //;first_sync);
|
|
|
|
while(1)
|
|
{ if(status!=ST_PLAY)
|
|
break;
|
|
|
|
for(;;)
|
|
{ outcount = 0;
|
|
if( !read_frame(&rd, &fr))
|
|
{ done = 1;
|
|
break;
|
|
};
|
|
fr.do_layer(&fr, outPtr,&outcount);
|
|
outPtr+= outcount;
|
|
totalout+=outcount;
|
|
outremain-=outcount;
|
|
if(outremain < outcount*2)
|
|
break;
|
|
};
|
|
|
|
if(done)
|
|
{ if(totalout < 4096)
|
|
{ memset(outPtr,0,4096-totalout);
|
|
totalout = 4096;
|
|
};
|
|
}
|
|
else
|
|
if(totalout < 8192)
|
|
continue;
|
|
|
|
outPtr = outbuf;
|
|
while (totalout >= 4096)
|
|
{
|
|
|
|
WaveOut(hBuff,outPtr,4096);
|
|
if(status!=ST_PLAY)
|
|
{ if(status != ST_EXIT)
|
|
status = ST_STOP;
|
|
return;
|
|
};
|
|
totalout-=4096;
|
|
outPtr+=4096;
|
|
outremain+=4096;
|
|
};
|
|
if(done)
|
|
break;
|
|
|
|
memmove(outbuf,outPtr, totalout);
|
|
outPtr = outbuf+totalout;
|
|
}
|
|
|
|
if(status != ST_EXIT)
|
|
status = ST_STOP;
|
|
};
|
|
|
|
void play_wave()
|
|
{ int count;
|
|
|
|
set_reader(&rd,44);
|
|
while(1)
|
|
{
|
|
if(status!=ST_PLAY)
|
|
break;
|
|
|
|
if( count=stream_read_raw(&rd,outbuf,32768))
|
|
{
|
|
WaveOut(hBuff,outbuf,count);
|
|
continue;
|
|
}
|
|
done = 1;
|
|
break;
|
|
};
|
|
|
|
if(status != ST_EXIT)
|
|
status = ST_STOP;
|
|
};
|
|
|
|
void play_xm(){ /* uFMOD integration */
|
|
while(status == ST_PLAY){ /* uFMOD integration */
|
|
uFMOD_WaveOut(hBuff); /* uFMOD integration */
|
|
delay(8); /* uFMOD integration */
|
|
} /* uFMOD integration */
|
|
if(status != ST_EXIT) status = ST_STOP; /* uFMOD integration */
|
|
} /* uFMOD integration */
|
|
|
|
void snd_stop()
|
|
{
|
|
StopBuffer(hBuff);
|
|
};
|
|
|
|
void _stdcall thread_proc(void *param)
|
|
{ int evnt;
|
|
int pos;
|
|
int key;
|
|
DWORD offset;
|
|
|
|
_asm
|
|
{
|
|
mov eax, 66
|
|
mov ebx, 1
|
|
mov ecx, 1
|
|
int 0x40
|
|
};
|
|
|
|
draw_window();
|
|
|
|
while(1)
|
|
{ if(status==ST_PLAY)
|
|
{ draw_progress_bar();
|
|
evnt = wait_for_event(80);
|
|
}
|
|
else
|
|
evnt = wait_for_event_infinite();
|
|
|
|
switch(evnt)
|
|
{
|
|
case EV_REDRAW:
|
|
draw_window();
|
|
break;
|
|
|
|
case EV_KEY:
|
|
if(!get_key(&key))
|
|
{
|
|
|
|
switch(key)
|
|
{ case 0xE0:
|
|
case 0xE1:
|
|
break;
|
|
default:
|
|
switch (key)
|
|
{
|
|
case 0x01: //Esc
|
|
status = ST_EXIT;
|
|
exit();
|
|
break;
|
|
|
|
case 0x47: //Home
|
|
if(l_vol < 0)
|
|
{ l_vol+=100;
|
|
r_vol+=100;
|
|
SetVolume(hBuff,l_vol,r_vol);
|
|
};
|
|
break;
|
|
case 0x4F: //End
|
|
if(l_vol > -10000)
|
|
{ l_vol-=100;
|
|
r_vol-=100;
|
|
SetVolume(hBuff,l_vol,r_vol);
|
|
};
|
|
break;
|
|
case 0x53:
|
|
if(pan > -10000)
|
|
{ pan -=100;
|
|
SetPan(hBuff,pan);
|
|
};
|
|
break;
|
|
case 0x51:
|
|
if(pan < 10000)
|
|
{ pan +=100;
|
|
SetPan(hBuff,pan);
|
|
};
|
|
break;
|
|
}
|
|
};
|
|
};
|
|
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(l_vol > -10000)
|
|
{
|
|
l_vol-=100;
|
|
r_vol-=100;
|
|
SetVolume(hBuff,l_vol,r_vol);
|
|
};
|
|
break;
|
|
|
|
case 0x15:
|
|
if(l_vol < 0)
|
|
{ l_vol+=100;
|
|
r_vol+=100;
|
|
SetVolume(hBuff,l_vol,r_vol);
|
|
};
|
|
break;
|
|
|
|
case 0x30:
|
|
if(status==ST_DONE)
|
|
break;
|
|
pos = (GetMousePos(REL_WINDOW)>>16)-7;
|
|
offset = ((fileinfo.size-44)/286*pos+44)&0xFFFFFFFC;
|
|
set_reader(&rd, offset);
|
|
draw_progress_bar();
|
|
break;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
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 *memmove ( void * dst, void * src, unsigned int count) /* uFMOD integration */
|
|
{ void *ret;
|
|
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;
|
|
};
|
|
//**********/
|
|
|
|
void * __cdecl mem_cpy(void * dst,const void * src,size_t count)
|
|
{ void * ret = dst;
|
|
while (count--)
|
|
{ *(char *)dst = *(char *)src;
|
|
dst = (char *)dst + 1;
|
|
src = (char *)src + 1;
|
|
};
|
|
return(ret);
|
|
}
|
|
|
|
char * __cdecl strrchr (const char * string,int ch)
|
|
{
|
|
char *start = (char *)string;
|
|
|
|
while (*string++) /* find end of string */
|
|
;
|
|
/* search towards front */
|
|
while (--string != start && *string != (char)ch)
|
|
;
|
|
|
|
if (*string == (char)ch) /* char found ? */
|
|
return( (char *)string );
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
int __cdecl _stricmp (const char * dst, const char * src)
|
|
{
|
|
int f, l;
|
|
|
|
do
|
|
{
|
|
if ( ((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z') )
|
|
f -= 'A' - 'a';
|
|
if ( ((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z') )
|
|
l -= 'A' - 'a';
|
|
}
|
|
while ( f && (f == l) );
|
|
|
|
return(f - l);
|
|
}
|
|
|
|
|