Sound INIT
Volume Number: 9
Issue Number: 3
Column Tag: C Workshop
INIT's: Fun with Sounds 
Playing with sounds at startup and using them for different purposes.
By By Randy Thelen, Campbell, California
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
About the author
Randy Thelen has been programming since his father first brought home a
Commodore PET 2001 in 1978. He knows half a dozen languages and applies them on
his Mac. He loves THINK-C because “it’s easy, fun, and intuitive.” Although, he uses
MPW 3.2 because it offers the most integrated development platform for C (his
favorite), Pascal (a language he hates), and assembly. Randy has contracted on and off
with Apple Computer, Inc. since 1985. He’ll graduate with his first degree in
December of 1992. If you see him on the beach, congratulate him: he doesn’t get out
often.
Some of you have written System Extensions (or INIT’s, as they were called in
the old days), the rest of us are still catching up. An extension is a piece of standalone
code that is loaded during startup and put into memory and wham!, it’s executed. The
only known code at that point is the system and the system patches. The code can rely
on System 7.x having loaded in and being as ready to run as any application can depend.
You’re code is given complete control of the system.
This article will show you how to incorporate sound calls into a fun extension
that you can type in whether you have THINK-C or MPW. (If you have THINK Pascal,
you can challenge yourself by converting this code to Pascal. I know it works because
the original extension was written in Pascal, I converted it to C.) The extension is
borrowed from the most excellent MPW text I’ve read to date (August ‘92), “Building
and Managing Programs in MPW.” (A short plug for the work: Addison-Wesley and
Apple Computer guide the reader through the most useful elements of MPW (Macintosh
Programmer’s Workshop) with real examples of how to use MPW today, long before
reading hundreds of pages of dry manuals. The sections are short, clear, and
captivating.)
The sample extension played all the sounds in the System before continuing.
Boring! So while my brother digitized the introduction theme to StarTrek: The Next
Generation, I extended the init into this code which plays one sound, the intro sound, at
start up.
However, if you’ve seen StarTrek: The Next Generation (like a thousand times),
it isn’t too long before you tire of the intro. There are times when it’s fun, and the
rest when it’s too long to sit through. So I made the following change to the code: when
the code gets loaded, it checks for the space bar being pressed down. If it is pressed,
then the sound isn’t played. Great! Until you start up your Mac and forget.
The real trick, then, is to play the sound asynchronously. (Yes, it’s a real word
which means a lack of synchronicity. Being synchronous would mean happening at the
same time. You have to love computer people when they use a word which means only
what they want it to mean but not what “Webster’s New World Dictionary” believes it
to mean. In the end, computer people believe that asynchronous means happening at
the same time. Go figure.) The benefit of an asynchronous sound is that the keyboard
can be polled (i.e., continuously checked) during the sound (actually, quite a bit can
happen in the background). If the user presses the space bar during the sound, the
sound can be stopped immediately. And that’s when a long sound like StarTrek’s
introduction can be most enjoyable: when it can be stopped at the press of a key.
Here, let’s look at the code. It’s really quite simple. Remember that /* */ and
// are both comments in C. The difference is that /* and */ must be balanced. The //
comment out to the end of the line.
/* 1 */
/* Both THINK-C 5.0 and MPW 3.2 includes: */
#include
#include
#include
#include
/* The next couple lines are proto types. */
/* KeyPressed returns true if a key is pressed */
Boolean KeyPressed(
short keyNum, unsigned char *keyMapPtr);
/* main plays sound ID # 129 until its done or a key is pressed */
void main( void);
/* Every program needs a bug, this program currently has none, as
you can clearly see because DEBUG is false. I encourage you to add
to this code until it has at least three good bugs. */
#define DEBUG false
/* The KillKey is currently set to the space bar
(0x31). The list of keys can be found in InsideMac’s Vol. I pg. 251;
Vol. IV pg. 250, and
Vol. VI pg. 191-2 */
#define KILLKEY 0x31
/* kSndRsrc holds the resource #, 129 is compatible with cdev’s, see
Dave Mark’s “Macintosh C Programming Primer Vol. II.” See chapter 3.
*/
#define kSndRsrc 129
/********************* main *********************/
void main()
{
SCStatus sndStatus; // Used while snd plays
Handle theSnd; // the snd resource
OSErr playStatus; // standard error var
KeyMap theKeys; // bit map of key presses
// the channel through which sound will come
SndChannelPtr theChannel;
/* If there are any bugs, then go to the debugger first. */
#if DEBUG
Debugger();
#endif
/* Check to see if the KillKey is pressed */
GetKeys( &theKeys); // Read the keyboard
if(KeyPressed(KILLKEY,
(unsigned char*)theKeys) == false)
{ // if the space bar is not pressed, continue
/* Set the channel ptr to NIL */
theChannel = (SndChannelPtr) 0l;
/* Allocate a new channel */
playStatus = SndNewChannel( &theChannel, 0,
(long int)0, (SndCallBackProcPtr) 0);
/* As long as that worked fine... */
if( playStatus == noErr)
{
/* Read the sound resource into memory */
theSnd = GetResource('snd ', kSndRsrc);
/* 0 is returned if there was a res error */
if( theSnd)
{
/* SoundPlay needs the channel, the sound, */
playStatus = SndPlay( theChannel, theSnd,
true); // and an ASYNC flag
/* Sound Channel Status will return, among
other things, the status of the sound */
playStatus = SndChannelStatus( theChannel,
sizeof( sndStatus), &sndStatus);
/* While the KillKey isn’t pressed, &
the sound is playing (i.e., busy) */
while(KeyPressed(KILLKEY,
(unsigned char*)theKeys) == 0 &&
sndStatus.scChannelBusy == true)
{
/* Read the keyboard */
GetKeys( &theKeys);
/* Get the sound channel status */
playStatus = SndChannelStatus(
theChannel, sizeof( sndStatus),
&sndStatus);
} // END while
} // END if( theSnd)
/* Kill the sound (true == dispose now) */
playStatus = SndDisposeChannel( theChannel, true);
} // END if( playStatus == true)
} // END if( KeyPressed( ...) == false
} // END main() {...}
/***************** KeyPressed *****************/
/* The following algorithm I typed directly
from Symantec’s THINK Reference. An excellent
tool that I highly recommend! Only $69 */
// returns
// true == the key is pressed
// false == the key is not pressed
Boolean KeyPressed( short keyNum,
unsigned char *keyMapPtr)
{
/* This convoluted but functional and tight
algorithm determines if the key keyNum
is pressed... Read InsideMac’s Vol. I pg. 251;
Vol. IV pg. 250, and Vol. VI pg. 191-2 */
return( (keyMapPtr[keyNum >> 3]
>> (keyNum & 7) ) & 1);
}
With MPW 3.2 (which is the latest version), the following build commands will
build the extension:
/* 2 */
C -r -sym on SoundINIT.c -w
Link -t INIT ∂
-c rndm ∂
-rt INIT=128 ∂
-m main ∂
-sg SoundINIT ∂
-sym on ∂
-mf ∂
-w ∂
SoundINIT.c.o ∂
-o SoundINIT
These instructions were generated with the Create Build Commands menu item
from the Build menu. It was pretty easy. The -c is the creator. The -rt is the
resource type and ID #. -m is the main subroutine name. -sg is the segment name.
-sym on turns symbols on for SADE and MacsBug. -mf is any one’s guess. And, -w
turns warnings off.
The following line will put the SoundINIT into the system’s extension folder. Use
help duplicate if any part of the line confuses you.
duplicate -y 'SoundINIT' "{SystemFolder}Extensions:"' SoundINIT'
If you’re using THINK-C. The interface is a little more visual. You’ll need to
include into the project both MacTraps and MacTraps2. The complete project should
look like this:
Use the Set Project Type menu item under the Project menu to get the following
dialog. You’ll probably want to put in your own Creator. Mine is rndm. The ID can
really be anything you want. I chose 128. Again, this offers compatibility with a cdev.
Dave Mark covers this.
So, that’s the code. It’s short (the comments easily doubled it’s length). Allow
me to point out some of it’s highlights. First, this extension uses no globals (all you
mighty programmers want to know how to use globals in extensions: THINK-C’s User
Manual for version 5.0 discusses it on page 119, and Building and Managing MPW
Programs discusses it in chapter 9, but it’s a little more in-depth coverage and a little
bit more work than with THINK).
Second, the routine main starts the program because it contains the code that is
first to be executed. MPW allows you to define which routine begins the code segment;
THINK-C puts a BRanch Always to main. Extensions work this way: after the code is
loaded, the system jmp’s to the first word.
Third, this version of the extension displays no ICN#. Dave Mark does this in his
book Macintosh C Programming Primer Vol. II. See chapter 3 and read the code in
appendix B, pp. 397 - 401. If you’ve just begun programming the Mac, I strongly
suggest you pick up a copy of Vol. I and II.
Fourth, this code doesn’t include the sound! You’ll need to digitize your favorite
sound (something you enjoy listening to, or try this: digitize a siren on your
computer; then if anyone but you starts up your computer, a siren will alert to the bad
guys presence) and then use ResEdit to copy and paste that sucker in the extension
resource. The sound will have to be ID # == 129.
Last, the code shows how to use the rudimentary commands in the Sound Manager.
After running this program, I suggest you pick up Inside Macintosh vol. II pg. 221,
vol. V pg. 473, & vol. VI chapter 22. They are ‘dehydrated reading’ (just add interest)
and give a good insight into the power of the microphone, sound compression, and
playing sounds straight from the disk!
Enjoy your code development, whether it be with extensions, drivers, cdev’s, or
actual programs. Until next time, this is Random saying “don’t do it right the first
time; experiment until you’re sure you can break it.”