TweetFollow Us on Twitter

Zoundz
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

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Recruit two powerful-sounding students t...
I am a fan of anime, and I hear about a lot that comes through, but one that escaped my attention until now is A Certain Scientific Railgun T, and that name is very enticing. If it's new to you too, then players of Blue Archive can get a hands-on... | Read more »
Top Hat Studios unveils a new gameplay t...
There are a lot of big games coming that you might be excited about, but one of those I am most interested in is Athenian Rhapsody because it looks delightfully silly. The developers behind this project, the rather fancy-sounding Top Hat Studios,... | Read more »
Bound through time on the hunt for sneak...
Have you ever sat down and wondered what would happen if Dr Who and Sherlock Holmes went on an adventure? Well, besides probably being the best mash-up of English fiction, you'd get the Hidden Through Time series, and now Rogueside has announced... | Read more »
The secrets of Penacony might soon come...
Version 2.2 of Honkai: Star Rail is on the horizon and brings the culmination of the Penacony adventure after quite the escalation in the latest story quests. To help you through this new expansion is the introduction of two powerful new... | Read more »
The Legend of Heroes: Trails of Cold Ste...
I adore game series that have connecting lore and stories, which of course means the Legend of Heroes is very dear to me, Trails lore has been building for two decades. Excitedly, the next stage is upon us as Userjoy has announced the upcoming... | Read more »
Go from lowly lizard to wicked Wyvern in...
Do you like questing, and do you like dragons? If not then boy is this not the announcement for you, as Loongcheer Game has unveiled Quest Dragon: Idle Mobile Game. Yes, it is amazing Square Enix hasn’t sued them for copyright infringement, but... | Read more »
Aether Gazer unveils Chapter 16 of its m...
After a bit of maintenance, Aether Gazer has released Chapter 16 of its main storyline, titled Night Parade of the Beasts. This big update brings a new character, a special outfit, some special limited-time events, and, of course, an engaging... | Read more »
Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »

Price Scanner via MacPrices.net

May 2024 Apple Education discounts on MacBook...
If you’re a student, teacher, or staff member at any educational institution, you can use your .edu email address when ordering at Apple Education to take up to $300 off the purchase of a new MacBook... Read more
Clearance 16-inch M2 Pro MacBook Pros in stoc...
Apple has clearance 16″ M2 Pro MacBook Pros available in their Certified Refurbished store starting at $2049 and ranging up to $450 off original MSRP. Each model features a new outer case, shipping... Read more
Save $300 at Apple on 14-inch M3 MacBook Pros...
Apple has 14″ M3 MacBook Pros with 16GB of RAM, Certified Refurbished, available for $270-$300 off MSRP. Each model features a new outer case, shipping is free, and an Apple 1-year warranty is... Read more
Apple continues to offer 14-inch M3 MacBook P...
Apple has 14″ M3 MacBook Pros, Certified Refurbished, available starting at only $1359 and ranging up to $270 off MSRP. Each model features a new outer case, shipping is free, and an Apple 1-year... Read more
Apple AirPods Pro with USB-C return to all-ti...
Amazon has Apple’s AirPods Pro with USB-C in stock and on sale for $179.99 including free shipping. Their price is $70 (28%) off MSRP, and it’s currently the lowest price available for new AirPods... Read more
Apple Magic Keyboards for iPads are on sale f...
Amazon has Apple Magic Keyboards for iPads on sale today for up to $70 off MSRP, shipping included: – Magic Keyboard for 10th-generation Apple iPad: $199, save $50 – Magic Keyboard for 11″ iPad Pro/... Read more
Apple’s 13-inch M2 MacBook Airs return to rec...
Apple retailers have 13″ MacBook Airs with M2 CPUs in stock and on sale this weekend starting at only $849 in Space Gray, Silver, Starlight, and Midnight colors. These are the lowest prices currently... Read more
Best Buy is clearing out iPad Airs for up to...
In advance of next week’s probably release of new and updated iPad Airs, Best Buy has 10.9″ M1 WiFi iPad Airs on record-low sale prices for up to $200 off Apple’s MSRP, starting at $399. Sale prices... Read more
Every version of Apple Pencil is on sale toda...
Best Buy has all Apple Pencils on sale today for $79, ranging up to 39% off MSRP for some models. Sale prices for online orders only, in-store prices may vary. Order online and choose free shipping... Read more
Sunday Sale: Apple Studio Display with Standa...
Amazon has the standard-glass Apple Studio Display on sale for $300 off MSRP for a limited time. Shipping is free: – Studio Display (Standard glass): $1299.97 $300 off MSRP For the latest prices and... Read more

Jobs Board

Liquor Stock Clerk - S. *Apple* St. - Idaho...
Liquor Stock Clerk - S. Apple St. Boise Posting Begin Date: 2023/10/10 Posting End Date: 2024/10/14 Category: Retail Sub Category: Customer Service Work Type: Part Read more
*Apple* App Developer - Datrose (United Stat...
…year experiencein programming and have computer knowledge with SWIFT. Job Responsibilites: Apple App Developer is expected to support essential tasks for the RxASL Read more
Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.