`Volumes I, II, and III
`
`CL
`
`A
`VV
`
`Addison-Wesley Publishing Company, Inc.
`Reading, Massachusetts Menlo Park, California New York
`Don Mills, Ontario Wokingham, England Amsterdam Bonn
`Sidney Singapore Tokyo Madrid San Juan Paris
`Seoul Milan Mexico City Taipei
`
`Apple Exhibit 1328 Page 00001
`
`Apple Exhibit 1328 Page 00001
`
`
`
`Copyright © 1985 by Apple Computer, Inc.
`All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or
`transmitted, in any form or by any means, electronic, mechanical, photocopying, recording, or
`otherwise, without pnor written permission of Apple Computer, Inc. Printed in the United States of
`
`This book was produced using the Apple Macintosh computer and the LaserWn'ter printer.
`ISBN 0-201-17737-4
`
`12 l3 l4 l5 l6 l7 18—MU—959493929l
`Twelfth printing, October 1991
`
`Page 00002
`
`Page 00002
`
`
`
`
`
`cc
`(1:o
`r:
`:r
`a.
`
`.<(D..,
`
`UE
`
`Page 00003
`
`The Sound Driver
`
`
`
`ABOUT THIS CHAPTER
`
`The Sound Driver is a Macintosh device driver for handling sound and music generation in a
`Macintosh application. This chapter describes the Sound Driver in detail.
`
`You should already be familiar with:
`
`I events, as discussed in chapter 8 of Volume I
`
`I the Memory Manager
`
`I the use of devices and device drivers, as described in chapter 6
`
`
`
`ABOUT THE SOUND DRIVER
`
`The Sound Driver is a standard Macintosh device driver in ROM that's used to synthesize sound.
`You can generate sound characterized by any kind of waveform by using the three different
`sound synthesizers in the Sound Driver:
`
`I The four-tone synthesizer is used to make simple harmonic tones, with up to four
`"voices" producing sound simultaneously; it requires about 50% of the microprocessor's
`attention during any given time interval.
`
`I The square-wave synthesizer is used to produce less harmonic sounds such as beeps,
`and requires about 2% of the processor's time.
`
`I The free-form synthesizer is used to make complex music and speech; it requires about
`20% of the processor's time.
`
`The Macintosh XL is equipped only with a square-wave synthesizer; all information in this
`chapter about four-tone and free-form sound applies only to the Macintosh 128K and 512K.
`
`Figure 1 depicts the waveform of a typical sound wave, and the terms used to describe it. The
`magnitude is the vertical distance between any given point on the wave and the horizontal line
`about which the wave oscillates; you can think of the magnitude as the volume level. The
`amplitude is the maximum magnitude of a periodic wave. The wavelength is the horizontal
`extent of one complete cycle of the wave. Magnitude and wavelength can be measured in any
`unit of distance. The period is the time elapsed during one complete cycle of a wave. The
`frequency is the reciprocal of the period, or the number of cycles per second—also called hertz
`(Hz). The phase is some fraction of a wave cycle (measured from a fixed point on the wave).
`
`There are many different types of waveforms, three of which are depicted in Figure 2. Sine
`waves are generated by objects that oscillate periodically at a single frequency (such as a tuning
`fork). Square waves are generated by objects that toggle instantly between two states at a single
`frequency (such as an electronic "beep"). Free-form waves are the most common of all, and are
`generated by objects that vibrate at rapidly changing frequencies with rapidly changing
`magnitudes (such as your vocal cords).
`
`About the Sound Driver [1-223
`
`Page 00003
`
`
`
`Inside Macintosh
`
`period T (sec)
`g‘ wavelength§.
`
`frequency 1‘ (Hz) :
`
`=1
`T
`
`
`
` amplitude
`We Uflflfllfllfl Ll.
`
`:- phase
`
`__ one cycle “4'
`
`Figure 1. Waveform
`
`sine wave
`
`square wave
`
`free-form wave
`
`Figure 2. Types of Waveforms
`
`Figure 3 shows analog and digital representations of a waveform. The Sound Driver represents
`waveforms digitally, so all waveforms must be converted from their analog representation to a
`digital representation. The rows of numbers at the bottom of the figure are digital representations
`of the waveform. The numbers in the upper row are the magnitudes relative to the horizontal
`zero-magnitude line. The numbers in the lower row all represent the same relative magnitudes,
`but have been normalized to positive numbers; you’ll use numbers like these when calling the
`Sound Driver.
`
`11-224 About the Sound Driver
`
`Page 00004
`
`Page 00004
`
`
`
`time/ distance
`
`The Sound Driver
`
`+
`
`i
`E 0
`a
`E
`
`
`
`EEEEEEEEEEEHEEEE
`
`llllllllllllllll
`III-IIIIIIII-III
`
`
`
`
`
`analo re resentetion
`‘4
`p
`
`
`
`
`
`
`
`
`
`
`
`IIIIIIIIIIIIIIII
`o 3 5 s 7 e 5 3 0-3-5-6-7-6-5-3 o
`7muumnum74z1o1247
`
`}digital representation:
`
`I“
`
`mmo=5a
`
`
`
`. C1<(
`
`D1
`
`Figure 3. Analog and Digital Representations of a Waveform
`
`SOUND DRIVER SYNTHESIZERSX
`
`A description of the sound to be generated by a synthesizer is contained in a data structure called a
`synthesizer buffer. A synthesizer buffer contains the duration, pitch, phase, and waveform of
`the sound the synthesizer will generate. The exact structure of a synthesizer buffer differs for
`each type of synthesizer being used. The first word in every synthesizer buffer is an integer that
`identifies the synthesizer, and must be one of the following predefined constants:
`CONST stode
`ftMode
`ffMode
`
`IIII"
`
`—l;
`l;
`0;
`
`{square-wave synthesizer}
`{four-tone synthesizer}
`{free-form synthesizer}
`
`Sguare-Wave Synthesizer
`
`The square-wave synthesizer is used to make sounds such as beeps. A square-wave synthesizer
`buffer has the following structure:
`
`TYPE SWSynthRec = RECORD
`INTEGER;
`mode:
`triplets: Tones
`END;
`
`{always stode}
`{sounds}
`
`SWSynthPtr = ASWSynthRec;
`
`Tones = ARRAY[O..5000] OF Tone;
`Tone
`= RECORD
`
`count:
`amplitude:
`duration:
`END;
`
`INTEGER;
`INTEGER;
`INTEGER
`
`{frequency}
`(amplitude, 0-255}
`{duration in ticks}
`
`Sound Driver Synthesizers 11—225
`
`Page 00005
`
`
`
`Page 00005
`
`
`
`
`
`Inside Macintosh
`
`Each tone triplet contains the count, amplitude, and duration of a different sound. You can store
`as many triplets in a synthesizer buffer as there's room for.
`
`The count integer can range in value from 0 to 65535. The actual frequency the count
`corresponds to is given by the relationship:
`
`frequency (Hz) = 783360 / count
`
`A partial list of count values and corresponding frequencies for notes is given in the summary at
`the end of this chapter.
`
`The type Tones is declared with 5001 elements to allow you to pass up to 5000 sounds (the last
`element must contain 0). To be space-efficient, your application shouldn't declare a variable of
`type Tones; instead, you can do something like this:
`
`VAR myPtr: Ptr;
`myl-Iandle : Handle;
`mySWPtr: SWSynthPtr;
`
`{allocate space for the buffer}
`myHandle := NewHandle(buffSize);
`{lock the buffer}
`HLock(myHandle);
`{dereference the handle}
`myPtr
`:= myHandle‘;
`{coerce type to SWSynthPtr}
`mySWPtr
`:= SWSynthPtr(myPtr) ;
`{identify the synthesizer}
`mySWPtr“.mode := stode;
`{fill the buffer with values }
`mySWPtr“.triplets[0].count
`{ describing the sound}
`.
`.
`.
`StartSound(myPtr,buffSize,POINTER(-l));
`{produce the sound}
`HUnlock(myHandle)
`{unlock the buffer}
`
`:= 2;
`
`where buffSize contains the number of bytes in the synthesizer buffer. This example
`dereferences handles instead of using pointers directly, to minimize the number of nomelocatable
`objects in the heap.
`
`Assembly-language note: The global variable CurPitch contains the current value of
`the count field.
`
`The amplitude can range from O to 255. The duration specifies the number of ticks that the sound
`will be generated.
`
`The list of tones ends with a triplet in which all fields are set to 0. When the square-wave
`synthesizer is used, the sound specified by each triplet is generated once, and then the synthesizer
`stops.
`
`Four-Tone Synthesizer
`
`The four—tone synthesizer is used to produce harmonic sounds such as music. It can
`simultaneously generate four different sounds, each with its own frequency, phase, and
`waveform.
`
`11—226 Sound Driver Synthesizers
`
`Page 00006
`
`
`
`Page 00006
`
`
`
`The Sound Driver
`
`A four-tone synthesizer buffer has the following structure:
`
`TYPE FTSynthRec = RECORD
`
`INTEGER;
`mode:
`sndRec: FTSndRecPtr
`END;
`
`{always ftMode}
`{tones to play}
`
`FTSynthPtr = AFCI‘SynthRec;
`
`The sndRec field points to a four-tone record, which describes the four tones:
`
`TYPE FTSoundRec
`
`= RECORD
`
`INTEGER;
`duration:
`Fixed;
`sounleate:
`LONGINT;
`sounlehase:
`Fixed;
`soundZRate:
`LONGINT;
`soundZPhase:
`Fixed;
`sound3Rate:
`sound3Phase: LONGINT;
`sound4Rate:
`Fixed;
`sound4Phase:
`LONGINT;
`sounleave: WavePtr:
`sound2Wave: WavePtr:
`sound3Wave: WavePtr:
`sound4Wave: WavePtr:
`END;
`
`{duration in ticks}
`{tone 1 cycle rate}
`{tone 1 byte offset}
`{tone 2 cycle rate}
`{tone 2 byte offset}
`{tone 3 cycle rate}
`{tone 3 byte offset}
`{tone 4 cycle rate}
`{tone 4 byte offset}
`{tone 1 waveform}
`{tone 2 waveform}
`{tone 3 waveform}
`{tone 4 waveform}
`
`FT SndRecPtr = "E‘TSoundRec:
`
`Wave
`WavePtr
`
`= PACKED ARRAY[0. .255] OF Byte;
`= AWave;
`
`
`
`Assembly-language note: The address of the four-tone record currently in use is
`stored in the global variable SoundPtI.
`
`The duration integer indicates the number of ticks that the sound will be generated. Each phase
`long integer indicates the byte within the waveform description at which the synthesizer should
`begin producing sound (the first byte is byte number 0). Each rate value determines the speed at
`which the synthesizer cycles through the waveform, from 0 to 255.
`
`The four-tone synthesizer creates sound by starting at the byte in the waveform description
`specified by the phase, and skipping ahead the number of bytes specified by the rate field every
`44.93 microseconds; when the time specified by the duration has elapsed, the synthesizer stops.
`The rate field determines how the waveform will be "sampled", as shown in Figure 4. For
`nonperiodic waveforms, this is best illustrated by example: If the rate field is 1, each byte value
`in the waveform will be used, each producing sound for 44.93 microseconds. If the rate field is
`0.1, each byte will be used 10 times, each therefore producing sound for a total of 449.3
`microseconds. If the rate field is 5, only every fifth byte in the waveform will be sampled, each
`producing sound for 44.93 microseconds.
`
`
`
`1&qupunos3
`
`Sound Driver Synthesizers 11-227
`
`Page 00007
`
`Page 00007
`
`
`
`Inside Macintosh
`
`If the waveform contains one wavelength, the frequency that the rate corresponds to is given by:
`
`frequency (Hz) = 1000000 / (44.93 / (rate/256))
`
`You can use the Toolbox Utility routines FixMul and FixRatio to calculate this, as follows:
`
`frequency := FixMul(rate,FixRatio(22257,256))
`
`The maximum rate of 256 corresponds to approximately 22.3 kilohertz if the waveform contains
`one wavelength, and a rate of 0 produces no sound. A partial list of rate values and
`corresponding frequencies for notes is given in the summary at the end of this chapter.
`
`Free-Form Synthesizer
`
`The free—form synthesizer is used to synthesize complex music and speech. The sound to be
`produced is represented as a waveform whose complexity and length are limited only by available
`memory.
`
`A free—form synthesizer buffer has the following structure:
`
`TYPE FFSynthRec = RECORD
`INTEGER;
`mode:
`Fixed;
`count:
`waveBytes : FreeWave
`END;
`
`{always ffMode}
`{"sampling" factor}
`{waveform description}
`
`FFSynthPtr = AFE‘SynthRec;
`
`FreeWave
`
`= PACKED ARRAY[O..30000] OF Byte;
`
`The type FreeWave is declared with 30001 elements to allow you to pass a very long waveform.
`To be space-efficient, your application shouldn't declare a variable of type FreeWave; instead,
`you can do something like this:
`
`VAR antr: Ptr;
`myHandle: Handle;
`myFFPtr: FFSynthPtr;
`
`myHandle := NewHandle(buffSize);
`HLock(myHandle);
`myPtr := myHandle‘;
`myFFPtr
`:= FFSynthPtr(myPtr);
`myFFPtrA.mode := ffMode;
`myFFPtr“.count
`:= FixRatio(l,1);
`myFFPtr".waveBytes[0]
`:= 0;
`
`{allocate Space for the buffer}
`{lock the buffer]
`{dereference the handle}
`{coerce type to FFSynthPtr}
`{identify the synthesizer}
`{fill the buffer with values }
`{ describing the sound}
`
`StartSound(myPtr,buffSize,POINTER(—1));
`HUnlock(myHandle)
`
`{produce the sound}
`{unlock the buffer}
`
`where buffSize contains the number of bytes in the synthesizer buffer. This example
`dereferences handles instead of using pointers directly, to minimize the number of nonrelocatable
`objects in the heap.
`
`[1-228 Sound Driver Synthesizers
`
`Page 00008
`
`Page 00008
`
`
`
`W(
`
`I)o
`
`ESD
`
`1
`
`. U1v
`
`:a'
`
`The Sound Driver
`
`original wave
`
`M r
`
`ate field:
`
`M r
`
`ate field=
`
`v
`
`rate field = .5
`
`'
`
`Figure 4. Effect of the Rate Field
`
`Sound Driver Synthesizers 11-229
`
`Page 00009
`
`Page 00009
`
`
`
`Inside Macintosh
`
`The free-form synthesizer creates sound by starting at the first byte in the waveform and skipping
`ahead the number of bytes specified by count every 44.93 microseconds. The count field
`determines how the waveform will be "sampled"; it's analogous to the rate field of the four—tone
`synthesizer (see Figure 4 above). When the end of the waveform is reached, the synthesizer will
`stop.
`
`For periodic waveforms, you can determine the frequency of the wave cycle by using the
`following relationship:
`
`frequency (Hz) = 1000000 / (44.93 * (wavelength/count»
`
`You can calculate this with Toolbox Utility routines as follows:
`
`frequency := FixMul(count,FixRatio(22257,wavelength))
`
`The wavelength is given in bytes. For example, the frequency of a wave with a lOO-byte
`wavelength played at a count value of 2 would be approximately 445 Hz.
`
`
`
`USING THE SOUND DRIVER
`
`The Sound Driver is opened automatically when the system starts up. Its driver name is
`'.Sound', and its driver reference number is —4. To close or open the Sound Driver, you can use
`the Device Manager Close and Open functions. Because the driver is in ROM, there's really no
`reason to close it.
`
`To use one of the three types of synthesizers to generate sound, you can do the following: Use
`the Memory Manager function NewHandle to allocate heap space for a synthesizer buffer; then
`lock the buffer, fill it with values describing the sound, and make a StartSound call to the Sound
`Driver. StartSound can be called either synchronously or asynchronously (with an optional
`completion routine). When called synchronously, control returns to your application after the
`sound is completed. When called asynchronously, control returns to your application
`immediately, and your application is free to perform other tasks while the sound is produced.
`
`To produce continuous, unbroken sounds, it's sometimes advantageous to preallocate space for
`all the synthesizer buffers you require before you make the first StartSound call. Then, while one
`asynchronous StartSound call is being completed, you can calculate the waveform values for the
`next call.
`
`To avoid the click that may occur between StartSound calls when using the four-tone synthesizer,
`set the duration field to a large value and just change the value of one of the rate fields to start a
`new sound. To avoid the clicks that may occur during four-tone and free—form sound generation,
`fill the waveform description with multiples of 740 bytes.
`
`Warning: The Sound Driver uses interrupts to produce sound. If other device drivers are
`in use, they may turn off interrupts, making sound production unreliable. For instance, if
`the Disk Driver is accessing a disk during sound generation, a "crackling" sound may be
`produced.
`
`To determine when the sound initiated by a StartSound call has been completed, you can poll the
`SoundDone function. You can cancel any current StartSound call and any pending asynchronous
`StartSound calls by calling StopSound. By calling GetSoundVol and SetSoundVol, you can get
`and set the current speaker volume level.
`
`11-230 Sound Driver Synthesizers
`
`Page 00010
`
`Page 00010
`
`