ftp.nice.ch/pub/next/audio/apps/Reverb.1.3.N.bs.tar.gz#/Reverb/DEController.h

This is DEController.h in view mode; [Download] [Up]

/*
 *	DEController Object
 *	Copyright 1989 Metaresearch, Inc.
 *
 *	Created 10/10/89 by A. D. Laird
 *
 *	Modifications:
 *
 *	Description:
 *
 *	The DEController object is a subclass of the NeXT Sound object that offers 
 *	increased functionality and performance for users who desire more control over 
 *	the DSP port and the sound data that enters the NeXT.  In addition, the 
 *	DEController does all of the necessary memory stream allocation so that data of  
 *	arbitrary length can reliably be recorded from the DSP.  For information on the  
 *	Sound object, users should consult the documentation for the Sound object in  
 *	the NeXT Reference Manual. 
 *	
 *	The recording mechanism used by the DEController is based upon the DERecorder  
 *	object, a preliminary version of a general memory/stream control object that  
 *	will soon be available from Metaresearch.  This method differs significantly  
 *	from that used by the Sound object.  Consequently, users of the DEController  
 *	should NOT use the following methods that are implemented by the Sound object : 
 *	 
 *		- soundStructBeingProcessed	- soundBeingProcessed 
 *	
 *	Before data may be recorded, the appropriate memory channels must be set up,  
 *	and for recording from the DSP port, an assembler program must be downloaded to  
 *	the DSP.  This initialization is done via the prepareToRecord: method and takes  
 *	about a second.   If you do not call this method prior to recording, it is  
 *	called automatically before the recording actually begins.  Thus, if it is  
 *	important to start recording exactly, call prepareToRecord: first.  The  
 *	recording is prepared according to the parameters specified when the  
 *	DEController is created, or when you call the  
 *	setDataSize:dataFormat:samplingRate:channelCount:infoSize:  method.  
 *	
 *	When the recording is prepared, incoming data begins streaming to the delegate  
 *	via the dataBeingRecorded::: method (if implemented),  but it is not written to  
 *	disk.  The data begins writing to disk as soon as the record method is called.   
 *	Recording may be paused by calling the pause method.  Data continues to be sent  
 *	to the delegate, though it stops writing to disk.  To resume recording, call  
 *	resume.
 *
 *	Playback of a sound is accomplished by sending the play message to the  
 *	DEController.  To begin playback from somewhere other than the beginning of the  
 *	sound, use playFrom: instead.  For very large sounds, offsetting the sound data  
 *	may take a fraction of a second; thus, if it is important to begin playback at  
 *	an exact moment, call the prepareToPlayFrom: method first.  A sound which is  
 *	playing may also be paused and resumed, though when it is paused, data is not  
 *	sent to the delegate.
 * 
 *	In addition to the delegate methods provided by the Sound object, the  
 *	DEController's delegate  may also implement the following methods : 
 *	 
 *		- playPaused:		Called after playback is paused  
 *		- playResumed:		Called after playback resumes from a pause 
 *		- recordReady:		Called after the NeXT is set up for recording  
 *		- recordPaused:		Called after recording is paused  
 *		- recordResumed:	Called after recording resumes from a pause 
 *		- dataBeingPlayed::: 	Called during playback of sound 
 *		- dataBeingRecorded:::	Called during recording, even if paused 
 *	 
 *	The last two methods should be implemented by the DEController's delegate if  
 *	the data is to be processed further (to draw scope traces, animate meters,  
 *	compute voltage values, etc.).  When processing the data it is important to  
 *	know how many bytes per frame (channel-independent) are contained in the data.   
 *	This can be obtained by querying the DEController with the bytesPerFrame  
 *	message. 
 *	 
 *	During recording, the DEController's delegate is sent the dataBeingRecorded:::  
 *	message for every block of data that enters the DSP or CODEC.  If the delegate  
 *	does extensive processing or graphing of the data, the block may not be written  
 *	to disk in time for the next block to be accurately recorded.  For example, for  
 *	stereo DSP recording at 44.1 kHz sampling, the dataBeingRecorded::: method is  
 *	called over 40 times every second with around 1024 data points each time.  For  
 *	simple animation and computations this poses no problem; however, if your  
 *	delegate does extensive computation and graphics (e.g. if it computes the  
 *	Fourier transform on the data, draws the original trace, and then draws the  
 *	Fourier trace) there is no possible way to perform all of those operations 40  
 *	times a second. Depending upon the amount of additional processing your  
 *	delegate does, you may wish to process only every other chunk of data, or every  
 *	third, fourth or fifth chunk of data.  Though this may seem like a lot of  
 *	effort, it is the fastest way that you can manage the data in real time.  If  
 *	you do not care if a little bit of information is lost, you may do whatever you  
 *	like to the data; the next chunk will be sent after all of your processing is  
 *	done.  If it is critical that no data be lost, and you wish to do extensive  
 *	computations and animation with the data, the best alternative is to record the  
 *	data and save it to disk first with no additional processing, then process each  
 *	chunk of (saved) data separately as fast as your particular processing scheme  
 *	allows.  This will likely not be in realtime, but no data will be lost. 
 *	 
 *	If you only want to look at the incoming data , use the startTrace: method to  
 *	begin streaming in data from the specified input.  The data is sent to the  
 *	delegate via the dataBeingRecorded::: method (the same as for recording),  
 *	except that it is not written to disk.  To stop this data transfer, call the  
 *	stopTrace: method.  This "trace mode" will be disabled before recording or  
 *	playing any data.   
 *	
 *	Please refer to the DEController documentation for more details about using 
 *	the dataBeingPlayed::: and dataBeingRecorded::: delegate methods.
 */
 
