Important: Inside Macintosh: Sound is deprecated as of Mac OS X v10.5. For new audio development in Mac OS X, use Core Audio. See the Audio page in the ADC Reference Library.
Recording Sounds Directly From a Device
The Sound Input Manager provides a number of routines that you can use for low-level control over the recording process (such as the ability to intercept sound input data at interrupt time). You can open a sound input device and read data from it by calling these low-level Sound Input Manager routines. Several of those routines access information through a sound input parameter block, which is defined by theSPB
data type:
TYPE SPB = RECORD inRefNum: LongInt; {reference number of input device} count: LongInt; {number of bytes to record} milliseconds: LongInt; {number of milliseconds to record} bufferLength: LongInt; {length of buffer to record into} bufferPtr: Ptr; {pointer to buffer to record into} completionRoutine: ProcPtr; {pointer to a completion routine} interruptRoutine: ProcPtr; {pointer to an interrupt routine} userLong: LongInt; {for application's use} error: OSErr; {error returned after recording} unused1: LongInt; {reserved} END;TheinRefNum
field indicates the reference number of the sound input device from which the recording is to occur. You can obtain the reference number of the default sound input device by using theSPBOpenDevice
function.The
count
,milliseconds
, andbufferLength
fields jointly determine the length of recording. Thecount
field indicates the number of bytes to record; themilliseconds
field indicates the number of milliseconds to record; and thebufferLength
field indicates the length in bytes of the buffer into which the recorded sound data is to be placed. If thecount
andmilliseconds
fields are not equivalent, then the field which specifies the longer recording time is used. If the buffer specified by thebufferLength
field is shorter than this recording time, then the recording time is truncated so that the recorded data can fit into the buffer specified by thebufferPtr
field. The Sound Input Manager provides two functions,SPBMilliSecondsToBytes
andSPBBytesToMilliSeconds
, that allow you to convert between byte and millisecond values.After recording finishes, the
count
andmilliseconds
fields indicate the number of bytes and milliseconds actually recorded.The
completionRoutine
andinterruptRoutine
fields allow your application to define a sound input completion routine and a sound input interrupt routine, respectively. More information on these routines is provided later in this section.The
userLong
field contains a long integer that is provided for your application's own use. You can use this field, for instance, to pass a handle to an application-defined structure to the sound input completion or interrupt routine. Or, you can use this field to store the value of your application's A5 register, so that your sound input completion or interrupt routine can access your application's global variables. For more information on preserving the value of the A5 register, see the discussion of theSetA5
andSetCurrentA5
functions in the chapter "Memory Management Utilities" in Inside Macintosh: Memory.The
error
field describes any errors that occur during the recording. This field contains a value greater than 0 while recording unless an error occurs, in which case it contains a value less than 0 that indicates an operating system error. Your application can poll this field to check on the status of an asynchronous recording. If recording terminates without an error, this field contains 0.Listing 3-1 shows how to set up a sound parameter block and record synchronously using the
SPBRecord
function. This procedure takes one parameter, a handle to a block of memory in which the recorded sound data is to be stored. It is assumed that the block of memory is large enough to hold the sound to be recorded.Listing 3-1 Recording directly from a sound input device
PROCEDURE MyRecordSnd (mySndH: Handle); CONST kAsync = TRUE; kMiddleC = 60; VAR mySPB: SPB; {a sound input parameter block} myInRefNum: LongInt; {device reference number} myBuffSize: LongInt; {size of buffer to record into} myHeadrLen: Integer; {length of sound header} myNumChans: Integer; {number of channels} mySampSize: Integer; {size of a sample} mySampRate: Fixed; {sample rate} myCompType: OSType; {compression type} myErr: OSErr; BEGIN {Open the default input device for reading and writing.} myErr := SPBOpenDevice('', siWritePermission, myInRefNum); IF myErr = noErr THEN BEGIN {Get current settings of sound input device.} MyGetDeviceSettings(myInRefNum, myNumChans, mySampRate, mySampSize, myCompType); {Set up handle to contain the 'snd ' resource header.} myErr := SetupSndHeader(mySndH, myNumChans, mySampRate,mySampSize, myCompType, kMiddleC, 0, myHeadrLen); {Leave room in buffer for the sound resource header.} myBuffSize := GetHandleSize(mySndH) - myHeadrLen; {Lock down the sound handle until the recording is over.} HLockHi(mySndH); {Set up the sound input parameter block.} WITH mySPB do BEGIN inRefNum := myInRefNum; {input device reference number} count := myBuffSize; {number of bytes to record} milliseconds := 0; {no milliseconds} bufferLength := myBuffSize; {length of buffer} bufferPtr := Ptr(ORD4(mySndH^) + myHeadrLen); {put data after 'snd ' header} completionRoutine := NIL; {no completion routine} interruptRoutine := NIL; {no interrupt routine} userLong := 0; {no user data} error := noErr; {clear error field} unused1 := 0; {clear reserved field} END; {Record synchronously through the open sound input device.} myErr := SPBRecord(@mySPB, NOT kAsync); HUnlock(mySndH); {unlock the handle} {Indicate the number of bytes actually recorded.} myErr := SetupSndHeader(mySndH, myNumChans, mySampRate, mySampSize, myCompType, kMiddleC, mySPB.count, myHeadrLen); {Close the input device.} myErr := SPBCloseDevice(myInRefNum); END; END;TheMyRecordSnd
procedure defined in Listing 3-1 opens the default sound input device by using theSPBOpenDevice
function. You can specify one of two values for thepermission
parameter ofSPBOpenDevice
:
CONST siReadPermission = 0; {open device for reading} siWritePermission = 1; {open device for reading/writing}You must open a device for both reading and writing if you intend to use theSPBSetDeviceInfo
function or theSPBRecord
function. IfSPBOpenDevice
successfully opens the specified device for reading and writing,MyRecordSnd
calls theMyGetDeviceSettings
procedure (defined in Listing 3-3 on page 3-12). That procedure calls the Sound Input Manager functionSPBGetDeviceInfo
(explained in "Getting and Setting Sound Input Device Information" on page 3-10) to determine the current number of channels, sample rate, sample size, and compression type in use by the device.This information is then passed to the
SetupSndHeader
function, which sets up the handlemySndH
with a sound header describing the current device settings. After doing this,MyRecordSnd
sets up a sound input parameter block and calls theSPBRecord
function to record a sound. Note that the handle must be locked during the recording because the parameter block contains a pointer to the input buffer. After the recording is done,MyRecordSnd
once again calls theSetupSndHeader
function to fill in the actual number of bytes recorded.If the
MyRecordSnd
procedure defined in Listing 3-1 executes successfully, the handlemySndH
points to a resource of type'snd '
. Your application can then synchronously play the recorded sound, for example, by executing the following line of code:
myErr := SndPlay(NIL, mySndH, FALSE);For more information on playing sounds your application has recorded, see the chapter "Sound Manager" in this book.Defining a Sound Input Completion Routine
ThecompletionRoutine
field of the sound parameter block record contains the address of a completion routine that is executed when the recording terminates normally, either by reaching its prescribed time or size limits or by the application calling theSPBStopRecording
function. A completion routine should have the following format:
PROCEDURE MySICompletionRoutine (inParamPtr: SPBPtr);The completion routine is passed the address of the sound input parameter block that was passed to theSPBRecord
function. You can gain access to other data structures in your application by passing an address in theuserLong
field of the parameter block. After the completion routine executes, your application should check theerror
field of the sound input parameter block to see if an error code was returned.Your sound input interrupt routine is always called at interrupt time, so it should not call routines that might allocate or move memory or assume that A5 is set up. For more information on sound input interrupt routines, see "Sound Input Interrupt Routines" beginning on page 3-55.
Defining a Sound Input Interrupt Routine
TheinterruptRoutine
field of the sound input parameter block contains the address of a routine that executes when the internal buffers of an asynchronous recording device are filled. The internal buffers contain raw sound samples taken directly from the input device. The interrupt routine can modify the samples in the buffer in any way it requires. The processed samples are then written to the application buffer. If compression is enabled, the modified data is compressed after your interrupt routine operates on the samples and before the samples are written to the application buffer.Your sound input interrupt routine is always called at interrupt time, so it should not call routines that might allocate or move memory or assume that A5 is set up. For more information on sound input interrupt routines, see "Sound Input Interrupt Routines" beginning on page 3-55.