home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- *
- * WAV Datatype, based on the sourcecode found in OS3.1 Native Developer Kit
- *
- * Written by David N.Junod and Christian Buchner
- *
- ******************************************************************************
- * dispatch.c
- * TO DO: Implement different decompression techniques (ADPCM, ยต-law, a-law...)
- */
-
- #include "classbase.h"
-
- /*****************************************************************************/
-
- #define DEBUG 0
-
- #if DEBUG
-
- #define DB(x) x
-
- #include <stdarg.h>
- void __stdargs Error(struct ClassBase *cb,UBYTE *Msg,...)
- {
- va_list Arg;
- struct EasyStruct Req={sizeof(struct EasyStruct),0,"WAV debug message",0,"Okay"};
- va_start(Arg,Msg);
- Req.es_TextFormat=Msg;
- EasyRequestArgs(NULL,&Req,0,Arg);
- va_end(Arg);
- }
-
- #else
-
- #define DB(x)
-
- #endif
-
-
-
- /*****************************************************************************/
-
- Class *initClass (struct ClassBase * cb)
- {
- Class *cl;
-
- if (cl = MakeClass (WAVDTCLASS, SOUNDDTCLASS, NULL, NULL, 0L))
- {
- cl->cl_Dispatcher.h_Entry = (ULONG (*)())Dispatch;
- cl->cl_UserData = (ULONG) cb;
- AddClass (cl);
- }
-
- return (cl);
- }
-
- /*****************************************************************************/
-
- ULONG ASM Dispatch (REG (a0) Class * cl, REG (a2) Object * o, REG (a1) Msg msg)
- {
- struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
- ULONG retval = 0L;
-
- switch (msg->MethodID)
- {
- case OM_NEW:
- if (retval = DoSuperMethodA (cl, o, msg))
- {
- if (!(ConvertObjectData (cb, cl, (Object *) retval, ((struct opSet *) msg)->ops_AttrList)))
- {
- CoerceMethod (cl, (Object *) retval, OM_DISPOSE);
- retval = NULL;
- }
- }
- break;
-
- /* Let the superclass handle everything else */
-
- default:
- retval = (ULONG) DoSuperMethodA (cl, o, msg);
- break;
- }
-
- return (retval);
- }
-
- /*****************************************************************************/
-
- #define SWAPW(a) (WORD)(((UWORD)a>>8)+((((UWORD)a&0xff)<<8)))
- #define SWAPU(a) (UWORD)(((UWORD)a>>8)+((((UWORD)a&0xff)<<8)))
- #define SWAPL(a) (LONG)(((ULONG)a>>24)+(((ULONG)a&0xff0000)>>8)+(((ULONG)a&0xff00)<<8)+(((ULONG)a&0xff)<<24))
-
- /*****************************************************************************/
-
- #define fmt_ID MAKE_ID('f','m','t',' ')
- #define data_ID MAKE_ID('d','a','t','a')
-
- /*****************************************************************************/
-
- /* RIFF header */
- struct RIFFHeader
- {
- ULONG rh_RIFF;
- ULONG rh_Size;
- ULONG rh_Format;
- };
-
- /*****************************************************************************/
-
- /* RIFF chunk */
- struct RIFFChunk
- {
- ULONG rc_ID;
- ULONG rc_Size;
- };
-
- /*****************************************************************************/
-
- struct WaveFormat
- {
- WORD wf_Format;
- WORD wf_Channels;
- ULONG wf_SamplesPerSec;
- ULONG wf_AvgBytesPerSec;
- WORD wf_BlockAlign;
- };
-
- /* wf_Format values */
- #define WAVE_FORMAT_PCM 1
-
- /*****************************************************************************/
-
- struct PCMData
- {
- UWORD pd_BitsPerSample;
- };
-
- /*****************************************************************************/
-
- /*****************************************************************************/
-
- BOOL ConvertObjectData (struct ClassBase * cb, Class * cl, Object * o, struct TagItem * attrs)
- {
- LONG ErrorCode=0;
- struct FileInfoBlock *fib;
- struct VoiceHeader *vhdr;
- STRPTR Title;
- ULONG Memory;
- LONG size;
- BPTR FH;
-
- ULONG SampleLength;
- UBYTE *Sample;
-
- /* Maximum block size for file IO */
- ULONG MAXBUF=16384;
-
- /* IO related */
- UBYTE *buffer;
- ULONG ID;
- ULONG ChunkLen;
- ULONG Left;
- ULONG Got;
-
- /* RIFF related */
- BOOL GotWaveFormat=FALSE;
- UWORD Format;
- UWORD Channels;
- ULONG SamplesPerSec;
- UWORD BitsPerSample;
- UWORD BytesPerSample;
-
- Title = (UBYTE*)GetTagData(DTA_Name, NULL, attrs);
-
- getdtattrs (cb, o,
- SDTA_VoiceHeader, &vhdr,
- DTA_Handle, &FH,
- TAG_DONE);
-
- if (FH && vhdr)
- {
- /* Allocate a temporary file info block */
- if (!(fib = (struct FileInfoBlock *) AllocMem (sizeof (struct FileInfoBlock), NULL)))
- {
- ErrorCode=ERROR_NO_FREE_STORE;
- DB (Error (cb,"not enough memory"));
- }
- else
- {
- /* Get the size of the file */
- if (ExamineFH (FH, fib))
- {
- MAXBUF = size = fib->fib_Size;
- }
- else
- {
- Seek (FH, 0, OFFSET_END);
- MAXBUF = size = Seek (FH, 0, OFFSET_BEGINNING);
- }
-
- /* Free the temporary file info block */
- FreeMem (fib, sizeof (struct FileInfoBlock));
-
- /* Limit the size of the IO block to 32K */
- if (MAXBUF>32768) MAXBUF=32768;
-
- /* Allocate Buffered IO block */
- if (!(buffer = AllocVec(MAXBUF, MEMF_ANY)))
- {
- ErrorCode=ERROR_NO_FREE_STORE;
- DB (Error (cb,"not enough memory"));
- }
- else
- {
- /* Read the RIFF header into the buffer */
- Get(cb, FH, buffer, sizeof(struct RIFFHeader) ,&ErrorCode);
- if (!ErrorCode)
- {
- /* Check the RIFF header */
- if (((struct RIFFHeader*)buffer)->rh_RIFF!=MAKE_ID('R','I','F','F') ||
- ((struct RIFFHeader*)buffer)->rh_Format!=MAKE_ID('W','A','V','E'))
- {
- ErrorCode=ERROR_OBJECT_WRONG_TYPE;
- DB(Error(cb,"unknown format"));
- }
- else
- {
- /* Get size from RIFF header */
- ChunkLen = SWAPL (((struct RIFFHeader*)buffer)->rh_Size) + 8;
- DB (Error (cb,"RIFF: %ld", ChunkLen));
-
- /* Make sure we have the right size */
- /* one missing byte is tolerated! */
- if (ChunkLen != size && ChunkLen != size+1)
- {
- ErrorCode=ERROR_BAD_HUNK;
- DB (Error (cb,"mangled file"));
- }
- else
- {
- /* Loop: Read in chunk header till EOF (Got=0) */
- while((!ErrorCode) && (Got=Get(cb, FH, buffer,sizeof(struct RIFFChunk),&ErrorCode)))
- {
- if (!ErrorCode)
- {
- /* Get chunk ID and len */
- ID = ((struct RIFFChunk*)buffer)->rc_ID;
- Left = ChunkLen = SWAPL(((struct RIFFChunk*)buffer)->rc_Size);
- DB (Error (cb,"Chunk: '%lc%lc%lc%lc', %ld", (ULONG)(ID>>24), (ULONG)(ID>>16)&0xff, (ULONG)(ID>>8)&0xff, (ULONG)(ID&0xff), ChunkLen));
-
- /* Read as much of the chunk as fits into buffer */
- Left-=(Got=Get(cb, FH, buffer, Left > MAXBUF ? MAXBUF : Left, &ErrorCode));
-
- if (!ErrorCode)
- {
- /* Handle the chunk types */
- switch (ID)
- {
- /* WaveForm structure */
- case fmt_ID:
- {
- if (Left!=0)
- {
- /* format chunk CANNOT be larger than buffer!!! */
- ErrorCode=ERROR_BAD_HUNK;
- DB(Error(cb,"format chunk overflow"));
- }
- else
- {
- struct WaveFormat *wf=(struct WaveFormat *)buffer;
-
- Format = SWAPW (wf->wf_Format);
- Channels = SWAPW (wf->wf_Channels);
- SamplesPerSec = SWAPL (wf->wf_SamplesPerSec);
-
- DB (Error (cb,"Wave Format\n"
- "Format: %ld\n"
- "Channels: %ld\n"
- "SPS: %ld\n"
- "Avg.BPS: %ld\n"
- "Align: %ld",
- (LONG) Format,
- (LONG) Channels,
- (LONG) SamplesPerSec,
- (LONG) SWAPL (wf->wf_AvgBytesPerSec) ,
- (LONG) SWAPW (wf->wf_BlockAlign)));
-
- /* We can only handle PCM format */
-
- if (Format!=WAVE_FORMAT_PCM)
- {
- ErrorCode=DTERROR_UNKNOWN_COMPRESSION;
- DB (Error (cb,"unknown compression"));
- }
- else
- {
- BitsPerSample = SWAPW(((struct PCMData*)(buffer+sizeof(struct WaveFormat)))->pd_BitsPerSample);
- BytesPerSample = BitsPerSample/8;
- DB (Error (cb,"BitsPerSample: %ld",(LONG)BitsPerSample));
-
- /* Make sure we have something that we can really handle */
- if ( (BitsPerSample!=8 && BitsPerSample!=16) || (Channels!=1 && Channels!=2) )
- {
- ErrorCode=ERROR_OBJECT_WRONG_TYPE;
- DB (Error (cb,"unsupported type"));
- }
- else
- {
- GotWaveFormat=TRUE;
- }
- }
- }
- }
- break;
-
- /* Sound data */
- case data_ID:
- {
- /* Make sure we have had a WaveFormat structure */
- if (!GotWaveFormat)
- {
- ErrorCode=ERROR_REQUIRED_ARG_MISSING;
- DB (Error (cb,"no waveform structure"));
- }
- else
- {
- /* sound.datatype V40 can replay */
- /* directly from Fast RAM */
-
- Memory = (SuperClassBase->lib_Version>39) ?
- MEMF_ANY : MEMF_CHIP;
-
- SampleLength = (ChunkLen/Channels)/BytesPerSample;
-
- if (!(Sample = AllocVec (SampleLength, Memory)))
- {
- ErrorCode=ERROR_NO_FREE_STORE;
- DB (Error (cb,"not enough memory"));
- }
- else
- {
- /* Sample conversion / buffered loading loop */
-
- ULONG Offset=0;
- while (!ErrorCode)
- {
- /* Convert the data to 8 bit signed format */
- /* Efficiently mix all channels into one */
- /* and copy the Sample to chip memory */
-
- ULONG DestBlockLen=(Got/Channels)/BytesPerSample;
- UBYTE *dst = (Memory == MEMF_CHIP) ? buffer : Sample+Offset;
-
- if (BitsPerSample==8 && Channels==1)
- ConvertMono8(buffer,dst,DestBlockLen);
-
- if (BitsPerSample==8 && Channels==2)
- ConvertStereo8(buffer,dst,DestBlockLen);
-
- if (BitsPerSample==16 && Channels==1)
- ConvertMono16(buffer,dst,DestBlockLen);
-
- if (BitsPerSample==16 && Channels==2)
- ConvertStereo16(buffer,dst,DestBlockLen);
-
- /* For V39 soundclass only: */
- /* Now copy sound data into chip RAM.*/
- /* This is significantly faster than */
- /* decoding directly into Chip RAM. */
-
- if (Memory == MEMF_CHIP)
- CopyMem( buffer, Sample+Offset, DestBlockLen );
-
- /* Increase offset in destination data */
- Offset+=DestBlockLen;
-
- /* Read on if data left otherwise exit loop */
- if (Left)
- Left-=(Got=Get(cb, FH, buffer, Left > MAXBUF ? MAXBUF : Left, &ErrorCode));
- else
- break;
- }
-
- /* Fill in the VoiceHeader */
-
- memset(vhdr,0,sizeof(struct VoiceHeader));
- vhdr->vh_OneShotHiSamples = SampleLength;
- vhdr->vh_SamplesPerSec = SamplesPerSec;
- vhdr->vh_Octaves = 1;
- vhdr->vh_Compression = CMP_NONE;
- vhdr->vh_Volume = 64;
-
- /* Tell the super-class about the attributes */
- setdtattrs (cb, o,
- DTA_ObjName, Title,
- SDTA_Sample, Sample,
- SDTA_SampleLength, SampleLength,
- SDTA_Period, (ULONG)(SysBase->ex_EClockFrequency*5)/(ULONG)vhdr->vh_SamplesPerSec,
- SDTA_Volume, 64,
- SDTA_Cycles, 1,
- TAG_DONE);
- }
- }
- }
- break;
- }
- }
- }
- }
- }
- }
- }
- /* Free the buffer */
- FreeVec (buffer);
- }
- }
- }
- if (ErrorCode)
- {
- SetIoErr(ErrorCode);
- return(FALSE);
- }
- return(TRUE);
- }
-
- /*****************************************************************************/
-
- ULONG Get(struct ClassBase *cb, BPTR FH, UBYTE *buf, ULONG size, LONG *ErrorCode)
- {
- LONG got;
-
- /* read in size bytes */
- got=Read(FH, buf, size);
-
- /* Io error? */
- if (got<0)
- {
- *ErrorCode=IoErr();
- got=0;
- }
- /* don't care at all about short reads */
- return((ULONG)got);
- }
-
- /*****************************************************************************/
-
- ULONG setdtattrs (struct ClassBase * cb, Object * o, ULONG data,...)
- {
- return (SetDTAttrsA (o, NULL, NULL, (struct TagItem *) & data));
- }
-
- /*****************************************************************************/
-
- ULONG getdtattrs (struct ClassBase * cb, Object * o, ULONG data,...)
- {
- return (GetDTAttrsA (o, (struct TagItem *) & data));
- }
-