diff OpenALSoundProvider.h @ 2324:b2e3ac05f2b3

Merge
author Grumpy7
date Thu, 27 Mar 2014 23:30:02 +0100
parents 9987f93d7e1f
children a2d95b16e28b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OpenALSoundProvider.h	Thu Mar 27 23:30:02 2014 +0100
@@ -0,0 +1,343 @@
+#pragma once
+#include "lib/OpenAL/al.h"
+#include "lib/OpenAL/alc.h"
+#pragma comment(lib, "OpenAL32.lib")
+
+#include "stuff.h"
+
+class OpenALSoundProvider
+{
+  public:
+    struct TrackBuffer
+    {
+      unsigned int source_id;
+      unsigned int buffer_id;
+    };
+
+    struct StreamingTrackBuffer
+    {
+      unsigned int source_id;
+      ALenum       sample_format;
+      int          sample_rate;
+    };
+
+    inline OpenALSoundProvider()
+    {
+      this->device = nullptr;
+      this->context = nullptr;
+    }
+
+    inline bool Initialize()
+    {
+      auto device_names = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
+      if (!device_names)
+        device_names = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
+      if (device_names)
+      {
+        for (auto device_name = device_names; device_name[0]; device_name += strlen(device_name))
+        {
+          continue;
+        }
+      }
+
+      device = alcOpenDevice(nullptr);
+      if (!device || CheckError())
+        return false;
+
+      context = alcCreateContext(device, nullptr);
+      if (!context || CheckError())
+        return Release(), false;
+
+      alcMakeContextCurrent(context);
+
+      bool eax2 = alIsExtensionPresent("EAX2.0");
+      bool eax3 = alIsExtensionPresent("EAX3.0");
+      bool eax4 = alIsExtensionPresent("EAX4.0");
+      bool eax5 = alIsExtensionPresent("EAX5.0");
+      
+      auto vendor = alGetString(AL_VENDOR);
+      auto version = alGetString(AL_VERSION);
+      auto extensions = alcGetString(device, ALC_EXTENSIONS);
+
+      return true;
+    }
+
+    void Release()
+    {
+      alcMakeContextCurrent(nullptr);
+      if (context)
+      {
+        alcDestroyContext(context);
+        context = nullptr;
+      }
+      if (device)
+      {
+        alcCloseDevice(device);
+        device = nullptr;
+      }
+    }
+
+
+    void DeleteBuffer16(TrackBuffer **buffer)
+    {
+      alDeleteBuffers(1, &(*buffer)->buffer_id);
+      CheckError();
+
+      delete *buffer;
+      *buffer = nullptr;
+    }
+
+    float alBufferLength(unsigned int buffer)
+    {
+      int size, bits, channels, freq;
+
+      alGetBufferi(buffer, AL_SIZE, &size);
+      alGetBufferi(buffer, AL_BITS, &bits);
+      alGetBufferi(buffer, AL_CHANNELS, &channels);
+      alGetBufferi(buffer, AL_FREQUENCY, &freq);
+      if (CheckError())
+        return 0.0f;
+
+      return (ALfloat)((ALuint)size / channels / (bits / 8)) / (ALfloat)freq;
+    }
+
+    StreamingTrackBuffer *CreateStreamingTrack16(int num_channels, int sample_rate, int bytes_per_sample)
+    {
+      Assert(bytes_per_sample == 2, "OpenALSoundProvider: unsupported sample size: %u", bytes_per_sample);
+
+      ALenum sound_format;
+      switch (num_channels)
+      {
+        case 1: sound_format = AL_FORMAT_MONO16;    break;
+        case 2: sound_format = AL_FORMAT_STEREO16;  break;
+        default:
+          if (bool multichannel = alIsExtensionPresent("AL_EXT_MCFORMATS"))
+          {
+            switch (num_channels)
+            {
+              case 4: sound_format = alGetEnumValue("AL_FORMAT_QUAD16");  break;
+              case 6: sound_format = alGetEnumValue("AL_FORMAT_51CHN16"); break;
+              case 7: sound_format = alGetEnumValue("AL_FORMAT_61CHN16"); break;
+              case 8: sound_format = alGetEnumValue("AL_FORMAT_71CHN16"); break;
+            }
+          }
+          Error("Unsupported number of audio channels: %u", num_channels);
+      }
+
+      unsigned int al_source = -1;
+      alGenSources(1, &al_source);
+      if (CheckError())
+        return nullptr;
+
+      float sound_pos[] = {0.0f, 0.0f, 0.0f},
+            sound_vel[] = {0.0f, 0.0f, 0.0f};
+
+      alSourcei(al_source, AL_LOOPING, AL_FALSE);
+      alSourcef(al_source, AL_PITCH, 1.0f);
+      alSourcef(al_source, AL_GAIN, 1.0f);
+      alSourcefv(al_source, AL_POSITION, sound_pos);
+      alSourcefv(al_source, AL_VELOCITY, sound_vel);
+
+      auto ret = new StreamingTrackBuffer;
+      ret->source_id = al_source;
+      ret->sample_format = sound_format;
+      ret->sample_rate = sample_rate;
+      return ret;
+    }
+
+    void Stream16(StreamingTrackBuffer *buffer, int num_samples, const void *samples, bool wait = false)
+    {
+      int bytes_per_sample = 2;
+
+      unsigned int al_buffer;
+      alGenBuffers(1, &al_buffer);
+      alBufferData(al_buffer, buffer->sample_format, samples, num_samples * bytes_per_sample, buffer->sample_rate);
+      if (CheckError())
+      {
+        alDeleteBuffers(1, &al_buffer);
+        return;
+      }
+
+      int num_processed_buffers = 0;
+      alGetSourcei(buffer->source_id, AL_BUFFERS_PROCESSED, &num_processed_buffers);
+      for (int i = 0; i < num_processed_buffers; ++i)
+      {
+        unsigned int processed_buffer_id;
+        alSourceUnqueueBuffers(buffer->source_id, 1, &processed_buffer_id);
+        if (!CheckError())
+          alDeleteBuffers(1, &processed_buffer_id);
+      }
+
+      alSourceQueueBuffers(buffer->source_id, 1, &al_buffer);
+      if (CheckError())
+      {
+        alDeleteBuffers(1, &al_buffer);
+        return;
+      }
+
+      volatile int status;
+      alGetSourcei(buffer->source_id, AL_SOURCE_STATE, (int *)&status);
+      if (status != AL_PLAYING)
+      {
+        float listener_pos[] = {0.0f, 0.0f, 0.0f};
+        float listener_vel[] = {0.0f, 0.0f, 0.0f};
+        float listener_orientation[] = {0.0f, 0.0f, -1.0f, // direction
+                                        0.0f, 1.0f, 0.0f}; // up vector
+        alListenerfv(AL_POSITION, listener_pos);
+        alListenerfv(AL_VELOCITY, listener_vel);
+        alListenerfv(AL_ORIENTATION, listener_orientation);
+
+        alSourcePlay(buffer->source_id);
+        if (CheckError())
+          __debugbreak();
+
+        if (wait)
+        {
+          do
+          {
+            alGetSourcei(buffer->source_id, AL_SOURCE_STATE, (int *)&status);
+          }
+          while (status == AL_PLAYING);
+        }
+      }
+    }
+
+
+
+
+    TrackBuffer *CreateTrack16(int num_channels, int sample_rate, int bytes_per_sample, int num_samples, const void *samples)
+    {
+      Assert(bytes_per_sample == 2, "OpenALSoundProvider: unsupported sample size: %u", bytes_per_sample);
+
+      ALenum sound_format;
+      switch (num_channels)
+      {
+        case 1: sound_format = AL_FORMAT_MONO16;    break;
+        case 2: sound_format = AL_FORMAT_STEREO16;  break;
+        default:
+          if (bool multichannel = alIsExtensionPresent("AL_EXT_MCFORMATS"))
+          {
+            switch (num_channels)
+            {
+              case 4: sound_format = alGetEnumValue("AL_FORMAT_QUAD16");  break;
+              case 6: sound_format = alGetEnumValue("AL_FORMAT_51CHN16"); break;
+              case 7: sound_format = alGetEnumValue("AL_FORMAT_61CHN16"); break;
+              case 8: sound_format = alGetEnumValue("AL_FORMAT_71CHN16"); break;
+            }
+          }
+          Error("Unsupported number of audio channels: %u", num_channels);
+      }
+
+      unsigned int al_source = -1;
+      alGenSources(1, &al_source);
+      if (CheckError())
+        return nullptr;
+
+      float sound_pos[] = {0.0f, 0.0f, 0.0f},
+            sound_vel[] = {0.0f, 0.0f, 0.0f};
+
+      alSourcei(al_source, AL_LOOPING, AL_FALSE);
+      alSourcef(al_source, AL_PITCH, 1.0f);
+      alSourcef(al_source, AL_GAIN, 1.0f);
+      alSourcefv(al_source, AL_POSITION, sound_pos);
+      alSourcefv(al_source, AL_VELOCITY, sound_vel);
+
+      unsigned int al_buffer = -1;
+      alGenBuffers(1, &al_buffer);
+      if (CheckError())
+      {
+        alDeleteSources(1, &al_source);
+        return nullptr;
+      }
+
+      alBufferData(al_buffer, sound_format, samples, num_samples * bytes_per_sample, sample_rate);
+      if (CheckError())
+      {
+        alDeleteSources(1, &al_source);
+        alDeleteBuffers(1, &al_buffer);
+        return nullptr;
+      }
+
+      alSourcei(al_source, AL_BUFFER, al_buffer);
+      if (CheckError())
+      {
+        alDeleteSources(1, &al_source);
+        alDeleteBuffers(1, &al_buffer);
+        return nullptr;
+      }
+
+      auto ret = new TrackBuffer;
+      ret->source_id = al_source;
+      ret->buffer_id = al_buffer;
+      return ret;
+    }
+
+
+    void PlayTrack16(TrackBuffer *buffer, bool loop = false, bool wait = false)
+    {
+      volatile int status;
+      alGetSourcei(buffer->source_id, AL_SOURCE_STATE, (int *)&status);
+      if (status == AL_PLAYING)
+        Error("Already playing");
+      else
+      {
+        float listener_pos[] = {0.0f, 0.0f, 0.0f};
+        float listener_vel[] = {0.0f, 0.0f, 0.0f};
+        float listener_orientation[] = {0.0f, 0.0f, -1.0f, // direction
+                                        0.0f, 1.0f, 0.0f}; // up vector
+        alListenerfv(AL_POSITION, listener_pos);
+        alListenerfv(AL_VELOCITY, listener_vel);
+        alListenerfv(AL_ORIENTATION, listener_orientation);
+
+        alSourcei(buffer->source_id, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
+        alSourcePlay(buffer->source_id);
+        if (CheckError())
+          __debugbreak();
+
+        if (wait && !loop)
+        {
+          float track_length = alBufferLength(buffer->buffer_id);
+          do
+          {
+            float track_offset = 0;
+            alGetSourcef(buffer->source_id, AL_SEC_OFFSET, &track_offset);
+            log("playing: %.4f/%.4f\n", track_offset, track_length);
+
+            alGetSourcei(buffer->source_id, AL_SOURCE_STATE, (int *)&status);
+          }
+          while (status == AL_PLAYING);
+        }
+      }
+    }
+
+
+
+  protected:
+    ALCdevice    *device;
+    ALCcontext   *context;
+
+
+    bool CheckError()
+    {
+      ALenum code1 = alGetError();
+      if (code1 != AL_NO_ERROR)
+      {
+        DWORD w;
+        const char *message = alGetString(code1);
+        WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), message, lstrlenA(message), &w, nullptr);
+        WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), "\n", 1, &w, nullptr);
+        return true;
+      }
+
+      ALenum code2 = alcGetError(device);
+      if (code2 != ALC_NO_ERROR)
+      {
+        DWORD w;
+        const char *message = alcGetString(device, code2);
+        WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), message, lstrlenA(message), &w, nullptr);
+        WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), "\n", 1, &w, nullptr);
+        return true;
+      }
+      return false;
+    }
+};
\ No newline at end of file