home *** CD-ROM | disk | FTP | other *** search
-
- #import <gamekit/gamekit.h>
- #import <daymisckit/daymisckit.h>
- #import <soundkit/soundkit.h>
- #import <sound/sound.h>
- #import <sys/param.h>
-
- @implementation GKSoundStream
-
- - init
- { // This method should be avoided.
- return [self initStreams:1];
- }
-
- - initStreams:(int)nstr
- {
- int i;
- id stream, timeLeft;
- if (!_initialized) [super init];
- else [self freeObjects];
- streamList = [[List alloc] initCount:nstr];
- timeLeftList = [[List alloc] initCount:nstr];
- device = [[NXSoundOut alloc] init]; // set up sound out device
- for (i=0; i<nstr; i++) {
- // In 3.1 need to use -initOnDevice:withParameters: to set this up
- // right and remove the obsolete play method used down below. *****
- stream = [[NXPlayStream alloc] initOnDevice:device];
- [stream activate]; // set up our output stream
- [streamList addObject:stream];
- timeLeft = [[DAYTime alloc] initWithCurrentTime];
- [timeLeftList addObject:timeLeft];
- }
- currentTime = [[DAYTime alloc] init]; // alloc here so only alloc'd once
- _initialized = YES; tag = 0;
- return self;
- }
-
- - playSoundStruct:(SNDSoundStruct *)sound
- { // We assume proper format sounds. Whatever object calls this one
- // should assure that any SNDSoundStruct passed in is for a sound
- // which is: (1) non-fragmented, (2) 16-bit linear, (3) 22.05 kHz,
- // and (4) mono. If you don't stick to this, weird things might
- // happen!!! (I don't check for any of this. In the future, I
- // probably should do so, and adjust for it. *****
- int i, best = 0; // num is stream num we choose
- id stream, time = [timeLeftList objectAt:best];
- long timeOnStream;
- // return if no data to play
- if (!sound) return self;
- [currentTime initWithCurrentTime];
- // find the stream which will be available soonest.
- #ifdef NOISYDEBUG
- fprintf(stderr, "GKSoundStream: Now is: %s (%d)\n",
- [currentTime stringValue], [currentTime microsecond]);
- fprintf(stderr, "GKSoundStream: Stream #%d: %s (%d)\n",
- 0, [time stringValue], [time microsecond]);
- #endif
- for (i=1; i<[streamList count]; i++) {
- id tempTime = [timeLeftList objectAt:i];
- #ifdef NOISYDEBUG
- fprintf(stderr, "GKSoundStream: Stream #%d: %s (%d)\n",
- i, [tempTime stringValue], [tempTime microsecond]);
- #endif
- if ([time isAfter:tempTime]) {
- time = tempTime;
- best = i;
- }
- }
- stream = [streamList objectAt:best];
- #ifdef NOISYDEBUG
- fprintf(stderr, "GKSoundStream: Best time is #%d.\n", best);
- #endif
- // enqueue the sound for playback
- [stream playBuffer:(char *)sound+sound->dataLocation
- size:sound->dataSize tag:tag++ channelCount:sound->channelCount
- samplingRate:sound->samplingRate];
- // estimate how long sound is to be on stream:
- // (based on 16it 22050 Hz mono sounds.)
- timeOnStream = (sound->dataSize / 2) * 45.3514739229;
- // set up when stream will be finished.
- if ([currentTime isAfter:time]) [time initWithCurrentTime]; // gap in play
- // (above 'if' fails if stuff is on the stream right now. Needed because
- // if there was a gap in stream playback, then we start playing NOW, but
- // it the stream is busy, then we start when it finishes.) Note that
- // realistically, I should add in a fudge factor if the if is true since
- // the stream doesn't start to play _immediately_. This seems to be
- // close enough for my purposes, though. Eventually, I may play with
- // adding in a fudge factor to try and take this into account. *****
- // Note: the stream delegate method - soundStream:didStartBuffer:
- // might be adequate here.
- [time addMicroseconds:timeOnStream];
- #ifdef NOISYDEBUG
- fprintf(stderr, "GKSoundStream: On stream for %ld usec.\n", timeOnStream);
- fprintf(stderr, "GKSoundStream: Estimate of time when done: %s (%d)\n\n",
- [time stringValue], [time microsecond]);
- #endif
- return time;
- }
-
- - freeObjects
- {
- [timeLeftList freeObjects];
- [timeLeftList free];
- [streamList freeObjects];
- [streamList free];
- [device free];
- [currentTime free];
- return self;
- }
-
- - free
- {
- [self freeObjects];
- return nil;
- }
-
- - streamList { return streamList; }
- - timeLeftList { return timeLeftList; }
-
- @end
-