|
Volume Number: | 5 | |||
Issue Number: | 9 | |||
Column Tag: | Intermediate Mac'ing |
Related Info: Sound Manager
'snd ' Zoundz Great!
By Kirk Chase, Anaheim, CA
Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.
Piano Lessons--Yech!
When I was a boy, my mother made me take piano lessons (a fate that has fallen upon many young boys). I wasn’t too interested in the piano, so I soon traded the ivory keyboard for the Qwerty keyboard. I can still hear my mother telling me that I’ll regret the day I stopped playing the piano; I didn’t think so-until now.
I wanted to add sound to an application I was writing. Not knowing anything about sound other than the simple beep, I decided the Macintosh ‘snd ‘ resource was my next attack of study. So after an evening with Inside Macintosh, Vol. 5, I decided I had to be a MIDI maniac to understand a lot of the information found there, but I did manage to get a grasp on some of the simpler elements. So here is a simple overview.
To make a sound, you basically create a sound channel to a particular synthesizer and pass it a list of sound commands which, among other things, generate sounds--simple. A synthesizer allows music to be played in a certain way; there is currently a note synthesizer, a wave synthesizer, a sampled sound synthesizer, and some MIDI synthesizers. Which one you use depends on how you are going to generate the sound. I chose the note synthesizer for my sound generating application.
A sound channel is a record that holds information for processing the sound. It contains modifiers, call-back procedures, and a queue of sound commands. The sound commands are in a ‘snd ‘ resource format.
Figure 1. ‘snd ‘ Resource Format
The ‘snd ‘ Resource
The ‘snd ‘ resource has currently two types. The second type is used for representing an instrument or digitally recorded sound. Type one is used by us non-MIDI people. The first word in the ‘snd ‘ resource specifies this format type, 1 or 2. I use format type 1.
The second word tells how many synthesizers and modifiers that follow. A modifier, for a quick explination, is some code that alters the sound generated in some manner. I use this second word to open up a note synthesizer. This word is followed by a word identifying the synthesizer and a long integer giving the initialization procedure, if any. This is repeated for each synthesizer and modifier as specified in the second word.
After that, there is a word telling how many sound commands are to follow. Then the sound commands and any needed data are given. The format of the sound command is a word specifying which sound command, another word for param1, and a long for param2. If this is all confusing, see figure 1.
Sound Commands
For my application, I use the simple note synthesizer. Out of all the commands that generate sound, the note synthesizer recognizes only the note, rest, quiet, frequency, amplitude, and timbre commands. I use only the note, timbre, rest, and quiet commands in my application.
The note command has the ability to specify the pitch, amplitude, and duration. To further confuse matters, the pitch may be specified in two ways. The first way is to use a value between 0 and 127. This is then converted to a piano key (60 is middle C; 61 is C#). The other way is to give the actual frequency. I use the first way. The amplitude (0 255) is also added to the pitch and stored in the long (See figure 2). The duration, param1, is specified in milliseconds.
Figure 2. Combining Pitch and Amplitude
Zoundz 1.0
Zoundz gives the user the ability to draw a wave type description of the sound. There are four graphs the user draws to generate the sound--frequency, amplitude, duration, and timbre. Each vertical column is a note. You may also control the display of each graph (the drawing goes faster if you turn off the drawing of the other graphs).
The user may specify the exact values of a particular note. Use the scroll bar below the graphs to move the note you wish to modify to the left edge of the rectangle. The individual values may then be adjusted using the scroll bars in the upper right corner of the window. You may also specify which note to start and end your selection. When you are ready, just press the “Play Sound” button (be sure to specify the selection range). Figure 3 shows the Zoundz window.
Figure 3. Zoundz Window
Some editing shortcuts can be found under the “Extend” menu. Just set the selection range and select one of the menu items under this menu. The value selected in the menu of the current note (left edge) is given to the notes in the selection range.
When you save the sound, the values for each of the 100 possible notes are saved in the data fork. In the resource fork, a ‘snd ‘ resource is created with your sound. The name is the same as the one you gave to the file, and its ID=9000. Just use ResEdit to paste the sound into the system file (you may wish to give it a new ID number). You may also get a printed dump of your ‘snd ' resource by selecting the print option from the “File” menu.
Zoundz is pretty nice. It handles Finder startups for the documents to either print or open. It gives us non-musicians the chance to sketch our sound. Zoundz is not very good at producing composed music. I did however get it to play “Happy Birthday”. Try drawing patterns and listen to the outcome. You might create something that zoundz good.
Figure 4. Zoundz Build Order
Listing: MyGlobals unit MyGlobals; interface uses PrintTraps, Sound; const L_Apple = 1001; {Menu list} MI_About_Zoundz = 1; L_File = 1002; {Menu list} MI_New = 1; MI_Open = 2; MI_Close = 4; MI_Save = 5; MI_Save_As = 6; MI_Page_Setup = 8; MI_Print = 9; MI_Quit = 11; L_Edit = 1003; {Menu list} MI_Undo = 1; MI_Cut = 3; MI_Copy = 4; MI_Paste = 5; L_Extend = 1004;{Menu list} MI_Frequency = 1; MI_Amplitude = 2; MI_Duration = 3; MI_Timbre = 4; I_Yes = 1; I_Cancel = 2; I_No = 3; type DocPtr = ^DocRec; DocRec = record {Sound Doc Structure} Freq, Amp, Dur, Timbre: array[1..100] of integer; EndValue, StartValue: integer; end; MySoundRec = packed record {Snd structure} format: integer; SynthCount: integer; SynthType: integer; SynthInit: longint; CommandCount: integer; MySounds: array[1..202] of SndCommand; end; MySoundPtr = ^MySoundRec; MySoundHdl = ^MySoundPtr; var FreqText, AmpText, DurText, TimbreText: Str255; NoteText, StartText, EndText: Str255; NoteIndex, DrawTool: integer; {Indices} MyDoc: DocPtr; {Sound Document} Dirty: boolean; NoteRect, FreqRect, AmpRect, DurRect, TimbreRect: Rect; EndRect, StartRect, NotePallete: Rect; MyHandle: Handle; {Various Handles} MySoundHandle: MySoundHdl; AppleMenu: MenuHandle; {Menu handle} M_File: MenuHandle; M_Edit: MenuHandle; M_Extend: MenuHandle; MyWindow: WindowPtr; {Window pointer} FileName: str255; {File Stuff} volRefNum, FileStatus: integer; theSquare, theWatch: CursHandle; {Cursor Stuff} ThePrintRec: THPrint; {Printing Stuff} ThePrintPort: TPPrPort; PrintStatus: TPrStatus; PageRect: rect; implementation end.
Listing: MySound.pas unit MySound; interface uses PrintTraps, Sound, MyGlobals; {creates a ‘snd ‘ resource} procedure CreateSndResource (StartSel, EndSel: integer); implementation procedure CreateSndResource; var i, j: integer; amplong, freqlong: longint; lastTimbre: integer; theErr: OSErr; theSize: integer; begin lastTimbre := -1; if Handle(MySoundHandle) <> nil then begin DisposHandle(Handle(MySoundHandle)); DisposHandle(MyHandle); end; MySoundHandle := MySoundHdl(NewHandle(sizeof(MySoundRec))); with MySoundHandle^^ do begin format := 1; {set up header stuff} SynthCount := 1; SynthType := 1; SynthInit := 0; with MyDoc^ do begin j := 0; for i := StartSel to EndSel do begin {get sound commands} j := j + 1; if timbre[i] <> lastTimbre then begin MySounds[j].cmd := timbreCmd; MySounds[j].param1 := timbre[i]; MySounds[j].param2 := 0; lastTimbre := timbre[i]; j := j + 1; end; {of timbre command} if freq[i] = 128 then {is it a rest?} begin MySounds[j].cmd := restCmd; MySounds[j].param1 := dur[i]; MySounds[j].param2 := 0; end else {no, regular note} begin ampLong := amp[i]; ampLong := BitAnd(BitShift(ampLong, 24), $FF000000); freqLong := BitAnd(freq[i], $000000FF); MySounds[j].cmd := noteCmd; MySounds[j].param1 := dur[i]; MySounds[j].param2 := ampLong + freqLong; end; end; {of for loop} end; {with MyDoc} j := j + 1; MySounds[j].cmd := noteCmd; {turn off sound} MySounds[j].param1 := 0; MySounds[j].param2 := 0; j := j + 1; MySounds[j].cmd := quietCmd; MySounds[j].param1 := 0; MySounds[j].param2 := 0; CommandCount := j; end; { of with MySoundHandle} theSize := 12 + (j * 8); MyHandle := Handle(MySoundHandle); theErr := HandToHand(MyHandle); SetHandleSize(MyHandle, Size(theSize)); end; { of CreateSndResource} end.
Listing: InitTheMenus.pas unit InitTheMenus; interface uses PrintTraps, Sound, MyGlobals; procedure Init_My_Menus; {Initialize the menus} implementation procedure Init_My_Menus; {Initialize the menus} const Menu1 = 1001; {Menu resource ID} Menu2 = 1002; {Menu resource ID} Menu3 = 1003; {Menu resource ID} Menu4 = 1004; begin {Start of Init_My_Menus} ClearMenuBar; {Clear any old menu bars} AppleMenu := GetMenu(Menu1); InsertMenu(AppleMenu, 0); AddResMenu(AppleMenu, ‘DRVR’); M_File := GetMenu(Menu2); InsertMenu(M_File, 0); M_Edit := GetMenu(Menu3); InsertMenu(M_Edit, 0); M_Extend := GetMenu(Menu4); InsertMenu(M_Extend, 0); DrawMenuBar; end; {End of procedure Init_My_Menus} end.
Listing: Message.pas unit Message; interface procedure A_Message (s0, s1, s2, s3: str255; var theItem: integer); implementation procedure A_Message; var itemHit: Integer; AlertResHandle: AlertTHndl; tempRect: Rect; begin {Start of alert handler} ParamText(s0, s1, s2, s3); AlertResHandle := AlertTHndl(GetResource(‘ALRT’, 4)); HLock(Handle(AlertResHandle)); tempRect := AlertResHandle^^.boundsRect; tempRect.Left := ((screenBits.Bounds.Right - screenBits.Bounds.Left) - (tempRect.Right - tempRect.Left)) div 2;{Center Horz} tempRect.Bottom := tempRect.Top + (AlertResHandle^^.boundsRect.Bottom - AlertResHandle^^.boundsRect.Top); tempRect.Right := tempRect.Left + (AlertResHandle^^.boundsRect.Right - AlertResHandle^^.boundsRect.Left); AlertResHandle^^.boundsRect := tempRect; theItem := NoteAlert(4, nil); HUnLock(Handle(AlertResHandle)); end; {End of procedure} end. {End of unit}
Listing: save_changes.pas unit save_changes; interface function D_save_changes: integer; implementation const I_Yes = 1; I_Cancel = 2; I_No = 3; I_x = 4; var ExitDialog: boolean; DoubleClick: boolean; MyPt: Point; MyErr: OSErr; function D_save_changes; var GetSelection: DialogPtr; tempRect: Rect; DType: Integer; DItem: Handle; itemHit: Integer; procedure Refresh_Dialog; var rTempRect: Rect; begin SetPort(GetSelection); {Point to our dialog window} GetDItem(GetSelection, I_Yes, DType, DItem, tempRect); PenSize(3, 3); InsetRect(tempRect, -4, -4); FrameRoundRect(tempRect, 16, 16); PenSize(1, 1); end; begin {Start of dialog handler} GetSelection := GetNewDialog(3, nil, Pointer(-1)); ShowWindow(GetSelection); SelectWindow(GetSelection); SetPort(GetSelection); Refresh_Dialog; ExitDialog := FALSE; repeat ModalDialog(nil, itemHit); D_save_changes := itemHit; if (ItemHit = I_Yes) or (ItemHit = I_Cancel) or (ItemHit = I_No) then ExitDialog := TRUE; until ExitDialog; DisposDialog(GetSelection); end; end. {End of unit}
Listing: MyFileStuff.pas unit MyFileStuff; interface uses PrintTraps, Sound, MyGlobals, Message, MySound; procedure doSave; procedure doSaveAs; procedure OpenFile; procedure doOpen; implementation const SFPutLeft = 82; SFPutTop = 50; myType = ‘ZZDC’; myCreator = ‘KCZZ’; var SFPutPt: Point; theReply: SFReply; refNum, resRef: integer; bytes: longint; title: str255; theLength: longint; theErr: OSErr; theItem: integer; oldHandle: Handle; function HandleError (theStr: Str255; theError: OSErr; chk, chksum: integer; CloseIt: boolean): boolean; var STemp: str255; begin if (theError <> noErr) then begin A_Message(theStr, ‘’, ‘’, ‘’, theItem); if CloseIt then begin theErr := FSClose(refNum); theErr := FlushVol(nil, VolRefNum); end; HandleError := true; end else if (chk <> chksum) then begin A_Message(theStr, ‘Checksum Error’, ‘’, ‘’, theItem); if CloseIt then begin theErr := FSClose(refNum); theErr := FlushVol(nil, VolRefNum); end; HandleError := true; end else HandleError := false; end; procedure doSave; begin if VolRefNum = 0 then begin {bad volume reference number} A_Message(‘Bad Volume Number’, ‘’, ‘’, ‘’, theItem); Exit(doSave); end else {good volume reference number} begin theErr := FSOpen(FileName, VolRefNum, refNum); if HandleError(‘Could Not Open File’, theErr, 0, 0, false) then Exit(doSave) else {file was open ok} begin theErr := SetFPos(refNum, FSFromStart, 0); if HandleError(‘Could Not Open File Position’, theErr, 0, 0, true) then Exit(doSave) else {ready to go} begin bytes := sizeof(DocRec); theLength := bytes; theErr := FSWrite(refNum, bytes, ptr(MyDoc)); if HandleError(‘Trouble Writing To File’, theErr, bytes, theLength, true) then Exit(doSave); end; end; {of file open ok} theErr := FSClose(refNum); theErr := FlushVol(nil, VolRefNum); theErr := SetVol(nil, VolRefNum); CreateResFile(FileName); resRef := OpenResFile(FileName); if resRef = -1 then begin {could not be opened} A_Message(‘Could not write sound to’, FileName, ‘’, ‘’, theItem); Exit(doSave); end else {ready to write out sound} begin OldHandle := GetResource(‘snd ‘, 9000); if OldHandle <> nil then begin {existing sound to remove} RmveResource(OldHandle); DisposHandle(OldHandle); UpdateResFile(resRef); end; CreateSndResource(MyDoc^.StartValue, MyDoc^.EndValue); AddResource(MyHandle, ‘snd ‘, 9000, FileName); UpdateResFile(resRef); CloseResFile(resRef); DisposHandle(MyHandle); DisposHandle(Handle(MySoundHandle)); end; end;{ of good vol ref num} end; {of doSave} procedure doSaveAs; begin SetPt(SFPutPt, SFPutLeft, SFPutTop); GetWTitle(MyWindow, title); SFPutFile(SFPutPt, ‘Save Zoundz as ’, title, nil, theReply); if theReply.good then begin theErr := Create(theReply.fname, theReply.vRefNum, myCreator, myType); if theErr <> noErr then {duplicate or problem} begin if theErr = dupFNerr then begin {duplicate} theErr := FSDelete(theReply.fname, theReply.vRefNum); if theErr <> noErr then begin {cannot delete file} A_Message(‘Cannot Delete File.’, ‘’, ‘’, ‘’, theItem); Exit(doSaveAs); end; theErr := Create(theReply.fname, theReply.vRefNum, myCreator, myType); if theErr <> noErr then begin {error in creating after deleting duplicate} A_Message(‘Cannot Create’, theReply.fname, ‘’, ‘’, theItem); Exit(doSaveAs); end; end else { a problem} begin A_Message(‘Cannot Create’, theReply.fname, ‘’, ‘’, theItem); Exit(doSaveAs); end; end {duplicate or problem} else {ready to save} begin VolRefNum := theReply.vRefNum; FileName := theReply.fname; SetWTitle(MyWindow, FileName); theErr := FlushVol(nil, VolRefNum); doSave; end; {ready to save} end; {good reply} end; procedure OpenFile; begin theErr := FSOpen(FileName, VolRefNum, refNum); if HandleError(‘Could Not Open File’, theErr, 0, 0, false) then Exit(OpenFile) else {file was open ok} begin theErr := SetFPos(refNum, FSFromStart, 0); if HandleError(‘Could Not Open File Position’, theErr, 0, 0, true) then begin VolRefNum := 0; Exit(OpenFile); end else {ready to go} begin bytes := sizeof(DocRec); theLength := bytes; theErr := FSRead(refNum, bytes, ptr(MyDoc)); if HandleError(‘Trouble Reading File’, theErr, bytes, theLength, true) then begin VolRefNum := 0; Exit(OpenFile); end; end; end; {of file open ok} theErr := FSClose(refNum); theErr := FlushVol(nil, VolRefNum); MyWindow := nil; NoteText := ‘1’; NumToString(MyDoc^.StartValue, StartText); NumToString(MyDoc^.EndValue, EndText); NumToString(MyDoc^.freq[1], FreqText); NumToString(MyDoc^.amp[1], AmpText); NumToString(MyDoc^.dur[1], DurText); NumToString(MyDoc^.timbre[1], TimbreText); NoteIndex := 1; DrawTool := 1; MySoundHandle := nil; MyHandle := nil; end; procedure doOpen; var theTypes: SFTypeList; begin SetPt(SFPutPt, SFPutLeft, SFPutTop); theTypes[0] := myType; SFGetFile(SFPutPt, ‘Open Zoundz file ’, nil, 1, theTypes, nil, theReply); VolRefNum := 0; if theReply.good then begin VolRefNum := theReply.vRefNum; FileName := theReply.fName; OpenFile; end; end; end.
Listing: MyPrintStuff.pas unit MyPrintStuff; interface uses PrintTraps, Sound, MyGlobals, MySound, Message; procedure doSetUp; procedure doPrint; implementation var theItem: integer; procedure doSetUp; var confirmed: boolean; begin PrOpen; InitCursor; confirmed := PrValidate(ThePrintRec); confirmed := PrStlDialog(ThePrintRec); if PrError <> noErr then A_Message(‘Problem with style dialog’, ‘’, ‘’, ‘’, theItem) else PageRect := ThePrintRec^^.prInfo.rpage; PrClose; end; procedure PrintIt; var leftEdge, lineTop, lineBottom, lineSize: integer; title: str255; i: integer; procedure NumToHexString (n: longint; var s: str255); var d, i: integer; begin s := ‘’; i := 32; while i > 0 do begin d := BitAnd(n, 15); n := BitShift(n, -4); i := i - 4; if d < 10 then s := concat(chr(ord(‘0’) + d), s) else s := concat(chr(ord(‘A’) + d - 10), s); end; end; procedure LineFeed; begin lineTop := lineTop + lineSize; lineBottom := lineBottom + lineSize; MoveTo(leftEdge, lineBottom); end; procedure PrintHeader; var s1: str255; begin s1 := ‘Snd name is “‘; s1 := concat(s1, title, ‘“‘); MoveTo(leftEdge, lineBottom); TextFace([bold]); DrawString(s1); TextFace([]); LineFeed; LineFeed; end; procedure PrintFirstPart; var s1, s2: str255; num: longint; begin num := MySoundHandle^^.format; s1 := ‘Snd Format = ‘; NumToString(num, s2); s1 := concat(s1, s2); DrawString(s1); LineFeed; num := MySoundHandle^^.SynthCount; s1 := ‘Synthizers = ‘; NumToString(num, s2); s1 := concat(s1, s2); DrawString(s1); LineFeed; num := MySoundHandle^^.SynthType; s1 := ‘Snd Format = ‘; NumToString(num, s2); s1 := concat(s1, s2, ‘ (noteSynth)’); DrawString(s1); LineFeed; num := MySoundHandle^^.SynthInit; s1 := ‘Snd Initialization = ‘; NumToHexString(num, s2); s1 := concat(s1, ‘$’, s2); DrawString(s1); LineFeed; num := MySoundHandle^^.CommandCount; s1 := ‘Number of Sound Commands = ‘; NumToString(num, s2); s1 := concat(s1, s2); DrawString(s1); LineFeed; DrawString(‘ # cmd param1 param2 Description’); MoveTo(leftEdge, lineBottom + 2); LineTo(PageRect.right, lineBottom + 2); MoveTo(leftEdge, lineBottom); LineFeed; end; procedure PrintNote (i: integer); var s1, s2, s3: str255; num: longint; c, p1: integer; p2: longint; begin c := MySoundHandle^^.MySounds[i].cmd; p1 := MySoundHandle^^.MySounds[i].param1; p2 := MySoundHandle^^.MySounds[i].param2; num := i; {put index number} NumToString(num, s1); if i < 10 then s1 := concat(‘ ’, s1); if i < 100 then s1 := concat(‘ ’, s1); s1 := concat(s1, ‘ ’); NumToString(c, s2); if c < 10 then s2 := concat(‘ ’, s2); s1 := concat(s1, s2, ‘ $’); NumToHexString(p1, s2); NumToHexString(p2, s3); s1 := concat(s1, s2, ‘ $’, s3, ‘ ’); case c of quietCmd: begin s1 := concat(s1, ‘quietCmd - The End’); end; timbreCmd: begin s1 := concat(s1, ‘timbreCmd - Value ’); NumToString(p1, s2); s1 := concat(s1, s2); end; restCmd: begin s1 := concat(s1, ‘restCmd - Rest ’); NumToString(p1, s2); s1 := concat(s1, s2, ‘ milliseconds’); end; noteCmd: begin s1 := concat(s1, ‘noteCmd - Note ’); num := BitAnd(p2, $FF); NumToString(num, s2); s1 := concat(s1, s2, ‘, Amp. ’); num := BitAnd(BitShift(p2, -24), $FF); NumToString(num, s2); s1 := concat(s1, s2, ‘, Duration ’); NumToString(p1, s2); s1 := concat(s1, s2, ‘ milliseconds’); end; otherwise begin s1 := concat(s1, ‘Unknown sound command’); end; end; DrawString(s1); end; begin {set up position} PenNormal; TextFont(monaco); TextFace([]); TextSize(9); lineTop := PageRect.top; lineSize := 12; lineBottom := lineTop + lineSize; leftEdge := 30; GetWTitle(MyWindow, title); PrOpenPage(ThePrintPort, nil); {open page} PrintHeader; {print header} PrintFirstPart; {print first part} for i := 1 to MySoundHandle^^.CommandCount do begin if lineBottom > PageRect.bottom then begin {if position is too great} PrClosePage(ThePrintPort);{close page} PrOpenPage(ThePrintPort, nil); {open page} lineTop := PageRect.top; lineBottom := lineTop + lineSize; PrintHeader; {print header} DrawString(‘ # cmd param1 param2 Description’); MoveTo(leftEdge, lineBottom + 2); LineTo(PageRect.right, lineBottom + 2); MoveTo(leftEdge, lineBottom); LineFeed; end; PrintNote(i);{print note} LineFeed; end; PrClosePage(ThePrintPort);{close page} end; procedure doPrint; var DoIt: boolean; myPrPort: TPPrPort; savePort: GrafPtr; copies, count: integer; begin GetPort(savePort); SetCursor(arrow); PrOpen; if PrError = noErr then begin DoIt := PrValidate(ThePrintRec); DoIt := PrJobDialog(ThePrintRec); if PrError <> noErr then A_Message(‘Problem with job dialog’, ‘’, ‘’, ‘’, theItem); if DoIt then begin {print document} SetCursor(theWatch^^); ThePrintPort := PrOpenDoc(ThePrintRec, nil, nil); if PrError = noErr then begin {ok port} CreateSndResource(MyDoc^.StartValue, MyDoc^.EndValue); copies := ThePrintRec^^.prJob.iCopies; PageRect := ThePrintRec^^.prInfo.rpage; for count := 1 to copies do begin {copies loop} PrintIt; {print the document} end; {copies loop} DisposHandle(MyHandle); DisposHandle(Handle(MySoundHandle)); MyHandle := nil; MySoundHandle := nil; end else {bad port} A_Message(‘Open Document Error’, ‘’, ‘’, ‘’, theItem); PrCloseDoc(ThePrintPort); if (ThePrintRec^^.prJob.bJDocLoop = bSpoolLoop) and (PrError = noErr) then PrPicFile(ThePrintRec, nil, nil, nil, PrintStatus); end; {printing document} end; PrClose; SetPort(savePort); SetCursor(arrow) end; end.
Listing: About.pas unit About; interface procedure D_About; implementation const I_OK = 1; I_x = 2; I_x3 = 3; var ExitDialog: boolean; DoubleClick: boolean; MyPt: Point; MyErr: OSErr; procedure D_About; var GetSelection: DialogPtr; tempRect: Rect; DType: Integer; DItem: Handle; itemHit: Integer; procedure Refresh_Dialog; var rTempRect: Rect; begin SetPort(GetSelection); GetDItem(GetSelection, I_OK, DType, DItem, tempRect); PenSize(3, 3); InsetRect(tempRect, -4, -4); FrameRoundRect(tempRect, 16, 16); PenSize(1, 1); end; begin GetSelection := GetNewDialog(2, nil, Pointer(-1)); tempRect := GetSelection^.portRect; tempRect.Top := ((screenBits.Bounds.Bottom - screenBits.Bounds.Top) - (tempRect.Bottom - tempRect.Top)) div 2; tempRect.Left := ((screenBits.Bounds.Right - screenBits.Bounds.Left) - (tempRect.Right - tempRect.Left)) div 2; MoveWindow(GetSelection, tempRect.Left, tempRect.Top, TRUE); ShowWindow(GetSelection); SelectWindow(GetSelection); SetPort(GetSelection); Refresh_Dialog; ExitDialog := FALSE; repeat ModalDialog(nil, itemHit); GetDItem(GetSelection, itemHit, DType, DItem, tempRect); if (ItemHit = I_OK) then begin ExitDialog := TRUE; end; until ExitDialog; DisposDialog(GetSelection); end; end. {End of unit}
Listing: Untitled.pas unit Untitled; interface uses PrintTraps, Sound, MyGlobals, MySound; {Initialize us so all our routines can be activated} procedure Init_Untitled; {Close our window} procedure Close_Untitled (whichWindow: WindowPtr); {Open our window and draw everything} procedure Open_Untitled; {Update our window, someone uncovered a part of us} procedure Update_Untitled (whichWindow: WindowPtr); {Handle action to our window, like controls} procedure Do_Untitled (myEvent: EventRecord); implementation const B_Play_Sound = 26; {Button ID} CB_Timbre = 16; {Checkbox IDs} CB_Duration = 15; CB_Amplitude = 14; CB_Frequency = 13; RB_Timbre = 20; {Radio IDs} RB_Duration = 19; RB_Amplitude = 18; RB_Frequency = 17; I_DurationScrollbar = 41; {Scroll bar IDs} I_AmplitudeScrollbar = 40; I_FrequencyScrollbar = 39; I_TimbreScrollbar = 38; I_EndScrollbar = 31; I_StartScrollbar = 27; I_NoteScrollbar = 12; var tempRect: Rect; {Temporary rectangle} sTemp: Str255; {Get text entered, temp holding} C_EndScrollbar: ControlHandle; C_StartScrollbar: ControlHandle; C_NoteScrollbar: ControlHandle; R1Control: array[1..4] of ControlHandle; C_Play_Sound: ControlHandle; C_Timbre: ControlHandle; C_Duration: ControlHandle; C_Amplitude: ControlHandle; C_Frequency: ControlHandle; C_DurationScrollbar: ControlHandle; C_AmplitudeScrollbar: ControlHandle; C_FrequencyScrollbar: ControlHandle; C_TimbreScrollbar: ControlHandle; {=================================} {Initialize us so all our routines can be activated} procedure Init_Untitled; var i: integer; begin {Start of Window initialize routine} MyWindow := nil; NoteText := ‘1’; {Init Texts} StartText := ‘1’; EndText := ‘1’; FreqText := ‘0’; AmpText := ‘0’; DurText := ‘0’; TimbreText := ‘0’; NoteIndex := 1; {Init Miscellaneous} DrawTool := 1; MyDoc^.EndValue := 1; MyDoc^.StartValue := 1; MySoundHandle := nil; MyHandle := nil; volRefNum := 0; for i := 1 to 100 do {initialize arrays} begin MyDoc^.freq[i] := 0; MyDoc^.amp[i] := 0; MyDoc^.dur[i] := 0; MyDoc^.timbre[i] := 0; end; end; {End of Init_Untitled} {=================================} {Close our window} procedure Close_Untitled; begin if (MyWindow <> nil) and ((MyWindow = whichWindow) or (ord4(whichWindow) = -1)) then begin DisposeWindow(MyWindow); MyWindow := nil; end; end; {End of Close_Untitled} {=================================} {draws a square according to the pattern} procedure DrawSquare (vert, horiz: integer; thePat: pattern); var theSquare: rect; begin SetRect(theSquare, horiz, vert, horiz + 10, vert + 10); InSetRect(theSquare, 1, 1); PenNormal; FillRect(theSquare, thePat); FrameRect(theSquare); end; {of DrawSquare} {=================================} {Takes a point and returns vertical and horizontal values} procedure Unconvert (thePoint: Point; range: integer; var value, column: integer); var Lvalue, Lrange: longint; begin if thePoint.h < 5 then {out of range} column := -1 else {get column} column := (thePoint.h - 5) div 10; if column > 22 then {out of range} column := -1; if (thePoint.v < 5) or (thePoint.v > 260) then value := -1 {out of range} else begin {get value} Lvalue := thePoint.v - 5; Lrange := range; Lvalue := Lvalue * Lrange; value := LValue div 255; end; end; {of unconvert} {=================================} {returns vertical position} function Convert (value, range: integer): integer; var Lvalue, Lrange: longint; begin Lvalue := value; LRange := range; Convert := ((Lvalue * 245) div Lrange) + 5; end; {of Convert} {=================================} {Update our window, someone uncovered a part of us} procedure UpDate_Untitled; var SavePort: WindowPtr; {Place to save the last port} theValue, theTop, i, rangeStop, RangeStart: integer; begin if (MyWindow <> nil) and (MyWindow = whichWindow) then begin GetPort(SavePort); {Save the current port} SetPort(MyWindow); {Set the port to my window} TextFont(systemFont);{Set the font to draw in} { Draw DrawGraph Stuff} SetRect(TempRect, 245, 20, 355, 105); FrameRect(TempRect);{Frame this rectangle area} SetRect(tempRect, 265, 5, 345, 20); sTemp := ‘Draw Graph’; TextBox(Pointer(ord(@sTemp) + 1), length(sTemp), tempRect, teJustLeft); SetRect(tempRect, 248, 28, 258, 38); FillRect(tempRect, black); FrameRect(tempRect); SetRect(tempRect, 248, 48, 258, 58); FillRect(tempRect, dkgray); FrameRect(tempRect); SetRect(tempRect, 248, 68, 258, 78); FillRect(tempRect, gray); FrameRect(tempRect); SetRect(tempRect, 248, 88, 258, 98); FillRect(tempRect, ltgray); FrameRect(tempRect); FrameRect(tempRect); TextBox(Pointer(ord(@FreqText) + 1), length(FreqText), FreqRect, teJustLeft); TextBox(Pointer(ord(@AmpText) + 1), length(AmpText), AmpRect, teJustLeft); TextBox(Pointer(ord(@DurText) + 1), length(DurText), DurRect, teJustLeft); TextBox(Pointer(ord(@TimbreText) + 1), length(TimbreText), TimbreRect, teJustLeft); { Draw a rectangle, ViewGraphRect } SetRect(TempRect, 390, 190, 490, 275);{left,top,right,bottom} FrameRect(TempRect);{Frame this rectangle area} SetRect(tempRect, 400, 175, 475, 190); sTemp := ‘View Graph’; TextBox(Pointer(ord(@sTemp) + 1), length(sTemp), tempRect, teJustLeft); { Draw a rectangle, NotePallete } PenPat(white); PaintRect(NotePallete); PenNormal; FrameRect(NotePallete);{Frame this rectangle area} RangeStart := GetCtlValue(C_NoteScrollbar); RangeStop := RangeStart + 22; if RangeStop > 100 then RangeStop := 100; for i := RangeStart to RangeStop do begin if GetCtlValue(C_Timbre) = 1 then begin theValue := MyDoc^.timbre[i]; theTop := Convert(theValue, 254); DrawSquare(theTop, (i - RangeStart) * 10 + 5, ltgray); end; if GetCtlValue(C_Duration) = 1 then begin theValue := MyDoc^.dur[i]; theTop := Convert(theValue, 250); DrawSquare(theTop, (i - RangeStart) * 10 + 5, gray); end; if GetCtlValue(C_Amplitude) = 1 then begin theValue := MyDoc^.amp[i]; theTop := Convert(theValue, 255); DrawSquare(theTop, (i - RangeStart) * 10 + 5, dkgray); end; if GetCtlValue(C_Frequency) = 1 then begin theValue := MyDoc^.freq[i]; theTop := Convert(theValue, 128); DrawSquare(theTop, (i - RangeStart) * 10 + 5, black); end; end; {Music Selection Stuff} SetRect(tempRect, 255, 175, 365, 190); sTemp := ‘Music Selection’; TextBox(Pointer(ord(@sTemp) + 1), length(sTemp), tempRect, teJustLeft); SetRect(TempRect, 245, 190, 375, 275); FrameRect(TempRect);{Frame this rectangle area} TextBox(Pointer(ord(@EndText) + 1), length(EndText), EndRect, teJustLeft); TextBox(Pointer(ord(@StartText) + 1), length(StartText), StartRect, teJustLeft); SetRect(tempRect, 250, 235, 280, 250); sTemp := ‘End:’; TextBox(Pointer(ord(@sTemp) + 1), length(sTemp), tempRect, teJustLeft); SetRect(tempRect, 250, 195, 290, 210); sTemp := ‘Start:’; TextBox(Pointer(ord(@sTemp) + 1), length(sTemp), tempRect, teJustLeft); {Draw NoteIndex} SetRect(tempRect, 370, 5, 410, 20); sTemp := ‘Note:’; TextBox(Pointer(ord(@sTemp) + 1), length(sTemp), tempRect, teJustLeft); TextBox(Pointer(ord(@NoteText) + 1), length(NoteText), NoteRect, teJustLeft); TextFont(applFont);{Set the default application font} DrawControls(MyWindow);{Draw all the controls} SetPort(SavePort); {Restore the old port} end; {End for if (MyWindow<>nil)} end; {End of Update_Untitled} {=================================} {Open our window and draw everything} procedure Open_Untitled; begin if (MyWindow = nil) then begin MyWindow := GetNewWindow(1, nil, Pointer(-1)); SetPort(MyWindow); { Make a button, Play Sound } C_Play_Sound := GetNewControl(B_Play_Sound, MyWindow); { Make a checkboxes } C_Timbre := GetNewControl(CB_Timbre, MyWindow); C_Duration := GetNewControl(CB_Duration, MyWindow); C_Amplitude := GetNewControl(CB_Amplitude, MyWindow); C_Frequency := GetNewControl(CB_Frequency, MyWindow); { Make a radio buttons } R1Control[4] := GetNewControl(RB_Timbre, MyWindow); R1Control[3] := GetNewControl(RB_Duration, MyWindow); R1Control[2] := GetNewControl(RB_Amplitude, MyWindow); R1Control[1] := GetNewControl(RB_Frequency, MyWindow); { Make a scroll bars } C_DurationScrollbar := GetNewControl(I_DurationScrollbar, MyWindow); SetCtlValue(C_DurationScrollbar, MyDoc^.dur[NoteIndex]); C_AmplitudeScrollbar := GetNewControl(I_AmplitudeScrollbar, MyWindow); SetCtlValue(C_AmplitudeScrollbar, MyDoc^.amp[NoteIndex]); C_FrequencyScrollbar := GetNewControl(I_FrequencyScrollbar, MyWindow); SetCtlValue(C_FrequencyScrollbar, MyDoc^.freq[NoteIndex]); C_TimbreScrollbar := GetNewControl(I_TimbreScrollbar, MyWindow); SetCtlValue(C_TimbreScrollbar, MyDoc^.timbre[NoteIndex]); C_EndScrollbar := GetNewControl(I_EndScrollbar, MyWindow); C_StartScrollbar := GetNewControl(I_StartScrollbar, MyWindow); SetCtlValue(C_EndScrollbar, MyDoc^.EndValue); SetCtlValue(C_StartScrollbar, MyDoc^.StartValue); C_NoteScrollbar := GetNewControl(I_NoteScrollbar, MyWindow); ShowWindow(MyWindow); SelectWindow(MyWindow); end else SelectWindow(MyWindow); end; {End of Open_Untitled} {=================================} {Handle action to our window, like controls} procedure Do_Untitled; var RefCon: longint; code: integer; theValue: integer; whichWindow: WindowPtr; myPt: Point; theControl: ControlHandle; MyErr: OSErr; tempRect: rect; newValue, NewPosition: integer; procedure Do_A_Button; begin HiliteControl(theControl, 10); RefCon := GetCRefCon(theControl); case RefCon of {Select correct button} B_Play_Sound:{Play Sound, button} begin {start for this button} CreateSndResource(GetCtlValue(C_StartScrollbar), GetCtlValue(C_EndScrollbar)); MyErr := SndPlay(nil, MyHandle, false); DisposHandle(MyHandle); DisposHandle(Handle(MySoundHandle)); MyHandle := nil; MySoundHandle := nil; end; {end for this button} otherwise begin {start} end; {end of otherwise} end; {end of case} HiliteControl(theControl, 0);{Lighten the button} end; {Handle a button being pressed} procedure Do_A_Checkbox; var Index: integer; {Index used for radios} procedure Clear1RadioGroup; var Index: integer; {Index used for radios} begin {Start of the clear routine} for Index := 1 to 4 do {Step thru all radios} SetCtlValue(R1Control[Index], 0); end; {End of the clear routine} begin {Handle a checkbox being pressed} RefCon := GetCRefCon(theControl); theValue := GetCtlValue(theControl); theValue := (theValue + 1) mod 2; InvalRect(NotePallete); case RefCon of CB_Timbre, CB_Duration, CB_Amplitude, CB_Frequency: begin SetCtlValue(theControl, theValue); end; {end for this checkbox} RB_Timbre: {Timbre , radio button} begin {start for this radio button} DrawTool := 4; Clear1RadioGroup; SetCtlValue(theControl, 1);{Select this Radio} SetCtlValue(C_Timbre, 1); end; RB_Duration:{Duration , radio button} begin {start for this radio button} DrawTool := 3; Clear1RadioGroup;{Clear Radio values} SetCtlValue(theControl, 1);{Select this Radio} SetCtlValue(C_Duration, 1); end; RB_Amplitude:{Amplitude , radio button} begin {start for this radio button} DrawTool := 2; Clear1RadioGroup; SetCtlValue(theControl, 1);{Select this Radio} SetCtlValue(C_Amplitude, 1); end; RB_Frequency:{Frequency , radio button} begin {start for this radio button} DrawTool := 1; Clear1RadioGroup; SetCtlValue(theControl, 1);{Select this Radio} SetCtlValue(C_Frequency, 1); end; otherwise begin end; end; {end of case} end; {Handle a checkbox being pressed} procedure Do_A_ScrollBar (code: integer); procedure HandleWScrollBar (code, Start, Stop, Increment, LIncrement: integer; theControl: ControlHandle); var theValue: integer;{Value of the scrollbar} MaxTick: longint; {Timer for repeat scrolling} FirstTime: boolean; {Flag to start scrolling} begin FirstTime := TRUE; while (StillDown or FirstTime) do begin {Timer used for repeat scrolling} FirstTime := FALSE; HiliteControl(theControl, code); theValue := GetCtlValue(theControl); if (code = inUpButton) then begin theValue := theValue - Increment; if (theValue < Start) then theValue := Start; end; if (code = inDownButton) then begin theValue := theValue + Increment; if (theValue > Stop) then theValue := Stop;{Bump at the stop value} end; if (code = inPageUp) then begin theValue := theValue - LIncrement; if (theValue < Start) then theValue := Start; end; if (code = inPageDown) then begin theValue := theValue + LIncrement; if (theValue > Stop) then theValue := Stop;{Bump at the Stop value} end; if (code = inThumb) then begin code := TrackControl(theControl, myPt, nil);{Let the OS drag it around} theValue := GetCtlValue(theControl); end; SetCtlValue(theControl, theValue);{Set new state} MaxTick := TickCount + 9; repeat {Start of delay routine} until not (Button) or (TickCount > MaxTick);{Exit when time up or mouse button up} HiliteControl(theControl, 0);{Lighten the arrow} end; {End for StillDown} end;{End of handle scroll bar} begin {Handle a ScrollBar being pressed} RefCon := GetCRefCon(theControl);{get control refcon} TempRect := NotePallete; TempRect.left := 6; TempRect.right := TempRect.left + 8; case RefCon of {Select correct scrollbar} I_DurationScrollbar:{DurationScrollbar, scroll bar} begin dirty := true; HandleWScrollBar(code, 0, 250, 1, 10, theControl); theValue := GetCtlValue(theControl); MyDoc^.dur[NoteIndex] := theValue; NumToString(theValue, DurText); InvalRect(DurRect); end; I_AmplitudeScrollbar:{AmplitudeScrollbar, scroll bar} begin dirty := true; HandleWScrollBar(code, 0, 255, 1, 10, theControl); theValue := GetCtlValue(theControl); MyDoc^.amp[NoteIndex] := theValue; NumToString(theValue, AmpText); InvalRect(AmpRect); end; I_FrequencyScrollbar:{FrequencyScrollbar, scroll bar} begin dirty := true; HandleWScrollBar(code, 0, 128, 1, 10, theControl); theValue := GetCtlValue(theControl); MyDoc^.freq[NoteIndex] := theValue; if theValue < 128 then NumToString(theValue, FreqText) else FreqText := ‘Rest’; InvalRect(FreqRect); end; I_TimbreScrollbar:{TimbreScrollbar, scroll bar} begin dirty := true; HandleWScrollBar(code, 0, 254, 1, 10, theControl); theValue := GetCtlValue(theControl); MyDoc^.timbre[NoteIndex] := theValue; NumToString(theValue, TimbreText); InvalRect(TimbreRect); end; I_EndScrollbar:{EndScrollbar, scroll bar} begin dirty := true; HandleWScrollBar(code, GetCtlValue(C_StartScrollbar), 100, 1, 10, theControl); theValue := GetCtlValue(theControl); MyDoc^.EndValue := theValue; NumToString(theValue, EndText); TempRect := EndRect; end; I_StartScrollbar:{StartScrollbar, scroll bar} begin {start for this scroll bar} dirty := true; HandleWScrollBar(code, 1, 100, 1, 10, theControl); theValue := GetCtlValue(theControl); MyDoc^.StartValue := theValue; NumToString(theValue, StartText); InvalRect(StartRect); SetCtlMin(C_EndScrollbar, theValue); theValue := GetCtlValue(C_EndScrollbar); MyDoc^.EndValue := theValue; NumToString(theValue, EndText); TempRect := EndRect; end; I_NoteScrollbar:{NoteScrollbar, scroll bar} begin HandleWScrollBar(code, 1, 100, 1, 10, theControl); theValue := GetCtlValue(theControl); NoteIndex := theValue; NumToString(theValue, NoteText); InvalRect(NoteRect); SetCtlValue(C_DurationScrollbar, MyDoc^.dur[NoteIndex]); SetCtlValue(C_FrequencyScrollbar, MyDoc^.freq[NoteIndex]); SetCtlValue(C_AmplitudeScrollbar, MyDoc^.amp[NoteIndex]); SetCtlValue(C_TimbreScrollbar, MyDoc^.timbre[NoteIndex]); NumToString(MyDoc^.timbre[NoteIndex], TimbreText); NumToString(MyDoc^.dur[NoteIndex], durText); NumToString(MyDoc^.amp[NoteIndex], ampText); if MyDoc^.freq[NoteIndex] < 128 then NumToString(MyDoc^.freq[NoteIndex], FreqText) else FreqText := ‘Rest’; InvalRect(durRect); InvalRect(freqRect); InvalRect(ampRect); InvalRect(timbreRect); TempRect := NotePallete; InsetRect(TempRect, 1, 1); end; {end for this scroll bar} otherwise begin end; end; {end of case} InvalRect(TempRect); end; {Handle a ScrollBar being pressed} begin {Start of Window handler} if (MyWindow <> nil) then begin code := FindWindow(myEvent.where, whichWindow); if (myEvent.what = MouseDown) and (MyWindow = whichWindow) then begin myPt := myEvent.where;{Get mouse position} GlobalToLocal(myPt); end; if (MyWindow = whichWindow) and (code = inContent) then begin code := FindControl(myPt, whichWindow, theControl); if (code = inUpButton) or (code = inDownButton) or (code = inThumb) or (code = inPageDown) or (code = inPageUp) then Do_A_ScrollBar(code);{Do scrollbars} if (code <> 0) then{Check type of control} code := TrackControl(theControl, myPt, nil);{Track the control} if code = inButton then Do_A_Button;{Do buttons} if code = inCheckBox then Do_A_Checkbox;{Do checkboxes} if PtInRect(myPt, NotePallete) then repeat dirty := true; case DrawTool of 1: UnConvert(myPt, 128, newValue, NewPosition); 2: UnConvert(myPt, 255, newValue, NewPosition); 3: UnConvert(myPt, 250, newValue, NewPosition); 4: UnConvert(myPt, 254, newValue, NewPosition); end; if (newValue <> -1) and (newPosition <> -1) then begin {still in NotePallete?} case DrawTool of 1: begin MyDoc^.freq[GetCtlValue(C_NoteScrollbar) + NewPosition] := newValue; if NewPosition = 0 then begin SetCtlValue(C_FrequencyScrollbar, newValue); if newValue <> 128 then NumToString(newValue, FreqText) else FreqText := ‘Rest’; InvalRect(FreqRect); end; end; 2: begin MyDoc^.amp[GetCtlValue(C_NoteScrollbar) + NewPosition] := newValue; if NewPosition = 0 then begin SetCtlValue(C_AmplitudeScrollbar, newValue); NumToString(newValue, AmpText); InvalRect(AmpRect); end; end; 3: begin MyDoc^.dur[GetCtlValue(C_NoteScrollbar) + NewPosition] := newValue; if NewPosition = 0 then begin SetCtlValue(C_DurationScrollbar, newValue); NumToString(newValue, DurText); InvalRect(DurRect); end; end; 4: begin MyDoc^.timbre[GetCtlValue(C_NoteScrollbar) + NewPosition] := newValue; if NewPosition = 0 then begin SetCtlValue(C_TimbreScrollbar, newValue); NumToString(newValue, TimbreText); InvalRect(TimbreRect); end; end; end; { of Case} SetRect(TempRect, (NewPosition * 10 + 6), 6, (NewPosition * 10 + 5) + 9, 259); InvalRect(TempRect); end; {end of still in NotePallete} BeginUpdate(MyWindow); Update_Untitled(MyWindow); EndUpdate(MyWindow); GetMouse(myPt); until not (StillDown); end; {End for if (MyWindow=whichWindow)} end; {End for if (MyWindow<>nil)} end; {End of procedure} end. {End of unit}
Listing: HandleTheMenus.pas unit HandleTheMenus; interface uses PrintTraps, Message, save_changes, About, Untitled, Sound, MyGlobals, MyFileStuff, MyPrintStuff; procedure AdjustMenus; procedure Handle_My_Menu (var doneFlag: boolean; theMenu, theItem: integer);{Handle menu selection} implementation procedure AdjustMenus; begin if (FrontWindow <> MyWindow) then begin {Something up there} DisableItem(M_Extend, 0); EnableItem(M_Edit, 0); DisableItem(M_File, MI_Open); DisableItem(M_File, MI_New); DisableItem(M_File, MI_Close); DisableItem(M_File, MI_Save); DisableItem(M_File, MI_Save_As); DisableItem(M_File, MI_Page_Setup); DisableItem(M_File, MI_Print); end else if MyWindow <> nil then begin {My Window up there} EnableItem(M_Extend, 0); DisableItem(M_Edit, 0); DisableItem(M_File, MI_Open); DisableItem(M_File, MI_New); EnableItem(M_File, MI_Close); EnableItem(M_File, MI_Save); EnableItem(M_File, MI_Save_As); EnableItem(M_File, MI_Page_Setup); EnableItem(M_File, MI_Print); end else begin {nothing up there} VolRefNum := 0; {no need to save any changes} DisableItem(M_Extend, 0); DisableItem(M_Edit, 0); EnableItem(M_File, MI_Open); EnableItem(M_File, MI_New); DisableItem(M_File, MI_Close); DisableItem(M_File, MI_Save); DisableItem(M_File, MI_Save_As); DisableItem(M_File, MI_Page_Setup); DisableItem(M_File, MI_Print); end; end; procedure Handle_My_Menu; var DNA: integer; BoolHolder: boolean; DAName, title: Str255; SavePort: GrafPtr; i, theValue: integer; begin {Start of procedure} case theMenu of {Do selected menu list} L_Apple: begin case theItem of MI_About_Zoundz: begin D_About; end; otherwise{Handle the DAs} begin GetPort(SavePort); GetItem(AppleMenu, theItem, DAName); DNA := OpenDeskAcc(DAName); SetPort(SavePort); end; end; {End of item case} end; {End for Apple Menu list} L_File: begin case theItem of MI_New: begin Init_Untitled; Open_Untitled; dirty := false; end; MI_Open: begin doOpen; if VolRefNum <> 0 then begin Open_Untitled; SetWTitle(MyWindow, FileName); dirty := false; end; end; MI_Close: begin if dirty then begin {need saving} GetWTitle(MyWindow, title); ParamText(title, ‘’, ‘’, ‘’); theValue := D_save_changes; if (theValue = I_Yes) then begin {wants to save changes} if VolRefNum = 0 then doSaveAs else doSave; if VolRefNum <> 0 then Close_Untitled(MyWindow); end else if theValue = I_No then Close_Untitled(MyWindow); end {of needing saved} else {no need to save} Close_Untitled(MyWindow); end; MI_Save: begin if VolRefNum = 0 then doSaveAs else doSave; if VolRefNum <> 0 then dirty := false; end; MI_Save_As: begin doSaveAs; if VolRefNum <> 0 then dirty := false; end; MI_Page_Setup: begin doSetUp; end; MI_Print: begin doPrint; end; MI_Quit: begin if (MyWindow <> nil) and dirty then begin {need saving} GetWTitle(MyWindow, title); ParamText(title, ‘’, ‘’, ‘’); theValue := D_save_changes; case theValue of I_Yes: begin if VolRefNum = 0 then doSaveAs else doSave; if VolRefNum <> 0 then doneFlag := TRUE; end; {of Yes} I_No: doneFlag := True; otherwise ; end; {of case} end {of needing saved} else {no need to save} doneFlag := TRUE; end; otherwise ; end; {of item list} end; {of File Menu List } L_Edit: begin BoolHolder := SystemEdit(theItem - 1); {DA Editing} end; L_Extend: begin case theItem of{Handle extending values} MI_Frequency: begin theValue := MyDoc^.freq[NoteIndex]; for i := MyDoc^.StartValue to MyDoc^.EndValue do MyDoc^.freq[i] := theValue; end; {of Frequency} MI_Amplitude: begin theValue := MyDoc^.amp[NoteIndex]; for i := MyDoc^.StartValue to MyDoc^.EndValue do MyDoc^.amp[i] := theValue; end; {of Amplitude} MI_Duration: begin theValue := MyDoc^.dur[NoteIndex]; for i := MyDoc^.StartValue to MyDoc^.EndValue do MyDoc^.dur[i] := theValue; end; {of duration} MI_Timbre: begin theValue := MyDoc^.timbre[NoteIndex]; for i := MyDoc^.StartValue to MyDoc^.EndValue do MyDoc^.timbre[i] := theValue; end; {of timbre} otherwise ; end; { of items in Extend Menu} InvalRect(NotePallete); end; {of Extend Menu List} otherwise ; end; {End for the Menus} HiliteMenu(0); {Turn menu selection off} end; {End of procedure Handle_My_Menu} end. {End of unit}
Listing: Zoundz.pas program Zoundz; {Program name: Zoundz.Pas } {Function: Allows creation of ‘snd ‘ resource ID=9000. } {History: 4/17/89 Original by Prototyper. } {Modified: 5/1/89 by Kirk Chase} uses PrintTraps, Message, save_changes, About, Untitled, InitTheMenus, HandleTheMenus, Sound, MyGlobals, MyFileStuff, MyPrintStuff; const WNETrapNum = $60; UnImplTrapNum = $9F; MultiEvt = 15; bit0 = 31; GrayRgnLowMemGlobal = $9EE; var {Main variables} myEvent: EventRecord; ResumePeek: WindowPeek; theWorld: SysEnvRec; doneFlag, DoIt, WNE, sysResult: boolean; code, theValue: integer; whichWindow: WindowPtr; dragRect: Rect; mResult: longint; theMenu, theItem: integer; chCode: integer; ch: char; myPt: Point; title: str255; nDocs, message, index, sleep: integer; theFile: AppFile; theErr: OSErr; procedure InitMac; {initializes Macintosh} begin MoreMasters; {This reserves space for more handles} InitGraf(@thePort); {Quickdraw Init} InitFonts; {Font manager init} InitWindows; {Window manager init} InitMenus; {Menu manager init} TEInit; {Text edit init} InitDialogs(nil); {Dialog manager} FlushEvents(everyEvent, 0);{Clear out all events} InitCursor; {Make an arrow cursor} end; procedure InitApp; {initialize application} var tempHandle: handle; begin doneFlag := FALSE; {Do not exit program yet} Init_My_Menus; {Initialize menu bar} MyDoc := DocPtr(NewPtr(sizeof(DocRec))); {get doc} ThePrintRec := nil; {print initialization} PrOpen; tempHandle := NewHandle(sizeof(TPrint)); ThePrintRec := THPrint(tempHandle); PrintDefault(ThePrintRec); PageRect := ThePrintRec^^.prInfo.rpage; PrClose; dragRect := screenbits.bounds;{Get drag area} SetRect(dragRect, dragRect.Left + 10, dragRect.Top + 25, dragRect.Right - 10, dragRect.Bottom - 10); SetRect(NotePallete, 5, 5, 235, 260);{set rectangles} SetRect(EndRect, 345, 235, 370, 250); SetRect(StartRect, 345, 195, 370, 210); SetRect(TimbreRect, 465, 85, 490, 100); SetRect(DurRect, 465, 65, 490, 80); SetRect(AmpRect, 465, 45, 490, 60); SetRect(FreqRect, 465, 25, 500, 40); SetRect(NoteRect, 420, 5, 445, 20); Dirty := false; theWatch := GetCursor(watchCursor); HLock(Handle(theWatch)); theSquare := GetCursor(crossCursor); HLock(Handle(theSquare)); theErr := SysEnvirons(1, theWorld); if (theWorld.machineType >= 0) and (NGetTrapAddress(WNETrapNum, ToolTrap) = NGetTrapAddress(UnImplTrapNum, ToolTrap)) then WNE := false else WNE := true; sleep := 10; end; procedure AdjustCursor; {set cursor} begin if (FrontWindow = MyWindow) and (MyWindow <> nil) then begin {our window in front} GetMouse(myPt); if PtInRect(myPt, NotePallete) then SetCursor(theSquare^^) {over note pallete} else SetCursor(arrow); {over other stuff} end else SetCursor(arrow); end; begin {Start of main body} InitMac; InitApp; {finder startup} CountAppFiles(message, nDocs); if nDocs = 0 then begin {no files to open} Init_Untitled; {Initialize the window routines} Open_Untitled; {Open window routines at program start} end else begin {files to print or open} if message = appPrint then begin {print docs} for index := 1 to nDocs do begin {Loop through docs} GetAppFiles(index, theFile); if theFile.fType = ‘ZZDC’ then begin {my file} VolRefNum := theFile.vRefNum; FileName := theFile.fName; OpenFile; if VolRefNum <> 0 then begin Open_Untitled; SetWTitle(MyWindow, FileName); doPrint; Close_Untitled(MyWindow); end; end; ClrAppFiles(index); end; {Loop through docs} doneFlag := true; {quit when done} end {print docs} else begin {open first file, can’t open multiple} GetAppFiles(1, theFile); if theFile.fType = ‘ZZDC’ then begin VolRefNum := theFile.vRefNum; FileName := theFile.fName; OpenFile; if VolRefNum = 0 then begin Init_Untitled; {Init window routines} FileName := ‘Untitled’; end; Open_Untitled; {Open window routines} SetWTitle(MyWindow, FileName); for index := 1 to nDocs do ClrAppFiles(index); end; end; end; repeat {Start of main event loop} AdjustMenus; AdjustCursor; if WNE then DoIt := WaitNextEvent(everyEvent, myEvent, sleep, nil) else begin SystemTask; DoIt := GetNextEvent(everyEvent, myEvent); end; if DoIt then{If event then...} begin {Start handling the event} code := FindWindow(myEvent.where, whichWindow); case myEvent.what of{Decide type of event} MouseDown:{Mouse button pressed} begin if (code = inMenuBar) then begin mResult := MenuSelect(myEvent.Where); theMenu := HiWord(mResult); theItem := LoWord(mResult); Handle_My_Menu(doneFlag, theMenu, theItem); end;{End of inMenuBar} if (code = InDrag) then begin DragWindow(whichWindow, myEvent.where, dragRect); end; if (code = inGoAway) then begin if TrackGoAway(whichWindow, myEvent.where) then begin if dirty then begin {need saving} GetWTitle(MyWindow, title); ParamText(title, ‘’, ‘’, ‘’); theValue := D_save_changes; if (theValue = I_Yes) then begin {wants to save changes} if VolRefNum = 0 then doSaveAs else doSave; if VolRefNum <> 0 then Close_Untitled(MyWindow); end else if theValue = I_No then Close_Untitled(MyWindow); end {of needing saved} else {no need to save} Close_Untitled(MyWindow); end; end;{End of InGoAway} if (code = inContent) then begin if (whichWindow <> FrontWindow) then SelectWindow(whichWindow) else begin SetPort(whichWindow); Do_Untitled(myEvent); end; end;{End of inContent} if (code = inSysWindow) then SystemClick(myEvent, whichWindow); end; {End of MouseDown} KeyDown, AutoKey:{Handle key inputs} begin with myevent do begin chCode := BitAnd(message, CharCodeMask); ch := CHR(chCode); if (Odd(modifiers div CmdKey)) then begin mResult := MenuKey(ch); theMenu := HiWord(mResult); theItem := LoWord(mResult); if (theMenu <> 0) then Handle_My_Menu(doneFlag, theMenu, theItem); end; end; end; {End for KeyDown,AutoKey} UpDateEvt:{Update event for a window} begin whichWindow := WindowPtr(myEvent.message); BeginUpdate(whichWindow); Update_Untitled(whichWindow); EndUpdate(whichWindow); end; {End of UpDateEvt} DiskEvt: {Disk inserted event} begin if (HiWord(myevent.message) <> noErr) then begin{due to unformatted diskette inserted} myEvent.where.h := ((screenbits.bounds.Right - screenbits.bounds.Left) div 2) - (304 div 2); myEvent.where.v := ((screenbits.bounds.Bottom - screenbits.bounds.Top) div 3) - (104 div 2); InitCursor; chCode := DIBadMount(myEvent.where, myevent.message);{Let the OS handle the diskette} end; end; {End of DiskEvt} ActivateEvt:{Window activated event} begin whichWindow := WindowPtr(myevent.message); if odd(myEvent.modifiers) then begin{Handle the activate} SelectWindow(whichWindow); end; end; {End of ActivateEvt} MultiEvt: begin if Odd(myEvent.message) then begin {resume event} if FrontWindow = MyWindow then begin SetPort(MyWindow); InvalRect(MyWindow^.portRect); end else if FrontWindow <> nil then begin ResumePeek := WindowPeek(FrontWindow); if ResumePeek^.windowKind < 0 then begin myEvent.what := activateEvt; BitSet(@myEvent.modifiers, bit0); sysResult := SystemEvent(myEvent); end; end; end {of resume event} else {suspend event} begin if FrontWindow = MyWindow then begin SetPort(MyWindow); InvalRect(MyWindow^.portRect); end else if FrontWindow <> nil then begin ResumePeek := WindowPeek(FrontWindow); if ResumePeek^.windowKind < 0 then begin myEvent.what := activateEvt; BitClr(@myEvent.modifiers, bit0); sysResult := SystemEvent(myEvent); end; end; end; end; {of MultiEvt} otherwise ; end; {End of case} end; {end of GetNextEvent} until doneFlag; {End of the event loop} end. {End of the program}
Listing: Zoundz.r * RMaker resource file sources. * File: Zoundz.R Zoundz.RSRC ???????? include CursIcons include AppStuff Type DLOG ,3 ;;Resource ID save changes ;;Dialog title 50 120 188 365 ;;Top Left Bottom Right Visible NoGoAway ;;Visible GoAway 1 ;;ProcID, dialog def ID 3 ;;Refcon, reference value 3 ;;ID of item list Type DITL ,3 ;;Resource ID 4 ;;Number of controls in list Button Enabled ;;Push button 70 30 90 100 ;;Top Left Bottom Right Yes ;;message Button Enabled ;;Push button 100 150 120 220 ;;Top Left Bottom Right Cancel ;;message Button Enabled ;;Push button 100 30 120 100 ;;Top Left Bottom Right No ;;message StaticText ;;Static text 10 30 55 220 ;;Top Left Bottom Right Save changes to ^0? ;;message Type WIND ,1 ;;Resource ID Untitled ;;Window title 42 5 337 506 ;;Top Left Bottom Right InVisible GoAway ;;Visible GoAway 4 ;;ProcID, Window def ID 1 ;;Refcon, reference value Type CNTL ,26 ;;Resource ID Play Sound ;;Title for a Button 120 245 160 490 ;;Top Left Bottom Right Visible ;;Initially visible 0 ;;ProcID (Control definition ID) 26 ;;RefCon (reference value) 0 1 0 ;;Min Max Value ,16 ;;Resource ID Timbre ;;Title for a Checkbox 255 395 270 485 ;;Top Left Bottom Right Visible ;;Initially visible 1 ;;ProcID (Control definition ID) 16 ;;RefCon (reference value) 0 1 1 ;;Min Max Value ,15 ;;Resource ID Duration ;;Title for a Checkbox 235 395 250 485 ;;Top Left Bottom Right Visible ;;Initially visible 1 ;;ProcID (Control definition ID) 15 ;;RefCon (reference value) 0 1 1 ;;Min Max Value ,14 ;;Resource ID Amplitude ;;Title for a Checkbox 215 395 230 485 ;;Top Left Bottom Right Visible ;;Initially visible 1 ;;ProcID (Control definition ID) 14 ;;RefCon (reference value) 0 1 1 ;;Min Max Value ,13 ;;Resource ID Frequency ;;Title for a Checkbox 195 395 210 485 ;;Top Left Bottom Right Visible ;;Initially visible 1 ;;ProcID (Control definition ID) 13 ;;RefCon (reference value) 0 1 1 ;;Min Max Value ,20 ;;Resource ID Timbre ;;Title for a RadioButton 85 260 100 350 ;;Top Left Bottom Right Visible ;;Initially visible 2 ;;ProcID (Control definition ID) 20 ;;RefCon (reference value) 0 1 0 ;;Min Max Value ,19 ;;Resource ID Duration ;;Title for a RadioButton 65 260 80 350 ;;Top Left Bottom Right Visible ;;Initially visible 2 ;;ProcID (Control definition ID) 19 ;;RefCon (reference value) 0 1 0 ;;Min Max Value ,18 ;;Resource ID Amplitude ;;Title for a RadioButton 45 260 60 350 ;;Top Left Bottom Right Visible ;;Initially visible 2 ;;ProcID (Control definition ID) 18 ;;RefCon (reference value) 0 1 0 ;;Min Max Value ,17 ;;Resource ID Frequency ;;Title for a RadioButton 25 260 40 350 ;;Top Left Bottom Right Visible ;;Initially visible 2 ;;ProcID (Control definition ID) 17 ;;RefCon (reference value) 0 1 1 ;;Min Max Value ,41 ;;Resource ID DurationScrollbar ;;Title for a Scrollbar 65 360 81 460 ;;Top Left Bottom Right Visible ;;Initially visible 16 ;;ProcID (Control definition ID) 41 ;;RefCon (reference value) 0 250 0 ;;Min Max Value ,40 ;;Resource ID AmplitudeScrollbar ;;Title for a Scrollbar 45 360 61 460 ;;Top Left Bottom Right Visible ;;Initially visible 16 ;;ProcID (Control definition ID) 40 ;;RefCon (reference value) 0 255 0 ;;Min Max Value ,39 ;;Resource ID FrequencyScrollbar ;;Title for a Scrollbar 25 360 41 460 ;;Top Left Bottom Right Visible ;;Initially visible 16 ;;ProcID (Control definition ID) 39 ;;RefCon (reference value) 0 128 0 ;;Min Max Value ,38 ;;Resource ID TimbreScrollbar ;;Title for a Scrollbar 85 360 101 460 ;;Top Left Bottom Right Visible ;;Initially visible 16 ;;ProcID (Control definition ID) 38 ;;RefCon (reference value) 0 254 0 ;;Min Max Value ,31 ;;Resource ID EndScrollbar ;;Title for a Scrollbar 255 250 271 370 ;;Top Left Bottom Right Visible ;;Initially visible 16 ;;ProcID (Control definition ID) 31 ;;RefCon (reference value) 1 100 1 ;;Min Max Value ,27 ;;Resource ID StartScrollbar ;;Title for a Scrollbar 215 250 231 370 ;;Top Left Bottom Right Visible ;;Initially visible 16 ;;ProcID (Control definition ID) 27 ;;RefCon (reference value) 1 100 1 ;;Min Max Value ,12 ;;Resource ID NoteScrollbar ;;Title for a Scrollbar 266 5 282 231 ;;Top Left Bottom Right Visible ;;Initially visible 16 ;;ProcID (Control definition ID) 12 ;;RefCon (reference value) 1 100 1 ;;Min Max Value Type ALRT ,4 ;;Resource ID 75 124 210 385 ;;Top Left Bottom Right 4 ;;ID of item list CCCC ;;stages of alert in hexadecimal Type DITL ,4 ;;Resource ID 2 ;;Number of controls in list StaticText ;;Static text 10 55 80 245 ;;Top Left Bottom Right ^0\0D^1\0D^2\0D^3 ;;message Button Enabled ;;Push button 90 140 110 200 ;;Top Left Bottom Right OK ;;message Type DLOG ,2 ;;Resource ID About ;;Dialog title 112 136 210 373 ;;Top Left Bottom Right Visible NoGoAway ;;Visible GoAway 1 ;;ProcID, dialog def ID 2 ;;Refcon, reference value 2 ;;ID of item list Type DITL ,2 ;;Resource ID 3 ;;Number of controls in list Button Enabled ;;Push button 60 75 87 155 ;;Top Left Bottom Right OK ;;message StaticText ;;Static text 10 35 25 205 ;;Top Left Bottom Right Zoundz 1.0 By Kirk Chase ;;message StaticText ;;Static text 35 10 50 225 ;;Top Left Bottom Right © 1989 Kirk Chase and MacTutor ;;message Type MENU ,1001 ;;Resource ID \14 ;;APPLE menu title About Zoundz... ;;item title (- ;; ,1002 ;;Resource ID File ;;menu title (New/N ;;item title (Open.../O ;;item title (- ;; Close ;;item title Save/S ;;item title Save As... ;;item title (- ;; Page Setup... ;;item title Print... ;;item title (- ;; Quit/Q ;;item title ,1003 ;;Resource ID Edit ;;menu title Undo/Z ;;item title (- ;; Cut/X ;;item title Copy/C ;;item title Paste/V ;;item title ,1004 Extend Frequency Amplitude Duration Timbre
- SPREAD THE WORD:
- Slashdot
- Digg
- Del.icio.us
- Newsvine