Index: Source/NSSound.m =================================================================== --- Source/NSSound.m (revision 28325) +++ Source/NSSound.m (working copy) @@ -32,20 +32,26 @@ #include "AppKit/NSPasteboard.h" #include "AppKit/NSSound.h" -#ifdef HAVE_AUDIOFILE_H -#include +#include "NSSoundPrivate.h" +#include "NSSound+AU.h" +#include "NSSound+WAV.h" + +#if defined(HAVE_SNDFILE_H) +#include #endif -#define BUFFER_SIZE_IN_FRAMES 4096 +#if defined(HAVE_AL_AL_H) +#include +#include -#define DEFAULT_CHANNELS 2 +static ALCdevice *device = NULL; +static ALCcontext *context = NULL; +#endif /* Class variables and functions for class methods */ static NSMutableDictionary *nameDict = nil; static NSDictionary *nsmapping = nil; -#define GSNDNAME @"GNUstepGSSoundServer" - @implementation NSBundle (NSSoundAdditions) - (NSString *) pathForSoundResource: (NSString *)name @@ -60,10 +66,10 @@ unsigned i; for (i = 0; path == nil && i < c; i++) - { - ext = [types objectAtIndex: i]; - path = [self pathForResource: name ofType: ext]; - } + { + ext = [types objectAtIndex: i]; + path = [self pathForResource: name ofType: ext]; + } } else { @@ -75,300 +81,131 @@ @end address@hidden GSSoundSvr - -- (BOOL) playSound: (id)aSound; -- (BOOL) stopSoundWithIdentifier: (NSString *)identifier; -- (BOOL) pauseSoundWithIdentifier: (NSString *)identifier; -- (BOOL) resumeSoundWithIdentifier: (NSString *)identifier; -- (BOOL) isPlayingSoundWithIdentifier: (NSString *)identifier; - address@hidden - @interface NSSound (PrivateMethods) -+ (id) gsnd; -+ (void) localServer: (id)s; -+ (id) lostServer: (NSNotification*)notification; +- (BOOL) _getContext; +- (BOOL) _bufferData; -- (BOOL) getDataFromFileAtPath: (NSString *)path; -- (void) setIdentifier: (NSString *)identifier; -- (NSString *) identifier; -- (float) samplingRate; -- (float) frameSize; -- (long) frameCount; -- (NSData *) data; - @end @implementation NSSound (PrivateMethods) -#ifdef HAVE_AUDIOFILE_H -static id the_server = nil; - -+ (id) gsnd +#if defined(HAVE_AL_AL_H) +- (BOOL) _getContext { - if (the_server == nil) + if ((context = alcGetCurrentContext()) == NULL) { - NSString *host; - NSString *description; - - host = [[NSUserDefaults standardUserDefaults] stringForKey: @"NSHost"]; - if (host == nil) - { - host = @""; - } - else - { - NSHost *h = [NSHost hostWithName: host]; - if (h == nil) - { - NSLog(@"Unknown NSHost (%@) ignored", host); - host = @""; - } - else if ([h isEqual: [NSHost currentHost]] == YES) - { - host = @""; - } - else - { - host = [h name]; - } - } - - if ([host length] == 0) - { - description = @"local host"; - } - else - { - description = host; - } - - the_server = (id)[NSConnection - rootProxyForConnectionWithRegisteredName: GSNDNAME host: host]; - - if (the_server == nil && [host length] > 0) - { - NSString *service = [GSNDNAME stringByAppendingFormat: @"-%@", host]; - - the_server = (id)[NSConnection - rootProxyForConnectionWithRegisteredName: service host: @"*"]; - } - - if (RETAIN ((id)the_server) != nil) - { - NSConnection* conn = [(id)the_server connectionForProxy]; - - [[NSNotificationCenter defaultCenter] - addObserver: self - selector: @selector(lostServer:) - name: NSConnectionDidDieNotification - object: conn]; - } - else - { - static BOOL recursion = NO; - static NSString *cmd = nil; - static NSArray *args = nil; - - if (cmd == nil && recursion == NO) - { - cmd = [NSTask launchPathForTool: @"gnustep_sndd"]; - } - - if (recursion == YES || cmd == nil) - { - NSLog(@"Unable to contact sound server - " - @"please ensure that gnustep_sndd is running for address@hidden", - description); - return nil; - } - else - { - NSLog(@"\nI couldn't contact the sound server for %@ -\n" - @"so I'm attempting to to start one - which will take a few seconds.\n" - @"Trying to launch gnustep_sndd from %@ or a machine/operating-system subdirectory.\n" - @"It is recommended that you start the sound server (gnustep_sndd) when\n" - @"your windowing system is started up.\n", description, - [cmd stringByDeletingLastPathComponent]); - - if ([host length] > 0) - { - args = [[NSArray alloc] initWithObjects: @"-NSHost", host, nil]; - } - - [NSTask launchedTaskWithLaunchPath: cmd arguments: args]; - - [NSTimer scheduledTimerWithTimeInterval: 5.0 - invocation: nil repeats: NO]; - - [[NSRunLoop currentRunLoop] runUntilDate: - [NSDate dateWithTimeIntervalSinceNow: 5.0]]; - - recursion = YES; - [self gsnd]; - recursion = NO; - } - } + device = alcOpenDevice (NULL); + if (device == NULL) + { + return NO; + } + context = alcCreateContext (device, NULL); + alcMakeContextCurrent (context); + if (alGetError() != AL_NO_ERROR) + { + return NO; + } } - - return the_server; + device = alcGetContextsDevice (context); + + return YES; } -+ (void) localServer: (id)s +- (BOOL) _bufferData { - the_server = s; -} - -+ (id) lostServer: (NSNotification*)notification -{ - id obj = the_server; - - the_server = nil; - [[NSNotificationCenter defaultCenter] - removeObserver: self - name: NSConnectionDidDieNotification - object: [notification object]]; - RELEASE (obj); - return self; -} - -- (BOOL) getDataFromFileAtPath: (NSString *)path -{ - NSMutableData *d; - AFfilehandle file; - AFframecount framesRead; - void *buffer; - -#define CHECK_AF_ERR(x) \ -if ((x) == -1) { \ -afCloseFile(file); \ -return NO; \ -} - - if ((file = afOpenFile([path fileSystemRepresentation], "r", NULL)) - == AF_NULL_FILEHANDLE) + ALenum format; + + alGenSources (1, &_sndSource); + if (alGetError() != AL_NO_ERROR) { return NO; } - - _dataFormat = AF_SAMPFMT_TWOSCOMP; - CHECK_AF_ERR (afSetVirtualSampleFormat(file, AF_DEFAULT_TRACK, _dataFormat, 16)); - _channelCount = DEFAULT_CHANNELS; - CHECK_AF_ERR (afSetVirtualChannels(file, AF_DEFAULT_TRACK, _channelCount)); - CHECK_AF_ERR (_samplingRate = afGetRate(file, AF_DEFAULT_TRACK)); - CHECK_AF_ERR (_frameCount = afGetFrameCount(file, AF_DEFAULT_TRACK)); - CHECK_AF_ERR (_frameSize = afGetVirtualFrameSize(file, AF_DEFAULT_TRACK, 1)); - CHECK_AF_ERR (_dataLocation = afGetDataOffset(file, AF_DEFAULT_TRACK)); - - buffer = NSZoneMalloc(NSDefaultMallocZone(), BUFFER_SIZE_IN_FRAMES * _frameSize); - d = [[NSMutableData alloc] initWithCapacity: 1]; - - CHECK_AF_ERR (framesRead = afReadFrames(file, AF_DEFAULT_TRACK, buffer, - BUFFER_SIZE_IN_FRAMES)); - while (framesRead > 0) - { - [d appendBytes: (const void *)buffer - length: framesRead * _frameSize]; - CHECK_AF_ERR (framesRead = afReadFrames(file, AF_DEFAULT_TRACK, buffer, - BUFFER_SIZE_IN_FRAMES)); + alSourcef (_sndSource, AL_MIN_GAIN, 0.0); + alSourcef (_sndSource, AL_MAX_GAIN, 1.0); + if (alGetError() != AL_NO_ERROR) + { + return NO; } - - _data = d; - _dataSize = [_data length]; - NSZoneFree(NSDefaultMallocZone(), buffer); - afCloseFile(file); - + + alGenBuffers (1, &_sndBuffer); + if (alGetError() != AL_NO_ERROR) + { + return NO; + } + + switch (_channelCount) + { + case 1: format = AL_FORMAT_MONO16; + break; + case 2: format = AL_FORMAT_STEREO16; + break; + default: format = 0; + } + + alBufferData (_sndBuffer, format, [_data bytes], + (ALsizei)[_data length], (ALsizei)_sampleRate); + if (alGetError() != AL_NO_ERROR) + { + NSLog (@"Could not buffer"); + return NO; + } + + alSourcei (_sndSource, AL_BUFFER, _sndBuffer); return YES; } - #else -/* No sound software */ - -+ (id) gsnd +- (BOOL) _getContext { - return nil; + NSLog(@"NSSound: No sound software installed, cannot create context"); + return NO; } -+ (void) localServer: (id)s +- (BOOL) _bufferData { -} - -+ (id) lostServer: (NSNotification*)notification -{ - return self; -} - -- (BOOL) getDataFromFileAtPath: (NSString *)path -{ - NSLog(@"NSSound: No sound software installed, cannot get sound"); + NSLog(@"NSSound: No sound software installed, cannot buffer sound"); return NO; } #endif -- (void) setIdentifier: (NSString *)identifier -{ - ASSIGN (_uniqueIdentifier, identifier); -} - -- (NSString *) identifier -{ - return _uniqueIdentifier; -} - -- (float) samplingRate -{ - return _samplingRate; -} - -- (float) frameSize -{ - return _frameSize; -} - -- (long) frameCount -{ - return _frameCount; -} - -- (NSData *) data -{ - return _data; -} - @end @implementation NSSound + (void) initialize { - if (self == [NSSound class]) + if (self == [NSSound class]) { NSString *path = [NSBundle pathForLibraryResource: @"nsmapping" - ofType: @"strings" - inDirectory: @"Sounds"]; - [self setVersion: 1]; + ofType: @"strings" + inDirectory: @"Sounds"]; + [self setVersion: 2]; nameDict = [[NSMutableDictionary alloc] initWithCapacity: 10]; - if (path) - { - nsmapping = RETAIN([[NSString stringWithContentsOfFile: path] - propertyListFromStringsFileFormat]); - } + if (path) + { + nsmapping = RETAIN([[NSString stringWithContentsOfFile: path] + propertyListFromStringsFileFormat]); + } } } - (void) dealloc { TEST_RELEASE (_data); - if ((_name != nil) && self == [nameDict objectForKey: _name]) + if ((_name != nil) && self == [nameDict objectForKey: _name]) { [nameDict removeObjectForKey: _name]; } +#if defined(HAVE_AL_AL_H) + alDeleteSources (1, &_sndSource); + alDeleteBuffers (1, &_sndBuffer); +#endif TEST_RELEASE (_name); - TEST_RELEASE (_uniqueIdentifier); + TEST_RELEASE (_playbackDeviceIdentifier); + TEST_RELEASE (_channelMap); + NSZoneFree(NSDefaultMallocZone(), _data); [super dealloc]; } @@ -377,20 +214,25 @@ // - (id) initWithContentsOfFile: (NSString *)path byReference:(BOOL)byRef { - self = [super init]; + _onlyReference = byRef; + ASSIGN (_name, [path lastPathComponent]); + [nameDict setObject: self forKey: _name]; + + { + NSData *fileData; + + fileData = [NSData dataWithContentsOfMappedFile: path]; + if (!fileData) + { + NSLog (@"Could not get sound data from: %@", path); + DESTROY(self); + return nil; + } + + [self initWithData: fileData]; + RELEASE(fileData); + } - if (self) - { - _onlyReference = byRef; - ASSIGN (_name, [path lastPathComponent]); - _uniqueIdentifier = nil; - if ([self getDataFromFileAtPath: path] == NO) - { - NSLog(@"Could not get sound data from %@", path); - DESTROY (self); - } - } - return self; } @@ -402,13 +244,19 @@ - (id) initWithData: (NSData *)data { - [self notImplemented: _cmd]; - return nil; + NSRange range = NSMakeRange (0,0); + return [self initWithData: data + raw: NO + range: range + format: GSSoundFormatUnknown + channels: 0 + sampleRate: 0 + byteOrder: NS_UnknownByteOrder]; } - (id) initWithPasteboard: (NSPasteboard *)pasteboard { - if ([NSSound canInitWithPasteboard: pasteboard] == YES) + if ([NSSound canInitWithPasteboard: pasteboard] == YES) { NSData *d = [pasteboard dataForType: @"NSGeneralPboardType"]; return [self initWithData: d]; @@ -417,49 +265,149 @@ } // -// Playing +// Playing and Information // +#if defined(HAVE_AL_AL_H) + - (BOOL) pause { - if (_uniqueIdentifier) + alSourcePause (_sndSource); + return (alGetError() == AL_NO_ERROR ? YES : NO); +} + +- (BOOL) play +{ + alSourcePlay (_sndSource); + return (alGetError() == AL_NO_ERROR ? YES : NO); +} + +- (BOOL) resume +{ + ALint value; + alGetSourcei (_sndSource, AL_SOURCE_STATE, &value); + if (value == AL_PLAYING) { - return [[NSSound gsnd] pauseSoundWithIdentifier: _uniqueIdentifier]; - } + return YES; + } + alSourcePlay (_sndSource); + return (alGetError() == AL_NO_ERROR ? YES : NO); +} + +- (BOOL) stop +{ + alSourceStop (_sndSource); + return (alGetError() == AL_NO_ERROR ? YES : NO); +} + +- (BOOL) isPlaying +{ + ALint value; + alGetSourcei (_sndSource, AL_SOURCE_STATE, &value); + return (value == AL_PLAYING ? YES : NO); +} + +- (float) volume +{ + ALfloat value; + alGetSourcef (_sndSource, AL_GAIN, &value); + return (float)value; +} + +- (void) setVolume: (float) volume +{ + alSourcef (_sndSource, AL_GAIN, (ALfloat)volume); +} + +- (NSTimeInterval) currentTime +{ + ALfloat value; + alGetSourcef (_sndSource, AL_SEC_OFFSET, &value); + return (NSTimeInterval)value; +} + +- (void) setCurrentTime: (NSTimeInterval) currentTime +{ + alSourcef (_sndSource, AL_SEC_OFFSET, (ALfloat)currentTime); +} + +- (BOOL) loops +{ + ALint value; + alGetSourcei (_sndSource, AL_LOOPING, &value); + return (value == AL_TRUE ? YES : NO); +} + +- (void) setLoops: (BOOL) loops +{ + ALint value; + (loops == YES) ? (value = AL_TRUE) : (value = AL_FALSE); + alSourcei (_sndSource, AL_LOOPING, value); +} + +#else + +- (BOOL) pause +{ return NO; } - (BOOL) play { - return [[NSSound gsnd] playSound: self]; + return NO; } - (BOOL) resume { - if (_uniqueIdentifier) - { - return [[NSSound gsnd] resumeSoundWithIdentifier: _uniqueIdentifier]; - } return NO; } - (BOOL) stop { - if (_uniqueIdentifier) - { - return [[NSSound gsnd] stopSoundWithIdentifier: _uniqueIdentifier]; - } return NO; } - (BOOL) isPlaying { - if (_uniqueIdentifier) - { - return [[NSSound gsnd] isPlayingSoundWithIdentifier: _uniqueIdentifier]; - } return NO; } +- (float) volume +{ + return 0.0; +} + +- (void) setVolume: (float) volume +{ + return; +} + +- (NSTimeInterval) currentTime; +{ + return 0.0; +} + +- (void) setCurrentTime: (NSTimeInterval) currentTime +{ + return; +} + +- (BOOL) loops; +{ + return NO; +} + +- (void) setLoops: (BOOL) loops +{ + return; +} + +#endif + +- (NSTimeInterval) duration +{ + return _duration; +} + // // Working with pasteboards // @@ -508,14 +456,14 @@ NSString *realName = [nsmapping objectForKey: name]; NSSound *sound; - if (realName) + if (realName) { name = realName; } sound = (NSSound *)[nameDict objectForKey: name]; - if (sound == nil) + if (sound == nil) { NSString *extension; NSString *path = nil; @@ -530,7 +478,7 @@ main_bundle = [NSBundle mainBundle]; extension = [name pathExtension]; - if (extension != nil && [extension length] == 0) + if (extension != nil && [extension length] == 0) { extension = nil; } @@ -538,7 +486,7 @@ /* Check if extension is one of the sound types */ array = [NSSound soundUnfilteredFileTypes]; - if ([array indexOfObject: extension] != NSNotFound) + if ([array indexOfObject: extension] != NSNotFound) { /* Extension is one of the sound types So remove from the name */ @@ -553,7 +501,7 @@ } /* First search locally */ - if (extension) + if (extension) { path = [main_bundle pathForResource: the_name ofType: extension]; } @@ -562,10 +510,10 @@ id o, e; e = [array objectEnumerator]; - while ((o = [e nextObject])) + while ((o = [e nextObject])) { path = [main_bundle pathForResource: the_name ofType: o]; - if (path != nil && [path length] != 0) + if (path != nil && [path length] != 0) { break; } @@ -573,9 +521,9 @@ } /* If not found then search in system */ - if (!path) + if (!path) { - if (extension) + if (extension) { path = [NSBundle pathForLibraryResource: the_name ofType: extension @@ -590,7 +538,7 @@ path = [NSBundle pathForLibraryResource: the_name ofType: o inDirectory: @"Sounds"]; - if (path != nil && [path length] != 0) + if (path != nil && [path length] != 0) { break; } @@ -598,12 +546,12 @@ } } - if ([path length] != 0) + if ([path length] != 0) { sound = [[self allocWithZone: NSDefaultMallocZone()] initWithContentsOfFile: path byReference: NO]; - if (sound != nil) + if (sound != nil) { [sound setName: name]; RELEASE(sound); @@ -619,9 +567,18 @@ + (NSArray *) soundUnfilteredFileTypes { - return [NSArray arrayWithObjects: @"aiff", @"waw", @"snd", @"au", nil]; + return [NSArray arrayWithObjects: @"wav", @"aiff", @"aifc", @"aif", @"au", @"snd", +#if defined(HAVE_SNDFILE_H) + @"mat", @"mat4", @"mat5", @"paf", @"sf", @"voc", @"w64", @"xi", @"caf", @"sd2", @"flac", @"ogg", @"oga", +#endif + nil]; } ++ (NSArray *) soundUnfilteredTypes +{ + return [NSArray arrayWithObjects: nil]; +} + - (NSString *) name { return _name; @@ -631,12 +588,12 @@ { BOOL retained = NO; - if (!aName || [nameDict objectForKey: aName]) + if (!aName || [nameDict objectForKey: aName]) { return NO; } - if ((_name != nil) && self == [nameDict objectForKey: _name]) + if ((_name != nil) && self == [nameDict objectForKey: _name]) { /* We retain self in case removing from the dictionary releases us */ @@ -648,7 +605,7 @@ ASSIGN(_name, aName); [nameDict setObject: self forKey: _name]; - if (retained) + if (retained) { RELEASE (self); } @@ -656,7 +613,178 @@ return YES; } +- (NSString *) playbackDeviceIdentifier +{ + [self notImplemented: _cmd]; + return nil; +} + +- (void) setPlaybackDeviceIdentifier: (NSString *)playbackDeviceIdentifier +{ + [self notImplemented: _cmd]; +} + +- (NSArray *) channelMapping +{ + [self notImplemented: _cmd]; + return nil; +} + +- (void) setChannelMapping: (NSArray *)channelMapping +{ + [self notImplemented: _cmd]; +} + // +// GNUstep Additions +// +#if defined(HAVE_SNDFILE_H) +- (id)initWithData: (NSData *)data + raw: (BOOL)raw + range: (NSRange)range + format: (int)format + channels: (int)channels + sampleRate: (int)sampleRate + byteOrder: (NSByteOrder)byteOrder +{ + SNDFILE *file; + SF_INFO fileInfo; + SoundData soundData; + long itemsRead; + long bufferSize; + short *buffer; + + _playbackDeviceIdentifier = nil; + _channelMap = nil; + + soundData.currentPosition = 0; + soundData.data = (NSMutableData *)data; + + if (raw) + { + fileInfo.format = SF_FORMAT_RAW; + switch (format) + { + case GSSoundFormatUnknown: RELEASE(self); + return nil; + case GSSoundFormatPCMS8: fileInfo.format |= SF_FORMAT_PCM_S8; + break; + case GSSoundFormatPCM16: fileInfo.format |= SF_FORMAT_PCM_16; + break; + case GSSoundFormatPCM24: fileInfo.format |= SF_FORMAT_PCM_24; + break; + case GSSoundFormatPCM32: fileInfo.format |= SF_FORMAT_PCM_32; + break; + case GSSoundFormatPCMU8: fileInfo.format |= SF_FORMAT_PCM_U8; + break; + case GSSoundFormatFloat32: fileInfo.format |= SF_FORMAT_FLOAT; + break; + case GSSoundFormatFloat64: fileInfo.format |= SF_FORMAT_DOUBLE; + break; + case GSSoundFormatULaw: fileInfo.format |= SF_FORMAT_ULAW; + break; + case GSSoundFormatALaw: fileInfo.format |= SF_FORMAT_ALAW; + break; + default: RELEASE(self); + return nil; + } + switch (byteOrder) + { + case NS_UnknownByteOrder: fileInfo.format |= SF_ENDIAN_CPU; + break; + case NS_LittleEndian: fileInfo.format |= SF_ENDIAN_LITTLE; + break; + case NS_BigEndian: fileInfo.format |= SF_ENDIAN_BIG; + break; + default: RELEASE(self); + break; + } + + if (channels != 1 || channels != 2) + { + RELEASE(self); + return nil; + } + fileInfo.channels = channels; + fileInfo.samplerate = sampleRate; + } + else + { + fileInfo.format = 0; + } + + if ((file = sf_open_virtual (&dataIO, SFM_READ, &fileInfo, &soundData)) == NULL) + { + NSLog (@"Could not read data!"); + DESTROY(self); + return nil; + } + + _channelCount = (int)fileInfo.channels; + _sampleRate = (int)fileInfo.samplerate; + _frameCount = (long)fileInfo.frames; + _duration = (NSTimeInterval)((double)_frameCount) / ((double)_sampleRate); + NSLog (@"duration = %f", _duration); + + bufferSize = _frameCount * _channelCount * sizeof(short); + buffer = NSZoneMalloc(NSDefaultMallocZone(), bufferSize); + /** The 1 bit shift of bufferSize servers as a way to divide it by 2 */ + itemsRead = sf_read_short (file, buffer, (bufferSize>>1)); + + _data = [[NSData alloc] initWithBytesNoCopy: buffer + length: (NSUInteger)(itemsRead<<1) + freeWhenDone: YES]; + + sf_close (file); + + if ([self _getContext] == NO) + { + NSLog (@"Could not get context"); + DESTROY (self); + return nil; + } + if ([self _bufferData] == NO) + { + NSLog (@"Could not buffer data!"); + DESTROY (self); + return nil; + } + + return self; +} + +#else + +- (id)initWithData: (NSData *)data + raw: (BOOL)raw + range: (NSRange)range + format: (int)format + channels: (int)channels + sampleRate: (int)sampleRate + byteOrder: (NSByteOrder)byteOrder +{ + if (raw) + { + /* FIXME: do nothing for now */ + } + else + { + if ([isa _soundIsAU: data]) + { + return [self _initSoundWithAU: data]; + } + if ([isa _soundIsWAV: data]) + { + return [self _initSoundWithWAV: data]; + } + } + + RELEASE(self); + return nil; +} +#endif + +// // NSCoding // - (void) encodeWithCoder: (NSCoder *)coder @@ -670,26 +798,20 @@ [coder encodeValueOfObjCType: @encode(BOOL) at: &_onlyReference]; [coder encodeObject: _name]; - if (_onlyReference == YES) - { - return; - } - - if (_uniqueIdentifier != nil) - { - [coder encodeObject: _uniqueIdentifier]; - } - + if (_onlyReference == YES) + { + return; + } [coder encodeConditionalObject: _delegate]; - [coder encodeValueOfObjCType: @encode(long) at: &_dataLocation]; - [coder encodeValueOfObjCType: @encode(long) at: &_dataSize]; - [coder encodeValueOfObjCType: @encode(int) at: &_dataFormat]; - [coder encodeValueOfObjCType: @encode(float) at: &_samplingRate]; - [coder encodeValueOfObjCType: @encode(float) at: &_frameSize]; + [coder encodeValueOfObjCType: @encode(NSTimeInterval) at: &_duration]; [coder encodeValueOfObjCType: @encode(long) at: &_frameCount]; + [coder encodeValueOfObjCType: @encode(int) at: &_sampleRate]; [coder encodeValueOfObjCType: @encode(int) at: &_channelCount]; + [coder encodeValueOfObjCType: @encode(unsigned int) at: &_sndSource]; + [coder encodeValueOfObjCType: @encode(unsigned int) at: &_sndBuffer]; + /* FIXME: need to encode _data */ - [coder encodeObject: _data]; + [coder encodeObject: _playbackDeviceIdentifier]; } } @@ -703,30 +825,29 @@ { [decoder decodeValueOfObjCType: @encode(BOOL) at: &_onlyReference]; - if (_onlyReference == YES) - { - NSString *theName = [decoder decodeObject]; - - RELEASE (self); - self = RETAIN ([NSSound soundNamed: theName]); - [self setName: theName]; - } + if (_onlyReference == YES) + { + NSString *theName = [decoder decodeObject]; + + RELEASE (self); + self = RETAIN ([NSSound soundNamed: theName]); + [self setName: theName]; + } else - { - _name = TEST_RETAIN ([decoder decodeObject]); - _uniqueIdentifier = TEST_RETAIN ([decoder decodeObject]); - [self setDelegate: [decoder decodeObject]]; - - [decoder decodeValueOfObjCType: @encode(long) at: &_dataLocation]; - [decoder decodeValueOfObjCType: @encode(long) at: &_dataSize]; - [decoder decodeValueOfObjCType: @encode(int) at: &_dataFormat]; - [decoder decodeValueOfObjCType: @encode(float) at: &_samplingRate]; - [decoder decodeValueOfObjCType: @encode(float) at: &_frameSize]; - [decoder decodeValueOfObjCType: @encode(long) at: &_frameCount]; - [decoder decodeValueOfObjCType: @encode(int) at: &_channelCount]; - - _data = RETAIN([decoder decodeObject]); - } + { + _name = TEST_RETAIN ([decoder decodeObject]); + [self setDelegate: [decoder decodeObject]]; + + [decoder decodeValueOfObjCType: @encode(NSTimeInterval) at: &_duration]; + [decoder decodeValueOfObjCType: @encode(long) at: &_frameCount]; + [decoder decodeValueOfObjCType: @encode(int) at: &_sampleRate]; + [decoder decodeValueOfObjCType: @encode(int) at: &_channelCount]; + [decoder decodeValueOfObjCType: @encode(unsigned int) at: &_sndSource]; + [decoder decodeValueOfObjCType: @encode(unsigned int) at: &_sndBuffer]; + /* FIXME: need to decode _data */ + + _playbackDeviceIdentifier = RETAIN([decoder decodeObject]); + } } return self; } @@ -741,11 +862,10 @@ // - (id) copyWithZone: (NSZone *)zone { + /* FIXME: need to copy _data and all the other stuff */ NSSound *newSound = (NSSound *)NSCopyObject(self, 0, zone); - newSound->_data = [_data copyWithZone: zone]; - newSound->_name = [_name copyWithZone: zone]; - newSound->_uniqueIdentifier = [_uniqueIdentifier copyWithZone: zone]; + newSound->_name = [_name copyWithZone: zone]; return newSound; } Index: configure.ac =================================================================== --- configure.ac (revision 28325) +++ configure.ac (working copy) @@ -354,32 +354,9 @@ #-------------------------------------------------------------------- # NSSound #-------------------------------------------------------------------- -AC_ARG_ENABLE(gsnd, - [ --disable-gsnd Disable gsnd server],, - enable_gsnd=yes) -BUILD_GSND= - -# This is only for gsnd, so don't add it to LIBS -save_LIBS="$LIBS" -AC_CHECK_LIB(portaudio, Pa_OpenDefaultStream, have_portaudio=yes, have_portaudio=no) -LIBS="$save_LIBS" - -AC_CHECK_LIB(audiofile, afGetVirtualFrameSize) -AC_CHECK_HEADERS(portaudio.h audiofile.h) - -AC_MSG_CHECKING(for portaudio version >= 19) -have_portaudio19=no -if test $ac_cv_header_portaudio_h = yes; then - AC_EGREP_HEADER(PaStreamCallback, portaudio.h, - have_portaudio19=yes, have_portaudio19=no) -fi -AC_MSG_RESULT($have_portaudio19) - -if test $have_portaudio19 = yes -a $have_portaudio = yes -a $enable_gsnd = yes; then - BUILD_GSND=gsnd -fi -AC_SUBST(BUILD_GSND) - +AC_CHECK_LIB(sndfile, sf_error) +AC_CHECK_LIB(openal, alGetError) +AC_CHECK_HEADERS(sndfile.h AL/al.h) #-------------------------------------------------------------------- # Find CUPS #-------------------------------------------------------------------- Index: Headers/AppKit/NSSound.h =================================================================== --- Headers/AppKit/NSSound.h (revision 28325) +++ Headers/AppKit/NSSound.h (working copy) @@ -32,6 +32,7 @@ #include #include +#include @class NSArray; @class NSData; @@ -40,34 +41,84 @@ @class NSString; @class NSURL; +enum +{ + GSSoundFormatUnknown = 0x0000, + GSSoundFormatPCMS8 = 0x0001, + GSSoundFormatPCM16 = 0x0002, + GSSoundFormatPCM24 = 0x0003, + GSSoundFormatPCM32 = 0x0004, + GSSoundFormatPCMU8 = 0x0005, + GSSoundFormatFloat32 = 0x0006, + GSSoundFormatFloat64 = 0x0007, + + GSSoundFormatULaw = 0x0010, + GSSoundFormatALaw = 0x0011 +}; + @interface NSSound : NSObject { NSString *_name; - NSString *_uniqueIdentifier; + NSString *_playbackDeviceIdentifier; + NSArray *_channelMap; /* Currently unused */ BOOL _onlyReference; - id _delegate; - + id _delegate; + + NSTimeInterval _duration; + NSData *_data; - float _samplingRate; - float _frameSize; - long _dataLocation; - long _dataSize; - long _frameCount; - int _channelCount; - int _dataFormat; + long _frameCount; + int _sampleRate; + int _channelCount; + + /* Used for OpenAL */ + unsigned int _sndSource; + unsigned int _sndBuffer; } // // Creating an NSSound // +/** + * Initalizes the receiver object with the contents of file located at path. + * If byRef is set to YES only the name of the NSSound is encoded with -encodeWithCoder:; + * if set to NO the data is encoded. + *

