🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
8.5 KiB

  1. /*
  2. * OpenAL HRTF Example
  3. *
  4. * Copyright (c) 2015 by Chris Robinson <chris.kcat@gmail.com>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. /* This file contains an example for selecting an HRTF. */
  25. #include <stdio.h>
  26. #include <assert.h>
  27. #include <math.h>
  28. #include <SDL_sound.h>
  29. #include "AL/al.h"
  30. #include "AL/alc.h"
  31. #include "AL/alext.h"
  32. #include "common/alhelpers.h"
  33. #ifndef M_PI
  34. #define M_PI (3.14159265358979323846)
  35. #endif
  36. static LPALCGETSTRINGISOFT alcGetStringiSOFT;
  37. static LPALCRESETDEVICESOFT alcResetDeviceSOFT;
  38. /* LoadBuffer loads the named audio file into an OpenAL buffer object, and
  39. * returns the new buffer ID.
  40. */
  41. static ALuint LoadSound(const char *filename)
  42. {
  43. Sound_Sample *sample;
  44. ALenum err, format;
  45. ALuint buffer;
  46. Uint32 slen;
  47. /* Open the audio file */
  48. sample = Sound_NewSampleFromFile(filename, NULL, 65536);
  49. if(!sample)
  50. {
  51. fprintf(stderr, "Could not open audio in %s\n", filename);
  52. return 0;
  53. }
  54. /* Get the sound format, and figure out the OpenAL format */
  55. if(sample->actual.channels == 1)
  56. {
  57. if(sample->actual.format == AUDIO_U8)
  58. format = AL_FORMAT_MONO8;
  59. else if(sample->actual.format == AUDIO_S16SYS)
  60. format = AL_FORMAT_MONO16;
  61. else
  62. {
  63. fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format);
  64. Sound_FreeSample(sample);
  65. return 0;
  66. }
  67. }
  68. else if(sample->actual.channels == 2)
  69. {
  70. if(sample->actual.format == AUDIO_U8)
  71. format = AL_FORMAT_STEREO8;
  72. else if(sample->actual.format == AUDIO_S16SYS)
  73. format = AL_FORMAT_STEREO16;
  74. else
  75. {
  76. fprintf(stderr, "Unsupported sample format: 0x%04x\n", sample->actual.format);
  77. Sound_FreeSample(sample);
  78. return 0;
  79. }
  80. }
  81. else
  82. {
  83. fprintf(stderr, "Unsupported channel count: %d\n", sample->actual.channels);
  84. Sound_FreeSample(sample);
  85. return 0;
  86. }
  87. /* Decode the whole audio stream to a buffer. */
  88. slen = Sound_DecodeAll(sample);
  89. if(!sample->buffer || slen == 0)
  90. {
  91. fprintf(stderr, "Failed to read audio from %s\n", filename);
  92. Sound_FreeSample(sample);
  93. return 0;
  94. }
  95. /* Buffer the audio data into a new buffer object, then free the data and
  96. * close the file. */
  97. buffer = 0;
  98. alGenBuffers(1, &buffer);
  99. alBufferData(buffer, format, sample->buffer, slen, sample->actual.rate);
  100. Sound_FreeSample(sample);
  101. /* Check if an error occured, and clean up if so. */
  102. err = alGetError();
  103. if(err != AL_NO_ERROR)
  104. {
  105. fprintf(stderr, "OpenAL Error: %s\n", alGetString(err));
  106. if(buffer && alIsBuffer(buffer))
  107. alDeleteBuffers(1, &buffer);
  108. return 0;
  109. }
  110. return buffer;
  111. }
  112. int main(int argc, char **argv)
  113. {
  114. ALCdevice *device;
  115. ALboolean has_angle_ext;
  116. ALuint source, buffer;
  117. const char *soundname;
  118. const char *hrtfname;
  119. ALCint hrtf_state;
  120. ALCint num_hrtf;
  121. ALdouble angle;
  122. ALenum state;
  123. /* Print out usage if no arguments were specified */
  124. if(argc < 2)
  125. {
  126. fprintf(stderr, "Usage: %s [-device <name>] [-hrtf <name>] <soundfile>\n", argv[0]);
  127. return 1;
  128. }
  129. /* Initialize OpenAL, and check for HRTF support. */
  130. argv++; argc--;
  131. if(InitAL(&argv, &argc) != 0)
  132. return 1;
  133. device = alcGetContextsDevice(alcGetCurrentContext());
  134. if(!alcIsExtensionPresent(device, "ALC_SOFT_HRTF"))
  135. {
  136. fprintf(stderr, "Error: ALC_SOFT_HRTF not supported\n");
  137. CloseAL();
  138. return 1;
  139. }
  140. /* Define a macro to help load the function pointers. */
  141. #define LOAD_PROC(d, x) ((x) = alcGetProcAddress((d), #x))
  142. LOAD_PROC(device, alcGetStringiSOFT);
  143. LOAD_PROC(device, alcResetDeviceSOFT);
  144. #undef LOAD_PROC
  145. /* Check for the AL_EXT_STEREO_ANGLES extension to be able to also rotate
  146. * stereo sources.
  147. */
  148. has_angle_ext = alIsExtensionPresent("AL_EXT_STEREO_ANGLES");
  149. printf("AL_EXT_STEREO_ANGLES%s found\n", has_angle_ext?"":" not");
  150. /* Check for user-preferred HRTF */
  151. if(strcmp(argv[0], "-hrtf") == 0)
  152. {
  153. hrtfname = argv[1];
  154. soundname = argv[2];
  155. }
  156. else
  157. {
  158. hrtfname = NULL;
  159. soundname = argv[0];
  160. }
  161. /* Enumerate available HRTFs, and reset the device using one. */
  162. alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtf);
  163. if(!num_hrtf)
  164. printf("No HRTFs found\n");
  165. else
  166. {
  167. ALCint attr[5];
  168. ALCint index = -1;
  169. ALCint i;
  170. printf("Available HRTFs:\n");
  171. for(i = 0;i < num_hrtf;i++)
  172. {
  173. const ALCchar *name = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i);
  174. printf(" %d: %s\n", i, name);
  175. /* Check if this is the HRTF the user requested. */
  176. if(hrtfname && strcmp(name, hrtfname) == 0)
  177. index = i;
  178. }
  179. i = 0;
  180. attr[i++] = ALC_HRTF_SOFT;
  181. attr[i++] = ALC_TRUE;
  182. if(index == -1)
  183. {
  184. if(hrtfname)
  185. printf("HRTF \"%s\" not found\n", hrtfname);
  186. printf("Using default HRTF...\n");
  187. }
  188. else
  189. {
  190. printf("Selecting HRTF %d...\n", index);
  191. attr[i++] = ALC_HRTF_ID_SOFT;
  192. attr[i++] = index;
  193. }
  194. attr[i] = 0;
  195. if(!alcResetDeviceSOFT(device, attr))
  196. printf("Failed to reset device: %s\n", alcGetString(device, alcGetError(device)));
  197. }
  198. /* Check if HRTF is enabled, and show which is being used. */
  199. alcGetIntegerv(device, ALC_HRTF_SOFT, 1, &hrtf_state);
  200. if(!hrtf_state)
  201. printf("HRTF not enabled!\n");
  202. else
  203. {
  204. const ALchar *name = alcGetString(device, ALC_HRTF_SPECIFIER_SOFT);
  205. printf("HRTF enabled, using %s\n", name);
  206. }
  207. fflush(stdout);
  208. /* Initialize SDL_sound. */
  209. Sound_Init();
  210. /* Load the sound into a buffer. */
  211. buffer = LoadSound(soundname);
  212. if(!buffer)
  213. {
  214. Sound_Quit();
  215. CloseAL();
  216. return 1;
  217. }
  218. /* Create the source to play the sound with. */
  219. source = 0;
  220. alGenSources(1, &source);
  221. alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE);
  222. alSource3f(source, AL_POSITION, 0.0f, 0.0f, -1.0f);
  223. alSourcei(source, AL_BUFFER, buffer);
  224. assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source");
  225. /* Play the sound until it finishes. */
  226. angle = 0.0;
  227. alSourcePlay(source);
  228. do {
  229. al_nssleep(10000000);
  230. /* Rotate the source around the listener by about 1/4 cycle per second,
  231. * and keep it within -pi...+pi.
  232. */
  233. angle += 0.01 * M_PI * 0.5;
  234. if(angle > M_PI)
  235. angle -= M_PI*2.0;
  236. /* This only rotates mono sounds. */
  237. alSource3f(source, AL_POSITION, (ALfloat)sin(angle), 0.0f, -(ALfloat)cos(angle));
  238. if(has_angle_ext)
  239. {
  240. /* This rotates stereo sounds with the AL_EXT_STEREO_ANGLES
  241. * extension. Angles are specified counter-clockwise in radians.
  242. */
  243. ALfloat angles[2] = { (ALfloat)(M_PI/6.0 - angle), (ALfloat)(-M_PI/6.0 - angle) };
  244. alSourcefv(source, AL_STEREO_ANGLES, angles);
  245. }
  246. alGetSourcei(source, AL_SOURCE_STATE, &state);
  247. } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING);
  248. /* All done. Delete resources, and close down SDL_sound and OpenAL. */
  249. alDeleteSources(1, &source);
  250. alDeleteBuffers(1, &buffer);
  251. Sound_Quit();
  252. CloseAL();
  253. return 0;
  254. }