home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-16 | 43.9 KB | 1,831 lines | [TEXT/MMCC] |
- //----------------
- // Hollywood API for use with the Macintosh Sound Manager 3.0
- //
- // This code depends upon Universal Interfaces 2.0a3 or better from Apple Computer, Inc
- //
- // History
- // 1/8/95 Created by Steve Hales
- //----------------
-
- #include <Types.h>
- #include <Memory.h>
- #include <Quickdraw.h>
- #include <OSEvents.h>
- #include <Desk.h>
- #include <Events.h>
- #include <Resources.h>
- #include <Windows.h>
- #include <Fonts.h>
- #include <TextEdit.h>
- #include <Menus.h>
- #include <Dialogs.h>
- #include <ToolUtils.h>
- #include <Retrace.h>
- #include <StandardFile.h>
- #include <Sound.h>
- #include <SoundInput.h>
- #include <AIFF.h>
- #include <Gestalt.h>
- #include <Errors.h>
- #include <Traps.h>
- #include <ConditionalMacros.h>
- #include <FixMath.h>
-
- #ifndef __MIXEDMODE__
- #include <SysEqu.h>
- #else
- #include <LowMem.h>
- #define LMGetSoundActive() (* (unsigned char *) 0x27E)
- #endif
-
- #if THINK_C
- #include <Think.h>
- #else
- #define TRUE true
- #define FALSE false
- #endif
-
- #include "Hollywood.h"
-
- #if 0
- #define DEBUGSTR(x)
- #else
- #define DEBUGSTR(x) DebugStr(x)
- #endif
-
- #define kMaxCallbackQueue 50 // total number of queued events
-
- // Structures
- struct MM_SoundVoice
- {
- SndChannelPtr theChannel;
-
- CustomCallbackProc customCallback;
- short int voiceNumber;
- long userData;
- UnsignedFixed lastRate;
-
- ExtSoundHeader theSndBuffer;
- Boolean voiceActive;
- Boolean voicePaused;
- Boolean filePlay;
- FSSpec fileSpec;
- short int fileRef;
- };
- typedef struct MM_SoundVoice MM_SoundVoice;
-
- // This queue is put together via an interrupt to process events at non-interrupt time
- struct MM_CallbackQueue
- {
- CustomCallbackProc customCallback;
- short int voiceNumber;
- long userData;
- short int filePlayRef; // 0 = no file play to close
- Boolean active;
- };
- typedef struct MM_CallbackQueue MM_CallbackQueue;
-
- // Variables
- static long globalA5;
- static short int maxSoundVoices = 0; // Max voices allocated for Sound Manager 3.0
- static MM_SoundVoice *theSoundVoices = NULL;
- static MM_CallbackQueue theCallbackQueue[kMaxCallbackQueue];
-
- static long * taskPtr;
- static VBLTask * theSoundVBPtr;
- static void (*vblankProcPtr)(void);
-
- static long totalRegisteredSounds;
- static long currentBlockSizeForRegisteredSounds;
- static SndReference * registeredSounds; // current list of registered sounds
-
- #ifdef __MIXEDMODE__
- SndCallBackUPP theMasterSoundCallbackProcPtr;
- #else
- SndCallBackProcPtr theMasterSoundCallbackProcPtr;
- #endif
-
-
- // Internal Defines
- #define kSoundManagerID 'sm' // used to fix a bug in the Sound Manager. It pre-fires the callback, so
- // you must check that its our callback. We do this by 'wasting' the param1.
- // Note that param1 is only 16 bits.
-
- #define kMaxSoundManagerVoices 4 // total number of voices that the Sound Manager can allocate. This may change
- // as CPU performance increases
-
- #define kRegisterSoundBlockSize 40 // inital number of sounds that can be registered without reallocating the
- // block array
-
- // forward references
- static pascal void HYP_HandleSoundDoneCallBack(SndChannelPtr pChannel, register SndCommand *pCmd);
- static void SHYP_Callback(short int voiceNumber, short int what, long userData);
- static OSErr HYP_PostCallbackFunction(SndChannelPtr pChannel, long userData);
- static OSErr HYP_AddToCallbackQueue(MM_CallbackQueue *newQueue);
-
- // Private functions
- //
- // This will return TRUE if the new sound manager is installed, otherwise FALSE
-
- static Boolean HYP_IsNewSoundManagerInstalled(void)
- {
- NumVersion theVersion;
- void * trap1;
- void * trap2;
- Boolean installed;
-
- installed = FALSE;
- trap1 = (void *)GetToolTrapAddress(_SoundDispatch); /* SndSoundManagerVersion Trap */
- trap2 = (void *)GetToolTrapAddress(_Unimplemented); /* Unimplemented Trap */
- if (trap1 != trap2)
- {
- theVersion = SndSoundManagerVersion();
- if (theVersion.majorRev >= 3)
- {
- installed = TRUE;
- }
- }
- return installed;
- }
-
-
- // This will return TRUE if the virtual memory manager is installed, otherwise FALSE.
-
- static Boolean HYP_IsVirtualMemoryAvailable(void)
- {
- long feature;
-
- feature = 0;
- if (Gestalt(gestaltVMAttr, &feature) == noErr)
- {
- if (feature & (1<<gestaltVMPresent))
- {
- return TRUE;
- }
- }
- return FALSE;
- }
-
- static short int HYP_GetFreeVoice(void)
- {
- register short int count, freeVoice;
-
- freeVoice = kUseAnyVoice;
- for (count = 0; count < maxSoundVoices; count++)
- {
- if (theSoundVoices[count].voiceActive == FALSE)
- {
- freeVoice = count;
- break;
- }
- }
- return freeVoice;
- }
-
- static MM_SoundVoice * HYP_GetPrivateDataFromVoice(register short int voice)
- {
- register MM_SoundVoice *pVoice;
-
- pVoice = NULL;
- if (theSoundVoices)
- {
- if ( (voice < maxSoundVoices) && (voice >= 0) )
- {
- if (theSoundVoices[voice].theChannel)
- {
- pVoice = &theSoundVoices[voice];
- }
- }
- }
- return pVoice;
- }
-
-
- static short int HYP_GetVoiceFromChannel(register SndChannelPtr pChannel)
- {
- register short int count;
-
- count = -1;
- for (count = 0; count < maxSoundVoices; count++)
- {
- if (pChannel == theSoundVoices[count].theChannel)
- {
- break;
- }
- }
- return count;
- }
-
- // For use with Apple's Sound Manager
- static pascal void HYP_FilePlayCompletionDone(SndChannelPtr pChannel)
- {
- register long saveA5;
- register MM_SoundVoice *pVoice;
- register short int voiceNumber;
- MM_CallbackQueue newQueue;
-
- #if GENERATING68K == 1
- saveA5 = SetA5(pChannel->userInfo); /* restore previous a5 */
- #else
- saveA5;
- #endif
- voiceNumber = HYP_GetVoiceFromChannel(pChannel);
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- if (pChannel != pVoice->theChannel)
- {
- DEBUGSTR("\pChannel doesn't match voiceNumber");
- }
-
- if (pVoice->customCallback)
- {
- (*pVoice->customCallback)(voiceNumber,
- kSoundDoneNormalStop,
- pVoice->userData);
- newQueue.customCallback = pVoice->customCallback;
- newQueue.voiceNumber = pVoice->voiceNumber;
- newQueue.userData = pVoice->userData;
- newQueue.filePlayRef = pVoice->fileRef;
- if (HYP_AddToCallbackQueue(&newQueue))
- {
- DEBUGSTR("\pQueue Full!");
- }
- }
- pVoice->voiceActive = FALSE;
- }
- /* Restore A5 for the rest of the interupt process
- */
- #if GENERATING68K == 1
- SetA5(saveA5); /* restore previous a5 */
- #endif
-
- }
-
-
- static pascal void HYP_HandleSoundDoneCallBack(SndChannelPtr pChannel, register SndCommand *pCmd)
- {
- register long saveA5;
- register MM_SoundVoice *pVoice;
- register short int voiceNumber;
- MM_CallbackQueue newQueue;
-
- if (pCmd->param1 == kSoundManagerID)
- {
- #if GENERATING68K == 1
- saveA5 = SetA5(pChannel->userInfo); /* restore previous a5 */
- #else
- saveA5;
- #endif
- voiceNumber = HYP_GetVoiceFromChannel(pChannel);
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- if (pChannel != pVoice->theChannel)
- {
- DEBUGSTR("\pChannel doesn't match voiceNumber");
- }
-
- if (pVoice->customCallback)
- {
- (*pVoice->customCallback)(voiceNumber,
- kSoundDoneNormalStop,
- pVoice->userData);
- newQueue.customCallback = pVoice->customCallback;
- newQueue.voiceNumber = pVoice->voiceNumber;
- newQueue.userData = pVoice->userData;
- newQueue.filePlayRef = 0;
- if (HYP_AddToCallbackQueue(&newQueue))
- {
- DEBUGSTR("\pQueue Full!");
- }
- }
- pVoice->voiceActive = FALSE;
- }
- /* Restore A5 for the rest of the interupt process
- */
- #if GENERATING68K == 1
- SetA5(saveA5); /* restore previous a5 */
- #endif
- }
- }
-
- static OSErr HYP_PostCallbackFunction(SndChannelPtr pChannel, long userData)
- {
- SndCommand theCmd;
- OSErr theErr;
-
- if (pChannel)
- {
- theCmd.cmd = callBackCmd;
- theCmd.param1 = kSoundManagerID; // used for ID. Bug in SM that a callback is
- // sometimes called at the begining of a sample
- // with the wrong information.
- // Use this to make sure that it is our callback.
- theCmd.param2 = userData;
- pChannel->userInfo = globalA5;
- theErr = SndDoCommand(pChannel, &theCmd, FALSE);
- }
- else
- {
- theErr = badChannel;
- }
- return theErr;
- }
-
-
- static void HYP_SetupQueues(void)
- {
- short int count;
-
- for (count = 0; count < kMaxCallbackQueue; count++)
- {
- theCallbackQueue[count].active = FALSE;
- theCallbackQueue[count].customCallback = NULL;
- }
- }
-
- static void HYP_CleanupQueues(void)
- {
- }
-
- static OSErr HYP_AddToCallbackQueue(MM_CallbackQueue *newQueue)
- {
- OSErr theErr;
- short int count;
- Boolean foundQueue;
-
- // DEBUGSTR("\pHYP_AddToCallbackQueue");
- theErr = noErr;
-
- foundQueue = FALSE;
- for (count = 0; count < kMaxCallbackQueue; count++)
- {
- if (theCallbackQueue[count].active == FALSE)
- {
- theCallbackQueue[count] = *newQueue;
- theCallbackQueue[count].active = TRUE;
- foundQueue = TRUE;
- break;
- }
- }
- if (foundQueue == FALSE)
- {
- theErr = qErr;
- }
- return theErr;
- }
-
- static void HYP_ProcessNextCallbackQueue(void)
- {
- register MM_CallbackQueue * theQueue;
- short int count;
-
- // DEBUGSTR("\pHYP_ProcessNextCallbackQueue");
- for (count = 0; count < kMaxCallbackQueue; count++)
- {
- theQueue = &theCallbackQueue[count];
- if (theQueue->active)
- {
- // DEBUGSTR("\pHYP_ProcessNextCallbackQueue:BEFORE CALLBACK");
- if (theQueue->filePlayRef)
- {
- FSClose(theQueue->filePlayRef);
- theQueue->filePlayRef = 0;
- }
- if (theQueue->customCallback)
- {
- (*theQueue->customCallback)(theQueue->voiceNumber, kSoundDoneNoInterrupt, theQueue->userData);
- theQueue->customCallback = NULL;
- }
- theQueue->active = FALSE;
- }
- }
- }
-
- // General purpose VBL task to execute user defined task
- static void HYP_ProcessVBLTask(void)
- {
- if (vblankProcPtr)
- {
- (*vblankProcPtr)();
- }
- }
-
- #if GENERATING68K == 1
- // 68k based VBL task function
- #pragma parameter __D0 GetA0toVariable
- pascal long GetA0toVariable(void) = {0x2028, 0xFFFC};
-
- static pascal void HYP_PreProcessVBLTask(void)
- {
- long saveA5, newA5;
-
- newA5 = GetA0toVariable(); /* Globals register points the vbl task structure */
-
- saveA5 = SetA5(newA5); /* set current a5 */
- theSoundVBPtr->vblCount = 1; /* tell it to contiue */
-
- HYP_ProcessVBLTask();
-
- /* Restore A5 for the rest of the interupt process
- */
- SetA5(saveA5); /* restore previous a5 */
- }
- #else
- // PowerPC based VBL task function
- static pascal void HYP_PreProcessVBLTask(VBLTaskPtr theVBLTask)
- {
- theSoundVBPtr->vblCount = 1; /* tell it to contiue */
-
- HYP_ProcessVBLTask();
- }
-
- #endif
-
-
- #if GENERATING68K == 1
- // 68k based VBL task setup and cleanup
- static OSErr HYP_SetupVBLTask(void)
- {
- OSErr theErr;
- struct Jump
- {
- short bsr_inderect; // 0
- void * address; // 4
- long movea; // 8
- short jmp_a1; // 12
- };
- struct Jump *heapJumpPtr;
-
- /*
- 0x6104, bsr.s 6(pc)
- 0x0000, 0x0000, dc.l 0
- 0x225F movea.l (a7)+, a1
- 0x2251 move (a1), a1
- 0x4Ed1 jmp (a1)
- */
-
- /* Set up Vertical Blank Interrupt
- */
- taskPtr = (long *)NewPtrClear((long)sizeof(VBLTask) + sizeof(long));
- heapJumpPtr = (struct Jump *)NewPtrSys((long)sizeof(struct Jump));
- if ( (taskPtr) && (heapJumpPtr) )
- {
- if (HYP_IsVirtualMemoryAvailable())
- {
- LockMemory(taskPtr, (long)sizeof(VBLTask) + sizeof(long));
- LockMemory(heapJumpPtr, (long)sizeof(struct Jump));
- }
-
- theSoundVBPtr = (VBLTask *)( ((Byte *)taskPtr) + sizeof(long) );
- taskPtr[0] = SetCurrentA5();
- heapJumpPtr->bsr_inderect = 0x6104;
- heapJumpPtr->address = HYP_PreProcessVBLTask;
- heapJumpPtr->movea = 0x225F2251L;
- heapJumpPtr->jmp_a1 = 0x4Ed1;
-
- theSoundVBPtr->vblAddr = (VBLUPP)heapJumpPtr;
- theSoundVBPtr->vblCount = 1; /* Every 1/60th of a second */
- theSoundVBPtr->qType = vType;
- theSoundVBPtr->qLink = NULL;
- theSoundVBPtr->vblPhase = 0;
-
- /* Ok, flush the code/data cache for the '040 Macs. */
- #ifndef __MIXEDMODE__
- if (*((char *)CPUFlag) >= 2)
- #else
- if (LMGetCPUFlag() >= 2)
- #endif
- {
- FlushInstructionCache();
- FlushDataCache();
- }
-
- theErr = VInstall((QElemPtr)theSoundVBPtr);
- }
- else
- {
- if (heapJumpPtr)
- {
- if (HYP_IsVirtualMemoryAvailable())
- {
- UnlockMemory((Ptr)heapJumpPtr, 12L);
- }
- DisposePtr((Ptr)heapJumpPtr);
- }
- if (taskPtr)
- {
- if (HYP_IsVirtualMemoryAvailable())
- {
- UnlockMemory(taskPtr, (long)sizeof(VBLTask) + sizeof(long));
- }
- DisposePtr((Ptr)taskPtr);
- taskPtr = NULL;
- theSoundVBPtr = NULL;
- }
- }
- return theErr;
- }
-
- static OSErr HYP_CleanupVBLTask(void)
- {
- if (theSoundVBPtr)
- {
- if (theSoundVBPtr->vblAddr)
- {
- if (HYP_IsVirtualMemoryAvailable())
- {
- UnlockMemory((Ptr)theSoundVBPtr->vblAddr, 12L);
- }
- DisposePtr((Ptr)theSoundVBPtr->vblAddr);
- }
- VRemove((QElemPtr)theSoundVBPtr);
- theSoundVBPtr = NULL;
- }
- if (taskPtr)
- {
- if (HYP_IsVirtualMemoryAvailable())
- {
- UnlockMemory(taskPtr, (long)sizeof(VBLTask) + sizeof(long));
- }
- DisposePtr((Ptr)taskPtr);
- }
- return noErr;
- }
- #else
- // PowerPC based VBL task setup and cleanup
- static OSErr HYP_SetupVBLTask(void)
- {
- OSErr theErr;
- /* Set up Vertical Blank Interrupt
- */
- theErr = noErr;
- taskPtr = NULL;
- theSoundVBPtr = (VBLTask *)NewPtrSysClear((long)sizeof(VBLTask));
- if (theSoundVBPtr)
- {
- if (HYP_IsVirtualMemoryAvailable())
- {
- LockMemory(theSoundVBPtr, (long)sizeof(VBLTask));
- }
- theSoundVBPtr->vblAddr = NewVBLProc(HYP_PreProcessVBLTask);
- theSoundVBPtr->vblCount = 1; /* Every 1/60th of a second */
- theSoundVBPtr->qType = vType;
- theSoundVBPtr->qLink = NULL;
- theSoundVBPtr->vblPhase = 0;
-
- theErr = VInstall((QElemPtr)theSoundVBPtr);
- }
- return theErr;
- }
-
- static OSErr HYP_CleanupVBLTask(void)
- {
- if (theSoundVBPtr)
- {
- if (theSoundVBPtr->vblAddr)
- {
- DisposeRoutineDescriptor((VBLUPP)theSoundVBPtr->vblAddr);
- theSoundVBPtr->vblAddr = NULL;
- }
- VRemove((QElemPtr)theSoundVBPtr);
-
- if (HYP_IsVirtualMemoryAvailable())
- {
- UnlockMemory(theSoundVBPtr, (long)sizeof(VBLTask));
- }
- DisposePtr((Ptr)theSoundVBPtr);
- theSoundVBPtr = NULL;
- }
- return noErr;
- }
- #endif
-
- static Boolean HYP_IsThisSoundRegistered(SndReference theSound)
- {
- register short int count;
- register Boolean foundPlace;
-
- foundPlace = FALSE;
- for (count = 0; count < totalRegisteredSounds; count++)
- {
- if (registeredSounds[count] == theSound)
- {
- foundPlace = TRUE;
- }
- }
- return foundPlace;
- }
-
-
- static void HYP_RegisterThisSound(SndReference theSound)
- {
- register short int count;
- register Boolean foundPlace;
- SndReference * newArray;
- register long theSize;
-
- if (registeredSounds == NULL) // first time to register?
- {
- theSize = (long)sizeof(SndReference *) * kRegisterSoundBlockSize;
- registeredSounds = (SndReference *)NewPtrClear(theSize);
- totalRegisteredSounds = 0;
- currentBlockSizeForRegisteredSounds = kRegisterSoundBlockSize;
- }
- if (registeredSounds)
- {
- if (HYP_IsThisSoundRegistered(theSound) == FALSE) // don't register a sound twice
- {
- // walk through the sound register array and see if there are any free blocks, if so, then put
- // our reference there
- foundPlace = FALSE;
- for (count = 0; count < totalRegisteredSounds; count++)
- {
- if (registeredSounds[count] == NULL)
- {
- registeredSounds[count] = theSound;
- foundPlace = TRUE;
- }
- }
- // if we didn't find a place in our array, go ahead and put it into the next place. if we've need more
- // in the array then reallocate and then place it in there
- if (foundPlace == FALSE)
- {
- totalRegisteredSounds++; // next entry
- if (totalRegisteredSounds > currentBlockSizeForRegisteredSounds)
- {
- // out of space, so reallocate a new array and copy all the current registered sounds into it
- theSize = sizeof(SndReference *) * (currentBlockSizeForRegisteredSounds + kRegisterSoundBlockSize);
- newArray = (SndReference *)NewPtrClear(theSize);
- if (newArray)
- {
- theSize = (long)sizeof(SndReference *) * currentBlockSizeForRegisteredSounds;
- BlockMove((Ptr)registeredSounds, (Ptr)newArray, theSize);
- DisposePtr((Ptr)registeredSounds);
-
- registeredSounds = newArray; // replace old one with new one
- currentBlockSizeForRegisteredSounds += kRegisterSoundBlockSize; // increase our tollerance
- }
- }
- // we have enough room in our current array or the array has been enlarged,
- // so put our reference in the next place
- registeredSounds[totalRegisteredSounds-1] = theSound;
- }
- }
- }
- }
-
- static void HYP_UnregisterThisSound(SndReference theSound)
- {
- register short int count;
-
- // walk through our reference array and remove by setting the placeholder to NULL, our
- // reference. We never shrink the reference array because it will never get that big, and
- // its wastes time
- if (registeredSounds)
- {
- for (count = 0; count < totalRegisteredSounds; count++)
- {
- if (registeredSounds[count] == theSound)
- {
- registeredSounds[count] = NULL; // ok remove from our list
- }
- }
- }
- }
-
- static void HYP_UnregisterAllSounds(void)
- {
- register short int count;
-
- // walk through our reference array and remove by setting the placeholder to NULL, our
- // reference. At this point dispose of the reference array too
- if (registeredSounds)
- {
- for (count = 0; count < totalRegisteredSounds; count++)
- {
- if (registeredSounds[count])
- {
- registeredSounds[count] = NULL; // ok remove from our list
- }
- }
- DisposePtr((Ptr)registeredSounds);
- registeredSounds = NULL;
- }
- }
-
- // Public functions
- //
-
- void HY_SetSoundVBCallBack(void (*theProc)(void))
- {
- vblankProcPtr = theProc;
- }
-
-
- #define kCompressionPacketSize 6 // 2 bytes at 3:1 is 6 bytes for a packet
- // 1 byte at 6:1 is 6 bytes also
- Handle HY_GetMACESound(register CmpSoundHeaderPtr pSndBuffer,
- Ptr *pWave, long *length,
- long *pLoopStart, long *loopend,
- long *rate)
- {
- Ptr inBuffer, outBuffer, theInState, theOutState;
- CmpSoundHeader * csndHeaderPtr;
- Handle outHandle;
- unsigned long sampleCount;
- long buffLen;
-
- outHandle = NULL;
- csndHeaderPtr = (CmpSoundHeaderPtr) pSndBuffer;
- if (csndHeaderPtr->compressionID) // see if sound is compressed
- {
- sampleCount = csndHeaderPtr->numFrames; // get number of number of frames
- buffLen = sampleCount * kCompressionPacketSize; // bufferLen = number of frames * packet size */
-
- theInState = NewPtrClear(128L); // allocate working buffers
- theOutState = NewPtrClear(128L);
- outHandle = NewHandleClear(buffLen);
- if ((theInState && theOutState && outHandle))
- {
- HLock(outHandle);
- outBuffer = *outHandle;
- if ((inBuffer = csndHeaderPtr->samplePtr) == NULL) // get ptr to sample data
- {
- inBuffer = (Ptr) csndHeaderPtr->sampleArea;
- } /* decompress sound */
-
- switch(csndHeaderPtr->compressionID) // MACE compression ID's only
- {
- case threeToOne:
- Exp1to3(inBuffer, outBuffer, sampleCount, (StateBlockPtr)theInState, (StateBlockPtr)theOutState,
- csndHeaderPtr->numChannels, 1);
- break;
- case sixToOne:
- Exp1to6(inBuffer,outBuffer, sampleCount, (StateBlockPtr)theInState, (StateBlockPtr)theOutState,
- csndHeaderPtr->numChannels, 1);
- break;
- default:
- BlockMove(inBuffer, outBuffer, sampleCount);
- break;
- }
- *pWave = outBuffer;
- *length = buffLen;
- *pLoopStart = csndHeaderPtr->loopStart;
- *loopend = csndHeaderPtr->loopEnd;
- *rate = csndHeaderPtr->sampleRate;
- }
- if (theInState)
- {
- DisposePtr(theInState);
- }
- if (theOutState)
- {
- DisposePtr(theOutState);
- }
- }
- return outHandle;
- }
-
-
- void HY_RegisterThisSound(SndReference theSound)
- {
- if (theSound)
- {
- HLock(theSound);
- HYP_RegisterThisSound(theSound); // register this sound
- }
- }
-
-
- SndReference HY_GetSoundResource(short int resourceID)
- {
- Handle theSoundData;
- SndReference theSndRef;
-
- theSndRef = NULL;
- theSoundData = GetResource('snd ', resourceID); // get the resource data type 'snd '
- if (theSoundData)
- {
- HLock(theSoundData); // lock it down
- HYP_RegisterThisSound(theSoundData); // register this sound
- theSndRef = (SndReference)theSoundData;
- }
- return theSndRef;
- }
-
- void HY_UnregisterSoundResource(SndReference theSound)
- {
- if (HYP_IsThisSoundRegistered(theSound)) // only work with sounds that have been access through our API
- {
- HYP_UnregisterThisSound(theSound);
- HUnlock((Handle)theSound);
- }
- }
-
- void HY_UnregisterAllSoundResources(void)
- {
- register short int count;
-
- // walk through our reference array and remove by setting the placeholder to NULL, our
- // reference. At this point dispose of the reference array too
- if (registeredSounds)
- {
- for (count = 0; count < totalRegisteredSounds; count++)
- {
- if (registeredSounds[count])
- {
- HY_UnregisterSoundResource(registeredSounds[count]); // ok remove from our list
- }
- }
- HYP_UnregisterAllSounds();
- }
- }
-
-
- Boolean HY_Is16BitAvailable(void)
- {
- long feature;
-
- feature = 0;
- if (Gestalt(gestaltSoundAttr, &feature) == noErr)
- {
- if (feature & (1<<gestalt16BitSoundIO))
- {
- return TRUE;
- }
- }
- return FALSE;
- }
-
- Boolean HY_IsStereoAvailable(void)
- {
- long feature;
-
- feature = 0;
- if (Gestalt(gestaltSoundAttr, &feature) == noErr)
- {
- if (feature & (1<<gestaltStereoCapability))
- {
- return TRUE;
- }
- }
- return FALSE;
- }
-
-
- OSErr HY_Setup(short int featureMask, short int maxVoices)
- {
- OSErr theErr;
- short int count;
- register MM_SoundVoice *pVoice;
- register long features;
- SoundVolume fullVolume;
-
- if (HYP_IsNewSoundManagerInstalled())
- {
- theErr = noErr;
- maxSoundVoices = 0;
- fullVolume.left = kFullVolume;
- fullVolume.right = kFullVolume;
-
- registeredSounds = NULL; // no sounds registered
-
- #if GENERATING68K == 1
- globalA5 = (long)SetCurrentA5(); // we do this here, so HY_PlaySample can be called via interrupt
- #else
- globalA5 = 0;
- #endif
- theSoundVoices = (MM_SoundVoice *)NewPtrClear((long)sizeof(MM_SoundVoice) * maxVoices);
- if (theSoundVoices)
- {
- #ifdef __MIXEDMODE__
- theMasterSoundCallbackProcPtr = NewSndCallBackProc(HYP_HandleSoundDoneCallBack);
- #else
- theMasterSoundCallbackProcPtr = (void *)HYP_HandleSoundDoneCallBack;
- #endif
-
- features = 0L;
- if ((featureMask & kUseStereo) == kUseStereo)
- {
- features |= initStereo; // stereo sound support
- }
- else
- {
- features |= initMono; // mono sound support
- }
- if ((featureMask & kMaxQuality) == kMaxQuality)
- {
- features |= initNoDrop; // keep interpolation on, turn off drop sample convertion (CPU heavy)
- }
- else
- {
- features |= initNoInterp; // turn off interpolation
- }
- for (count = 0; count < maxVoices; count++)
- {
- pVoice = &theSoundVoices[count];
- theErr = SndNewChannel(&pVoice->theChannel,
- sampledSynth,
- features,
- theMasterSoundCallbackProcPtr);
- if (theErr)
- { /* we failed, so bail
- */
- pVoice->theChannel = NULL;
- HY_Cleanup();
- break;
- }
- else
- { // success
- maxSoundVoices++; // we increment our global in case we fail so we can back
- // out easily
- pVoice->voiceActive = FALSE;
- pVoice->voicePaused = FALSE;
- pVoice->filePlay = FALSE;
- pVoice->theChannel->callBack = theMasterSoundCallbackProcPtr; // extra, just in case
- pVoice->theChannel->userInfo = globalA5;
- }
- }
- for (count = 0; count < maxVoices; count++)
- {
- HY_SetVolume(count, fullVolume);
- if (HY_Is16BitAvailable())
- {
- HY_SetRate(count, rate22050hz);
- }
- else
- {
- HY_SetRate(count, rate22khz);
- }
- }
- HYP_SetupQueues();
- HYP_SetupVBLTask();
- }
- else
- {
- theErr = memFullErr;
- }
- }
- else
- {
- theErr = smRevisionErr; // we can only work with Sound Manager 3.0. We're using cool features of SM 3.0
- }
- return theErr;
- }
-
- OSErr HY_Cleanup(void)
- {
- register short int count;
-
- HYP_CleanupVBLTask(); // clean up our VBL task
- HY_UnregisterAllSoundResources(); // clean up and remove all references to sounds. This calls HYP_UnregisterAllSounds
-
- if (theSoundVoices)
- {
- for (count = 0; count < maxSoundVoices; count++)
- {
- if (theSoundVoices[count].theChannel)
- {
- HY_StopSample(count);
-
- SndDisposeChannel(theSoundVoices[count].theChannel, TRUE);
- theSoundVoices[count].theChannel = NULL;
- }
- }
- #ifdef __MIXEDMODE__
- if (theMasterSoundCallbackProcPtr)
- {
- DisposeRoutineDescriptor(theMasterSoundCallbackProcPtr);
- }
- #endif
-
- theMasterSoundCallbackProcPtr = NULL;
- DisposePtr((Ptr)theSoundVoices);
- theSoundVoices = NULL;
- }
- return noErr;
- }
-
- Boolean HY_Active(void)
- {
- return (theSoundVoices) ? TRUE : FALSE;
- }
-
- OSErr HY_PlaySample( short int voiceNumber, // voice to play sample on
- void *pSample, // morph data pointer
- long length, // sample length
- UnsignedFixed rate, // Fixed 16.16 value
- short dataBitSize, // 8 or 16 bit data
- short channelSize, // 1 or 2 channels of date
- CustomCallbackProc customCallback, // callback when finished, event what
- long userData,
- Boolean killSound)
- {
- SndCommand theCmd;
- register MM_SoundVoice *pVoice;
- register OSErr theErr;
- ExtSoundHeader theSndBuffer;
-
- theErr = noErr;
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- if (voiceNumber == kUseAnyVoice)
- {
- theErr = channelBusy;
- }
- }
- if (length < 1) // data length greater than zero
- {
- theErr = buffersTooSmall;
- }
- if ( (dataBitSize != 8) && (dataBitSize != 16) ) // sample bit size is 8 or 16 bits
- {
- theErr = badFormat;
- }
- if ( (channelSize != 1) && (channelSize != 2) ) // mono or stereo
- {
- theErr = badFormat;
- }
- if (rate < 0x10000L) // sample rate is at least 1.0
- {
- theErr = siInvalidSampleRate;
- }
- if (theErr == noErr)
- {
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber); // voice to play on is in range
- if (pVoice)
- {
- if (pVoice->voiceActive)
- {
- if (killSound)
- {
- HY_StopSample(voiceNumber);
- }
- else
- {
- theErr = channelBusy;
- }
- }
- if (theErr == noErr)
- {
- pVoice->customCallback = customCallback;
- pVoice->userData = userData;
- /* Play sample */
-
- theSndBuffer.samplePtr = (Ptr)pSample;
- theSndBuffer.numChannels = channelSize;
- theSndBuffer.sampleRate = rate;
- theSndBuffer.loopStart = 0; // Apple Sound Manager looping doesn't work for one shot sounds
- theSndBuffer.loopEnd = 0;
- theSndBuffer.encode = extSH;
- theSndBuffer.baseFrequency = 0;
- theSndBuffer.numFrames = length;
- // theSndBuffer.AIFFSampleRate = 0;
- theSndBuffer.markerChunk = NULL;
- theSndBuffer.instrumentChunks = NULL;
- theSndBuffer.AESRecording = NULL;
- theSndBuffer.sampleSize = dataBitSize;
- theSndBuffer.futureUse1 = 0;
- theSndBuffer.futureUse2 = 0;
- theSndBuffer.futureUse3 = 0;
- theSndBuffer.futureUse4 = 0;
- pVoice->theSndBuffer = theSndBuffer;
- theCmd.param1 = 0;
- theCmd.param2 = (long)&theSndBuffer;
- theCmd.cmd = bufferCmd;
- theErr = SndDoCommand(pVoice->theChannel, &theCmd, FALSE); // start sound
- if (theErr == noErr)
- {
- theErr = HYP_PostCallbackFunction(pVoice->theChannel, (long)pVoice);
- }
- pVoice->voiceActive = TRUE;
- }
- }
- else
- {
- theErr = qtParamErr;
- }
- }
- if (theErr)
- {
- DEBUGSTR("\pError in HY_PlaySample");
- }
- return theErr;
- }
-
- void HY_StopSample(register short int voiceNumber)
- {
- register MM_SoundVoice *pVoice;
- SndCommand theCmd;
-
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- }
-
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- if (HY_IsVoiceEmpty(voiceNumber) == FALSE)
- {
- if (pVoice->filePlay)
- {
- SndStopFilePlay(pVoice->theChannel, TRUE);
- FSClose(pVoice->fileRef);
- pVoice->filePlay = FALSE;
- pVoice->fileRef = 0;
- }
- theCmd.param1 = 0;
- theCmd.param2 = 0;
- theCmd.cmd = quietCmd;
- SndDoImmediate(pVoice->theChannel, &theCmd);
- theCmd.cmd = flushCmd;
- SndDoImmediate(pVoice->theChannel, &theCmd);
- if (pVoice->customCallback)
- {
- (*pVoice->customCallback)( voiceNumber,
- kSoundDoneForcedStop,
- pVoice->userData);
- }
- pVoice->voiceActive = FALSE;
- }
- }
- }
-
- OSErr HY_PlaySoundHandle( short int voiceNumber,
- SndReference theSound,
- CustomCallbackProc customCallback,
- long userData,
- Boolean killSound)
- {
- register MM_SoundVoice *pVoice;
- register OSErr theErr;
-
- theErr = noErr;
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- if (voiceNumber == kUseAnyVoice)
- {
- theErr = channelBusy;
- }
- }
- // only work with sounds that have been access through our API
- if ( (theErr == noErr) && (HYP_IsThisSoundRegistered(theSound)))
- {
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber); // voice to play on is in range
- if (pVoice)
- {
- if (pVoice->voiceActive)
- {
- if (killSound)
- {
- HY_StopSample(voiceNumber);
- }
- else
- {
- theErr = channelBusy;
- }
- }
- if (theErr == noErr)
- {
- pVoice->customCallback = customCallback;
- pVoice->userData = userData;
-
- // Play sound sample. This allows the sound reference to be a MACE compressed sound, 8 or 16 bit, mono,
- // stereo, or whatever.
- theErr = SndPlay(pVoice->theChannel, (SndListHandle)theSound, TRUE);
- if (theErr == noErr)
- {
- // now post a callback to process this sample when its finished
- theErr = HYP_PostCallbackFunction(pVoice->theChannel, (long)pVoice);
- pVoice->voiceActive = TRUE;
- }
- }
- }
- }
- return noErr;
- }
-
-
-
- Boolean HY_IsVoiceEmpty(register short int voiceNumber)
- {
- SCStatus status;
- register OSErr theErr;
- register MM_SoundVoice *pVoice;
- register Boolean empty;
-
- empty = TRUE;
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- }
-
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- // Our voiceActive works because we set it at the end of a sample playback. But we're going to query
- // the Sound Manager, just in case it fails to call our callback that sets the flag and we'll store the
- // query in our variable voiceActive;
- empty = ! pVoice->voiceActive;
- theErr = SndChannelStatus(pVoice->theChannel, sizeof(SCStatus), &status);
- if (theErr == noErr)
- {
- if (pVoice->voiceActive != status.scChannelBusy)
- {
- pVoice->voiceActive = status.scChannelBusy;
- }
- empty = ! pVoice->voiceActive;
- }
- }
- return empty;
- }
-
- void HY_SetRate(short int voiceNumber, UnsignedFixed newRate)
- {
- register MM_SoundVoice *pVoice;
- SndCommand theCmd;
-
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- }
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- pVoice->lastRate = newRate;
- // Convert the passed rate into a relative sample multipler
- newRate = UnsignedFixedMulDiv(newRate, 0x10000, rate22khz);
-
- theCmd.param1 = 0;
- theCmd.param2 = (long)newRate;
- theCmd.cmd = rateCmd;
- SndDoImmediate(pVoice->theChannel, &theCmd); // change rate now for this channel
- }
- }
-
- UnsignedFixed HY_GetRate(short int voiceNumber)
- {
- register MM_SoundVoice *pVoice;
- UnsignedFixed oldRate;
- SndCommand theCmd;
-
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- }
- oldRate = rate22khz;
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- oldRate = pVoice->lastRate;
- if (pVoice->voiceActive)
- {
- theCmd.param1 = 0;
- theCmd.param2 = (long)&oldRate;
- theCmd.cmd = getRateCmd;
- SndDoImmediate(pVoice->theChannel, &theCmd); // get the current rate for this channel
-
- // Use this cool Toolbox routine to determine the actual sample rate
- oldRate = UnsignedFixedMulDiv(rate22khz, oldRate, 0x10000);
- }
- }
- return oldRate;
- }
-
- void HY_SetVolume(short int voiceNumber, SoundVolume newVolume)
- {
- register MM_SoundVoice *pVoice;
- SndCommand theCmd;
-
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- }
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- theCmd.param1 = 0;
- // by breaking down the volumes here, we become a little more flexible to compilers
- theCmd.param2 = (long)((long)newVolume.right << 16L | (newVolume.left & 0xFFFF));
- theCmd.cmd = volumeCmd;
- SndDoImmediate(pVoice->theChannel, &theCmd); // change volume now for this channel
- }
- }
-
- SoundVolume HY_GetVolume(short int voiceNumber)
- {
- register MM_SoundVoice *pVoice;
- SndCommand theCmd;
- SoundVolume oldVolume;
- long soundVolume;
-
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- }
- *((long *)&oldVolume) = -1L;
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- soundVolume = 0;
- theCmd.param1 = 0;
- theCmd.param2 = (long)&soundVolume;
-
- theCmd.cmd = getVolumeCmd;
- SndDoImmediate(pVoice->theChannel, &theCmd); // get the current volume for this channel
-
- // by breaking down the volumes here, we become a little more flexible to compilers
- oldVolume.right = soundVolume >> 16L;
- oldVolume.left = soundVolume & 0xFFFFL;
- }
- return oldVolume;
- }
-
- void HY_SetStereoPosition(short int voiceNumber, short positionMask)
- {
- register MM_SoundVoice *pVoice;
- SoundVolume theVolume;
-
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- }
-
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- theVolume.right = kFullVolume + positionMask;
- theVolume.left = kFullVolume - positionMask;
-
- HY_SetVolume(voiceNumber, theVolume);
- }
- }
-
- short HY_GetStereoPosition(short int voiceNumber)
- {
- register MM_SoundVoice *pVoice;
- SoundVolume theVolume;
- short positionMask;
-
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- }
-
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber);
- if (pVoice)
- {
- theVolume = HY_GetVolume(voiceNumber);
- positionMask = theVolume.right - theVolume.left;
- }
- return positionMask;
- }
-
- void HY_ServiceTasks(void)
- {
- register short int count;
- SCStatus status;
- register OSErr theErr;
- register MM_SoundVoice *pVoice;
-
- HYP_ProcessNextCallbackQueue();
-
- for (count = 0; count < maxSoundVoices; count++)
- {
- pVoice = &theSoundVoices[count];
- if (pVoice->theChannel)
- {
- theErr = SndChannelStatus(pVoice->theChannel, sizeof(SCStatus), &status);
- if (theErr == noErr)
- {
- if (pVoice->voiceActive != status.scChannelBusy)
- {
- pVoice->voiceActive = status.scChannelBusy;
- }
- }
- }
- }
- }
-
- OSErr HY_PauseHardware(void)
- {
- register MM_SoundVoice *pVoice;
- register short int count;
-
- HYP_CleanupVBLTask();
-
- for (count = 0; count < maxSoundVoices; count++)
- {
- pVoice = &theSoundVoices[count];
- if (pVoice->theChannel)
- {
- if (pVoice->voicePaused == FALSE)
- {
- pVoice->voicePaused = TRUE;
- if (pVoice->voiceActive)
- {
- if (pVoice->filePlay)
- {
- SndPauseFilePlay(pVoice->theChannel); // pause file playback
- }
- }
- }
- }
- }
- return noErr;
- }
-
- OSErr HY_ResumeHardware(void)
- {
- register MM_SoundVoice *pVoice;
- register short int count;
-
- HYP_SetupVBLTask();
-
- for (count = 0; count < maxSoundVoices; count++)
- {
- pVoice = &theSoundVoices[count];
- if (pVoice->theChannel)
- {
- if (pVoice->voicePaused)
- {
- pVoice->voicePaused = FALSE;
- if (pVoice->voiceActive)
- {
- if (pVoice->filePlay)
- {
- SndPauseFilePlay(pVoice->theChannel); // resume file playback
- }
- }
- }
- }
- }
- return noErr;
- }
-
- OSErr HY_StartFilePlay(short int voiceNumber,
- FSSpec *pFile,
- CustomCallbackProc customCallback,
- long userData,
- long bufferSize,
- Boolean killSound)
- {
- register MM_SoundVoice *pVoice;
- register OSErr theErr;
-
- theErr = noErr;
- if (voiceNumber == kUseAnyVoice)
- {
- voiceNumber = HYP_GetFreeVoice();
- if (voiceNumber == kUseAnyVoice)
- {
- theErr = channelBusy;
- }
- }
- if (theErr == noErr)
- {
- pVoice = HYP_GetPrivateDataFromVoice(voiceNumber); // voice to play on is in range
- if (pVoice)
- {
- if (pVoice->voiceActive)
- {
- if (killSound)
- {
- HY_StopSample(voiceNumber);
- }
- else
- {
- theErr = channelBusy;
- }
- }
- if (theErr == noErr)
- {
- pVoice->customCallback = customCallback;
- pVoice->userData = userData;
- pVoice->theChannel->userInfo = globalA5;
- pVoice->fileSpec = *pFile;
-
- // We could use the cooler file open function, but it only works with System 7 or better. Sound Manager 3.0
- // can be installed on a System eariler than 7.0
- // theErr = FSpOpenDF(pFile, fsRdPerm, &pVoice->fileRef);
-
- theErr = HOpen(pFile->vRefNum, pFile->parID, pFile->name, fsRdPerm, &pVoice->fileRef);
- if (theErr == noErr)
- {
- theErr = SndStartFilePlay(pVoice->theChannel,
- pVoice->fileRef, 0,
- bufferSize, NULL,
- NULL,
- NewFilePlayCompletionProc(HYP_FilePlayCompletionDone),
- TRUE);
- if (theErr == noErr)
- {
- pVoice->filePlay = TRUE;
- pVoice->voiceActive = TRUE;
- }
- }
- }
- }
- }
- return theErr;
- }
-
-
- OSErr HY_GetSoundResourceInformation(Handle theSnd, long *pLoopStart, long *pLoopEnd,
- long *pSampleOffsetStart, long *pTotalSize, short *pBaseKey,
- short int *pNumChannels, short int *pBitSize,
- UnsignedFixed *pRate,
- short int *pCompressionType)
- {
- register SoundHeader * pSndBuffer;
- register CmpSoundHeader * pCmpBuffer;
- register ExtSoundHeader * pExtBuffer;
- short int soundFormat;
- short int numSynths, numCmds;
- long offset;
- register Ptr pSndFormat;
- OSErr theErr;
-
- theErr = badFormat;
- *pSampleOffsetStart = 0;
- *pTotalSize = 0;
- *pLoopStart = 0;
- *pLoopEnd = 0;
- *pBaseKey = 0;
- *pCompressionType = notCompressed;
- *pNumChannels = 1; // defaults for standard header
- *pBitSize = 8;
- *pRate = 0;
-
- if (theSnd)
- {
- HLock(theSnd);
- pSndFormat = (Ptr)*theSnd;
- soundFormat = *(short int *)pSndFormat;
- switch (soundFormat)
- {
- case 1: // format 1 sound
- // look inside the format 1 resource and decode offsets
- numSynths = ((short int *)pSndFormat)[1]; // get number of synths
- numCmds = *(short int *)(pSndFormat + 4 + numSynths * 6); // get number of commands
- break;
- case 2: // format 2 sound
- numSynths = 0; // format 2 has none
- numCmds = ((short int *)pSndFormat)[2];
- break;
- default:
- soundFormat = -1;
- break;
- }
-
- if (soundFormat != -1) /* did we get the right format? */
- {
- /* compute address of sound header.
- */
- offset = 6 + 6 * numSynths + 8 * numCmds;
- pSndBuffer = (SoundHeader *) (StripAddress(*theSnd) + offset);
- switch (pSndBuffer->encode)
- {
- case stdSH: // standard header
- *pSampleOffsetStart = (long)&pSndBuffer->sampleArea[0] - (long)((Byte *)*theSnd);
- *pTotalSize = pSndBuffer->length;
- *pLoopStart = pSndBuffer->loopStart;
- *pLoopEnd = pSndBuffer->loopEnd;
- *pBaseKey = pSndBuffer->baseFrequency;
- *pRate = pSndBuffer->sampleRate;
- theErr = noErr;
- break;
-
- case extSH: // extened header
- pExtBuffer = (ExtSoundHeader *)pSndBuffer;
- *pSampleOffsetStart = (long)&pExtBuffer->sampleArea[0] - (long)((Byte *)*theSnd);
- *pNumChannels = pExtBuffer->numChannels;
- *pBitSize = pExtBuffer->sampleSize;
- *pTotalSize = pExtBuffer->numFrames * (*pNumChannels) * (*pBitSize / 8);
- *pLoopStart = pExtBuffer->loopStart;
- *pLoopEnd = pExtBuffer->loopEnd;
- *pBaseKey = pExtBuffer->baseFrequency;
- *pRate = pExtBuffer->sampleRate;
- theErr = noErr;
- break;
-
- case cmpSH: // compressed header
- pCmpBuffer = (CmpSoundHeader *)pSndBuffer;
- *pSampleOffsetStart = (long)&pCmpBuffer->sampleArea[0] - (long)((Byte *)*theSnd);
- *pNumChannels = pCmpBuffer->numChannels;
- *pBitSize = pCmpBuffer->sampleSize;
- *pTotalSize = pCmpBuffer->numFrames * (*pNumChannels) * (*pBitSize / 8);
- *pLoopStart = pCmpBuffer->loopStart;
- *pLoopEnd = pCmpBuffer->loopEnd;
- *pBaseKey = pCmpBuffer->baseFrequency;
- *pRate = pCmpBuffer->sampleRate;
- *pCompressionType = pCmpBuffer->compressionID;
- theErr = noErr;
- break;
- }
- }
- HUnlock(theSnd);
- }
- return theErr;
- }
-
-
- OSErr HY_CreateAIFFFileFromPtr(FSSpec *pFile, Ptr pSample, long dataLength, UnsignedFixed sampleRate,
- short bitSize, short numChannels)
- {
- OSErr theErr;
- short int fileRef;
- long length;
-
- theErr = badFormat;
- if ( (bitSize == 8) || (bitSize == 16) || (numChannels == 1) || (numChannels == 2) )
- {
- theErr = FSpCreate(pFile, 'hlly', AIFFID , 0);
- if (theErr == noErr)
- {
- theErr = FSpOpenDF(pFile, fsRdWrPerm, &fileRef);
- if (theErr == noErr)
- {
- SetFPos(fileRef, fsFromStart, 0L);
- theErr = SetupAIFFHeader(fileRef, numChannels, sampleRate, bitSize, NoneType,
- 0L, dataLength);
- if (theErr == noErr)
- {
- length = dataLength * numChannels * (bitSize / 8);
- theErr = FSWrite(fileRef, &length, pSample);
- if (theErr == noErr)
- {
- SetFPos(fileRef, fsFromStart, 0L);
- theErr = SetupAIFFHeader(fileRef, numChannels, sampleRate, bitSize, NoneType,
- length, dataLength);
- }
- FSClose(fileRef);
- }
- }
- }
- }
- return theErr;
- }
-
- Handle HY_CreateSndResourceFromPtr(Ptr pSample, long dataLength, UnsignedFixed sampleRate,
- short bitSize, short numChannels,
- short int baseFreq)
- {
- OSErr theErr;
- Handle theSoundHeader;
- Handle theSound;
- short headerLength;
-
- theSound = NULL;
- // first allocate enough of a handle to setup the header information
- theSoundHeader = NewHandleClear(200L);
- if (theSoundHeader)
- {
- theErr = SetupSndHeader((SndListHandle)theSoundHeader, numChannels, sampleRate, bitSize, 'NONE',
- baseFreq, 0, &headerLength);
- if (theErr == noErr)
- {
- // ok, now we know how large header info is, so we can block move the sample data right after
- theSound = NewHandle(headerLength + dataLength);
- if (theSound)
- {
- HLock(theSound);
- BlockMove(*theSoundHeader, *theSound, headerLength);
- BlockMove(pSample, ((Byte *)*theSound) + headerLength, dataLength);
- HUnlock(theSound);
- DisposeHandle(theSoundHeader);
-
- // ok, now set the new length of the data
- theErr = SetupSndHeader((SndListHandle)theSound, numChannels, sampleRate, bitSize, 'NONE',
- baseFreq, dataLength, &headerLength);
- if (theErr)
- {
- DisposeHandle(theSound);
- theSound = NULL;
- }
- }
- }
- else
- {
- DisposeHandle(theSoundHeader);
- }
- }
- return theSound;
- }
-
- Handle HY_CreateMACESndResourceFromPtr(short maceType, Ptr pSample, long dataLength,
- UnsignedFixed sampleRate,
- short bitSize, short numChannels,
- short int baseFreq)
- {
- OSErr theErr;
- Handle theSoundHeader;
- Handle theSound;
- short headerLength;
- long compressLength;
- OSType compressionType;
- Byte compressInState[128];
- Byte compressOutState[128];
- Byte * pData;
- long count;
-
- theErr = badFormat;
- theSound = NULL;
- if ( (bitSize == 8) && (numChannels == 1) ) // MACE only supports 8 bit samples. Hollywood only supports mono
- {
- switch (maceType)
- {
- case threeToOne:
- compressionType = 'MAC3';
- compressLength = dataLength / 3L;
- theErr = noErr;
- break;
- case sixToOne:
- compressionType = 'MAC6';
- compressLength = dataLength / 6L;
- theErr = noErr;
- break;
- }
- }
- if (theErr == noErr)
- {
- // first allocate enough of a handle to setup the header information
- theSoundHeader = NewHandleClear(200L);
- if (theSoundHeader)
- {
- theErr = SetupSndHeader((SndListHandle)theSoundHeader, 1, sampleRate, bitSize, compressionType,
- baseFreq, 0, &headerLength);
- if (theErr == noErr)
- {
- // ok, now we know how large header info is, so we can block move the sample data right after
- theSound = NewHandle(headerLength + dataLength);
- if (theSound)
- {
- HLock(theSound);
- BlockMove(*theSoundHeader, *theSound, headerLength);
-
- // Clear state data for MACE compressor
- for (count = 0; count < 128; count++)
- {
- compressInState[count] = 0;
- compressOutState[count] = 0;
- }
-
- // MACE supports stereo compressed data, but we don't bother to put it together here.
- // In order to create stereo compressed data, you need to build to buffers, one for each
- // channel. Compress each channel into that buffer by calling CompXto1 with the last parameter
- // set to the channel you are compressing. Then to rebuild the final data, you need to interleave
- // the two buffers into one buffer for the final output. Simple huh! :o
- pData = ((Byte *)*theSound) + headerLength;
- switch (maceType)
- {
- case threeToOne:
- Comp3to1(pSample, pData, dataLength,
- NULL, NULL, 1, 1);
- // compressInState, compressOutState, 1, 1);
- break;
- case sixToOne:
- Comp6to1(pSample, pData, dataLength,
- NULL, NULL, 1, 1);
- // compressInState, compressOutState, 1, 1);
- break;
- }
- HUnlock(theSound);
- SetHandleSize(theSound, headerLength + compressLength + 6);
- theErr = MemError();
- DisposeHandle(theSoundHeader);
- if (theErr == noErr)
- {
- // ok, now set the new length of the data
- theErr = SetupSndHeader((SndListHandle)theSound, 1, sampleRate, bitSize, compressionType,
- baseFreq, compressLength, &headerLength);
- }
- if (theErr)
- {
- DisposeHandle(theSound);
- theSound = NULL;
- }
- }
- }
- else
- {
- if (theSound)
- {
- DisposeHandle(theSoundHeader);
- }
- }
- }
- }
- return theSound;
- }
-
-
-
- // EOF of Hollywood.c
-
-