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.