See Also:

+ * + * -initWithContentsOfURL:byReference: + * -initWithData: + * + */ - (id)initWithContentsOfFile:(NSString *)path byReference:(BOOL)byRef; +/** + * Initializes the receiver object with the contents of the data located in url. + * If byRef is set to YES only the name of the NSSound is encoded with -encodeWithCoder:; + * if set to NO the data is encoded. + *

See Also:

+ * + * -initWithContentsOfFile:byReference: + * -initWithData: + * + */ - (id)initWithContentsOfURL:(NSURL *)url byReference:(BOOL)byRef; +/** + * Initializes the receiver object with the contents of data with a + * valid magic number. + *

See Also:

+ * + * -initWithContentsOfFile:byReference: + * -initWithContentsOfURL:byReference: + * + */ - (id)initWithData:(NSData *)data; - (id)initWithPasteboard:(NSPasteboard *)pasteboard; // // Playing // +/** Pauses audio playback. + * Returns YES on success and NO if sound could not be paused. + */ - (BOOL)pause; - (BOOL)play; - (BOOL)resume; @@ -78,30 +129,108 @@ // Working with pasteboards // + (BOOL)canInitWithPasteboard:(NSPasteboard *)pasteboard; +/** Provides an array of file types that NSSound can understand. The returning + * array may be directly passed to [NSOpenPanel -runModalForTypes:]. + *

