This is GKSoundStream.m in view mode; [Download] [Up]
#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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.