/* * OpenAL Helpers * * Copyright (c) 2011 by Chris Robinson * * 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. */ /* This file contains routines to help with some menial OpenAL-related tasks, * such as opening a device and setting up a context, closing the device and * destroying its context, converting between frame counts and byte lengths, * finding an appropriate buffer format, and getting readable strings for * channel configs and sample types. */ #include #include "AL/al.h" #include "AL/alc.h" #include "AL/alext.h" #include "alhelpers.h" const char *ChannelsName(ALenum chans) { switch(chans) { case AL_MONO: return "Mono"; case AL_STEREO: return "Stereo"; case AL_REAR: return "Rear"; case AL_QUAD: return "Quadraphonic"; case AL_5POINT1: return "5.1 Surround"; case AL_6POINT1: return "6.1 Surround"; case AL_7POINT1: return "7.1 Surround"; } return "Unknown Channels"; } const char *TypeName(ALenum type) { switch(type) { case AL_BYTE: return "S8"; case AL_UNSIGNED_BYTE: return "U8"; case AL_SHORT: return "S16"; case AL_UNSIGNED_SHORT: return "U16"; case AL_INT: return "S32"; case AL_UNSIGNED_INT: return "U32"; case AL_FLOAT: return "Float32"; case AL_DOUBLE: return "Float64"; } return "Unknown Type"; } ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type) { switch(channels) { case AL_MONO: size *= 1; break; case AL_STEREO: size *= 2; break; case AL_REAR: size *= 2; break; case AL_QUAD: size *= 4; break; case AL_5POINT1: size *= 6; break; case AL_6POINT1: size *= 7; break; case AL_7POINT1: size *= 8; break; } switch(type) { case AL_BYTE: size *= sizeof(ALbyte); break; case AL_UNSIGNED_BYTE: size *= sizeof(ALubyte); break; case AL_SHORT: size *= sizeof(ALshort); break; case AL_UNSIGNED_SHORT: size *= sizeof(ALushort); break; case AL_INT: size *= sizeof(ALint); break; case AL_UNSIGNED_INT: size *= sizeof(ALuint); break; case AL_FLOAT: size *= sizeof(ALfloat); break; case AL_DOUBLE: size *= sizeof(ALdouble); break; } return size; } ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type) { return size / FramesToBytes(1, channels, type); } ALenum GetFormat(ALenum channels, ALenum type) { ALenum format = 0; /* We use the AL_EXT_MCFORMATS extension to provide output of Quad, 5.1, * and 7.1 channel configs, AL_EXT_FLOAT32 for 32-bit float samples, and * AL_EXT_DOUBLE for 64-bit float samples. */ if(type == AL_UNSIGNED_BYTE) { if(channels == AL_MONO) format = AL_FORMAT_MONO8; else if(channels == AL_STEREO) format = AL_FORMAT_STEREO8; else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { if(channels == AL_QUAD) format = alGetEnumValue("AL_FORMAT_QUAD8"); else if(channels == AL_5POINT1) format = alGetEnumValue("AL_FORMAT_51CHN8"); else if(channels == AL_6POINT1) format = alGetEnumValue("AL_FORMAT_61CHN8"); else if(channels == AL_7POINT1) format = alGetEnumValue("AL_FORMAT_71CHN8"); } } else if(type == AL_SHORT) { if(channels == AL_MONO) format = AL_FORMAT_MONO16; else if(channels == AL_STEREO) format = AL_FORMAT_STEREO16; else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { if(channels == AL_QUAD) format = alGetEnumValue("AL_FORMAT_QUAD16"); else if(channels == AL_5POINT1) format = alGetEnumValue("AL_FORMAT_51CHN16"); else if(channels == AL_6POINT1) format = alGetEnumValue("AL_FORMAT_61CHN16"); else if(channels == AL_7POINT1) format = alGetEnumValue("AL_FORMAT_71CHN16"); } } else if(type == AL_FLOAT && alIsExtensionPresent("AL_EXT_FLOAT32")) { if(channels == AL_MONO) format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32"); else if(channels == AL_STEREO) format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32"); else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) { if(channels == AL_QUAD) format = alGetEnumValue("AL_FORMAT_QUAD32"); else if(channels == AL_5POINT1) format = alGetEnumValue("AL_FORMAT_51CHN32"); else if(channels == AL_6POINT1) format = alGetEnumValue("AL_FORMAT_61CHN32"); else if(channels == AL_7POINT1) format = alGetEnumValue("AL_FORMAT_71CHN32"); } } else if(type == AL_DOUBLE && alIsExtensionPresent("AL_EXT_DOUBLE")) { if(channels == AL_MONO) format = alGetEnumValue("AL_FORMAT_MONO_DOUBLE"); else if(channels == AL_STEREO) format = alGetEnumValue("AL_FORMAT_STEREO_DOUBLE"); } /* NOTE: It seems OSX returns -1 from alGetEnumValue for unknown enums, as * opposed to 0. Correct it. */ if(format == -1) format = 0; return format; } int InitAL(void) { ALCdevice *device; ALCcontext *ctx; /* Open and initialize a device with default settings */ device = alcOpenDevice(NULL); if(!device) { fprintf(stderr, "Could not open a device!\n"); return 1; } ctx = alcCreateContext(device, NULL); if(ctx == NULL || alcMakeContextCurrent(ctx) == ALC_FALSE) { if(ctx != NULL) alcDestroyContext(ctx); alcCloseDevice(device); fprintf(stderr, "Could not set a context!\n"); return 1; } return 0; } void CloseAL(void) { ALCdevice *device; ALCcontext *ctx; /* Close the device belonging to the current context, and destroy the * context. */ ctx = alcGetCurrentContext(); if(ctx == NULL) return; device = alcGetContextsDevice(ctx); alcMakeContextCurrent(NULL); alcDestroyContext(ctx); alcCloseDevice(device); }