home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 6
/
AACD06.ISO
/
AACD
/
Sound
/
DelfMPEG
/
src
/
DelfMPEG.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-10-27
|
25KB
|
714 lines
/*****************************************************************************
DelfMPEG - MPEG audio player for Delfina DSP
Copyright (C) 1999 Michael Henke
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#define DELFINA_SAMPLES 1152
#define LOADBUFFERS 256 /* number of segments in ring buffer */
#define BUFFERSIZE 1792 /* MPG_MAXFRAMESIZE */
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/asyncio.h>
#include <proto/timer.h>
#include <proto/reqtools.h>
#include <exec/interrupts.h>
#include <exec/execbase.h>
#include <libraries/asyncio.h>
#include <devices/timer.h>
#include <libraries/reqtools.h>
#include <math.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
static UBYTE version[]="$VER: DelfMPEG 0.2 (Wed 27-Oct-1999)";
static UBYTE template[]="FILES/M,VERBOSE/S,NOPLAY/S,SHOWTAG/S,NOFASTL/S,NOFASTP/S";
struct loadbuf {
UBYTE *ptr;
ULONG framesize, delfcopysize, header;
UWORD layer, mode, modext, freq, errprot, br_ind, crc;
UWORD sblimit, jsbound, translate;
struct loadbuf *next;
};
struct loadbuf load_buf[LOADBUFFERS], *curr_load, *curr_play;
far UBYTE load_memory[BUFFERSIZE*LOADBUFFERS];
static ULONG mpg_freq[4]={44100,48000,32000,77777};
static UBYTE *mpg_modename[4]={"stereo ","j-stereo ","dual-ch ","single-ch"};
static UBYTE *mpg_layername[3]={"I ","II ","III"};
static UWORD mpg_bitrate[3][16]=
{ {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, /* I */
{0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, /* II */
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0} }; /* III */
static UWORD mpg_translate[3][2][16] =
{ { { 0,2,2,2,2,2,2,0,0,0,1,1,1,1,1,0 } , /* 44100 stereo */
{ 0,2,2,0,0,0,1,1,1,1,1,1,1,1,1,0 } } , /* 44100 mono */
{ { 0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0 } , /* 48000 stereo */
{ 0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0 } } , /* 48000 mono */
{ { 0,3,3,3,3,3,3,0,0,0,1,1,1,1,1,0 } , /* 32000 stereo */
{ 0,3,3,0,0,0,1,1,1,1,1,1,1,1,1,0 } } }; /* 32000 mono */
static UWORD mpg_sblimit[4]={27,30,8,12};
static ULONG ID3v1_TAG;
static UBYTE ID3v1_buffer[142];
#define SBLIMIT 32
#define SCALE_BLOCK 12
#define SSLIMIT 18
#define MPG_MD_STEREO 0
#define MPG_MD_JOINT_STEREO 1
#define MPG_MD_DUAL_CHANNEL 2
#define MPG_MD_MONO 3
#define HDR_MPEG1 0xfff80000
#define HDR_CONSTANT 0x00060c00 /* layer, sampling frequency */
#define ID3V1 0x54414700 /* TAG */
#define ID3V2 0x49443300 /* ID3 */
UBYTE get_delfina_48khz[32]; /* input buffer for GetVar() */
ULONG delfina_48khz=0;
extern struct DelfObj DSP56K_PCM;
extern struct DelfObj DSP56K_MP2;
extern struct DelfObj DSP56K_MP3;
#include <libraries/delfina.h>
extern struct ExecBase *SysBase;
struct Library *DelfinaBase=NULL;
struct Library *AsyncIOBase=NULL;
struct Library *TimerBase=NULL;
struct ReqToolsBase *ReqToolsBase=NULL;
struct AsyncFile *file;
struct FileInfoBlock *fib=NULL;
struct TagItem tag_done={TAG_DONE};
UBYTE rtfilename[128]={0};
struct Task *mytask;
ULONG bytes_total, bytes_loaded, buffers_filled, buffers_missed;
ULONG firstheader, prevheader, currheader, frames_loaded, frames_played;
struct Interrupt delfint={0};
struct DelfPrg *prg_pcm=NULL, *prg_mp2=NULL, *prg_mp3=NULL;
struct DelfModule *mod_pcm=NULL;
DELFPTR mem_mp2=NULL, mem_mp2p=NULL;
int key=0;
ULONG mono,freq,layer,pause,noplay,showtag;
ULONG verbose, ende=0, havetag, nofastl, nofastp;
int rc=0;
/*
**
** Delfina interrupt server **
**
*/
void int_server(void)
{
if(pause)
{
/*
** mute **
*/
Delf_Run( prg_pcm->prog+2, 99, DRUNF_ASYNCH, 0, 0, 0, 0 );
}
else
{
if(buffers_filled>0)
{
switch(layer)
{
case 2:
/*
** send framedata to Delfina and launch MP2 decoder **
*/
Delf_CopyMem( curr_play->ptr,
(void*)(prg_mp2->xdata+2048),
curr_play->delfcopysize,
DCPF_FROM_AMY|DCPF_XDATA|DCPF_24BIT );
Delf_Run( prg_mp2->prog+2, 99, DRUNF_ASYNCH,
mono,
Delf_Peek(prg_pcm->ydata,DMEMF_YDATA),
curr_play->translate,
curr_play->jsbound );
break;
case 3:
/*
** send framedata to Delfina and launch MP3 decoder **
*/
/**********************
Delf_CopyMem( curr_play->ptr,
(void*)prg_mp3->ydata,
curr_play->delfcopysize,
DCPF_FROM_AMY|DCPF_YDATA|DCPF_24BIT );
Delf_Run( prg_mp3->prog+2, 99, DRUNF_ASYNCH,
mono,
Delf_Peek(prg_pcm->ydata,DMEMF_YDATA),
0,0 );
**********************/
break;
default:
break;
}
frames_played++;
buffers_filled--;
curr_play=curr_play->next;
}
else buffers_missed++;
}
}
/*
**
** allocate Delfina resources **
**
*/
int init_delfina(void)
{
if(noplay) return(0);
if(!(prg_pcm=Delf_AddPrg(&DSP56K_PCM))) {
printf("**not enough Delfina memory\n");
return(0);
}
Delf_Run(prg_pcm->prog,0,0,mono,0,freq,0);
switch(layer)
{
case 2:
if(!nofastl) mem_mp2 =Delf_AllocMem( 96, DMEMF_LDATA|DMEMF_INTERNAL|DMEMF_ALIGN_64 );
if(!nofastp) mem_mp2p=Delf_AllocMem( 32, DMEMF_PROG |DMEMF_INTERNAL );
prg_mp2 =Delf_AddPrg( &DSP56K_MP2 );
if( !prg_mp2 ) {
printf("**not enough Delfina memory\n");
return(0);
}
Delf_Run( prg_mp2->prog, 0, 0, mem_mp2, mem_mp2p, 0, 0 );
if( (!mem_mp2 && !nofastl) || (!mem_mp2p && !nofastp) ) {
printf("warning: not enough internal DSP memory\n"
"the MPEG decoder might run too slow and could even crash!\n");
}
break;
case 3:
printf("**layer %d decoder is not implemented yet\n",layer);
return(0);
/****************
if(!(prg_mp3=Delf_AddPrg(&DSP56K_MP3))) {
printf("**not enough Delfina memory\n");
return(0);
}
Delf_Run( prg_mp3->prog, 0, 0, 0, 0, 0, 0 );
****************/
break;
default:
printf("**layer %d is currently not supported\n",layer);
return(0);
}
if(!(mod_pcm=Delf_AddModule( DM_Inputs, 0,
DM_Outputs, 1,
DM_Code, prg_pcm->prog+4,
DM_Freq, 48000, /* always 48kHz output */
DM_Name, "DelfMPEG", 0)))
{
printf("**couldn't create DelfModule\n");
return(0);
}
delfint.is_Code=(void(*)(void))int_server;
if (!(key=Delf_AddIntServer(prg_pcm->prog,&delfint))) {
printf("**couldn't create interrupt server\n");
return(0);
}
return(1);
}
/*
**
** free Delfina resources **
**
*/
void cleanup_delfina(void)
{
Disable();
if (key) { Delf_RemIntServer(key); key=0; }
if (mod_pcm) { Delf_RemModule(mod_pcm); mod_pcm=NULL; }
if (prg_pcm) { Delf_RemPrg(prg_pcm); prg_pcm=NULL; }
if (prg_mp2) { Delf_RemPrg(prg_mp2); prg_mp2=NULL; }
if (prg_mp3) { Delf_RemPrg(prg_mp3); prg_mp3=NULL; }
if (mem_mp2) { Delf_FreeMem(mem_mp2,DMEMF_LDATA|DMEMF_INTERNAL); mem_mp2=NULL; }
if (mem_mp2p){ Delf_FreeMem(mem_mp2p,DMEMF_PROG|DMEMF_INTERNAL); mem_mp2p=NULL; }
Enable();
}
/*
**
** analyze frame header and load frame **
**
*/
int read_frame(struct loadbuf *lb)
{
/** let's ignore these header infos (we don't need them here)
*** ->version, ->extension, ->copyright, ->original, ->emphasis **/
lb->header = currheader;
lb->layer = 4-((currheader>>17)&3);
lb->mode = ((currheader>>6)&0x3);
lb->modext = ((currheader>>4)&0x3);
lb->br_ind = ((currheader>>12)&0xf);
lb->freq = ((currheader>>10)&0x3);
lb->errprot = ((currheader>>16)&0x1)^0x1;
lb->translate= mpg_translate[lb->freq]
[(lb->mode==MPG_MD_MONO)?1:0]
[lb->br_ind];
lb->sblimit = mpg_sblimit[lb->translate];
lb->jsbound = (lb->mode==MPG_MD_JOINT_STEREO) ?
(lb->modext<<2)+4 : lb->sblimit;
lb->framesize = (mpg_bitrate[lb->layer-1][lb->br_ind]*144000)
/mpg_freq[lb->freq] + ((currheader>>9)&0x1); /* padding */
lb->delfcopysize = lb->framesize-4;
if(lb->errprot)
{
ReadAsync(file,&lb->crc,2);
lb->delfcopysize-=2;
}
ReadAsync(file,lb->ptr,lb->delfcopysize);
return(0);
}
int main(void)
{
struct RDArgs *rdargs;
LONG args[6]={0,0,0,0,0,0}, r1, i, taskpri;
ULONG sigs;
UBYTE **files_pt, *filename;
double duration, duration2;
ULONG minutes, seconds, millisec;
struct timeval time1,time2;
struct rtFileRequester *rtfilereq=NULL;
struct rtFileList *rtfilelist=NULL, *rtfilelist_curr=NULL;
BPTR lock_newdir=NULL, lock_olddir=NULL;
/*
**
** read args **
**
*/
printf("\33[1m%s by Smack/Infect!\33[0m\n",&version[6]);
rdargs=ReadArgs(template,args,NULL);
files_pt=(char**)args[0];
verbose=args[1];
noplay=args[2];
showtag=args[3];
nofastl=args[4];
nofastp=args[5];
if(verbose)
printf(
"\n"
" DelfMPEG - MPEG audio player for Delfina DSP\n"
" Copyright (C) 1999 Michael Henke\n"
"\n"
" This program is free software; you can redistribute it and/or modify\n"
" it under the terms of the GNU General Public License as published by\n"
" the Free Software Foundation; either version 2 of the License, or\n"
" (at your option) any later version.\n"
"\n"
" This program is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
" GNU General Public License for more details.\n"
"\n"
" You should have received a copy of the GNU General Public License\n"
" along with this program; if not, write to the Free Software\n"
" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
"\n" );
/*
**
** open libraries & stuff **
**
*/
if(!noplay)
{
if (!(DelfinaBase=OpenLibrary("delfina.library",4))) {
printf("**unable to open delfina.library V4\n");
rc=20;
goto exit_clean;
}
}
if (!(AsyncIOBase=OpenLibrary("asyncio.library",39))) {
printf("**unable to open asyncio.library V39\n");
rc=20;
goto exit_clean;
}
TimerBase=(struct Library*)FindName(&SysBase->DeviceList,"timer.device");
if(0<(GetVar("DELFINA_48KHZ",get_delfina_48khz,32,LV_VAR)))
{
delfina_48khz=strtoul(get_delfina_48khz,NULL,10);
if(verbose) printf(" ////read ENV: DELFINA_48KHZ = '%s' (%ldHz)\n",get_delfina_48khz,delfina_48khz);
if(delfina_48khz==ULONG_MAX) delfina_48khz=0;
}
mytask=FindTask(NULL);
if(!(fib=AllocDosObject(DOS_FIB,&tag_done)))
{
rc=20;
goto exit_clean;
}
/*
**
** init load buffers **
**
*/
for(i=0;i<LOADBUFFERS;i++)
{
load_buf[i].ptr =&load_memory[i*BUFFERSIZE];
load_buf[i].next=&load_buf[i+1];
}
load_buf[LOADBUFFERS-1].next=&load_buf[0];
/*
**
** reqtools filerequester if no files specified **
**
*/
if(!files_pt)
{
if((ReqToolsBase=(struct ReqToolsBase*)OpenLibrary("reqtools.library",38)))
{
if(!(rtfilereq=rtAllocRequest(RT_FILEREQ,NULL)))
{
rc=10;
goto exit_clean;
}
}
else
{
rc=5;
goto exit_clean;
}
}
next_filereq:
if(rtfilereq)
{
rtfilelist=rtFileRequest( rtfilereq, &rtfilename[0],
"DelfMPEG: select MPEG audio files",
RTFI_Flags, FREQF_MULTISELECT|FREQF_PATGAD,
TAG_DONE );
if(rtfilelist)
{
rtfilelist_curr=rtfilelist;
if(rtfilereq->Dir)
{
lock_newdir=Lock(rtfilereq->Dir,SHARED_LOCK);
lock_olddir=CurrentDir(lock_newdir);
}
}
else goto exit_clean;
}
/*
**
** files loop **
**
*/
do
{
/*
**
** get next filename **
**
*/
if(rtfilelist)
{
if(rtfilelist_curr)
{
filename=rtfilelist_curr->Name;
rtfilelist_curr=rtfilelist_curr->Next;
}
else filename=NULL;
}
else filename=(*files_pt++);
if(!filename) break;
printf("\n file: %s\n",filename);
curr_load=curr_play=&load_buf[0];
bytes_loaded=buffers_filled=buffers_missed=0;
firstheader=prevheader=currheader=0;
frames_loaded=frames_played=0;
pause=1;
/*
**
** open file **
**
*/
if((file=OpenAsync(filename,MODE_READ,128*1024)))
{
/*
**
** read first frame **
**
*/
ExamineFH(file->af_File,fib);
bytes_total=fib->fib_Size;
r1=ReadAsync(file,&currheader,4);
if( (r1==4) &&
((currheader&HDR_MPEG1)==HDR_MPEG1) )
{
if(showtag)
{
SeekAsync(file, -128, MODE_END);
ID3v1_TAG=0; havetag=0;
ReadAsync(file, &ID3v1_TAG, 3);
if((ID3v1_TAG&ID3V1)==ID3V1)
{
ReadAsync(file,&ID3v1_buffer[00],30); /* title */
ReadAsync(file,&ID3v1_buffer[31],30); /* artist */
ReadAsync(file,&ID3v1_buffer[62],30); /* album */
ReadAsync(file,&ID3v1_buffer[93],04); /* year */
ReadAsync(file,&ID3v1_buffer[98],30); /* comment*/
ReadAsync(file,&ID3v1_buffer[141],1); /* genre */
for(i=0;i<124;i++)
{
if(ID3v1_buffer[i]<0x20) ID3v1_buffer[i]=0x20;
}
ID3v1_buffer[30]=0x00;
ID3v1_buffer[30+1+30]=0x00;
ID3v1_buffer[30+1+30+1+30]=0x00;
ID3v1_buffer[30+1+30+1+30+1+4]=0x00;
ID3v1_buffer[30+1+30+1+30+1+4+1+30]=0x00;
havetag=1;
}
SeekAsync(file, 4, MODE_START);
}
read_frame(curr_load);
freq=mpg_freq[curr_load->freq];
mono=(curr_load->mode==MPG_MD_MONO) ? 1 : 0;
layer=curr_load->layer;
duration=(double)bytes_total/((double)freq/1152.0)/(double)curr_load->framesize;
printf(" type: layer %s %03dkbps %ldHz %s\n",
mpg_layername[layer-1],
mpg_bitrate[layer-1][curr_load->br_ind],
freq,
mpg_modename[curr_load->mode] );
millisec=(ULONG)(1000.0*modf(duration,&duration2));
minutes=(ULONG)(duration2/60.0);
seconds=(ULONG)(duration2-minutes*60.0);
printf(" time: %02ld min %02ld.%03ld sec\n",minutes,seconds,millisec);
if(verbose) printf(" ////filesize/framesize: %ld/%ld bytes\n",bytes_total,curr_load->framesize);
if(delfina_48khz)
{
freq=(ULONG)((double)freq*48000.0/(double)delfina_48khz);
if(verbose) printf(" ////adjusted freq: %ldHz\n",freq);
}
if(showtag && havetag)
{
printf( " TAG ID3v1\n title: %s\n artist: %s\n"
" album: %s\n comment: %s\n"
" year: %s genre: %d\n",
&ID3v1_buffer[00], /* title */
&ID3v1_buffer[31], /* artist */
&ID3v1_buffer[62], /* album */
&ID3v1_buffer[98], /* comment*/
&ID3v1_buffer[93], /* year */
(int)ID3v1_buffer[141] ); /* genre */
}
firstheader=prevheader=currheader;
buffers_filled++;
frames_loaded++;
bytes_loaded+=curr_load->framesize;
curr_load=curr_load->next;
if( init_delfina() )
{
printf(" playing..."); fflush(stdout);
taskpri=SetTaskPri(mytask,9);
pause=0;
GetSysTime(&time1);
/*
**
** frames loop **
**
*/
while(!ende)
{
sigs=mytask->tc_SigRecvd;
if(sigs&SIGBREAKF_CTRL_C)
{
printf(" break CTRL-C\n");
mytask->tc_SigRecvd&=!SIGBREAKF_CTRL_C;
pause=1;
break; /* exit frames loop */
}
if(sigs&SIGBREAKF_CTRL_D)
{
printf(" break CTRL-D\n");
mytask->tc_SigRecvd&=!SIGBREAKF_CTRL_D;
pause=1;
ende=1;
break; /* exit frames loop */
}
if(sigs&SIGBREAKF_CTRL_E)
{
mytask->tc_SigRecvd&=!SIGBREAKF_CTRL_E;
if(pause)
{
printf("\n playing..."); fflush(stdout);
pause=0;
}
else
{
pause=1;
printf(" pause"); fflush(stdout);
}
}
if( (buffers_filled<LOADBUFFERS) &&
(bytes_loaded<bytes_total) )
{
r1=ReadAsync(file,&currheader,4);
if( (r1==4) &&
((currheader&HDR_MPEG1)==HDR_MPEG1) )
{
if((currheader&HDR_CONSTANT)==(prevheader&HDR_CONSTANT))
{
read_frame(curr_load);
/* printf("//////sblimit/jsbound/alloc_table: %d/%d/%d\n",curr_load->sblimit,curr_load->jsbound,curr_load->translate);*/
prevheader=currheader;
buffers_filled++;
frames_loaded++;
bytes_loaded+=curr_load->framesize;
curr_load=curr_load->next;
}
else
{
printf(" (invalid MPEG file)");
if(verbose)
printf("\n **position=0x%08lx currheader=0x%08lx\n ",bytes_loaded,currheader);
bytes_loaded=bytes_total; /* force EOF */
fflush(stdout);
}
}
else /* frame header error */
{
if(r1==4)
{
printf(" (non-audio data)");
if(verbose)
printf("\n ////position=0x%08lx currheader=0x%08lx\n ",bytes_loaded,currheader);
}
bytes_loaded=bytes_total; /* force EOF */
fflush(stdout);
}
}
else
{
if( (bytes_loaded>=bytes_total) &&
(frames_played>=frames_loaded) )
{
printf(" done\n");
pause=1;
break; /* exit frames loop */
}
Delay(1);
}
}
GetSysTime(&time2);
SetTaskPri(mytask,taskpri);
if((buffers_missed>1) && verbose)
{
printf(" note: irq was missing data %ld times\n",buffers_missed-1);
}
SubTime(&time2,&time1);
millisec=(ULONG)((double)time2.tv_micro/1000.0);
minutes=(ULONG)((double)time2.tv_secs/60.0);
seconds=(ULONG)((double)time2.tv_secs-minutes*60.0);
duration2=(double)time2.tv_secs+(double)time2.tv_micro/1000000.0;
if(verbose)
{
printf(" ////frames played/loaded: %ld/%ld\n",frames_played,frames_loaded);
printf(" ////elapsed time: %02ld min %02ld.%03ld sec\n",minutes, seconds, millisec);
}
}
cleanup_delfina();
}
else printf("**MPEG file not recognized\n");
CloseAsync(file);
}
else printf("**unable to open file\n");
cleanup_delfina();
} while(!ende);
if(rtfilelist)
{
if(lock_olddir) { CurrentDir(lock_olddir); lock_olddir=NULL; }
if(lock_newdir) { UnLock(lock_newdir); lock_newdir=NULL; }
rtFreeFileList(rtfilelist); rtfilelist=NULL;
if(!ende) goto next_filereq;
}
exit_clean:
if(rdargs) FreeArgs(rdargs);
if(fib) FreeDosObject(DOS_FIB,fib);
if(rtfilereq) rtFreeRequest(rtfilereq);
if(ReqToolsBase) CloseLibrary((struct Library*)ReqToolsBase);
if(AsyncIOBase) CloseLibrary(AsyncIOBase);
if(DelfinaBase) CloseLibrary(DelfinaBase);
return(rc);
}