home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-06-16 | 16.8 KB | 700 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
- // 3/1/95 Music Architecture added by Jim Nitchals
- //----------------
- #include <Types.h>
- #include <Memory.h>
- #include <Quickdraw.h>
- #include <OSEvents.h>
- #include <Desk.h>
- #include <Events.h>
- #include <StandardFile.h>
- #include <Resources.h>
- #include <Windows.h>
- #include <Fonts.h>
- #include <TextEdit.h>
- #include <Menus.h>
- #include <Dialogs.h>
- #include <ToolUtils.h>
- #include <Sound.h>
- #include <AIFF.h>
-
- // These includes are for the Apple Music Architecture
- #include <QuickTimeComponents.h>
- #include <Components.h>
-
-
- #define TRUE true
- #define FALSE false
-
- #include "Hollywood.h"
-
- // Defines and Structures
- #define rAboutDialog 128
-
- // Menu defines
- #define kMaxMenus 2
-
- #define rAppleMenu 1
- #define kAbout 1
-
- #define rFileMenu 2
- #define kPlayFile 1
- #define kPlaySnd1 2
- #define kPlaySnd2 3
- #define kPlaySnd3 4
- #define kPlaySnd4 5
- #define kDoStereoPan 6
- #define kSaveAIFF 7
- #define kPlayMusicNotes 9
- #define kPlayQuickTime 10
- #define kQuitApp 12
-
- #define kStereoPanCount 30 // the amount of change during a stereo pan
- #define kStereoDelay 4L // amount of ticks to pass before changing the stereo position
- #define kPanVoice 1 // which voice to work with durning the pan test
-
- // Examples
- #define rExampleSound1 128 // snd examples
- #define rExampleSound2 129
-
- #define rExampleRaw1 128 // raw waveform examples
- #define rExampleRaw2 129
-
- // Variables
- static Boolean appDoneFlag;
- static Boolean movieInProgress;
- static WindowPtr theMovieDisplayWindow = NULL;
- static Movie theMovie;
-
- static char theDate[] = __DATE__;
- static char theTime[] = __TIME__;
-
- static MenuHandle Menu[kMaxMenus];
-
- static Boolean processStereoPan;
- static short int stereoPos, stereoDirection;
- static long lastProcessTick;
-
- // Functions
- static void StartQuickTimeMovie(void);
- static void ProcessQuickTimeMovie(void);
- static void EndQuickTimeMovie(void);
-
-
- static Boolean GetReadFileName(char *pName, short *pVRef, OSType *pType, short typeCount)
- {
- static Point anchor = {100, 7}; /* top-left */
- SFReply reply;
-
- SFGetFile(anchor, NULL, NULL, typeCount, pType, NULL, &reply);
-
- if (pType)
- {
- pType[0] = reply.fType;
- }
- BlockMove((void *)reply.fName, pName, 63L);
- *pVRef = reply.vRefNum;
- return(reply.good);
- }
-
- static Boolean GetWriteFileName(void *pName, short int *pVRef, void *pSaveText)
- {
- static Point anchor = {50, 105}; /* top-left */
- SFReply reply;
-
- SFPutFile(anchor, (ConstStr255Param)pSaveText, (ConstStr255Param)pName, NULL, &reply);
- if (reply.good == FALSE)
- {
- return(FALSE); /* user pressed CANCEL */
- }
-
- *pVRef = reply.vRefNum;
- BlockMove(reply.fName, pName, 63L);
- return(TRUE);
- }
-
- static void DisplayAboutBox(void)
- {
- DialogRecord dRecord;
- GrafPtr savePort;
- register DialogPtr theDialog;
- short theItem;
-
- GetPort(&savePort);
- theDialog = GetNewDialog(rAboutDialog, &dRecord, (WindowPtr)-1L);
- SetPort(theDialog);
- ModalDialog(NULL, &theItem);
- CloseDialog(theDialog); // I supplied memory for GetNewDialog
-
- SetPort(savePort);
- }
-
- static void StartQuickTimeMovie(void)
- {
- SFTypeList theTypeList;
- StandardFileReply theReply;
- short int myRef;
- Rect wRect;
- FSSpec theMidiFile;
- OSErr theErr;
-
- if (movieInProgress)
- {
- EndQuickTimeMovie();
- movieInProgress = FALSE;
- }
- /* Let the user select a movie */
- theTypeList[0] = MovieFileType;
- theTypeList[1] = 'Midi';
- StandardGetFile(NULL, 2, theTypeList, &theReply);
- if (theReply.sfGood)
- {
- /* initialize movie toolbox */
- theErr = EnterMovies();
- if (theErr == noErr)
- {
- if (theReply.sfType == 'Midi')
- { // Then we are converting a Midi file into a QuickTime movie
- theMidiFile = theReply.sfFile;
- StandardPutFile(NULL, theReply.sfFile.name, &theReply);
- if (theReply.sfGood)
- {
- theErr = ConvertFileToMovieFile(&theMidiFile, &theReply.sfFile, 'TVOD', 0,
- NULL, showUserSettingsDialog, 0L, NULL, 0L);
- }
- else
- {
- theErr = badFormat;
- }
- }
- /* open the movie file, get the movie from it, then close it */
- if ( (theErr == noErr) && (OpenMovieFile(&theReply.sfFile, &myRef, fsRdPerm) == noErr) )
- {
- if (NewMovieFromFile(&theMovie, myRef, NULL, NULL, newMovieActive, NULL) == noErr)
- {
- /* Find out the size of the movie. */
- GetMovieBox (theMovie, &wRect);
-
- /* If the movie has no video, don't display any window. */
- if (wRect.bottom)
- {
- wRect.top += 48;
- wRect.left += 48;
- wRect.bottom += 48;
- wRect.right += 48;
- theMovieDisplayWindow = NewCWindow (NULL, &wRect, "\pMovie Window", TRUE, plainDBox,
- (WindowPtr) -1L, TRUE, 0);
- SetMovieGWorld (theMovie, (CGrafPtr) theMovieDisplayWindow, 0);
- }
-
- /* Tell QuickTime we're playing from the beginning. */
- GoToBeginningOfMovie(theMovie);
-
- /* PrerollMovie helps QuickTime pre-load parts of the movie to
- give smoother playback.
-
- Second parameter is the time we expect to start playing at.
- Third parameter is the playback rate we expect to be using.
- 1.0 in fixed rate. */
- PrerollMovie(theMovie, 0, 0x10000);
-
- /* Start playing forward. */
- StartMovie(theMovie);
- movieInProgress = TRUE;
- }
- CloseMovieFile(myRef);
- }
- }
- }
- }
-
- static void ProcessQuickTimeMovie(void)
- {
- if (movieInProgress)
- {
- if (IsMovieDone(theMovie))
- {
- EndQuickTimeMovie();
- }
- else
- {
- /* Your event loop should call MoviesTask very regularly for smooth playback.
- The second parameter to MoviesTask is the maximum number of milliseconds
- QuickTime may use when playing multiple movies. Pass 0 to allow QuickTime
- to service every movie properly. */
- MoviesTask(theMovie, 0);
- }
- }
- }
-
- static void EndQuickTimeMovie(void)
- {
- if (movieInProgress)
- {
- /* Throw away the window if there was one. */
- if (theMovieDisplayWindow)
- {
- DisposeWindow(theMovieDisplayWindow);
- theMovieDisplayWindow = NULL;
- }
- /* Make this call to free up resources used by QuickTime and the movie. */
- DisposeMovie(theMovie);
- movieInProgress = FALSE;
- ExitMovies();
- }
- }
-
-
-
- static void PlayQuickTimeNotes(void)
- {
- NoteAllocator theNoteAllocator; /* The music note allocator component */
- NoteChannel myNoteChannel; /* A channel to play notes through */
- NoteRequest myNoteRequest; /* A structure describing the instrument we want to play */
- short int i, velocity, instrument_index;
- unsigned long current_tick_count;
- /* This is a list of General MIDI instrument numbers we want to play. */
- static int instrument_list[6] = {1, 5, 7, 8, 12, 13};
-
- /* Open the note allocator component */
- theNoteAllocator = OpenDefaultComponent(kNoteAllocatorType, 0);
-
- /* Walk through our list of available instruments. */
- for (instrument_index = 0; instrument_index < 6; instrument_index++)
- {
- /* Set up a NoteRequest structure with a request for a piano with polyphony of 1. */
- myNoteRequest.polyphony = 1;
- myNoteRequest.typicalPolyphony = 1<<16;
-
- /* We can request a specific instrument by name. If it's not found, the gmNumber field
- provides the General MIDI fallback instrument. */
- myNoteRequest.tone.synthesizerType = 0;
- myNoteRequest.tone.synthesizerName[0] = 0;
- myNoteRequest.tone.instrumentName[0] = 0;
- myNoteRequest.tone.instrumentNumber = 0;
- myNoteRequest.tone.gmNumber = instrument_list[instrument_index];
-
- /* Allocate a note channel with our desired instrument as filled out in the NoteRequest */
- NANewNoteChannel(theNoteAllocator, &myNoteRequest, &myNoteChannel);
-
- /* Load the resources needed by the instrument */
- NAPrerollNoteChannel(theNoteAllocator, myNoteChannel);
-
- /* Perform a loop, playing notes at increasing pitch and velocity, using TickCount()
- as a timebase. You can play notes at interrupt time, so you can schedule note
- events with the Time Manager, or through your own schemes. */
- current_tick_count = TickCount() + 6;
- for (i = 32; i < 90 && Button() == false; i += 3)
- {
- velocity = i + 10;
- /* Play the Note */
- NAPlayNote(theNoteAllocator, myNoteChannel, i, velocity);
-
- /* Wait awhile */
- while (current_tick_count > TickCount()) {};
- current_tick_count += 6; /* Prepare to do this again in another 1/10th-second. */
-
- /* Stop playing the note. */
- NAPlayNote(theNoteAllocator, myNoteChannel, i, 0);
- }
-
- /* Wait for the last note to decay away to silence. */
- current_tick_count += 20;
- while (current_tick_count > TickCount()) {};
-
- /* Dispose the note channel when we're done with it. */
- NADisposeNoteChannel(theNoteAllocator, myNoteChannel);
- }
- CloseComponent(theNoteAllocator);
- }
-
-
-
- static void FilePlayCallback(short int voiceNumber, short int what, long userData)
- {
-
- }
-
- static void PlayFile(void)
- {
- OSType types[2];
- FSSpec theFile;
- OSErr theErr;
-
- types[0] = AIFFID; // from AIFF.h
- types[1] = AIFCID; // from AIFF.h
-
- if (GetReadFileName((char *)theFile.name, &theFile.vRefNum, types, 2))
- {
- theFile.parID = 0;
- theErr = HY_StartFilePlay(kPanVoice, &theFile, FilePlayCallback, 0, 40000L, TRUE);
- }
- }
-
-
- static void PlaySoundEffect1(void)
- {
- static SndReference theSound1 = NULL;
-
- if (theSound1 == NULL) // only load this sample in once
- {
- theSound1 = HY_GetSoundResource(rExampleSound1);
- }
- if (theSound1)
- {
- HY_PlaySoundHandle(0, theSound1, NULL, 0, TRUE);
- }
- }
-
- static void PlaySoundEffect2(void)
- {
- static SndReference theSound2 = NULL;
-
- if (theSound2 == NULL) // only load this sample in once
- {
- theSound2 = HY_GetSoundResource(rExampleSound2);
- }
- if (theSound2)
- {
- HY_PlaySoundHandle(kPanVoice, theSound2, NULL, 0, TRUE);
- }
- }
-
- static void PlaySoundEffect3(void)
- {
- Handle theSample, theNewSample;
- Handle theCompressedSample;
-
- theSample = GetResource('wave', rExampleRaw1);
- if (theSample)
- {
- HLock(theSample);
- // our raw waveform is mono 8 bit, and should be played back at 11 kHz.
- theNewSample = HY_CreateSndResourceFromPtr(*theSample, GetHandleSize(theSample), rate11khz,
- 8, 1, kMiddleC);
- HUnlock(theSample);
-
- if (theNewSample)
- {
- HY_RegisterThisSound(theNewSample);
- HY_PlaySoundHandle(0, theNewSample, NULL, 0L, TRUE);
- while (HY_IsVoiceEmpty(0) == FALSE)
- {
- HY_ServiceTasks(); // at least call once in a while
- }
- HY_UnregisterSoundResource(theNewSample);
- DisposeHandle(theNewSample);
- }
-
- // now MACE compress it, and play it back.
- HLock(theSample);
- // 6 to 1 compression is pretty bad in this case, but 3 to 1 is ok
- theCompressedSample = HY_CreateMACESndResourceFromPtr(sixToOne, *theSample, GetHandleSize(theSample),
- rate11khz, 8, 1, kMiddleC);
- HUnlock(theSample);
- ReleaseResource(theSample);
-
- if (theCompressedSample)
- {
- HY_RegisterThisSound(theCompressedSample);
- HY_PlaySoundHandle(0, theCompressedSample, NULL, 0L, TRUE);
- while (HY_IsVoiceEmpty(0) == FALSE)
- {
- HY_ServiceTasks(); // at least call once in a while
- }
- HY_UnregisterSoundResource(theCompressedSample);
- DisposeHandle(theCompressedSample);
- }
- }
- }
-
- static void PlaySoundEffect4(void)
- {
- Handle theSample;
- Handle theNewSample;
-
- theSample = GetResource('wave', rExampleRaw2);
- if (theSample)
- {
- HLock(theSample);
- // our raw waveform is stereo 8 bit, and should be played back at 14321 kHz.
- theNewSample = HY_CreateSndResourceFromPtr(*theSample, GetHandleSize(theSample), X2Fix(20000.0),
- 8, 2, 60);
- HUnlock(theSample);
- ReleaseResource(theSample);
-
- if (theNewSample)
- {
- HY_RegisterThisSound(theNewSample);
- HY_PlaySoundHandle(0, theNewSample, NULL, 0L, TRUE);
- while (HY_IsVoiceEmpty(0) == FALSE)
- {
- HY_ServiceTasks(); // at least call once in a while
- }
- HY_UnregisterSoundResource(theNewSample);
- DisposeHandle(theNewSample);
- }
- }
- }
-
- static void PhaseWaveform(register char *p, register long size)
- {
- register char *ep;
-
- ep = p + size;
- while (p < ep)
- {
- *p -= 0x80;
- p++;
- }
- }
-
- static void SaveAIFFFile(void)
- {
- Handle theSample;
- FSSpec theFile;
- OSErr theErr;
- long length;
-
- theFile.name[0] = 0;
- if (GetWriteFileName(theFile.name, &theFile.vRefNum, "\pSave Example AIFF…"))
- {
- theFile.parID = 0;
- theSample = GetResource('wave', rExampleRaw1);
- if (theSample)
- {
- DetachResource(theSample);
- HLock(theSample);
- length = GetHandleSize(theSample);
-
- // AIFF files expect the volume levels to be in the range of -128 to 127 for 8 bit data, and
- // -32768 to 32767. Where zero is silence. The standard Macintosh 8 bit resource silence is 128,
- // so we have to phase the sample back.
-
- PhaseWaveform(*theSample, length);
-
- theErr = HY_CreateAIFFFileFromPtr(&theFile, *theSample, length,
- rate11khz,
- 8, 1);
- HUnlock(theSample);
- DisposeHandle(theSample);
- }
- }
- }
-
- static void ProcessStereoPan(short int voiceNumber)
- {
- if (TickCount() > lastProcessTick)
- {
- lastProcessTick = TickCount() + kStereoDelay;
-
- HY_SetStereoPosition(voiceNumber, stereoPos);
- stereoPos += stereoDirection;
- if (stereoPos < kFullLeft)
- {
- stereoDirection = kStereoPanCount;
- stereoPos += stereoDirection;
- }
- if (stereoPos > kFullRight)
- {
- stereoDirection = -kStereoPanCount;
- stereoPos += stereoDirection;
- }
- }
- }
-
- static void ProcessMenuCommands(long menuSelection)
- {
- short int theMenuSelection, theItemSelection;
- Str255 deskName;
- GrafPtr savePort;
-
- theMenuSelection = HiWord(menuSelection);
- theItemSelection = LoWord(menuSelection);
-
- switch (theMenuSelection)
- {
- case rAppleMenu:
- switch (theItemSelection)
- {
- case kAbout:
- DisplayAboutBox();
- break;
- default:
- GetItem(Menu[0], theItemSelection, deskName);
- GetPort(&savePort);
- OpenDeskAcc(deskName);
- SetPort(savePort);
- break;
- }
- break;
- case rFileMenu:
- switch (theItemSelection)
- {
- case kPlayFile:
- PlayFile();
- break;
- case kPlaySnd1:
- PlaySoundEffect1();
- break;
- case kPlaySnd2:
- PlaySoundEffect2();
- break;
- case kPlaySnd3:
- PlaySoundEffect3();
- break;
- case kPlaySnd4:
- PlaySoundEffect4();
- break;
- case kDoStereoPan:
- processStereoPan = TRUE;
- stereoPos = kMiddle;
- HY_SetStereoPosition(kPanVoice, stereoPos);
- stereoDirection = -kStereoPanCount; // start left
- lastProcessTick = TickCount() + kStereoDelay;
- break;
- case kSaveAIFF:
- SaveAIFFFile();
- break;
- case kPlayMusicNotes:
- PlayQuickTimeNotes();
- break;
- case kPlayQuickTime:
- StartQuickTimeMovie();
- break;
- case kQuitApp:
- appDoneFlag = TRUE;
- break;
- }
- break;
- }
- HiliteMenu(0);
- }
-
-
- void main()
- {
- EventRecord theEvents;
- WindowPtr theWindow;
- OSErr theErr;
- short int count;
-
- // NOTE: The order of initilizing the system seems very important when running under
- // MultFinder!!!
- #if THINK_C
- InitGraf(&thePort); // set up screen port
- #else
- InitGraf(&qd.thePort);
- #endif
- InitFonts(); // set up font manager
- InitWindows(); // set up window stuff
- InitMenus(); // set up menu mgr
- TEInit(); // set up text editor for system use
- InitDialogs(NULL); // set up Dialog stuff
- InitCursor(); // put pointer shape in mouse
-
- MaxApplZone(); // force expansion
- FlushEvents(everyEvent, 0); // clear all events
- MoreMasters();
- MoreMasters();
-
- // Setup menus
- Menu[0] = GetMenu(rAppleMenu);
- AddResMenu(Menu[0], 'DRVR');
- Menu[1] = GetMenu(rFileMenu);
-
- for (count = 0; count < kMaxMenus; count++)
- {
- if (Menu[count])
- {
- InsertMenu(Menu[count], 0);
- }
- }
- DrawMenuBar();
-
- theErr = HY_Setup(kUseStereo, 3);
- appDoneFlag = FALSE;
- processStereoPan = FALSE;
- movieInProgress = FALSE;
- while (appDoneFlag == FALSE)
- {
- HY_ServiceTasks();
-
- ProcessQuickTimeMovie();
- if (processStereoPan)
- {
- ProcessStereoPan(kPanVoice);
- }
- if (WaitNextEvent(everyEvent, &theEvents, 0L, NULL))
- {
- switch(theEvents.what)
- {
- case mouseDown:
- switch (FindWindow(theEvents.where, &theWindow))
- {
- case inSysWindow:
- SystemClick(&theEvents, theWindow);
- break;
- case inMenuBar:
- ProcessMenuCommands(MenuSelect(theEvents.where));
- break;
- }
- break;
- case app4Evt: // Suspend/Resume Events
- if ( ((theEvents.message >> 24L) & 0x00FF) == 0x01)
- {
- if (theEvents.message & 1) // message field contains flags
- {
- // HY_ResumeHardware();
- }
- else
- {
- // suspend
- // HY_PauseHardware();
- }
- }
- break;
- case autoKey:
- case keyDown:
- count = theEvents.message & 0xFF;
- if (theEvents.modifiers & cmdKey)
- {
- ProcessMenuCommands(MenuKey(count));
- }
- else
- {
- switch(count)
- {
- case 'q':
- appDoneFlag = TRUE;
- break;
- }
- }
- break;
- }
- }
- }
- // release menus
- for (count = 0; count < kMaxMenus; count++)
- {
- if (Menu[count])
- {
- ReleaseResource((Handle)Menu[count]);
- }
- }
- HY_UnregisterAllSoundResources();
- HY_Cleanup();
- EndQuickTimeMovie();
- FlushEvents(everyEvent, 0); // clear all events
- }
-
- // EOF of Hollywood API Test.c
-
-
-