home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD2.bin
/
bbs
/
util
/
macsnd_dt-1.7.lha
/
MacSND_dt
/
Source
/
Class.c
next >
Wrap
C/C++ Source or Header
|
1994-12-15
|
8KB
|
403 lines
/*
** MacSND DataType
**
** Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
** Public domain
**
** :ts=4
*/
#include "Global.h"
// Maximum supported replay rate, as per the "Amiga Hardware Reference Manual"
#define MAX_SAMPLE_RATE 28867
// The minimum sample rate we will allow when scaling a sound down
#define MIN_SAMPLE_RATE 5563
// How many bytes to read in one piece
#define MIN_FRAME_RATE (2048 * 8)
/* ConvertSample(const UBYTE *Src,BYTE *Dst,LONG NumSamples,const LONG Skip):
*
* Convert the native Macintosh format sample data into plain
* signed 8 bits/sample Amiga data
*/
STATIC VOID __regargs
ConvertSample(const UBYTE *Src,BYTE *Dst,LONG NumSamples,const LONG Skip)
{
LONG SkipCount;
UBYTE Value;
// Make sure that the first sample is converted
SkipCount = 1;
// Convert all the samples if possible
while(NumSamples-- > 0)
{
// It's easy to convert a Macintosh sample :^)
Value = *(Src++) ^ 0x80;
// Store this sample value?
if(--SkipCount < 1)
{
// Keep this sample
*Dst++ = (BYTE)Value;
// Skip the next samples if necessary
SkipCount = Skip;
}
}
}
/* GetSND(Object *object,struct TagItem *Tags,struct ClassBase *ClassBase):
*
* Convert a Macintosh "snd " resource into a DataTypes object
*/
STATIC BOOL __regargs
GetSND(Object *object,struct TagItem *Tags,struct ClassBase *ClassBase)
{
struct VoiceHeader *VoiceHeader = NULL;
BPTR File = NULL;
LONG Error = 0;
STRPTR Title = (STRPTR)GetTagData(DTA_Name,NULL,Tags);
BOOL Result = FALSE;
// Get the basic data
GetDTAttrs(object,
SDTA_VoiceHeader, &VoiceHeader,
DTA_Handle, &File,
TAG_DONE);
// Do we have everything we need?
if(File && VoiceHeader && Title)
{
BPTR FileHandle;
// Open the file
if(FileHandle = Open(Title,MODE_OLDFILE))
{
struct SoundDataHeader Header;
BOOL GotIt = FALSE;
// Add some cache
SetVBuf(FileHandle,NULL,BUF_FULL,4096);
// Read the MacBinary header if possible
if(ReadMacBinaryHeader(FileHandle,&Error,SysBase,DOSBase))
{
// If it's a MacBinary format file, read the rest
if(ScanResource(FileHandle,&Header,&Error,SysBase,DOSBase))
GotIt = TRUE;
}
// So it's not a MacBinary format file
if(!GotIt)
{
// Return to the beginning of the file
if(Seek(FileHandle,0,OFFSET_BEGINNING) != -1)
{
// Look for "snd " resources
if(ScanResource(FileHandle,&Header,&Error,SysBase,DOSBase))
GotIt = TRUE;
}
}
// Did we get anything?
if(GotIt)
{
BYTE *Sample = NULL;
UBYTE *Source;
ULONG Memory;
LONG Rate,Size,Skip,Frame;
// Fill in the basic data
Rate = Header . SampleRate;
Size = Header . SampleSize;
Skip = 1;
// Don't waste too much memory for reading
if(Header . SampleSize < MIN_FRAME_RATE)
Frame = Header . SampleSize;
else
Frame = MIN_FRAME_RATE;
// sound.datatype v40 no longer requires
// the entire sample to reside in chip memory
if(SuperClassBase -> lib_Version > 39)
Memory = MEMF_ANY;
else
Memory = MEMF_CHIP;
// Scale the sound down if the Amiga sound hardware
// would be unable to handle the replay rate
while(Size > 0 && Rate > MIN_SAMPLE_RATE && Rate > MAX_SAMPLE_RATE)
{
Size /= 2;
Rate /= 2;
Skip *= 2;
}
// Allocate the read buffer
if(Source = AllocVec(Frame,MEMF_ANY))
{
// Try to allocate memory for the sample data
while(!(Sample = AllocVec(Size,Memory | MEMF_CLEAR)) && Size > 0 && Rate > MIN_SAMPLE_RATE)
{
// Scale it down if necessary
Size /= 2;
Rate /= 2;
Skip *= 2;
}
// Did we get anything?
if(!Sample)
Error = ERROR_NO_FREE_STORE;
}
else
Error = ERROR_NO_FREE_STORE;
// Did we get what we wanted?
if(Sample && !Error)
{
BYTE *Dst = Sample;
LONG Total = Header . SampleSize,
Needed;
// Read the source data
while(!Error && Total > 0)
{
if(Frame > Total)
Needed = Total;
else
Needed = Frame;
if(Read(FileHandle,Source,Needed) == Needed)
{
// Convert the source data
ConvertSample(Source,Dst,Needed,Skip);
Total -= Needed;
Dst += Needed;
}
else
Error = IoErr();
}
// No read error so far?
if(!Error)
{
BYTE Smallest,Largest;
LONG i;
// Initialize the voice header
memset(VoiceHeader,0,sizeof(struct VoiceHeader));
VoiceHeader -> vh_OneShotHiSamples = Size;
VoiceHeader -> vh_SamplesPerSec = Rate;
VoiceHeader -> vh_Octaves = 1;
VoiceHeader -> vh_Compression = CMP_NONE;
VoiceHeader -> vh_Volume = 64;
// Look for the smallest and the largest
// sample value
Smallest = 127;
Largest = -128;
Dst = Sample;
for(i = 0 ; i < Size ; i++)
{
if(Dst[i] < Smallest)
Smallest = Dst[i];
if(Dst[i] > Largest)
Largest = Dst[i];
}
// Does it use the full range?
if(Smallest > -128 || Largest < 127)
{
BYTE Table[256],*Index;
WORD j;
// Point it into the middle
Index = &Table[128];
// Scale the negative values
// to use the full dynamic
// amplitude range
for(j = Smallest ; j < 0 ; j++)
Index[j] = (-128 * j) / Smallest;
// Cut off anything below the
// smallest value
for(j = -128 ; j < Smallest ; j++)
Index[j] = -128;
Index[0] = 0;
// Scale the positive values
// to use the full dynamic
// amplitude range
for(j = 1 ; j <= Largest ; j++)
Index[j] = (127 * j) / Largest;
// Cut off anything above the
// largest value
for(j = Largest + 1 ; j < 256 ; j++)
Index[j] = 127;
// Make the data use the full range
Dst = Sample;
for(i = 0 ; i < Size ; i++)
Dst[i] = Index[Dst[i]];
}
// Fill in the remaining information
SetDTAttrs(object,NULL,NULL,
DTA_ObjName, Title,
SDTA_Sample, Sample,
SDTA_SampleLength, VoiceHeader -> vh_OneShotHiSamples,
SDTA_Period, (ULONG)(SysBase -> ex_EClockFrequency * 5) / (ULONG)VoiceHeader -> vh_SamplesPerSec,
SDTA_Volume, 64,
SDTA_Cycles, 1,
TAG_DONE);
// Successful conversion
Result = TRUE;
}
}
// No success?
if(Error)
Result = FALSE;
// Clean up...
if(Source)
FreeVec(Source);
if(Sample && !Result)
FreeVec(Sample);
}
else
Error = ERROR_OBJECT_NOT_FOUND;
Close(FileHandle);
}
else
Error = IoErr();
}
else
Error = ERROR_OBJECT_NOT_FOUND;
// Set the error code
if(Error)
SetIoErr(Error);
return(Result);
}
/* RealClassDispatch():
*
* The class dispatcher routine.
*/
STATIC Object * __stdargs
RealClassDispatch(Class *class,Object *object,Msg msg)
{
struct ClassBase *ClassBase = (struct ClassBase *)class -> cl_UserData;
Object *Result;
// What message is it?
switch(msg -> MethodID)
{
// Create a new instance
case OM_NEW:
if(Result = (Object *)DoSuperMethodA(class,object,msg))
{
if(!GetSND(Result,((struct opSet *)msg) -> ops_AttrList,ClassBase))
{
CoerceMethod(class,Result,OM_DISPOSE);
Result = NULL;
}
}
break;
// Let the superclass handle the rest
default:
Result = (Object *)DoSuperMethodA(class,object,msg);
break;
}
return(Result);
}
/* ClassDispatch():
*
* The frontend to the real class dispatcher routine.
*/
Object * __saveds __asm
ClassDispatch(register __a0 Class *class,register __a2 Object *object,register __a1 Msg msg)
{
LONG Success;
return((Object *)StackCall(&Success,8192,3,(LONG (* __stdargs)(...))RealClassDispatch,class,object,msg));
}