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

djay Pro 1.1 - Transform your Mac into a...
djay Pro provides a complete toolkit for performing DJs. Its unique modern interface is built around a sophisticated integration with iTunes and Spotify, giving you instant access to millions of... Read more
Vivaldi 1.0.118.19 - Lightweight browser...
Vivaldi browser. In 1994, two programmers started working on a web browser. Our idea was to make a really fast browser, capable of running on limited hardware, keeping in mind that users are... Read more
Stacks 2.6.11 - New way to create pages...
Stacks is a new way to create pages in RapidWeaver. It's a plugin designed to combine drag-and-drop simplicity with the power of fluid layout. Features: Fluid Layout: Stacks lets you build pages... Read more
xScope 4.1.3 - Onscreen graphic measurem...
xScope is powerful set of tools that are ideal for measuring, inspecting, and testing on-screen graphics and layouts. Its tools float above your desktop windows and can be accessed via a toolbar,... Read more
Cyberduck 4.7 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Labels & Addresses 1.7 - Powerful la...
Labels & Addresses is a home and office tool for printing all sorts of labels, envelopes, inventory labels, and price tags. Merge-printing capability makes the program a great tool for holiday... Read more
teleport 1.2.1 - Use one mouse/keyboard...
teleport is a simple utility to let you use one single mouse and keyboard to control several of your Macs. Simply reach the edge of your screen, and your mouse teleports to your other Mac! The... Read more
Apple iMovie 10.0.8 - Edit personal vide...
With an all-new design, Apple iMovie lets you enjoy your videos like never before. Browse your clips more easily, instantly share your favorite moments, and create beautiful HD movies and Hollywood-... Read more
Box Sync 4.0.6233 - Online synchronizati...
Box Sync gives you a hard-drive in the Cloud for online storage. Note: You must first sign up to use Box. What if the files you need are on your laptop -- but you're on the road with your iPhone? No... Read more
Fantastical 2.0.3 - Create calendar even...
Fantastical 2 is the Mac calendar you'll actually enjoy using. Creating an event with Fantastical is quick, easy, and fun: Open Fantastical with a single click or keystroke Type in your event... Read more

SoundHound + LiveLyrics is Making its De...
SoundHound Inc. has announced that SoundHound + LiveLyrics, will be one of the first third-party apps to hit the Apple Watch. With  SoundHound you'll be able to tap on your watch and have the app recognize the music you are listening to, then have... | Read more »
Adobe Joins the Apple Watch Lineup With...
A whole tidal wave of apps are headed for the Apple Watch, and Adobe has joined in with 3 new ways to enhance your creativity and collaborate with others. The watch apps pair with iPad/iPhone apps to give you total control over your Adobe projects... | Read more »
Z Steel Soldiers, Sequel to Kavcom'...
Kavcom has released Z Steel Soldiers, which continues the story of the comedic RTS originally created by the Bitmap Brothers. [Read more] | Read more »
Seene Lets You Create 3D Images With You...
Seene, by Obvious Engineering, is a 3D capture app that's meant to allow you to create visually stunning 3D images with a tap of your finger, and then share them as a 3D photo, video or gif. [Read more] | Read more »
Lost Within - Tips, Tricks, and Strategi...
Have you just downloaded Lost Within and are you in need of a guiding hand? While it’s not the toughest of games out there you might still want some helpful tips to get you started. [Read more] | Read more »
Entertain Your Pet With Your Watch With...
The Petcube Camera is a device that lets you use live video to check in on your pet, talk to them, and play with them using a laser pointer - all while you're away. And the Petcube app is coming to the Apple Watch, so you'll be able to hang out with... | Read more »
Now You Can Manage Your Line2 Calls With...
You'll be able to get your Line2 cloud phone service on the Apple Watch very soon. The watch app can send and receive messages using hands-free voice dictation, or by selecting from a list of provided responses. [Read more] | Read more »
R.B.I. Baseball 15 (Games)
R.B.I. Baseball 15 1.01 Device: iOS Universal Category: Games Price: $4.99, Version: 1.01 (iTunes) Description: The legendary Major League Baseball franchise returns to the diamond. Make History. ** ALL iPOD Touch, the iPad 2 and the... | Read more »
Here's How You Can Tell if an App W...
The Apple Watch is pretty much here, and that means a whole lot of compatible apps and games are going to be updated or released onto the App Store. That's okay though, beacause Apple has quietly updated their app description pages to make things... | Read more »
Forgotten Memories : Alternate Realities...
Forgotten Memories : Alternate Realities 1.0.1 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.1 (iTunes) Description: + REDUCED PRICE ONLY THE LAUNCHING WEEK + "The most exciting horror game of 2015." - AppSpy... | Read more »