#import <soundkit/Sound.h>

#define APP_FOLDER		"AppFolder"
#define	DSP_RECORD		"/usr/lib/sound/dsprecord.snd"

float SNDSamplesToSeconds(int sampleCount, int channelCount, float samplingRate);
int SNDSecondsToSamples(float secondCount, int channelCount, float samplingRate);

@interface DEController : Sound
{
    BOOL	traceOn;		// YES if trace mode is active
    char	recordPath[1024];	// location to save new recording
    int		offsetSamps;		// num samps to offset data for playFrom:
    int		offsetBytes;		// num bytes to offset data for playFrom:
    int		recordedBytes;		// num bytes recorded to disk
    int		curErr;			// current error num generated by object
    
    id		derecorder;		// recorder object; controls DMA streams
    id		timer;			// animator object; sends data during playback
    id		openPan;		// pointer to Open Panel
    id		savePan;		// pointer to Save Panel

/* Private Variables */
    BOOL		_doSend;
    int			_recFD, _maxSamps, _bytespersample;
    char		*_curData;
}

+ new;
+ newFromSoundfile:(char *)filename;

/******************************************************************************
 *
 * The following methods are defined in the Sound object and are
 * reimplemented in order for the DEController to function 
 * properly.  Comments are added where the method functions differently
 * from that described in the Sound object.
 *
 ******************************************************************************/
 
- (int)pause;
- pause:sender;
/*
 *	Pauses any recording or playback of the sound.  If the object is 
 *	currently recording, data continues to be sent to the delegate via 
 *	the dataBeingRecorded::: method, though it is not written to disk.
 *	If the object is currently playing, the object's delegate is no
 *	longer sent the dataBeingPlayed::: message.  After the playback
 *	or recording pauses, the object's delegate is sent the playPaused:
 *	or recordPaused: message, respectively.
 */
 
- (int)play;
- play:sender;
/*
 *	Begins playback of sound data through the NeXT.  During playback, 
 *	the object's delegate is constantly sent the data that is currently
 *	being played via the dataBeingPlayed::: method (if implemented).
 */
 
- (int)record;
- record:sender;
/*
 *	Begins actual recording of data.  If the prepareToRecord: method
 *	(described below) has not been called before this method, it is done
 *	just before the recording begins.  The parameters for recording are set 
 *	when the DEController is read from disk, or when the Sound object method, 
 *	setDataSize:dataFormat:samplingRate:channelCount:infoSize: is called.
 */

- (int)resume;
- resume:sender;
/*
 *	Resumes recording or playback of the sound.  After the playback
 *	or recording resumes, the object's delegate is sent the playResumed:
 *	or recordResumed: message, respectively.
 */

- (int)stop;
- stop:sender;

- (int)waitUntilStopped;
- (int)sampleCount;
- (int)samplesProcessed;

