Start work on OpenAL support
(Really doesn't work as of this commit...)
This commit is contained in:
parent
bddec79afe
commit
f00d3bd2fe
31
GNUmakefile
31
GNUmakefile
@ -41,7 +41,7 @@ else
|
||||
LIBJS = js_static
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS = -I$(LIBJS_INC_DIR) -Isrc/SDL -Isrc/Core -Isrc/BSDCompat -Isrc/Core/Scripting -Isrc/Core/Materials -Isrc/Core/Entities -Isrc/Core/OXPVerifier -Isrc/Core/Debug -Isrc/Core/Tables -Isrc/Core/MiniZip
|
||||
ADDITIONAL_OBJC_LIBS = -lGLU -lGL -lX11 -lSDL -lSDL_mixer -lgnustep-base -l$(LIBJS) `nspr-config --libs` -lstdc++
|
||||
ADDITIONAL_OBJC_LIBS = -lGLU -lGL -lX11 -lSDL -lSDL_mixer -lgnustep-base -l$(LIBJS) `nspr-config --libs` -lstdc++ -lopenal
|
||||
ADDITIONAL_CFLAGS = -Wall -DLINUX -DNEED_STRLCPY `sdl-config --cflags` `nspr-config --cflags`
|
||||
ADDITIONAL_OBJCFLAGS = -Wall -std=c99 -DLOADSAVEGUI -DLINUX -DXP_UNIX -Wno-import `sdl-config --cflags` `nspr-config --cflags`
|
||||
oolite_LIB_DIRS += -L/usr/X11R6/lib/ -L$(LIBJS_LIB_DIR)
|
||||
@ -313,16 +313,29 @@ OOLITE_SCRIPTING_FILES = \
|
||||
OOJSFrameCallbacks.m \
|
||||
OOJSFont.m
|
||||
|
||||
#OOLITE_SOUND_FILES = \
|
||||
# OOBasicSoundReferencePoint.m \
|
||||
#
|
||||
# OOSDLConcreteSound.m \
|
||||
# OOSDLSound.m \
|
||||
# OOSDLSoundChannel.m \
|
||||
# OOSDLSoundMixer.m \
|
||||
# OOSoundSource.m \
|
||||
# OOSoundSourcePool.m \
|
||||
# SDLMusic.m
|
||||
|
||||
OOLITE_SOUND_FILES = \
|
||||
OOBasicSoundReferencePoint.m \
|
||||
OOMusicController.m \
|
||||
OOSDLConcreteSound.m \
|
||||
OOSDLSound.m \
|
||||
OOSDLSoundChannel.m \
|
||||
OOSDLSoundMixer.m \
|
||||
OOSoundSource.m \
|
||||
OOOpenALController.m \
|
||||
OOMusicController.m \
|
||||
OOSoundSource.m \
|
||||
OOSoundSourcePool.m \
|
||||
SDLMusic.m
|
||||
OOALMusic.m \
|
||||
OOALSound.m \
|
||||
OOALSoundChannel.m \
|
||||
OOALSoundMixer.m \
|
||||
OOALSoundDecoder.m \
|
||||
OOALBufferedSound.m
|
||||
|
||||
|
||||
OOLITE_UI_FILES = \
|
||||
GuiDisplayGen.m \
|
||||
|
@ -371,6 +371,7 @@
|
||||
sound.customSounds = $soundDebug;
|
||||
sound.customSounds.recursion = $soundError; // Circular dependency in customsounds.plist, e.g. [foo] = [bar], [bar] = [foo].
|
||||
sound.load.success = $soundDebug;
|
||||
sound.initialization.error = $soundError;
|
||||
|
||||
// Mac-specific sound messages
|
||||
sound.channel.cleanup.success = $soundDebugVerbose;
|
||||
@ -378,7 +379,6 @@
|
||||
sound.channel.cleanup.failed.broken = inherit;
|
||||
sound.channel.cleanup.failed.badState = inherit;
|
||||
sound.channel.machPortError = $soundError;
|
||||
sound.initialization.error = $soundError;
|
||||
sound.mixer.outOfChannels = $soundError;
|
||||
sound.mixer.inspector.loadFailed = $soundError;
|
||||
sound.mixer.replacingBrokenChannel = $soundDebug;
|
||||
|
43
src/Core/OOALBufferedSound.h
Normal file
43
src/Core/OOALBufferedSound.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
|
||||
OOALBufferedSound.h
|
||||
|
||||
OOALBufferedSound - OpenAL sound implementation for Oolite.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOSound.h"
|
||||
#import "OOALSoundDecoder.h"
|
||||
|
||||
@interface OOALBufferedSound: OOSound
|
||||
{
|
||||
@private
|
||||
float *_buffer;
|
||||
size_t _size;
|
||||
double _sampleRate;
|
||||
NSString *_name;
|
||||
BOOL _stereo;
|
||||
}
|
||||
|
||||
- (id)initWithDecoder:(OOALSoundDecoder *)inDecoder;
|
||||
|
||||
|
||||
@end
|
115
src/Core/OOALBufferedSound.m
Normal file
115
src/Core/OOALBufferedSound.m
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
|
||||
OOALBufferedSound.m
|
||||
|
||||
|
||||
OOALBufferedSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2005-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOALBufferedSound.h"
|
||||
#import "OOALSoundDecoder.h"
|
||||
|
||||
NSString * const kOOLogSoundLoadError = @"sound.load.error";
|
||||
|
||||
@implementation OOALBufferedSound
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
free(_buffer);
|
||||
_buffer = NULL;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (id)initWithDecoder:(OOALSoundDecoder *)inDecoder
|
||||
{
|
||||
BOOL OK = YES;
|
||||
|
||||
[OOSound setUp];
|
||||
if (![OOSound isSoundOK] || nil == inDecoder) OK = NO;
|
||||
|
||||
if (OK)
|
||||
{
|
||||
self = [super init];
|
||||
if (nil == self) OK = NO;
|
||||
}
|
||||
|
||||
if (OK)
|
||||
{
|
||||
_name = [[inDecoder name] copy];
|
||||
_sampleRate = [inDecoder sampleRate];
|
||||
if ([inDecoder isStereo])
|
||||
{
|
||||
OK = [inDecoder readMonoCreatingBuffer:&_buffer withFrameCount:&_size];
|
||||
/* TODO: implement stereo - needs to be interleaved for OpenAL, not
|
||||
* separate buffers */
|
||||
// OK = [inDecoder readStereoCreatingLeftBuffer:&_bufferL rightBuffer:&_bufferR withFrameCount:&_size];
|
||||
// _stereo = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
OK = [inDecoder readMonoCreatingBuffer:&_buffer withFrameCount:&_size];
|
||||
}
|
||||
}
|
||||
|
||||
if (!OK)
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (ALuint) soundBuffer
|
||||
{
|
||||
ALuint buffer;
|
||||
ALint error;
|
||||
OOAL(alGenBuffers(1,&buffer));
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
{
|
||||
OOLog(kOOLogSoundLoadError,@"Could not create OpenAL buffer");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_stereo)
|
||||
{
|
||||
alBufferData(buffer,AL_FORMAT_MONO16,_buffer,_size,_sampleRate);
|
||||
}
|
||||
else
|
||||
{
|
||||
alBufferData(buffer,AL_FORMAT_STEREO16,_buffer,_size,_sampleRate);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
43
src/Core/OOALConcreteSound.h
Normal file
43
src/Core/OOALConcreteSound.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
|
||||
OOALConcreteSound.h
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOALSound.h"
|
||||
#import "OOOpenALController.h"
|
||||
|
||||
|
||||
@interface OOALConcreteSound: OOSound
|
||||
{
|
||||
ALuint *_buffer;
|
||||
NSString *_name;
|
||||
}
|
||||
|
||||
- (ALuint) buffer;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
131
src/Core/OOALConcreteSound.m
Normal file
131
src/Core/OOALConcreteSound.m
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
|
||||
OOALConcreteSound.m
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2006-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <ogg/ogg.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
#import "OOALConcreteSound.h"
|
||||
#import "OOLogging.h"
|
||||
#import "NSDataOOExtensions.h"
|
||||
|
||||
size_t OOReadVorbis (void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||
|
||||
typedef struct {
|
||||
NSData *file;
|
||||
size_t seek;
|
||||
} OOOggBytes;
|
||||
|
||||
@implementation OOALConcreteSound
|
||||
|
||||
- (id) initWithContentsOfFile:(NSString *)path
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
NSData *fileData = [NSData oo_dataWithOXZFile:path];
|
||||
|
||||
OggVorbis_File _vf;
|
||||
ov_callbacks _callbacks = {
|
||||
OOReadVorbis, // read sequentially
|
||||
NULL, // no seek
|
||||
NULL, // no close
|
||||
NULL, // no tell
|
||||
};
|
||||
OOOggBytes bitData = {
|
||||
fileData,
|
||||
0
|
||||
};
|
||||
ov_open_callbacks(bitData, _vf, NULL, 0, _callbacks);
|
||||
|
||||
|
||||
|
||||
|
||||
SDL_RWops *soundData = SDL_RWFromConstMem([fileData bytes],[fileData length]);
|
||||
_chunk = Mix_LoadWAV_RW(soundData, 0);
|
||||
SDL_RWclose(soundData);
|
||||
|
||||
if (_chunk != NULL)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
OOLog(@"sound.load.success", @"Loaded a sound from \"%@\".", path);
|
||||
#endif
|
||||
_name = [[path lastPathComponent] copy];
|
||||
}
|
||||
else
|
||||
{
|
||||
OOLog(@"sound.load.failed", @"Could not load a sound from \"%@\".", path);
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
if (_chunk != NULL) Mix_FreeChunk(_chunk);
|
||||
[_name autorelease];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) descriptionComponents
|
||||
{
|
||||
return [NSString stringWithFormat:@"\"%@\"", _name];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
|
||||
- (ALuint) buffer
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// wants size*nmemb bytes from datasource transferred to ptr
|
||||
size_t OOReadVorbis (void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
size_t toRead = size*nmemb;
|
||||
NSData *file = (OOOggBytes)datasource.file;
|
||||
size_t seek = (OOOggBytes)datasource.seek;
|
||||
if (seek+toRead > [file length])
|
||||
{
|
||||
toRead = [file length] - seek;
|
||||
}
|
||||
[file getBytes:ptr range:((NSRange){seek, toRead})];
|
||||
(OOOggBytes)datasource.seek += toRead;
|
||||
return toRead;
|
||||
}
|
46
src/Core/OOALMusic.h
Normal file
46
src/Core/OOALMusic.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
|
||||
OOALMusic.h
|
||||
|
||||
Subclass of OOSound with additional controls specific to music playback. Only
|
||||
one instance of OOMusic may be playing at a time.
|
||||
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2005-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "OOALSound.h"
|
||||
|
||||
|
||||
@interface OOMusic: OOSound
|
||||
{
|
||||
@private
|
||||
OOSound *sound;
|
||||
}
|
||||
|
||||
- (void) playLooped:(BOOL)looped;
|
||||
- (void) stop;
|
||||
- (BOOL) isPlaying;
|
||||
|
||||
@end
|
108
src/Core/OOALMusic.m
Normal file
108
src/Core/OOALMusic.m
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
|
||||
OOALMusic.m
|
||||
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2005-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOALMusic.h"
|
||||
#import "OOSoundSource.h"
|
||||
|
||||
static OOMusic *sPlayingMusic = nil;
|
||||
static OOSoundSource *sMusicSource = nil;
|
||||
|
||||
|
||||
@implementation OOMusic
|
||||
|
||||
+ (id)allocWithZone:(NSZone *)inZone
|
||||
{
|
||||
return NSAllocateObject([OOMusic class], 0, inZone);
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (sPlayingMusic == self) [self stop];
|
||||
[sound release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id)initWithContentsOfFile:(NSString *)inPath
|
||||
{
|
||||
self = [super init];
|
||||
if (nil != self)
|
||||
{
|
||||
sound = [[OOSound alloc] initWithContentsOfFile:inPath];
|
||||
if (nil == sound)
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
return [sound name];
|
||||
}
|
||||
|
||||
|
||||
- (void)playLooped:(BOOL)inLoop
|
||||
{
|
||||
if (sPlayingMusic != self)
|
||||
{
|
||||
if (nil == sMusicSource)
|
||||
{
|
||||
sMusicSource = [[OOSoundSource alloc] init];
|
||||
}
|
||||
[sMusicSource stop];
|
||||
[sMusicSource setLoop:inLoop];
|
||||
[sMusicSource setSound:sound];
|
||||
[sMusicSource play];
|
||||
|
||||
sPlayingMusic = self;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isPlaying
|
||||
{
|
||||
return sPlayingMusic == self && [sMusicSource isPlaying];
|
||||
}
|
||||
|
||||
|
||||
- (void)stop
|
||||
{
|
||||
if (sPlayingMusic == self)
|
||||
{
|
||||
sPlayingMusic = nil;
|
||||
[sMusicSource stop];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
46
src/Core/OOALSound.h
Normal file
46
src/Core/OOALSound.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
|
||||
OOALSound.h
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "OOOpenALController.h"
|
||||
|
||||
@interface OOSound: NSObject
|
||||
|
||||
+ (BOOL) setUp;
|
||||
+ (void) update;
|
||||
|
||||
+ (void) setMasterVolume:(float) fraction;
|
||||
+ (float) masterVolume;
|
||||
|
||||
- (id) initWithContentsOfFile:(NSString *)path;
|
||||
|
||||
- (NSString *)name;
|
||||
|
||||
+ (BOOL) isSoundOK;
|
||||
|
||||
- (ALuint) soundBuffer;
|
||||
|
||||
@end
|
165
src/Core/OOALSound.m
Normal file
165
src/Core/OOALSound.m
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
|
||||
OOALSound.m
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOALSound.h"
|
||||
#import "OOLogging.h"
|
||||
#import "OOCollectionExtractors.h"
|
||||
#import "OOMaths.h"
|
||||
#import "OOALSoundDecoder.h"
|
||||
#import "OOOpenALController.h"
|
||||
#import "OOALBufferedSound.h"
|
||||
#import "OOALSoundMixer.h"
|
||||
|
||||
#define KEY_VOLUME_CONTROL @"volume_control"
|
||||
|
||||
static int sMaxBufferedSoundSize = 1 << 20; // 1 MB
|
||||
|
||||
static BOOL sIsSetUp = NO;
|
||||
static BOOL sIsSoundOK = NO;
|
||||
|
||||
@implementation OOSound
|
||||
|
||||
+ (BOOL) setUp
|
||||
{
|
||||
if (!sIsSetUp)
|
||||
{
|
||||
sIsSetUp = YES;
|
||||
OOOpenALController* controller = [OOOpenALController sharedController];
|
||||
if (controller != nil)
|
||||
{
|
||||
sIsSoundOK = YES;
|
||||
}
|
||||
}
|
||||
|
||||
return sIsSoundOK;
|
||||
}
|
||||
|
||||
|
||||
+ (void) setMasterVolume:(float) fraction
|
||||
{
|
||||
if (!sIsSetUp && ![self setUp])
|
||||
return;
|
||||
|
||||
fraction = OOClamp_0_1_f(fraction);
|
||||
|
||||
OOOpenALController *controller = [OOOpenALController sharedController];
|
||||
if (fraction != [controller masterVolume])
|
||||
{
|
||||
[controller setMasterVolume:fraction];
|
||||
[[NSUserDefaults standardUserDefaults] setFloat:[controller masterVolume] forKey:KEY_VOLUME_CONTROL];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (float) masterVolume
|
||||
{
|
||||
if (!sIsSetUp && ![self setUp] )
|
||||
return 0.0;
|
||||
|
||||
OOOpenALController *controller = [OOOpenALController sharedController];
|
||||
return [controller masterVolume];
|
||||
}
|
||||
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if (!sIsSetUp) [OOSound setUp];
|
||||
return [super init];
|
||||
}
|
||||
|
||||
|
||||
- (id) initWithContentsOfFile:(NSString *)path
|
||||
{
|
||||
[self release];
|
||||
if (!sIsSetUp && ![OOSound setUp]) return nil;
|
||||
|
||||
OOALSoundDecoder *decoder;
|
||||
|
||||
decoder = [[OOALSoundDecoder alloc] initWithPath:path];
|
||||
if (nil == decoder) return nil;
|
||||
|
||||
if ([decoder sizeAsBuffer] <= (size_t)sMaxBufferedSoundSize)
|
||||
{
|
||||
self = [[OOALBufferedSound alloc] initWithDecoder:decoder];
|
||||
}
|
||||
else
|
||||
{
|
||||
self = nil;
|
||||
// not yet implemented
|
||||
// self = [[OOALStreamingSound alloc] initWithDecoder:decoder];
|
||||
}
|
||||
[decoder release];
|
||||
|
||||
if (nil != self)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
OOLog(kOOLogSoundLoadingSuccess, @"Loaded sound %@", self);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
OOLog(kOOLogSoundLoadingError, @"Failed to load sound \"%@\"", path);
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (id)initWithDecoder:(OOALSoundDecoder *)inDecoder
|
||||
{
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
OOLogGenericSubclassResponsibility();
|
||||
return @"";
|
||||
}
|
||||
|
||||
|
||||
+ (void) update
|
||||
{
|
||||
OOSoundMixer * mixer = [OOSoundMixer sharedMixer];
|
||||
if( sIsSoundOK && mixer)
|
||||
[mixer update];
|
||||
}
|
||||
|
||||
+ (BOOL) isSoundOK
|
||||
{
|
||||
return sIsSoundOK;
|
||||
}
|
||||
|
||||
|
||||
- (ALuint) soundBuffer
|
||||
{
|
||||
OOLogGenericSubclassResponsibility();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
68
src/Core/OOALSoundChannel.h
Normal file
68
src/Core/OOALSoundChannel.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
|
||||
OOALSoundChannel.h
|
||||
|
||||
A channel for audio playback.
|
||||
|
||||
This class is an implementation detail. Do not use it directly; use an
|
||||
OOSoundSource to play an OOSound.
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2006-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "OOOpenALController.h"
|
||||
|
||||
@class OOSound;
|
||||
|
||||
|
||||
@interface OOSoundChannel: NSObject
|
||||
{
|
||||
OOSoundChannel *_next;
|
||||
id _delegate;
|
||||
OOSound *_sound;
|
||||
ALuint _source;
|
||||
BOOL _playing;
|
||||
}
|
||||
|
||||
- (void) update;
|
||||
|
||||
- (void) setDelegate:(id)delegate;
|
||||
|
||||
// Unretained pointer used to maintain simple stack
|
||||
- (OOSoundChannel *) next;
|
||||
- (void) setNext:(OOSoundChannel *)next;
|
||||
|
||||
- (BOOL) playSound:(OOSound *)sound looped:(BOOL)loop;
|
||||
- (void)stop;
|
||||
|
||||
- (OOSound *)sound;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface NSObject(OOSoundChannelDelegate)
|
||||
|
||||
- (void)channel:(OOSoundChannel *)inChannel didFinishPlayingSound:(OOSound *)inSound;
|
||||
|
||||
@end
|
144
src/Core/OOALSoundChannel.m
Normal file
144
src/Core/OOALSoundChannel.m
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
|
||||
OOALSoundChannel.m
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2006-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOALSoundChannel.h"
|
||||
#import "OOALSound.h"
|
||||
#import "OOLogging.h"
|
||||
|
||||
@interface OOSoundChannel (Private)
|
||||
|
||||
- (void) hasStopped;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OOSoundChannel
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
ALuint error;
|
||||
OOAL(alGenSources(1,&_source));
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
{
|
||||
OOLog(kOOLogSoundInitError,@"Could not create OpenAL source");
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void) update
|
||||
{
|
||||
// Check if we've reached the end of a sound.
|
||||
if (_sound != nil)
|
||||
{
|
||||
ALint check;
|
||||
OOAL(alGetSourcei(_source,AL_SOURCE_STATE,&check));
|
||||
if (check == AL_STOPPED)
|
||||
{
|
||||
[self hasStopped];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) setDelegate:(id)delegate
|
||||
{
|
||||
_delegate = delegate;
|
||||
}
|
||||
|
||||
|
||||
- (OOSoundChannel *) next
|
||||
{
|
||||
return _next;
|
||||
}
|
||||
|
||||
|
||||
- (void) setNext:(OOSoundChannel *)next
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) playSound:(OOSound *)sound looped:(BOOL)loop
|
||||
{
|
||||
if (sound == nil) return NO;
|
||||
|
||||
if (_sound != nil) [self stop];
|
||||
|
||||
// get sound data
|
||||
ALuint buffer = [sound soundBuffer];
|
||||
// bind sound data to buffer
|
||||
OOAL(alSourcei(_source, AL_BUFFER, buffer));
|
||||
ALuint error;
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
OOAL(alSourcePlay(_source));
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
_sound = [sound retain];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void) stop
|
||||
{
|
||||
if (_sound != nil)
|
||||
{
|
||||
OOAL(alSourceStop(_source));
|
||||
[self hasStopped];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) hasStopped
|
||||
{
|
||||
OOSound *sound = _sound;
|
||||
_sound = nil;
|
||||
|
||||
if (nil != _delegate && [_delegate respondsToSelector:@selector(channel:didFinishPlayingSound:)])
|
||||
{
|
||||
[_delegate channel:self didFinishPlayingSound:sound];
|
||||
}
|
||||
[sound release];
|
||||
}
|
||||
|
||||
|
||||
- (OOSound *)sound
|
||||
{
|
||||
return _sound;
|
||||
}
|
||||
|
||||
@end
|
62
src/Core/OOALSoundDecoder.h
Normal file
62
src/Core/OOALSoundDecoder.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
|
||||
OOALSoundDecoder.h
|
||||
|
||||
Class responsible for converting a sound to a PCM buffer for playback. This
|
||||
class is an implementation detail. Do not use it directly; use OOSound to
|
||||
load sounds.
|
||||
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2005-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface OOALSoundDecoder: NSObject
|
||||
|
||||
- (id)initWithPath:(NSString *)inPath;
|
||||
+ (OOALSoundDecoder *)codecWithPath:(NSString *)inPath;
|
||||
|
||||
// Full-buffer reading.
|
||||
- (BOOL)readMonoCreatingBuffer:(float **)outBuffer withFrameCount:(size_t *)outSize;
|
||||
- (BOOL)readStereoCreatingLeftBuffer:(float **)outLeftBuffer rightBuffer:(float **)outRightBuffer withFrameCount:(size_t *)outSize;
|
||||
|
||||
// Stream reading. This will always provide two channels (as non-interleaved PCM), discarding extra channels or doubling mono as necessary.
|
||||
- (size_t)streamStereoToBufferL:(float *)ioBufferL bufferR:(float *)ioBufferR maxFrames:(size_t)inMax;
|
||||
|
||||
// Returns the size of the data -readMonoCreatingBuffer:withFrameCount: will create.
|
||||
- (size_t)sizeAsBuffer;
|
||||
|
||||
- (BOOL)isStereo;
|
||||
|
||||
- (long)sampleRate;
|
||||
|
||||
// For streaming
|
||||
- (BOOL)atEnd;
|
||||
- (BOOL)scanToOffset:(uint64_t)inOffset;
|
||||
- (void)rewindToBeginning;
|
||||
|
||||
- (NSString *)name;
|
||||
|
||||
@end
|
615
src/Core/OOALSoundDecoder.m
Normal file
615
src/Core/OOALSoundDecoder.m
Normal file
@ -0,0 +1,615 @@
|
||||
/*
|
||||
|
||||
OOALSoundDecoder.m
|
||||
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2005-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOALSoundDecoder.h"
|
||||
#import "NSDataOOExtensions.h"
|
||||
#import <vorbis/vorbisfile.h>
|
||||
#import "OOLogging.h"
|
||||
#import "unzip.h"
|
||||
|
||||
#define ZIP_BUFFER_SIZE 8192
|
||||
|
||||
enum
|
||||
{
|
||||
kMaxDecodeSize = 1 << 20 // 2^20 frames = 4 MB
|
||||
};
|
||||
|
||||
static void MixDown(float *inChan1, float *inChan2, float *outMix, size_t inCount);
|
||||
static size_t OOReadOXZVorbis (void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||
static int OOCloseOXZVorbis (void *datasource);
|
||||
|
||||
@interface OOALSoundVorbisCodec: OOALSoundDecoder
|
||||
{
|
||||
OggVorbis_File _vf;
|
||||
NSString *_name;
|
||||
BOOL _atEnd;
|
||||
@public
|
||||
unzFile uf;
|
||||
size_t oxzPointer;
|
||||
}
|
||||
|
||||
- (NSDictionary *)comments;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OOALSoundDecoder
|
||||
|
||||
- (id)initWithPath:(NSString *)inPath
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
|
||||
if ([[inPath pathExtension] isEqual:@"ogg"])
|
||||
{
|
||||
self = [[OOALSoundVorbisCodec alloc] initWithPath:inPath];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
+ (OOALSoundDecoder *)codecWithPath:(NSString *)inPath
|
||||
{
|
||||
if ([[inPath pathExtension] isEqual:@"ogg"])
|
||||
{
|
||||
return [[[OOALSoundVorbisCodec alloc] initWithPath:inPath] autorelease];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (size_t)streamStereoToBufferL:(float *)ioBufferL bufferR:(float *)ioBufferR maxFrames:(size_t)inMax
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)readMonoCreatingBuffer:(float **)outBuffer withFrameCount:(size_t *)outSize
|
||||
{
|
||||
if (NULL != outBuffer) *outBuffer = NULL;
|
||||
if (NULL != outSize) *outSize = 0;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)readStereoCreatingLeftBuffer:(float **)outLeftBuffer rightBuffer:(float **)outRightBuffer withFrameCount:(size_t *)outSize
|
||||
{
|
||||
if (NULL != outLeftBuffer) *outLeftBuffer = NULL;
|
||||
if (NULL != outRightBuffer) *outRightBuffer = NULL;
|
||||
if (NULL != outSize) *outSize = 0;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (size_t)sizeAsBuffer
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isStereo
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (long)sampleRate
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)atEnd
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)rewindToBeginning
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)scanToOffset:(uint64_t)inOffset
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
return @"";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OOALSoundVorbisCodec
|
||||
|
||||
- (id)initWithPath:(NSString *)path
|
||||
{
|
||||
BOOL OK = NO;
|
||||
unsigned i, cl;
|
||||
NSArray *components = [path pathComponents];
|
||||
cl = [components count];
|
||||
for (i = 0 ; i < cl ; i++)
|
||||
{
|
||||
NSString *component = [components objectAtIndex:i];
|
||||
if ([[[component pathExtension] lowercaseString] isEqualToString:@"oxz"])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if i == cl then the path is entirely uncompressed
|
||||
if (i == cl)
|
||||
{
|
||||
/* Get vorbis data from a standard file stream */
|
||||
int err;
|
||||
FILE *file;
|
||||
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_name = [[path lastPathComponent] retain];
|
||||
|
||||
if (nil != path)
|
||||
{
|
||||
file = fopen([path UTF8String], "rb");
|
||||
if (NULL != file)
|
||||
{
|
||||
err = ov_open_callbacks(file, &_vf, NULL, 0, OV_CALLBACKS_DEFAULT);
|
||||
if (0 == err)
|
||||
{
|
||||
OK = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!OK)
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NSRange range;
|
||||
range.location = 0; range.length = i+1;
|
||||
NSString *zipFile = [NSString pathWithComponents:[components subarrayWithRange:range]];
|
||||
range.location = i+1; range.length = cl-(i+1);
|
||||
NSString *containedFile = [NSString pathWithComponents:[components subarrayWithRange:range]];
|
||||
|
||||
const char* zipname = [zipFile cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
if (zipname != NULL)
|
||||
{
|
||||
uf = unzOpen64(zipname);
|
||||
oxzPointer = 0;
|
||||
}
|
||||
if (uf == NULL)
|
||||
{
|
||||
OOLog(kOOLogFileNotFound, @"Could not unzip OXZ at %@", zipFile);
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* filename = [containedFile cStringUsingEncoding:NSUTF8StringEncoding];
|
||||
// unzLocateFile(*, *, 1) = case-sensitive extract
|
||||
if (unzLocateFile(uf, filename, 1) != UNZ_OK)
|
||||
{
|
||||
unzClose(uf);
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
int err = UNZ_OK;
|
||||
unz_file_info64 file_info = {0};
|
||||
err = unzGetCurrentFileInfo64(uf, &file_info, NULL, 0, NULL, 0, NULL, 0);
|
||||
if (err != UNZ_OK)
|
||||
{
|
||||
unzClose(uf);
|
||||
OOLog(kOOLogFileNotFound, @"Could not get properties of %@ within OXZ at %@", containedFile, zipFile);
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = unzOpenCurrentFile(uf);
|
||||
if (err != UNZ_OK)
|
||||
{
|
||||
unzClose(uf);
|
||||
OOLog(kOOLogFileNotFound, @"Could not read %@ within OXZ at %@", containedFile, zipFile);
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
ov_callbacks _callbacks = {
|
||||
OOReadOXZVorbis, // read sequentially
|
||||
NULL, // no seek
|
||||
OOCloseOXZVorbis, // close file
|
||||
NULL, // no tell
|
||||
};
|
||||
err = ov_open_callbacks(self, &_vf, NULL, 0, _callbacks);
|
||||
if (0 == err)
|
||||
{
|
||||
OK = YES;
|
||||
}
|
||||
if (!OK)
|
||||
{
|
||||
unzClose(uf);
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_name release];
|
||||
ov_clear(&_vf);
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
- (NSDictionary *)comments
|
||||
{
|
||||
vorbis_comment *comments;
|
||||
unsigned i, count;
|
||||
NSMutableDictionary *result = nil;
|
||||
NSString *comment, *key, *value;
|
||||
NSRange range;
|
||||
|
||||
comments = ov_comment(&_vf, -1);
|
||||
if (NULL != comments)
|
||||
{
|
||||
count = comments->comments;
|
||||
if (0 != count)
|
||||
{
|
||||
result = [NSMutableDictionary dictionaryWithCapacity:count];
|
||||
for (i = 0; i != count; ++i)
|
||||
{
|
||||
comment = [[NSString alloc] initWithBytesNoCopy:comments->user_comments[i] length:comments->comment_lengths[i] encoding:NSUTF8StringEncoding freeWhenDone:NO];
|
||||
range = [comment rangeOfString:@"="];
|
||||
if (0 != range.length)
|
||||
{
|
||||
key = [comment substringToIndex:range.location];
|
||||
value = [comment substringFromIndex:range.location + 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
key = comment;
|
||||
value = @"";
|
||||
}
|
||||
[result setObject:value forKey:key];
|
||||
|
||||
[comment release];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)readMonoCreatingBuffer:(float **)outBuffer withFrameCount:(size_t *)outSize
|
||||
{
|
||||
float *buffer = NULL, *dst, **src;
|
||||
size_t sizeInFrames = 0;
|
||||
int remaining;
|
||||
unsigned chanCount;
|
||||
long framesRead;
|
||||
ogg_int64_t totalSizeInFrames;
|
||||
BOOL OK = YES;
|
||||
|
||||
if (NULL != outBuffer) *outBuffer = NULL;
|
||||
if (NULL != outSize) *outSize = 0;
|
||||
if (NULL == outBuffer || NULL == outSize) OK = NO;
|
||||
|
||||
if (OK)
|
||||
{
|
||||
totalSizeInFrames = ov_pcm_total(&_vf, -1);
|
||||
assert ((uint64_t)totalSizeInFrames < (uint64_t)SIZE_MAX); // Should have been checked by caller
|
||||
sizeInFrames = (size_t)totalSizeInFrames;
|
||||
}
|
||||
|
||||
if (OK)
|
||||
{
|
||||
buffer = malloc(sizeof (float) * sizeInFrames);
|
||||
if (!buffer) OK = NO;
|
||||
}
|
||||
|
||||
if (OK && sizeInFrames)
|
||||
{
|
||||
remaining = (int)MIN(sizeInFrames, (size_t)INT_MAX);
|
||||
dst = buffer;
|
||||
|
||||
do
|
||||
{
|
||||
chanCount = ov_info(&_vf, -1)->channels;
|
||||
framesRead = ov_read_float(&_vf, &src, remaining, NULL);
|
||||
if (framesRead <= 0)
|
||||
{
|
||||
if (OV_HOLE == framesRead) continue;
|
||||
//else:
|
||||
break;
|
||||
}
|
||||
|
||||
if (1 == chanCount) bcopy(src[0], dst, sizeof (float) * framesRead);
|
||||
else MixDown(src[0], src[1], dst, framesRead);
|
||||
|
||||
remaining -= framesRead;
|
||||
dst += framesRead;
|
||||
} while (0 != remaining);
|
||||
|
||||
sizeInFrames -= remaining; // In case we stopped at an error
|
||||
}
|
||||
|
||||
if (OK)
|
||||
{
|
||||
*outBuffer = buffer;
|
||||
*outSize = sizeInFrames;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer) free(buffer);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)readStereoCreatingLeftBuffer:(float **)outLeftBuffer rightBuffer:(float **)outRightBuffer withFrameCount:(size_t *)outSize
|
||||
{
|
||||
float *bufferL = NULL, *bufferR = NULL, *dstL, *dstR, **src;
|
||||
size_t sizeInFrames = 0;
|
||||
int remaining;
|
||||
unsigned chanCount;
|
||||
long framesRead;
|
||||
ogg_int64_t totalSizeInFrames;
|
||||
BOOL OK = YES;
|
||||
|
||||
if (NULL != outLeftBuffer) *outLeftBuffer = NULL;
|
||||
if (NULL != outRightBuffer) *outRightBuffer = NULL;
|
||||
if (NULL != outSize) *outSize = 0;
|
||||
if (NULL == outLeftBuffer || NULL == outRightBuffer || NULL == outSize) OK = NO;
|
||||
|
||||
if (OK)
|
||||
{
|
||||
totalSizeInFrames = ov_pcm_total(&_vf, -1);
|
||||
assert ((uint64_t)totalSizeInFrames < (uint64_t)SIZE_MAX); // Should have been checked by caller
|
||||
sizeInFrames = (size_t)totalSizeInFrames;
|
||||
}
|
||||
|
||||
if (OK)
|
||||
{
|
||||
bufferL = malloc(sizeof (float) * sizeInFrames);
|
||||
if (!bufferL) OK = NO;
|
||||
}
|
||||
|
||||
if (OK)
|
||||
{
|
||||
bufferR = malloc(sizeof (float) * sizeInFrames);
|
||||
if (!bufferR) OK = NO;
|
||||
}
|
||||
|
||||
if (OK && sizeInFrames)
|
||||
{
|
||||
remaining = (int)MIN(sizeInFrames, (size_t)INT_MAX);
|
||||
dstL = bufferL;
|
||||
dstR = bufferR;
|
||||
|
||||
do
|
||||
{
|
||||
chanCount = ov_info(&_vf, -1)->channels;
|
||||
framesRead = ov_read_float(&_vf, &src, remaining, NULL);
|
||||
if (framesRead <= 0)
|
||||
{
|
||||
if (OV_HOLE == framesRead) continue;
|
||||
//else:
|
||||
break;
|
||||
}
|
||||
|
||||
bcopy(src[0], dstL, sizeof (float) * framesRead);
|
||||
if (1 == chanCount) bcopy(src[0], dstR, sizeof (float) * framesRead);
|
||||
else bcopy(src[1], dstR, sizeof (float) * framesRead);
|
||||
|
||||
remaining -= framesRead;
|
||||
dstL += framesRead;
|
||||
dstR += framesRead;
|
||||
} while (0 != remaining);
|
||||
|
||||
sizeInFrames -= remaining; // In case we stopped at an error
|
||||
}
|
||||
|
||||
if (OK)
|
||||
{
|
||||
*outLeftBuffer = bufferL;
|
||||
*outRightBuffer = bufferR;
|
||||
*outSize = sizeInFrames;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bufferL) free(bufferL);
|
||||
if (bufferR) free(bufferR);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
- (size_t)streamStereoToBufferL:(float *)ioBufferL bufferR:(float *)ioBufferR maxFrames:(size_t)inMax
|
||||
{
|
||||
float **src;
|
||||
unsigned chanCount;
|
||||
long framesRead;
|
||||
size_t size;
|
||||
int remaining;
|
||||
unsigned rightChan;
|
||||
|
||||
// Note: for our purposes, a frame is a set of one sample for each channel.
|
||||
if (NULL == ioBufferL || NULL == ioBufferR || 0 == inMax) return 0;
|
||||
if (_atEnd) return inMax;
|
||||
|
||||
remaining = (int)MIN(inMax, (size_t)INT_MAX);
|
||||
do
|
||||
{
|
||||
chanCount = ov_info(&_vf, -1)->channels;
|
||||
framesRead = ov_read_float(&_vf, &src, remaining, NULL);
|
||||
if (framesRead <= 0)
|
||||
{
|
||||
if (OV_HOLE == framesRead) continue;
|
||||
//else:
|
||||
_atEnd = YES;
|
||||
break;
|
||||
}
|
||||
|
||||
size = sizeof (float) * framesRead;
|
||||
|
||||
rightChan = (1 == chanCount) ? 0 : 1;
|
||||
bcopy(src[0], ioBufferL, size);
|
||||
bcopy(src[rightChan], ioBufferR, size);
|
||||
|
||||
remaining -= framesRead;
|
||||
ioBufferL += framesRead;
|
||||
ioBufferR += framesRead;
|
||||
} while (0 != remaining);
|
||||
|
||||
return inMax - remaining;
|
||||
}
|
||||
|
||||
|
||||
- (size_t)sizeAsBuffer
|
||||
{
|
||||
ogg_int64_t size;
|
||||
|
||||
size = ov_pcm_total(&_vf, -1);
|
||||
size *= sizeof(float) * ([self isStereo] ? 2 : 1);
|
||||
if ((uint64_t)SIZE_MAX < (uint64_t)size) size = (ogg_int64_t)SIZE_MAX;
|
||||
return (size_t)size;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isStereo
|
||||
{
|
||||
return 1 < ov_info(&_vf, -1)->channels;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [NSString stringWithFormat:@"<%@ %p>{\"%@\", comments=%@}", [self className], self, _name, [self comments]];
|
||||
}
|
||||
|
||||
|
||||
- (long)sampleRate
|
||||
{
|
||||
return ov_info(&_vf, -1)->rate;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)atEnd
|
||||
{
|
||||
return _atEnd;
|
||||
}
|
||||
|
||||
|
||||
- (void)rewindToBeginning
|
||||
{
|
||||
if (!ov_pcm_seek(&_vf, 0)) _atEnd = NO;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)scanToOffset:(uint64_t)inOffset
|
||||
{
|
||||
if (!ov_pcm_seek(&_vf, inOffset))
|
||||
{
|
||||
_atEnd = NO;
|
||||
return YES;
|
||||
}
|
||||
else return NO;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)name
|
||||
{
|
||||
return [[_name retain] autorelease];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// TODO: optimise, vectorise
|
||||
static void MixDown(float *inChan1, float *inChan2, float *outMix, size_t inCount)
|
||||
{
|
||||
while (inCount--)
|
||||
{
|
||||
*outMix++ = (*inChan1++ + *inChan2++) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static size_t OOReadOXZVorbis (void *ptr, size_t size, size_t nmemb, void *datasource)
|
||||
{
|
||||
OOALSoundVorbisCodec *src = (OOALSoundVorbisCodec *)datasource;
|
||||
size_t toRead = size*nmemb;
|
||||
void *buf = (void*)malloc(toRead);
|
||||
int err = UNZ_OK;
|
||||
err = unzReadCurrentFile(src->uf, buf, toRead);
|
||||
if (err > 0)
|
||||
{
|
||||
memcpy(ptr, buf, err);
|
||||
}
|
||||
if (err < 0)
|
||||
{
|
||||
return OV_EREAD;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int OOCloseOXZVorbis (void *datasource)
|
||||
{
|
||||
OOALSoundVorbisCodec *src = (OOALSoundVorbisCodec *)datasource;
|
||||
unzClose(src->uf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: implement seek/tell functions for OXZ datastream
|
61
src/Core/OOALSoundMixer.h
Normal file
61
src/Core/OOALSoundMixer.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
|
||||
OOALSoundMixer.h
|
||||
|
||||
Class responsible for managing and mixing sound channels. This class is an
|
||||
implementation detail. Do not use it directly; use an OOSoundSource to play an
|
||||
OOSound.
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2006-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class OOSoundChannel;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
kMixerGeneralChannels = 32
|
||||
};
|
||||
|
||||
|
||||
@interface OOSoundMixer: NSObject
|
||||
{
|
||||
OOSoundChannel *_channels[kMixerGeneralChannels];
|
||||
OOSoundChannel *_freeList;
|
||||
|
||||
uint32_t _maxChannels;
|
||||
uint32_t _playMask;
|
||||
|
||||
}
|
||||
|
||||
// Singleton accessor
|
||||
+ (id) sharedMixer;
|
||||
|
||||
- (void) update;
|
||||
|
||||
- (OOSoundChannel *) popChannel;
|
||||
- (void) pushChannel:(OOSoundChannel *)channel;
|
||||
|
||||
@end
|
166
src/Core/OOALSoundMixer.m
Normal file
166
src/Core/OOALSoundMixer.m
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
|
||||
OOALSoundMixer.m
|
||||
|
||||
OOALSound - OpenAL sound implementation for Oolite.
|
||||
Copyright (C) 2006-2013 Jens Ayton
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#import "OOALSoundMixer.h"
|
||||
#import "OOCocoa.h"
|
||||
#import "OOALSound.h"
|
||||
#import "OOALSoundChannel.h"
|
||||
|
||||
static OOSoundMixer *sSingleton = nil;
|
||||
|
||||
|
||||
@implementation OOSoundMixer
|
||||
|
||||
+ (id) sharedMixer
|
||||
{
|
||||
if (nil == sSingleton)
|
||||
{
|
||||
[[self alloc] init];
|
||||
}
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
|
||||
- (id) init
|
||||
{
|
||||
BOOL OK = YES;
|
||||
uint32_t idx = 0, count = kMixerGeneralChannels;
|
||||
OOSoundChannel *channel;
|
||||
|
||||
if (!(self = [super init])) return nil;
|
||||
if (![OOSound setUp]) OK = NO;
|
||||
|
||||
if (OK)
|
||||
{
|
||||
// Allocate channels
|
||||
do
|
||||
{
|
||||
channel = [[OOSoundChannel alloc] init];
|
||||
if (nil != channel)
|
||||
{
|
||||
_channels[idx++] = channel;
|
||||
[self pushChannel:channel];
|
||||
}
|
||||
} while (--count);
|
||||
}
|
||||
|
||||
if (!OK)
|
||||
{
|
||||
[super release];
|
||||
// static analyser complains about this next line; probably nothing - CIM
|
||||
self = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
sSingleton = self;
|
||||
}
|
||||
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
|
||||
- (void) update
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < kMixerGeneralChannels; ++i)
|
||||
{
|
||||
[_channels[i] update];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (OOSoundChannel *) popChannel
|
||||
{
|
||||
OOSoundChannel *channel = _freeList;
|
||||
_freeList = [channel next];
|
||||
[channel setNext:nil];
|
||||
|
||||
return channel;
|
||||
}
|
||||
|
||||
|
||||
- (void) pushChannel:(OOSoundChannel *)channel
|
||||
{
|
||||
assert(channel != nil);
|
||||
|
||||
[channel setNext:_freeList];
|
||||
_freeList = channel;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation OOSoundMixer (Singleton)
|
||||
|
||||
/* Canonical singleton boilerplate.
|
||||
See Cocoa Fundamentals Guide: Creating a Singleton Instance.
|
||||
See also +sharedMixer above.
|
||||
|
||||
NOTE: assumes single-threaded access.
|
||||
*/
|
||||
|
||||
+ (id)allocWithZone:(NSZone *)inZone
|
||||
{
|
||||
if (sSingleton == nil)
|
||||
{
|
||||
sSingleton = [super allocWithZone:inZone];
|
||||
return sSingleton;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (id)copyWithZone:(NSZone *)inZone
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (id)retain
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (NSUInteger)retainCount
|
||||
{
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
|
||||
- (void)release
|
||||
{}
|
||||
|
||||
|
||||
- (id)autorelease
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
40
src/Core/OOOpenAL.h
Normal file
40
src/Core/OOOpenAL.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
|
||||
OOOpenAL.h
|
||||
|
||||
Singleton controller for Open AL interfaces
|
||||
|
||||
Oolite
|
||||
Copyright (C) 2004-2013 Giles C Williams and contributors
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
|
||||
// alGetError should always be called before openAL calls to reset the
|
||||
// error stack
|
||||
#define OOAL(cmd) alGetError(); cmd;
|
||||
|
||||
@interface OOOpenAL : NSObject
|
||||
{
|
||||
@private
|
||||
ALCdevice *alcDevice;
|
||||
|
||||
|
||||
}
|
50
src/Core/OOOpenALController.h
Normal file
50
src/Core/OOOpenALController.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
|
||||
OOOpenALController.h
|
||||
|
||||
Singleton controller for Open AL interfaces
|
||||
|
||||
Oolite
|
||||
Copyright (C) 2004-2013 Giles C Williams and contributors
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
// alGetError should always be called before openAL calls to reset the
|
||||
// error stack
|
||||
#define OOAL(cmd) do { alGetError(); cmd; } while (0)
|
||||
static NSString * const kOOLogSoundInitError = @"sound.initialization.error";
|
||||
static NSString * const kOOLogSoundLoadingSuccess = @"sound.load.success";
|
||||
static NSString * const kOOLogSoundLoadingError = @"sound.load.error";
|
||||
|
||||
@interface OOOpenALController : NSObject
|
||||
{
|
||||
@private
|
||||
ALCdevice *device;
|
||||
ALCcontext *context;
|
||||
}
|
||||
|
||||
+ (OOOpenALController *) sharedController;
|
||||
|
||||
- (void) setMasterVolume:(ALfloat) fraction;
|
||||
- (ALfloat) masterVolume;
|
||||
|
||||
@end
|
83
src/Core/OOOpenALController.m
Normal file
83
src/Core/OOOpenALController.m
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
|
||||
OOOpenALController.m
|
||||
|
||||
|
||||
Oolite
|
||||
Copyright (C) 2004-2013 Giles C Williams and contributors
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA.
|
||||
|
||||
*/
|
||||
|
||||
#import "OOOpenALController.h"
|
||||
#import "OOLogging.h"
|
||||
|
||||
static id sSingleton = nil;
|
||||
|
||||
@implementation OOOpenALController
|
||||
|
||||
+ (OOOpenALController *) sharedController
|
||||
{
|
||||
if (sSingleton == nil)
|
||||
{
|
||||
sSingleton = [[self alloc] init];
|
||||
}
|
||||
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
|
||||
- (id) init
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
ALuint error;
|
||||
device = alcOpenDevice(NULL); // default device
|
||||
if (!device)
|
||||
{
|
||||
OOLog(kOOLogSoundInitError,@"Failed to open default sound device");
|
||||
return nil;
|
||||
}
|
||||
context = alcCreateContext(device,NULL); // default context
|
||||
if (!alcMakeContextCurrent(context))
|
||||
{
|
||||
OOLog(kOOLogSoundInitError,@"Failed to create default sound context");
|
||||
return nil;
|
||||
}
|
||||
if ((error = alGetError()) != AL_NO_ERROR)
|
||||
{
|
||||
OOLog(kOOLogSoundInitError,@"Error %d creating sound context",error);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void) setMasterVolume:(ALfloat) fraction
|
||||
{
|
||||
OOAL(alListenerf(AL_GAIN,fraction));
|
||||
}
|
||||
|
||||
- (ALfloat) masterVolume
|
||||
{
|
||||
ALfloat fraction = 0.0;
|
||||
OOAL(alGetListenerf(AL_GAIN,&fraction));
|
||||
return fraction;
|
||||
}
|
||||
|
||||
@end
|
@ -43,7 +43,14 @@ MA 02110-1301, USA.
|
||||
|
||||
#import "OOCocoa.h"
|
||||
|
||||
// currently on SDL platforms only as I can't test Mac OS X
|
||||
#define OOLITE_OPENAL OOLITE_SDL
|
||||
|
||||
#if OOLITE_OPENAL
|
||||
#import "OOALSound.h"
|
||||
#import "OOALMusic.h"
|
||||
#import "OOBasicSoundReferencePoint.h"
|
||||
#else
|
||||
#if OOLITE_SDL
|
||||
#import "OOSDLSound.h"
|
||||
#import "SDLMusic.h"
|
||||
@ -53,5 +60,6 @@ MA 02110-1301, USA.
|
||||
#import "OOCAMusic.h"
|
||||
#import "OOCASoundReferencePoint.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#import "OOSoundSource.h"
|
||||
|
Loading…
x
Reference in New Issue
Block a user