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

Apple High Sierra 10.13 - The latest OS...
macOS High Sierra introduces new core technologies that improve the most important functions of your Mac. From rearchitecting how it stores your data to improving the efficiency of video streaming to... Read more
ScreenFlow 7.1 - Create screen recording...
ScreenFlow is powerful, easy-to-use screencasting software for the Mac. With ScreenFlow you can record the contents of your entire monitor while also capturing your video camera, microphone and your... Read more
Airmail 3.5 - Powerful, minimal email cl...
Airmail is an mail client with fast performance and intuitive interaction. Support for iCloud, MS Exchange, Gmail, Google Apps, IMAP, POP3, Yahoo!, AOL, Outlook.com, Live.com. Airmail was designed... Read more
CleanMyMac 3.9.0 - $39.95
CleanMyMac makes space for the things you love. Sporting a range of ingenious new features, CleanMyMac lets you safely and intelligently scan and clean your entire system, delete large, unused files... Read more
Numi 3.17.2 - Menu-bar calculator suppor...
Numi is a calculator that magically combines calculations with text, and allows you to freely share your computations. Numi combines text editor and calculator Support plain English. For example, '5... Read more
OmniGraffle 7.4.3 - Create diagrams, flo...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
ExpanDrive 6.1.0 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
VueScan 9.5.86 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
Cocktail 11.0 - General maintenance and...
Cocktail is a general purpose utility for macOS that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
OmniGraffle Pro 7.4.3 - Create diagrams,...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more

Morphite guide - how to explore like a p...
The much anticipated space exploration game, Morphite, has finally arrived, and we can't get enough of it. The game is essentially everything we wanted No Man's Sky to be. It's a game that puts a heavy focus on exploring foreign worlds, but the... | Read more »
The best visual novels on mobile
Narrative games have been around for ages, but only now have they been creeping into the mainstream spotlight. These games tell some of the industry's finest stories, and they break new ground in terms of gameplay and mechanics regularly. Here are... | Read more »
The best new games we played this week -...
It's pretty much been one big release after another. We were privy to a bunch of surprises this week, with a lot of games we'd been waiting for quite some time dropping unexpectedly. We hope you're free this weekend, because there is a lot for... | Read more »
Stormbound: Kingdom Wars guide - how to...
Stormbound: Kingdom Wars is an excellent new RTS turned card battler out now on iOS and Android. Lovers of strategy will get a lot of enjoyment out of Stormbound's chess-like mechanics, and it's cardbased units are perfect for anyone who loves the... | Read more »
The best AR apps and games on iOS right...
iOS 11 has officially launched, and with it comes Apple's ARKit, a helpful framework that makes it easier than ever for developers to create mobile AR experiences. To celebrate the occassion, we're featuring some of the best AR apps and games on... | Read more »
Phoenix Wright: Ace Attorney - Spirit of...
Phoenix Wright: Ace Attorney - Spirit of Justice 1.00.00 Device: iOS Universal Category: Games Price: $.99, Version: 1.00.00 (iTunes) Description: ************************************************※IMPORTANT※・Please read the “When... | Read more »
Kpressor (Utilities)
Kpressor 1.0.0 Device: iOS Universal Category: Utilities Price: $4.99, Version: 1.0.0 (iTunes) Description: The ultimate ZIP compression application for iPhone and iPad. - Full integration of iOS 11 with support for multitasking.-... | Read more »
Find out how you can save £35 and win a...
Nothing raises excitement like a good competition, and we’re thrilled to announce our latest contest. We’ll be sending one lucky reader and a friend to the Summoners War World Arena Championship at Le Comedia in Paris on October 7th. It’s the... | Read more »
Another Lost Phone: Laura's Story...
Another Lost Phone: Laura's Story 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Another Lost Phone is a game about exploring the social life of a young woman whose phone you have just... | Read more »
The Witness (Games)
The Witness 1.0 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0 (iTunes) Description: You wake up, alone, on a strange island full of puzzles that will challenge and surprise you. You don't remember who you are, and... | Read more »

Price Scanner via MacPrices.net

Snag a Certified Refurbished Apple Pencil for...
Apple has Certified Refurbished Apple Pencils available for $85 including free shipping. Their price is $14 off MSRP, and it’s the lowest price available for a Pencil. Read more
12-inch 64GB iPad Pro on sale for $749, save...
Adorama has 12″ 64GB iPad Pros on sale today for $749 including free shipping plus NY & NJ sales tax only. Their price is $50 off MSRP. Read more
Apple Certified Refurbished iPad minis availa...
Apple has Certified Refurbished 128GB iPad minis available today for $339 including free shipping. Apple’s standard one-year warranty is included. Their price is $60 off MSRP. Read more
12-inch 1.2GHz Retina MacBook Pros on sale fo...
B&H Photo has 2017 12″ 1.2GHz Retina MacBooks on sale for $100 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: 12″ 1.2GHz Space Gray MacBook: $1199 $100 off MSRP 12... Read more
Sunday sale: 13-inch 3.1GHz MacBook Pros for...
Amazon has 2017 13″ 3.1GHz MacBook Pros on sale today for up to $150 off MSRP, each including free shipping: – 13″ 3.1GHz/256GB Space Gray MacBook Pro (MPXV2LL/A): $1649.99 $150 off MSRP – 13″ 3.1GHz... Read more
Looking for a 2017 12″ Retina MacBook? Save $...
Apple has Certified Refurbished 2017 12″ Retina MacBooks available for $200-$240 off the cost of new models. Apple will include a standard one-year warranty with each MacBook, and shipping is free.... Read more
Apple Offering Up To $455 Credit Toward iPhon...
iPhone 8 and 8 Plus are now available at the Apple Store, and you can receive up to $375 credit toward a new iPhone purchase when you trade in your eligible smartphone. Photo Courtesy Apple Just... Read more
AnyTrans Offers iOS Users Three Ways For Movi...
iMobie Inc. today announceed AnyTrans v6.0.1, which now can help iOS users move all data to iPhone 8/8 Plus seamlessly. The software is available both on Mac and Windows and fully able to move all... Read more
Snag a 13-inch 2.3GHz MacBook Pro for $100 of...
B&H Photo has 2017 13″ 2.3GHz MacBook Pros in stock today and on sale for $100 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more
Verizon offers new iPhone 8 for $100-$300 off...
Verizon is offering the new iPhone 8 for up to $300 off MSRP with an eligible trade-in: • $300 off: iPhone 6S/6S Plus/7/7 Plus, Google Pixel XL, LG G6, Moto Z2 Force, Samsung Galaxy S7/S7 edge/S8/S8... Read more

Jobs Board

Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
Data Engineer - *Apple* Media Products - Ap...
Job Summary Apple is seeking a highly skilled data engineer to join the Data Engineering team within Apple Media Products. AMP (home to Apple Music, App Read more
Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.