#define __USE_SYSBASE #include #include #include #include #include #include #include #include #ifdef __PPC__ #include #undef SetSignal #define SetSignal PPCSetSignal #undef Open #define Open PPCOpen #undef Close #define Close PPCClose #undef Read #define Read PPCRead #undef Write #define Write PPCWrite #undef CreatePool #define CreatePool PPCCreatePool #undef DeletePool #define DeletePool PPCDeletePool #undef AllocPooled #define AllocPooled PPCAllocPooled #undef FreePooled #define FreePooled PPCFreePooled #endif #include "common.h" static const char version[]="$VER: RAPlay 3.1 (14.05.02) The Amiga RealAudio v1/2/3 player/decoder, thanks to all!"; ULONG __nocommandline = 0; ULONG __stack = 32768; struct Library *AsyncIOBase = NULL; AsyncFile *InputFile = NULL; AsyncFile *OutputFile = NULL; Real_144 *Real144 = NULL; Real_288 *Real288 = NULL; Real_dnet *Realdnet = NULL; struct MsgPort *AHImp = NULL; struct AHIRequest *AHIio = NULL; struct AHIRequest *AHIio2 = NULL; BYTE AHIDevice = -1; struct RDArgs *rdargs = NULL; STRPTR Template = "INPUT,OUTPUT,U=UNIT/K/N,AIFF/S,VERBOSE/S"; enum { TEM_INPUT, TEM_OUTPUT, TEM_UNIT, TEM_AIFF, TEM_VERBOSE, TEM_NUMARGS }; signed short *outbuf=NULL,*dubbuf=NULL; BPTR StdIn, StdOut, StdErr; void *MemPool = NULL; #ifndef __GNUC__ static int break_cleanup(void) { /* Just a dummy so atexit() will work */ return 1; } #endif static void exit_cleanup(void) { if(Real144); { free_144(Real144); Real144 = NULL; } if(Real288); { free_288(Real288); Real288 = NULL; } if(Realdnet); { free_dnet(Realdnet); Realdnet = NULL; } if(InputFile); { CloseAsync(InputFile); InputFile = NULL; } if(OutputFile); { CloseAsync(OutputFile); OutputFile = NULL; } if(AsyncIOBase) { CloseLibrary(AsyncIOBase); AsyncIOBase = NULL; } if(!AHIDevice) { CloseDevice((struct IORequest *)AHIio); AHIDevice = -1; } if(AHIio) { DeleteIORequest((struct IORequest *)AHIio); AHIio = NULL; } if(AHIio2) { DeleteIORequest((struct IORequest *)AHIio2); AHIio2 = NULL; } if(AHImp) { DeleteMsgPort(AHImp); AHImp = NULL; } if(StdErr); { Close(StdErr); StdErr = NULL; } if(MemPool) { DeletePool(MemPool); MemPool = NULL; } if(rdargs) { FreeArgs(rdargs); rdargs = NULL; } } static void Fail(STRPTR reason) { FPrintf(StdErr, "%s\n", (ULONG)reason); exit(20); } static LONG DOSRead(APTR buf, LONG len) { return Read(StdIn, buf, len); } static LONG DOSWrite(APTR buf, LONG len) { return Write(StdOut, buf, len); } static LONG ASNRead(APTR buf, LONG len) { return ReadAsync(InputFile, buf, len); } static LONG ASNWrite(APTR buf, LONG len) { return WriteAsync(OutputFile, buf, len); } static void uint2tenbytefloat(unsigned int num, unsigned char *bytes) { int count, mask = 0x40000000; memset(bytes, 0, 10); if (num <= 1) { bytes[0] = 0x3F; bytes[1] = 0xFF; bytes[2] = 0x80; return; } bytes[0] = 0x40; if (num >= mask) { bytes[1] = 0x1D; return; } for (count=0; count<=32; count++) { if (num & mask) break; mask >>= 1; } num <<= count + 1; bytes[1] = 29 - count; bytes[2] = (num>>24) & 0xFF; bytes[3] = (num>>16) & 0xFF; bytes[4] = (num>>8) & 0xFF; bytes[5] = num & 0xFF; } static int GetCodec(unsigned char *buf, unsigned int *freq, unsigned int *chans, unsigned int *blocksize, unsigned short verbose) { int codec = 0; if (buf[0]=='.' && buf[1]=='r' && buf[2]=='a' && buf[3]==0xfd) { if (buf[5]==4) { int i; i = buf[56] + 58; if (buf[i]=='2' && buf[i+1]=='8' && buf[i+2]=='_' && buf[i+3]=='8') codec = 2; else if (buf[i]=='d' && buf[i+1]=='n' && buf[i+2]=='e' && buf[i+3]=='t') codec = 3; // else if (buf[i]=='s' && buf[i+1]=='i' && buf[i+2]=='p' && buf[i+3]=='r') codec = 4; *freq = (buf[48]<<8 | buf[49]); *chans = (buf[54]<<8 | buf[55]); *blocksize = (buf[24]<<24 | buf[25]<<16 | buf[26]<<8 | buf[27]); if (verbose) { int j; char *c, *s, *s2; s = buf + 57; j = buf[56] + 57; c = buf + j; j += *c + 1; *c = 0; s2 = c + 1; c = buf + j; *c = 0; FPrintf(StdErr, "Codec: %s/%s (v%ld)\n", (ULONG)s, (ULONG)s2, (ULONG)codec); s = buf + 70; j = buf[69] + 70; c = buf + j; j += *c + 1; *c = 0; FPrintf(StdErr, "Title: %s\n", (ULONG)s); s = c + 1; c = buf + j; j += *c + 1; *c = 0; FPrintf(StdErr, "Author: %s\n", (ULONG)s); s = c + 1; c = buf + j; *c = 0; FPrintf(StdErr, "Copyright: %s\n\n", (ULONG)s); } } else if (buf[5]==3) { codec = 1; *freq = 8000; *chans = (buf[8]<<8 | buf[9]); *blocksize = (buf[10]<<24 | buf[11]<<16 | buf[12]<<8 | buf[13]); if (verbose) { int j; char *c, *s; FPrintf(StdErr, "Codec: 14_4 (v%ld)\n", (ULONG)codec); s = buf + 23; j = buf[22] + 23; c = buf + j; j += *c + 1; *c = 0; FPrintf(StdErr, "Title: %s\n", (ULONG)s); s = c + 1; c = buf + j; j += *c + 1; *c = 0; FPrintf(StdErr, "Author: %s\n", (ULONG)s); s = c + 1; c = buf + j; *c = 0; FPrintf(StdErr, "Copyright: %s\n\n", (ULONG)s); } } } return codec; } static LONG ReadPackets(LONG (*ReadFunc)(APTR,LONG), unsigned char *buf, unsigned int chunksize, unsigned int *packets, unsigned short *streamid, unsigned short *rmf) { LONG ret = 0; if (*rmf) { int i; unsigned short len, id; while ((ret < chunksize) && (*packets)) { do { if (ReadFunc(buf, 12) <= 0) Fail("Unexpected EOF or error while reading."); if (buf[0] != 0 || buf[1] != 0) Fail("Unsupported packet-version in RealMedia file!"); len = (buf[2]<<8 | buf[3]) - 12; id = (buf[4]<<8 | buf[5]); if ((ret + len) > chunksize) { if (id == *streamid) { FPrintf(StdErr, "RealMedia packet won't fit in buffer, skipping...\n"); } i = chunksize - ret; while (len) { if (len < i) i = len; if (ReadFunc(buf, i) <= 0) Fail("Unexpected EOF or error while reading."); len -= i; } i = 0; } else { if ((i = ReadFunc(buf, len)) <= 0) Fail("Unexpected EOF or error while reading."); } --*packets; } while ((id != *streamid) && (*packets)); if (id == *streamid) { ret += i; buf += i; } } } else { ret = ReadFunc(buf, chunksize); } if ((ret > 0) && (ret < chunksize)) { int i = chunksize - ret; /* Clear the rest of the buffer */ memset(buf + ret, 0, i); } return ret; } static int ReadHeader(LONG (*ReadFunc)(APTR,LONG), unsigned char *buf, unsigned int *freq, unsigned int *chans, unsigned int *blocksize, unsigned int *packets, unsigned short *streamid, unsigned short *rmf, unsigned short verbose) { int i; int codec = 0; unsigned char *in = buf; if ((i = ReadFunc(in, 8)) <= 0) Fail("Unexpected EOF or error while reading."); in += i; if (buf[0]=='.' && buf[1]=='R' && buf[2]=='M' && buf[3]=='F') { int j; int size; int headers; *rmf = 1; size = (buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7]) - 8; if ((i = ReadFunc(in, size)) <= 0) Fail("Unexpected EOF or error while reading."); in += i; if (buf[8] != 0 || buf[9] != 0) Fail("Unsupported chunk-version in RealMedia file!"); headers = (buf[14]<<24 | buf[15]<<16 | buf[16]<<8 | buf[17]); for (j=0; j DATACHUNK2) { if (buf[0]=='M' && buf[1]=='D' && buf[2]=='P' && buf[3]=='R') { FPrintf(StdErr, "RealMedia MDPR-chunk won't fit in buffer, skipping...\n"); } i = DATACHUNK2 - 10; while (size) { if (size < i) i = size; if (ReadFunc(buf, i) <= 0) Fail("Unexpected EOF or error while reading."); size -= i; } } else { if (ReadFunc(in, size) <= 0) Fail("Unexpected EOF or error while reading."); if (verbose) { if (buf[0]=='C' && buf[1]=='O' && buf[2]=='N' && buf[3]=='T') { if (buf[8] == 0 && buf[9] == 0) { int j; char *c, *s; s = buf + 12; j = (buf[10]<<8) + buf[11] + 12; c = buf + j; j += (c[0]<<8) + c[1] + 2; *c = 0; FPrintf(StdErr, "Title: %s\n", (ULONG)s); s = c + 2; c = buf + j; j += (c[0]<<8) + c[1] + 2; *c = 0; FPrintf(StdErr, "Author: %s\n", (ULONG)s); s = c + 2; c = buf + j; j += (c[0]<<8) + c[1] + 2; *c = 0; FPrintf(StdErr, "Copyright: %s\n", (ULONG)s); s = c + 2; c = buf + j; *c = 0; FPrintf(StdErr, "Comment: %s\n\n", (ULONG)s); } } } if (buf[0]=='M' && buf[1]=='D' && buf[2]=='P' && buf[3]=='R') { if (codec) continue; if (buf[8] != 0 || buf[9] != 0) Fail("Unsupported chunk-version in RealMedia file!"); *streamid = (buf[10]<<8 | buf[11]); i = buf[40] + 1; i += buf[40+i] + 1; in = buf+40+i+4; codec = GetCodec(in, freq, chans, blocksize, verbose); } } } } else if (buf[0]=='.' && buf[1]=='r' && buf[2]=='a' && buf[3]==0xfd) { if (buf[5]==4) { int size; if ((i = ReadFunc(in, 14)) <= 0) Fail("Unexpected EOF or error while reading."); in += i; size = (buf[18]<<24 | buf[19]<<16 | buf[20]<<8 | buf[21]) - 6; if (ReadFunc(in, size) <= 0) Fail("Unexpected EOF or error while reading."); codec = GetCodec(buf, freq, chans, blocksize, verbose); } else if (buf[5]==3) { in = buf + 8; while (buf[6]) { if (ReadFunc(in, 256) <= 0) Fail("Unexpected EOF or error while reading."); } if (ReadFunc(in, buf[7]) <= 0) Fail("Unexpected EOF or error while reading."); codec = GetCodec(buf, freq, chans, blocksize, verbose); } } else { Fail("Unrecognized format!!!"); } return codec; } int main(void) { LONG (*ReadFunc)(APTR,LONG); LONG (*WriteFunc)(APTR,LONG); ULONG unit=0; BOOL terminated=FALSE; ULONG signals,AHIcount=0; struct AHIRequest *link = NULL; LONG ArgArray[TEM_NUMARGS]; unsigned short streamid=0,rmf=0,verbose=0; unsigned int s,x,bufsiz,size,blocksize,chunksize,freq,chans,type,codec=0,packets=0; unsigned char *in; unsigned char *deint; void *tmp; for(x=0;x3) Fail("Illegal unit number!"); if(!(MemPool = CreatePool(MEMF_PUBLIC, 65536, 65536))) Fail("Unable to allocate needed memory."); if(!(in=(unsigned char *)AllocPooled(MemPool, DATACHUNK2))) Fail("Unable to allocate needed memory."); if(ArgArray[TEM_INPUT]) { if(!(AsyncIOBase=OpenLibrary("asyncio.library", 39))) Fail("Unable to open asyncio.library."); #ifndef __GNUC__ onbreak(break_cleanup); #endif atexit(exit_cleanup); if(!(InputFile=OpenAsync((STRPTR)ArgArray[TEM_INPUT], MODE_READ, 16384))) Fail("Unable to open input file."); ReadFunc = ASNRead; if(ArgArray[TEM_OUTPUT]) { if(!(OutputFile=OpenAsync((STRPTR)ArgArray[TEM_OUTPUT], MODE_WRITE, 32768))) Fail("Unable to open output file."); WriteFunc = ASNWrite; } else { if(AHImp=CreateMsgPort()) if(AHIio=(struct AHIRequest *)CreateIORequest(AHImp,sizeof(struct AHIRequest))) { AHIio->ahir_Version = 4; AHIDevice=OpenDevice(AHINAME,unit,(struct IORequest *)AHIio,NULL); } if(AHIDevice) Fail("Unable to open ahi.device v4"); if(!(AHIio2=AllocMem(sizeof(struct AHIRequest), MEMF_PUBLIC))) Fail("Unable to allocate needed memory."); CopyMem(AHIio, AHIio2, sizeof(struct AHIRequest)); } } else { ReadFunc = DOSRead; WriteFunc = DOSWrite; } codec = ReadHeader(ReadFunc,in,&freq,&chans,&blocksize,&packets,&streamid,&rmf,verbose); if(verbose) { FPrintf(StdErr, "Frequency: %luHz\n", (ULONG)freq); FPrintf(StdErr, "Channels: %lu\n", (ULONG)chans); } switch(codec) { case 1: chunksize=blocksize*72; if(!(Real144 = init_144())) Fail("Decoder init failed!!!"); break; case 2: chunksize=blocksize*72; if(!(Real288 = init_288())) Fail("Decoder init failed!!!"); break; case 3: chunksize=blocksize*((chans==1)?8:4); if(!(Realdnet = init_dnet())) Fail("Decoder init failed!!!"); break; default: Fail("Unsupported codec!!!"); break; } if(ArgArray[TEM_AIFF] && !AHImp) { int c = ((chans==1)?1:2); /* Write AIFF header */ in[0]='F'; in[1]='O'; in[2]='R'; in[3]='M'; in[4]=0x7F; in[5]=0xFF; in[6]=0xFF; in[7]=0xFC; /* fake */ in[8]='A'; in[9]='I'; in[10]='F'; in[11]='F'; in[12]='C'; in[13]='O'; in[14]='M'; in[15]='M'; in[16]=0; in[17]=0; in[18]=0; in[19]=18; in[20]=((c>>8)&0xFF); in[21]=(c&0xFF); in[22]=0x3F; in[23]=0xFF; in[24]=0xFF; in[25]=0xFE; /* fake */ in[26]=0; in[27]=16; uint2tenbytefloat(freq,in+28); in[38]='S'; in[39]='S'; in[40]='N'; in[41]='D'; in[42]=0x7F; in[43]=0xFF; in[44]=0xFF; in[45]=0xFC; /* fake */ WriteFunc(in,46); } if(chunksize>DATACHUNK2) { FreePooled(MemPool, in, DATACHUNK2); if(!(in=(unsigned char *)AllocPooled(MemPool, chunksize))) Fail("Unable to allocate needed memory."); } if(codec>1) { if(!(deint=(unsigned char *)AllocPooled(MemPool, chunksize+8))) Fail("Unable to allocate needed memory."); memset(deint,0,chunksize+8); /* Prevent the decoder from reading junk */ } if(chans==1) type=AHIST_M16S; else type=AHIST_S16S; if(AHImp) if(!(dubbuf=(signed short *)AllocPooled(MemPool, AUDIOBUFFER*sizeof(short)))) Fail("Unable to allocate needed memory."); if(!(outbuf=(signed short *)AllocPooled(MemPool, AUDIOBUFFER*sizeof(short)))) Fail("Unable to allocate needed memory."); while((s=size=ReadPackets(ReadFunc,in,chunksize,&packets,&streamid,&rmf))>0) { bufsiz=0; if (!(size/=blocksize)) break; switch (codec) { case 1: for(x=0;xahir_Std.io_Message.mn_Node.ln_Pri = 0; AHIio->ahir_Std.io_Command = CMD_WRITE; AHIio->ahir_Std.io_Data = outbuf; AHIio->ahir_Std.io_Length = bufsiz*sizeof(short); AHIio->ahir_Std.io_Offset = 0; AHIio->ahir_Frequency = freq; AHIio->ahir_Type = type; AHIio->ahir_Volume = 0x10000; AHIio->ahir_Position = 0x8000; AHIio->ahir_Link = link; SendIO((struct IORequest *) AHIio); AHIcount++; if(link) { signals=Wait(SIGBREAKF_CTRL_C | (1L << AHImp->mp_SigBit)); #ifdef __PPC__ if((signals & SIGBREAKF_CTRL_C) || (SetSignal(0,0) & SIGBREAKF_CTRL_C)) #else if(signals & SIGBREAKF_CTRL_C) #endif { terminated=TRUE; break; } if(WaitIO((struct IORequest *) link)) Fail("I/O request failed."); } link = AHIio; tmp = outbuf; outbuf = dubbuf; dubbuf = tmp; tmp = AHIio; AHIio = AHIio2; AHIio2 = tmp; } else { WriteFunc(outbuf,bufsiz*sizeof(short)); if(SetSignal(0,0) & SIGBREAKF_CTRL_C) break; } } if(AHIcount) { if(terminated) { AbortIO((struct IORequest *) AHIio); WaitIO((struct IORequest *) AHIio); if(AHIcount>1) { AbortIO((struct IORequest *) AHIio2); WaitIO((struct IORequest *) AHIio2); } } else WaitIO((struct IORequest *) AHIio2); } if(ArgArray[TEM_AIFF] && !AHImp) { LONG size; if(OutputFile) { if((size=SeekAsync(OutputFile, 0, MODE_CURRENT)-46)>0) { if(SeekAsync(OutputFile, 4, MODE_START)!=-1) { ULONG samples; /* SSND size */ in[0] = (size & 0xFF000000) >> 24; in[1] = (size & 0x00FF0000) >> 16; in[2] = (size & 0x0000FF00) >> 8; in[3] = (size & 0x000000FF) >> 0; samples = size / 2 / ((chans==1)?1:2); size += 38; /* Number of samples */ in[4] = (samples & 0xFF000000) >> 24; in[5] = (samples & 0x00FF0000) >> 16; in[6] = (samples & 0x0000FF00) >> 8; in[7] = (samples & 0x000000FF) >> 0; /* FORM size */ in[8] = (size & 0xFF000000) >> 24; in[9] = (size & 0x00FF0000) >> 16; in[10] = (size & 0x0000FF00) >> 8; in[11] = (size & 0x000000FF) >> 0; WriteFunc(in+8, 4); if(SeekAsync(OutputFile, 22, MODE_START)!=-1) WriteFunc(in+4, 4); if(SeekAsync(OutputFile, 42, MODE_START)!=-1) WriteFunc(in, 4); } } } else { /* Worth a shot? */ if((size=Seek(StdOut, 0, OFFSET_CURRENT)-46)>0) { if(Seek(StdOut, 4, OFFSET_BEGINNING)!=-1) { ULONG samples; /* SSND size */ in[0] = (size & 0xFF000000) >> 24; in[1] = (size & 0x00FF0000) >> 16; in[2] = (size & 0x0000FF00) >> 8; in[3] = (size & 0x000000FF) >> 0; samples = size / 2 / ((chans==1)?1:2); size += 38; /* Number of samples */ in[4] = (samples & 0xFF000000) >> 24; in[5] = (samples & 0x00FF0000) >> 16; in[6] = (samples & 0x0000FF00) >> 8; in[7] = (samples & 0x000000FF) >> 0; /* FORM size */ in[8] = (size & 0xFF000000) >> 24; in[9] = (size & 0x00FF0000) >> 16; in[10] = (size & 0x0000FF00) >> 8; in[11] = (size & 0x000000FF) >> 0; WriteFunc(in+8, 4); if(Seek(StdOut, 22, OFFSET_BEGINNING)!=-1) WriteFunc(in+4, 4); if(Seek(StdOut, 42, OFFSET_BEGINNING)!=-1) WriteFunc(in, 4); } } } } return 0; }