Built with libsndfile:

+ * wav, aiff, aifc, aif, au, snd, mat, mat4, mat5, paf, sf, voc, w64, + * xi, caf, sd2, flac, ogg, oga + *

Built without libsndfile:

+ * wav, aiff, aifc, aif, au, snd + */ + (NSArray *)soundUnfilteredPasteboardTypes; - (void)writeToPasteboard:(NSPasteboard *)pasteboard; // // Working with delegates // +/** Returns the receiver's delegate + */ - (id)delegate; +/** Sets the receiver's delegate + */ - (void)setDelegate:(id)aDelegate; // -// Naming Sounds +// Sound Information // + (id)soundNamed:(NSString *)name; + (NSArray *)soundUnfilteredFileTypes; - (NSString *)name; - (BOOL)setName:(NSString *)aName; +#if OS_API_VERSION(MAC_OS_X_VERSION_10_5, GS_API_LATEST) +/** NOT IMPLEMENTED + */ ++ (NSArray *)soundUnfilteredTypes; +/** Returns the length, in seconds, of the receiver. + */ +- (NSTimeInterval)duration; +/** Returns the volume of the receiver. + * Volume will be between 0.0 and 1.0. + */ +- (float)volume; +/** Sets the volume of the receiver. + * Volume must be between 0.0 and 1.0. + */ +- (void)setVolume: (float)volume; +/** Returns the current position of the audio playback. + */ +- (NSTimeInterval)currentTime; +/** Sets the current time of the audio playback. + */ +- (void)setCurrentTime: (NSTimeInterval)currentTime; +/** Returns the current loop property of the receiver. + * YES indicates this NSSound will restart once it reaches the end, otherwise NO. + */ +- (BOOL)loops; +/** Sets the loop property of the receiver. + * YES indicates this NSSound will restart once it reaches the end, otherwise NO. + */ +- (void)setLoops: (BOOL)loops; + +- (NSString *)playbackDeviceIdentifier; +- (void)setPlaybackDeviceIdentifier: (NSString *)playbackDeviceIdentifier; +- (NSArray *)channelMapping; +- (void)setChannelMapping: (NSArray *)channelMapping; +#endif + @end +#if OS_API_VERSION(GS_API_NONE, GS_API_NONE) address@hidden NSSound (GNUstepExtensions) +/** Initializes the receiver object with the contents of data with + * specified range. + *

