ftp.nice.ch/pub/next/audio/player/TimeWarp.s.tar.gz#/TimeWarp/DACPlayer.h

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.