Price Scanner via MacPrices.net

Intel Compute Stick: A New Mini-Computing For...
The Intel Compute Stick, a new pocket-sized computer based on a quad-core Intel Atom processor running Windows 8.1 with Bing, is available now through Intel Authorized Dealers across much of the... Read more
Heal to Launch First One-Touch House Call Doc...
Santa Monica, California based Heal, a pioneer in on-demand personal health care services — will offer the first one-touch, on-demand house call doctor app for the Apple Watch. Heal’s Watch app,... Read more
Mac Notebooks: Avoiding MagSafe Power Adapter...
Apple Support says proper usage, care, and maintenance of Your Mac notebook’s MagSafe power adapter can substantially increase the the adapter’s service life. Of course, MagSafe itself is an Apple... Read more
12″ Retina MacBook In Shootout With Air And P...
BareFeats’ rob-ART morgan has posted another comparison of the 12″ MacBook with other Mac laptops, noting that the general goodness of all Mac laptops can make which one to purchase a tough decision... Read more
FileMaker Go for iPad and iPhone: Over 1.5 Mi...
FileMaker has announced that its FileMaker Go for iPad and iPhone app has surpassed 1.5 million downloads from the iTunes App Store. The milestone confirms the continued popularity of the FileMaker... Read more
Sale! 13-inch 2.7GHz Retina MacBook Pro for $...
 Best Buy has the new 2015 13″ 2.7GHz/128GB Retina MacBook Pro on sale for $1099 – $200 off MSRP. Choose free shipping or free local store pickup (if available). Price for online orders only, in-... Read more
Minimalist MacBook Confirms Death of Steve Jo...
ReadWrite’s Adriana Lee has posted a eulogy for the “Digital Hub” concept Steve Jobs first proposed back in 2001, declaring the new 12-inch MacBook with its single, over-subscribed USB-C port to be... Read more
13-inch 2.7GHz Retina MacBook Pro for $1234 w...
Adorama has the 13″ 2.7GHz/128GB Retina MacBook Pro in stock for $1234.99 ($65 off MSRP) including free shipping plus a free LG external DVD/CD optical drive. Adorama charges sales tax in NY & NJ... Read more
13-inch 2.5GHz MacBook Pro available for $999...
 Adorama has the 13-inch 2.5GHz MacBook Pro on sale for $999 including free shipping plus NY & NJ sales tax only. Their price is $100 off MSRP. Read more
Save up to $600 with Apple refurbished Mac Pr...
The Apple Store is offering Apple Certified Refurbished Mac Pros for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The... Read more

Jobs Board

*Apple* Software Support - Xerox Corporation...
…Imaging experience Full knowledge of Mac OS X and prior Mac OSX / Server Apple Remote Desktop Process Documentation Ability to prioritize multiple tasks in a fast pace Read more
*Apple* Support Technician IV - Jack Henry a...
Job Description Jack Henry & Associates is seeking an Apple Support Technician. This position while acting independently, ensures the proper day-to-day control of Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Service-Learning Counselor, *APPLE* Corps -...
…CONTRACT TITLE Higher Education Assistant FLSA Exempt CAMPUS SPECIFIC INFORMATION APPLE Corps (Academic Preparation Program for Law Enforcement), a partnership between Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.