If raw is YES will read data as raw PCM as described by format, + * channels (ie 2 for stereo), sampleRate (ie 44100 Hz) and byteOrder. + * If raw is NO all entries are disregarded.

+ *

Acceptable format values are:

+ * + * GSSoundFormatUnknown + * GSSoundFormatPCMS8 + * GSSoundFormatPCM16 + * GSSoundFormatPCM32 + * GSSoundFormatPCMU8 + * GSSoundFormatULaw + * GSSoundFormatALaw + * + */ +- (id)initWithData: (NSData *)data + raw: (BOOL)raw + range: (NSRange)range + format: (int)format + channels: (int)channels + sampleRate: (int)sampleRate + byteOrder: (NSByteOrder)byteOrder; address@hidden +#endif + // // Methods Implemented by the Delegate // @interface NSObject (NSSoundDelegate) +/** Method called when sound has finished playing. Currently this method is not called. + */ - (void)sound:(NSSound *)sound didFinishPlaying:(BOOL)aBool; @end Index: Headers/Additions/GNUstepGUI/config.h.in =================================================================== --- Headers/Additions/GNUstepGUI/config.h.in (revision 28325) +++ Headers/Additions/GNUstepGUI/config.h.in (working copy) @@ -6,8 +6,8 @@ /* Define to 1 if you have the header file. */ #undef HAVE_ASPELL_H -/* Define to 1 if you have the header file. */ -#undef HAVE_AUDIOFILE_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SNDFILE_H /* Define to 1 if you have the header file. */ #undef HAVE_CUPS_CUPS_H @@ -24,8 +24,8 @@ /* Define to 1 if you have the `aspell' library (-laspell). */ #undef HAVE_LIBASPELL -/* Define to 1 if you have the `audiofile' library (-laudiofile). */ -#undef HAVE_LIBAUDIOFILE +/* Define to 1 if you have the `sndfile' library (-lsndfile). */ +#undef HAVE_LIBSNDFILE /* Define to 1 if you have the `gif' library (-lgif). */ #undef HAVE_LIBGIF @@ -60,8 +60,8 @@ /* Define to 1 if you have the header file. */ #undef HAVE_MNTENT_H -/* Define to 1 if you have the header file. */ -#undef HAVE_PORTAUDIO_H +/* Define to 1 if you have the header file. */ +#undef HAVE_AL_AL_H /* Define to 1 if you have the `rint' function. */ #undef HAVE_RINT Index: config.make.in =================================================================== --- config.make.in (revision 28325) +++ config.make.in (working copy) @@ -6,8 +6,6 @@ ADDITIONAL_LIB_DIRS += @ADDITIONAL_LIB_DIRS@ ADDITIONAL_DEPENDS = @LIBS@ address@hidden@ - GSCUPS_CFLAGS = @GSCUPS_CFLAGS@ GSCUPS_LDFLAGS = @GSCUPS_LDFLAGS@ GSCUPS_LIBS = @GSCUPS_LIBS@