aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2015-10-28 18:52:49 -0700
committerChris Robinson <[email protected]>2015-10-28 18:52:49 -0700
commitf4a53cf6096adb63701ea36cecf941a2eaeb0ff2 (patch)
treefb877f90b6ef7c48dc52142fd50bbd4982ac8e75
parentbd73cdab0df049ece41f20ff6a83465b0bfb4e0a (diff)
Add an HRTF example
Doubles as a psuedo-test to play a sound with HRTF.
-rw-r--r--CMakeLists.txt5
-rw-r--r--ChangeLog2
-rw-r--r--examples/alhrtf.c247
3 files changed, 254 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index db918de0..bd73876c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1233,6 +1233,11 @@ IF(ALSOFT_EXAMPLES)
SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
${SDL_SOUND_INCLUDE_DIR})
+ ADD_EXECUTABLE(alhrtf examples/alhrtf.c)
+ TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME})
+ SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR}
+ ${SDL_SOUND_INCLUDE_DIR})
+
IF(ALSOFT_INSTALL)
INSTALL(TARGETS alstream alreverb allatency alloopback
RUNTIME DESTINATION bin
diff --git a/ChangeLog b/ChangeLog
index f5d04c75..40ff34ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -47,6 +47,8 @@ openal-soft-1.17.0:
Improved support for building as a sub-project.
+ Added an HRTF playback example.
+
Added a tone generator output test.
Added a toolchain to help with cross-compiling to Android.
diff --git a/examples/alhrtf.c b/examples/alhrtf.c
new file mode 100644
index 00000000..e787f5dd
--- /dev/null
+++ b/examples/alhrtf.c
@@ -0,0 +1,247 @@
+/*
+ * OpenAL HRTF Example
+ *
+ * Copyright (c) 2015 by Chris Robinson <[email protected]>
+ *
+ * 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 an example for selecting an HRTF. */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "AL/al.h"
+#include "AL/alc.h"
+#include "AL/alext.h"
+
+#include "common/alhelpers.h"
+#include "common/sdl_sound.h"
+
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
+static LPALCGETSTRINGISOFT alcGetStringiSOFT;
+static LPALCRESETDEVICESOFT alcResetDeviceSOFT;
+
+/* LoadBuffer loads the named audio file into an OpenAL buffer object, and
+ * returns the new buffer ID. */
+static ALuint LoadSound(const char *filename)
+{
+ ALenum err, format, type, channels;
+ ALuint rate, buffer;
+ size_t datalen;
+ void *data;
+ FilePtr sound;
+
+ /* Open the audio file */
+ sound = openAudioFile(filename, 1000);
+ if(!sound)
+ {
+ fprintf(stderr, "Could not open audio in %s\n", filename);
+ closeAudioFile(sound);
+ return 0;
+ }
+
+ /* Get the sound format, and figure out the OpenAL format */
+ if(getAudioInfo(sound, &rate, &channels, &type) != 0)
+ {
+ fprintf(stderr, "Error getting audio info for %s\n", filename);
+ closeAudioFile(sound);
+ return 0;
+ }
+
+ format = GetFormat(channels, type, NULL);
+ if(format == AL_NONE)
+ {
+ fprintf(stderr, "Unsupported format (%s, %s) for %s\n",
+ ChannelsName(channels), TypeName(type), filename);
+ closeAudioFile(sound);
+ return 0;
+ }
+
+ /* Decode the whole audio stream to a buffer. */
+ data = decodeAudioStream(sound, &datalen);
+ if(!data)
+ {
+ fprintf(stderr, "Failed to read audio from %s\n", filename);
+ closeAudioFile(sound);
+ return 0;
+ }
+
+ /* Buffer the audio data into a new buffer object, then free the data and
+ * close the file. */
+ buffer = 0;
+ alGenBuffers(1, &buffer);
+ alBufferData(buffer, format, data, datalen, rate);
+ free(data);
+ closeAudioFile(sound);
+
+ /* Check if an error occured, and clean up if so. */
+ err = alGetError();
+ if(err != AL_NO_ERROR)
+ {
+ fprintf(stderr, "OpenAL Error: %s\n", alGetString(err));
+ if(buffer && alIsBuffer(buffer))
+ alDeleteBuffers(1, &buffer);
+ return 0;
+ }
+
+ return buffer;
+}
+
+
+int main(int argc, char **argv)
+{
+ ALCdevice *device;
+ ALuint source, buffer;
+ const char *soundname;
+ const char *hrtfname;
+ ALCint hrtf_state;
+ ALCint num_hrtf;
+ ALdouble angle;
+ ALenum state;
+
+ /* Print out usage if no file was specified */
+ if(argc < 2 || (strcmp(argv[1], "-hrtf") == 0 && argc < 4))
+ {
+ fprintf(stderr, "Usage: %s [-hrtf <name>] <soundfile>\n", argv[0]);
+ return 1;
+ }
+
+ /* Initialize OpenAL with the default device, and check for HRTF support. */
+ if(InitAL() != 0)
+ return 1;
+
+ if(strcmp(argv[1], "-hrtf") == 0)
+ {
+ hrtfname = argv[2];
+ soundname = argv[3];
+ }
+ else
+ {
+ hrtfname = NULL;
+ soundname = argv[1];
+ }
+
+ device = alcGetContextsDevice(alcGetCurrentContext());
+ if(!alcIsExtensionPresent(device, "ALC_SOFT_HRTF"))
+ {
+ fprintf(stderr, "Error: ALC_SOFT_HRTF not supported\n");
+ CloseAL();
+ return 1;
+ }
+
+ /* Define a macro to help load the function pointers. */
+#define LOAD_PROC(d, x) ((x) = alcGetProcAddress((d), #x))
+ LOAD_PROC(device, alcGetStringiSOFT);
+ LOAD_PROC(device, alcResetDeviceSOFT);
+#undef LOAD_PROC
+
+ /* Enumerate available HRTFs, and reset the device using one. */
+ alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
+ if(!num_hrtf)
+ printf("No HRTFs found\n");
+ else
+ {
+ ALCint attr[5];
+ ALCint index = -1;
+ ALCint i;
+
+ printf("Available HRTFs:\n");
+ for(i = 0;i < num_hrtf;i++)
+ {
+ const ALCchar *name = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
+ printf(" %d: %s\n", i, name);
+
+ /* Check if this is the HRTF the user requested. */
+ if(hrtfname && strcmp(name, hrtfname) == 0)
+ index = i;
+ }
+
+ if(index == -1)
+ {
+ if(hrtfname)
+ printf("HRTF \"%s\" not found\n", hrtfname);
+ index = 0;
+ }
+ printf("Selecting HRTF %d...\n", index);
+
+ attr[0] = ALC_HRTF_SOFT;
+ attr[1] = ALC_TRUE;
+ attr[2] = ALC_HRTF_ID_SOFT;
+ attr[3] = index;
+ attr[4] = 0;
+
+ if(!alcResetDeviceSOFT(device, attr))
+ printf("Failed to reset device: %s\n", alcGetString(device, alcGetError(device)));
+ }
+
+ /* Check if HRTF is enabled, and show which is being used. */
+ alcGetIntegerv(device, ALC_HRTF_SOFT, 1, &hrtf_state);
+ if(!hrtf_state)
+ printf("HRTF not enabled!\n");
+ else
+ {
+ const ALchar *name = alcGetString(device, ALC_HRTF_SPECIFIER_SOFT);
+ printf("HRTF enabled, using %s\n", name);
+ }
+ fflush(stdout);
+
+ /* Load the sound into a buffer. */
+ buffer = LoadSound(soundname);
+ if(!buffer)
+ {
+ CloseAL();
+ return 1;
+ }
+
+ /* Create the source to play the sound with. */
+ source = 0;
+ alGenSources(1, &source);
+ alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
+ alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f);
+ alSourcei(source, AL_BUFFER, buffer);
+ assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source");
+
+ /* Play the sound until it finishes. */
+ angle = 0.0;
+ alSourcePlay(source);
+ do {
+ Sleep(10);
+
+ /* Rotate the source around the listener by about 1/4 cycle per second.
+ * Only affects mono sounds.
+ */
+ angle += 0.01 * M_PI * 0.5;
+ alSource3f(source, AL_POSITION, (ALfloat)sin(angle), 0.0f, -(ALfloat)cos(angle));
+
+ alGetSourcei(source, AL_SOURCE_STATE, &state);
+ } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING);
+
+ /* All done. Delete resources, and close OpenAL. */
+ alDeleteSources(1, &source);
+ alDeleteBuffers(1, &buffer);
+
+ CloseAL();
+
+ return 0;
+}