- (int)status;
/*
 *	Returns the current status of the DEController, which may be
 *	one of the following:
 *
 *		SK_STATUS_INITIALIZED		SK_STATUS_STOPPED
 *		SK_STATUS_PLAYING_PENDING	SK_STATUS_RECORDING_PENDING
 *		SK_STATUS_PLAYING		SK_STATUS_RECORDING
 *		SK_STATUS_PLAYING_PAUSED	SK_STATUS_RECORDING_PAUSED
 */ 

- (int)processingError;

/******************************************************************************
 *
 * The following are new methods defined in the DEController.
 *
 ******************************************************************************/

- (int)bytesPerFrame;
/*
 *	Returns the number of bytes in one (channel-independent) frame of data 
 */

- (int)playFrom:(int)startSample;
- (int)playFrom:(int)startSample until:(int)stopSample;
/*
 *	Begins playback of the sound from the specified 
 *	(channel-independent) start sample.  The second
 *	method allows the caller to specify the length
 *	of the selection to be played.
 */
 
- prepareToPlayFrom:(int)startSample;
/*
 *	Prepares playback of the sound from the specified 
 *	(channel-independent) start sample by offsetting 
 *	the soundStruct's data by the appropriate value.
 */
 
- (int)prepareToRecord;
- prepareToRecord:sender;
/*
 *	Prepare the NeXT for recording by setting up the appropriate
 *	data streams, loading DSP code, etc.  When this is done, the
 *	data begins streaming in and is sent to the delegate via the 
 *	dataBeingRecorded::: method (if implemented).  The method
 *	returns an error code.
 */
 
- (int)saveSound:(char *)savepath;
- save:sender;
/*
 *	Displays a save panel for the user to specify a location where the
 *	sound will be saved on disk.  If the user clicks the save panel's
 *	OK button, this method saves the sound and returns an error code.
 *	Otherwise, this method returns -1.
 */
 
- (int)openSound:(char *)openpath;
- open:sender;
/*
 *	Displays an open panel for the user to locate a sound saved on disk.
 *	If the user clicks the open panel's OK button, this method opens the
 *	sound and returns an error code. Otherwise, the method returns -1.
 */

- (int)setDspCode:(char *)file in:(char *)dir;
/*
 *	Sets the DSP code to be used for recording from the DSP.  The variable,
 *	"file", should be the filename of the code and may end in either ".lod"
 *	or ".snd".  The variable, "dir", should be the full path to the directory
 *	where the code is located.  If "dir" is set as the constant, APP_FOLDER,
 *	the method looks for the code in the application's .app folder.   
 */

- (char *)recordPath;
- setRecordPath:(char *)fullpath;
/*
 *	Gets/sets the location for saving newly-recorded sounds.  The variable, 
 *	"fullpath", should be a complete UNIX path with the ".snd" extension.
 *	In addition, the record path should be located on the internal hard disk 
 *	since writing sound data to optical disk 'on the fly' is unreliable.
 */
 
- (int)startTrace;
/*
 *	This method initiates the "trace mode" of the DEController, whereby
 *	data is constantly streamed to the delegate via the dataBeingRecorded:::
 *	method.  This method should not be called if the DEController is currently
 *	not stopped.
 */

- (int)stopTrace;
/*
 *	This method stops the "trace mode" of the DEController.
 */

- setTimerInterval:(float)dt;
/*
 *	This method sets the interval for sending playback data to the
 *	DEController's delegate.
 */

- (int)bytesRecorded;
/*
 *	This method returns the number of bytes actually written to
 *	disk during a recording.
 */

/******************************************************************************
 *
 * The following methods are used internally by the DEController for
 * messaging to the DERecorder object.  See the DERecorder documentation
 * for details.
 *
 ******************************************************************************/
 
- streamPrepared:sender;
- streamStopped:sender;
- dataBeingProcessed:sender:(char *)data:(int)numbytes;

@end


@interface DEDelegate:SoundDelegate

- playPaused:sender;
- playResumed:sender;

- recordReady:sender;
- recordPaused:sender;
- recordResumed:sender;

- dataBeingPlayed:sender:(char *)data:(int)playedsamples;
- dataBeingRecorded:sender:(char *)data:(int)datasamples;

@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.