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 (0255) 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;
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;