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.