This is DACPlayer.h in view mode; [Download] [Up]
/* * DACPlayer.h * Implementation of an object to play sound over the soundout device (DACs). * * You may freely copy, distribute, and reuse the code in this example. * NeXT disclaims any warranty of any kind, expressed or implied, as to its * fitness for any particular use. * * Written by: Robert Poor * Created: Sep/92 */ #import <sound/sounddriver.h> #import <sound/soundstruct.h> /* Tag for DMA messages going to sndout */ #define WRITE_TAG 2 #define HIGH_WATER ((512+256)*1024) #define LOW_WATER (512 * 1024) #define READ_BUF_SIZE (vm_page_size / sizeof(short)) /* The states that the recorder can be in. */ typedef enum { PLA_STOPPED, /* stopped, ports & resources freed */ PLA_PAUSED, /* ports allocated, awaiting DMA size from host */ PLA_RUNNING, /* running... */ PLA_STOPPING, /* draining remaining regions before stopping */ N_PLA_STATES } Pla_state_t; /* * values for dacPlayerFlags */ typedef struct { unsigned int willPlay:1; /* does delegate respond to willPlay? */ unsigned int didPlay:1; /* ... */ unsigned int playData:1; unsigned int didChangeState:1; } dacplayer_flags_t; @interface DACPlayer:Object { Pla_state_t playerState; /* current state of the player object */ int regionsQueued; /* # of regions currently queued */ int bytesPlayed; int bytesQueued; id delegate; /* the target of notification messages */ int samplingRate; /* sampling rate 44100 or 22050 */ int regionSize; /* # of bytes per call to playData */ int regionCount; /* # of regions to be queued in advance */ /* * It's not necessarily safe to update parameters while the DAC is * running, so we squirrel away the user-settable parameters and update * from them only when it's safe... */ int newSamplingRate, newRegionSize, newRegionCount; port_t devicePort; port_t ownerPort; port_t streamPort; port_t replyPort; dacplayer_flags_t flags; /* various bits */ } - init; - free; /* * METHODS THAT CONTROL DACPLAYER */ - prepare; /* * Prepares the DACPlayer object for playing. * * Upon entry, if the DACPlayer is running, we stop it first with a call * to [dacPlayer stop]. The prepare method then acquires all the resources * it needs (ports, soundout, etc), and calls [delegate willPlay:self]. * Even though the stream is left in a "paused" state, the delegate method * [delegate playData:::] will be called regionCount times to fill up the * region queue. The DACPlayer state is set to PLA_PAUSED. * * Returns nil if some resource couldn't be acquired. */ - run; /* * Starts (or resumes) the DACPlayer. If the state is PLA_STOPPED, then * the run method first calls [self prepare] to set up the stream. Otherwise, * if the state is anything but PLA_PAUSED, run simply returns nil. * * Otherwise, the stream is "unpaused" and the DACPlayer will start sending * data to the DACs. The DACPlayer will start calling he delegate method * [delegate playData:::] to fetch the data to be played. * * The DACPlayer state is set to PLA_RUNNING. */ - pause; /* * Upon entry, if the DACPlayer state is PLA_STOPPED, the pause method * simply returns [self prepare]. If the state is anything else besides * PLA_RUNNING, the pause method returns nil. * * Suspend output to the DACs. This merely pauses the sound stream, so it * stops making requests of [delegate playData:::]. Note that any buffers * of data that have been queued won't get played until the stream is run * again. * * The DACPlayer state is set to PLA_PAUSED. */ - stop; /* * Stop playing immediately. * If the DACPlayer state is PLA_STOPPED, then this method simply returns. * Otherwise, it frees all the resources acquired in -setup, calls * [delegate didPlay:] and sets the state to PLA_STOPPED. */ - finish; /* * Do a graceful shutdown of the DACPlayer. * If the DACPlayer state is PLA_RUNNING, then the DACPlayer will stop * enqueuing new regions (and will stop calling playData:::) and will set * the state to PLA_STOPPING. When the last available buffer has been played * by the sound driver, then the DACPlayer will call [self stop]. This all * means that any sound that has been queued up will get played before the * DACPlayer shuts down. */ /* * METHODS THAT CONFIGURE DACPLAYER */ - delegate; - setDelegate:anObject; /* * get/set the delegate for the dacPlayer. Strictly speaking, you don't need * a delegate in order to use dacPlayer, but the delegate is responsible * for doing something interesting with the data buffers (via the didPlay::: * method) before the buffers are sent to the DACs. So you will always * supply a delegate with a didPlay::: method unless you want to send streams * of zeros to the DACs. */ - (int)regionSize; - (int)regionCount; - setRegionSize:(int)bytes andCount:(int)count; /* * Sets (or gets) the size of each sound region and the number of regions * that we keep queued up for the sound driver. */ - (int)samplingRate; - setSamplingRate:(int)aRate; /* * get/set the sampling rate for the DACs. aRate must be either 44100 (the * default) or 22050. Sampling rate changes won't take effect until the * next call to -prepare */ /* * METHODS THAT QUERY DACPLAYER */ - (Pla_state_t)playerState; /* * gets the current state of the dac player, one of: * PLA_STOPPED stopped and idle, no resources allocated * PLA_PAUSED no sound playing, DAC resources allocated * PLA_RUNNING sound actively playing, DAC resources allocated * PLA_STOPPING sound actively playing, but will stop soon */ - (int)bytesPlayed; - (int)samplesPlayed; - (int)framesPlayed; - (double)secondsPlayed; /* * These methods return how many bytes, samples, sample frames have actually * been sent to the DACs since the most recent call to -prepare. (NB: two * stereo samples make up one sample frame). */ - (int)bytesQueued; - (int)samplesQueued; - (int)framesQueued; - (double)secondsQueued; /* * These methods return how many bytes, samples, sample frames have been * queued up for playing (and possible played). */ @end /*** *** DELEGATE METHODS *** *** Description of the Player's delegate methods ***/ @interface PlayerDelegate:Object - willPlay :player; /* * Called by the player when going from a stopped to a paused state. Called * after all the resources have been allocated but before any regions get * queued. The various dacPlayer configuration parameters MAY be set from * a willPlay: method. */ - didPlay :player; /* * Called when the player goes into a stopped state (either from a stop or * abort message) after all the sound resources have been freed. */ - playData :player :(char *)data :(int)nbytes; /* * Called whenever the player wants more sound data. player is the dacPlayer * requesting the data, data is a buffer of length nbytes. The buffer is * guaranteed to be zero'd out. The dacPlayer requires that the samples you * write are stereo 16 bit samples. The samples will be played at whatever * sampling rate you established in a call to setSamplingRate: */ - didChangeState :player from:(Pla_state_t)oldState to:(Pla_state_t)newState; /* * Called whenever the player changes state. */ @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.