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 wasnt 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 Ill regret the day I stopped playing the piano; I didnt 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, cant 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