{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;\f4\ftech Symbol;\f1\fmodern Ohlfs;}
\paperw13700
\paperh11400
\margl120
\margr120
{\colortbl;\red0\green0\blue0;}
\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\f0\b\i0\ulnone\fs36\fc0\cf0 TimeWarp
\pard\tx1340\tx2680\tx4020\tx5360\tx6720\tx8060\tx9400\tx10740\tx12080\tx13440\b0\fs24\fc0\cf0 \
by Robert Poor, NeXT Computer, Inc\
September 1992\
\

\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\b\fs28\fc0\cf0 Overview
\pard\tx1340\tx2680\tx4020\tx5360\tx6720\tx8060\tx9400\tx10740\tx12080\tx13440\b0\fs24\fc0\cf0 \
\
As powerful as it is, the NeXT Sound Kit
\f4 
\f0  doesn't give you many options for manipulating digital audio sound in real time.  On the other hand, programming at the Sound Driver level is complicated.  \
\
To simplify matters, we've created a 
\b DACPlayer
\b0  object that makes it easy to play digital audio sound through the built-in DACs on the NeXT computer.  Using the DACPlayer, you get a chance to manipulate sound data on the fly as it is sent to the DACs.\
\

\b TimeWarp
\b0  is a simple application that demonstrates one way you can use the DACPlayer object.  TimeWarp plays a sound file with a "speed control," much as you might find on a tape recorder, that lets you speed up and slow down the sound as it is played.  This version of TimeWarp uses simple linear interpolation between samples to change the effective playback rate.  While this approach has theoretical problems (interpolation is a form of low-pass filtering, you're subject to aliasing artifacts, etc), it sounds just fine for most sound sources and it's computationally simple.\
\
We use fixed point arithmetic in the inner loop, which interprets an int as a value with 1 sign bit, 15 bits of "whole part" and 16 bits of fraction.\
\

\b\fs28\fc1\cf1 About DACPlayer:
\b0\fs24\fc0\cf0 \
\
The file DACPlayer.h is well commented, but here are some additional notes on the use of the DACPlayer object:\
\
You will always set a delegate for the DACPlayer object, and at the very least, you will implement a 
\f1 playData:::
\f0  method. When the DACPlayer is run, it will call the following delegate methods:\
\

\f1\fc1\cf1 - willPlay :player;
\f0 \
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.\
\
\

\f1 - didPlay :player;
\f0 \
Called when the player goes into a stopped state (either from a stop or abort message) after all the sound resources have been freed.\
\
\

\f1 - playData :player :(char *)data :(int)nbytes;
\f0 \
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:\
\
\

\f1 - didChangeState :player from:(Pla_state_t)oldState to:(Pla_state_t)newState;
\f0 \
Called whenever the player changes state.  This method can be used to update status displays or perform certain operations, for example, when the DACPlayer stops.\
\

\b\fs28 Programming tips for DACPlayer:
\b0\fs24 \
\
You never need to call the 
\f1\fs28 prepare
\f0\fs24  method directly  you can always call the 
\f1 pause
\f0  method instead.  If the DACPlayer is in a stopped state, calling 
\f1 pause
\f0  will call 
\f1 prepare
\f0  for you.\
\
A good time to configure the DACPlayer parameters (regionSize, regionCount, samplingRate) is from within the 
\f1 willPlay:
\f0  delegate method.\
\
Call 
\f1 finish
\f0  rather than 
\f1 stop
\f0  if you want any queued data to get played rather than stopping immediately.\
\
The DACPlayer can only play what the built-in DAC can play, i.e. 16 bit stereo samples at sampling rates of either 44100 KHz or 22050 KHz.  (I don't mention that anywhere else, do I?)\
\
In theory (I haven't tested this), you can monitor how well the system is keeping up by watching how full the buffer queue stays.  In a call to 
\f1 playData:::
\f0 , compute 
\f1 headroom = [player samplesQueued] - [player samplesPlayed]
\f0 .  If headroom ever hits 0, you know that your 
\f1 playData:::
\f0  method has fallen behind in serving up samples to the sound driver.  (Did you hear a click?)\
\

\b\fs28 Changes since the last DACPlayer:
\b0\fs24 \
\
The previous version of DACPlayer didn't distingish (very well) between data that had been queued with the sound driver and sound data that has been played.  In particular, there was no clean way to stop the DACPlayer without cutting off the last few buffers of sound data.  Where before there was a single stop: method, there are now two methods:\
\

\f1 - stop;
\fs28 \

\f0\fs24 Calling the 
\f1\fs28 stop
\f0\fs24  method will stop the DACPlayer immediately, and any data that has been queued up is discarded.  \
\

\f1 - finish;
\fs28 \

\f0\fs24 Calling 
\f1\fs28 finish
\f0\fs24  will shut down the DACPlayer gracefully. If the DACPlayer state is PLA_RUNNING, then the DACPlayer will stop enqueuing new regions (and will stop calling 
\f1 playData:::
\f0 ) and will set the state to PLA_STOPPING.  Only when the last available buffer has been played by the sound driver will the DACPlayer stop.  A typical place to call the finish method is from within the delegate's 
\f1 playData:::
\f0  method when all incoming data has been processed.\
\
There are several new methods that make it easier to find out how much data is queued and how much data has actually been played since the last call to 
\f1\fs28 prepare:
\f0\fs24 \
\

\f1 - (int)bytesQueued;\
- (int)samplesQueued;\
- (int)framesQueued;\
- (double)secondsQueued;\
- (int)bytesPlayed;\
- (int)samplesPlayed;\
- (int)framesPlayed;\
- (double)secondsPlayed;\

\fs28 \

\f0\fs24 The priority of the DPSAddPort mechanism has been raised from 
\f1 NX_BASETHRESHOLD
\f0  to 
\f1 NX_MODALRESPTHRESHOLD
\f0  - this means that you can grab a slider with the mouse and the sound won't stop.\
\

\b\fs28 Future Directions:
\b0\fs24 \
\
A motivated progammer and lover of sound will consider the following rainy day programming tasks:\
\
Find and squash any bugs.  (Did I say it was perfect?)\
\
Make the necessary modifications so the application will compile cleanly under NeXTSTEP Release 3.0.\
\
Build in support for international language support and localization.\
\
Create a "Player" superclass and implement a "FilePlayer" subclass in addition to the DACPlayer.  A FilePlayer would have the same interface as the DACPlayer (except for some different configuration-setting methods) and would behave like the DACPlayer, but it would write its data to a file rather than the the DACs.\
\
Create other subclasses of Player that will send data out the DSP port to devices such as:\
	Singular Solutions A/D64x (AES/EBU and S/PDIF outputs)\
	Stealth Technologies ADA1800 (AES/EBU and 16bit DAC outputs)\
	Ariel ProPort 656 (16bit DAC outputs)\
	Ariel DATPort (AES/EBU and S/PDIF outputs)\
\
Search out and quash any "big-end/little-end" dependencies - NeXTSTEP 486 is coming.\

\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\fc1\cf1 \
Create a cool icon for the App.\
\

\pard\tx1140\tx2300\tx3440\tx4600\tx5760\tx6900\tx8060\tx9200\tx10360\tx11520\b\fs28\fc1\cf1 Other References
\b0\fs24 \
\
Valid for 2.0 \
Not valid  for 3.0 (compilesokay, but should use updated headers and Project Builder)\
\

}
