openal.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. #ifdef __APPLE__
  2. #include <al.h>
  3. #include <alc.h>
  4. #else
  5. #include <AL/al.h>
  6. #include <AL/alc.h>
  7. #endif
  8. namespace ruby {
  9. #include "openal.hpp"
  10. class pAudioOpenAL {
  11. public:
  12. AudioOpenAL &self;
  13. struct {
  14. ALCdevice *handle;
  15. ALCcontext *context;
  16. ALuint source;
  17. ALenum format;
  18. unsigned latency;
  19. unsigned queue_length;
  20. } device;
  21. struct {
  22. uint32_t *data;
  23. unsigned length;
  24. unsigned size;
  25. } buffer;
  26. struct {
  27. bool synchronize;
  28. unsigned frequency;
  29. unsigned latency;
  30. } settings;
  31. bool cap(Audio::Setting setting) {
  32. if(setting == Audio::Synchronize) return true;
  33. if(setting == Audio::Frequency) return true;
  34. if(setting == Audio::Latency) return true;
  35. return false;
  36. }
  37. uintptr_t get(Audio::Setting setting) {
  38. if(setting == Audio::Synchronize) return settings.synchronize;
  39. if(setting == Audio::Frequency) return settings.frequency;
  40. if(setting == Audio::Latency) return settings.latency;
  41. return false;
  42. }
  43. bool set(Audio::Setting setting, uintptr_t param) {
  44. if(setting == Audio::Synchronize) {
  45. settings.synchronize = param;
  46. return true;
  47. }
  48. if(setting == Audio::Frequency) {
  49. settings.frequency = param;
  50. return true;
  51. }
  52. if(setting == Audio::Latency) {
  53. if(settings.latency != param) {
  54. settings.latency = param;
  55. update_latency();
  56. }
  57. return true;
  58. }
  59. return false;
  60. }
  61. void sample(uint16_t sl, uint16_t sr) {
  62. buffer.data[buffer.length++] = sl + (sr << 16);
  63. if(buffer.length < buffer.size) return;
  64. ALuint albuffer = 0;
  65. int processed = 0;
  66. while(true) {
  67. alGetSourcei(device.source, AL_BUFFERS_PROCESSED, &processed);
  68. while(processed--) {
  69. alSourceUnqueueBuffers(device.source, 1, &albuffer);
  70. alDeleteBuffers(1, &albuffer);
  71. device.queue_length--;
  72. }
  73. //wait for buffer playback to catch up to sample generation if not synchronizing
  74. if(settings.synchronize == false || device.queue_length < 3) break;
  75. }
  76. if(device.queue_length < 3) {
  77. alGenBuffers(1, &albuffer);
  78. alBufferData(albuffer, device.format, buffer.data, buffer.size * 4, settings.frequency);
  79. alSourceQueueBuffers(device.source, 1, &albuffer);
  80. device.queue_length++;
  81. }
  82. ALint playing;
  83. alGetSourcei(device.source, AL_SOURCE_STATE, &playing);
  84. if(playing != AL_PLAYING) alSourcePlay(device.source);
  85. buffer.length = 0;
  86. }
  87. void update_latency() {
  88. if(buffer.data) delete[] buffer.data;
  89. buffer.size = settings.frequency * settings.latency / 1000.0 + 0.5;
  90. buffer.data = new uint32_t[buffer.size];
  91. }
  92. bool init() {
  93. update_latency();
  94. device.queue_length = 0;
  95. bool success = false;
  96. if(device.handle = alcOpenDevice(NULL)) {
  97. if(device.context = alcCreateContext(device.handle, NULL)) {
  98. alcMakeContextCurrent(device.context);
  99. alGenSources(1, &device.source);
  100. //alSourcef (device.source, AL_PITCH, 1.0);
  101. //alSourcef (device.source, AL_GAIN, 1.0);
  102. //alSource3f(device.source, AL_POSITION, 0.0, 0.0, 0.0);
  103. //alSource3f(device.source, AL_VELOCITY, 0.0, 0.0, 0.0);
  104. //alSource3f(device.source, AL_DIRECTION, 0.0, 0.0, 0.0);
  105. //alSourcef (device.source, AL_ROLLOFF_FACTOR, 0.0);
  106. //alSourcei (device.source, AL_SOURCE_RELATIVE, AL_TRUE);
  107. alListener3f(AL_POSITION, 0.0, 0.0, 0.0);
  108. alListener3f(AL_VELOCITY, 0.0, 0.0, 0.0);
  109. ALfloat listener_orientation[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
  110. alListenerfv(AL_ORIENTATION, listener_orientation);
  111. success = true;
  112. }
  113. }
  114. if(success == false) {
  115. term();
  116. return false;
  117. }
  118. return true;
  119. }
  120. void term() {
  121. if(alIsSource(device.source) == AL_TRUE) {
  122. int playing = 0;
  123. alGetSourcei(device.source, AL_SOURCE_STATE, &playing);
  124. if(playing == AL_PLAYING) {
  125. alSourceStop(device.source);
  126. int queued = 0;
  127. alGetSourcei(device.source, AL_BUFFERS_QUEUED, &queued);
  128. while(queued--) {
  129. ALuint albuffer = 0;
  130. alSourceUnqueueBuffers(device.source, 1, &albuffer);
  131. alDeleteBuffers(1, &albuffer);
  132. device.queue_length--;
  133. }
  134. }
  135. alDeleteSources(1, &device.source);
  136. device.source = 0;
  137. }
  138. if(device.context) {
  139. alcMakeContextCurrent(NULL);
  140. alcDestroyContext(device.context);
  141. device.context = 0;
  142. }
  143. if(device.handle) {
  144. alcCloseDevice(device.handle);
  145. device.handle = 0;
  146. }
  147. if(buffer.data) {
  148. delete[] buffer.data;
  149. buffer.data = 0;
  150. }
  151. }
  152. pAudioOpenAL(AudioOpenAL &self_) : self(self_) {
  153. device.source = 0;
  154. device.handle = 0;
  155. device.context = 0;
  156. device.format = AL_FORMAT_STEREO16;
  157. device.queue_length = 0;
  158. buffer.data = 0;
  159. buffer.length = 0;
  160. buffer.size = 0;
  161. settings.synchronize = true;
  162. settings.frequency = 22050;
  163. settings.latency = 40;
  164. }
  165. ~pAudioOpenAL() {
  166. term();
  167. }
  168. };
  169. bool AudioOpenAL::cap(Setting setting) { return p.cap(setting); }
  170. uintptr_t AudioOpenAL::get(Setting setting) { return p.get(setting); }
  171. bool AudioOpenAL::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
  172. void AudioOpenAL::sample(uint16_t sl, uint16_t sr) { p.sample(sl, sr); }
  173. bool AudioOpenAL::init() { return p.init(); }
  174. void AudioOpenAL::term() { p.term(); }
  175. AudioOpenAL::AudioOpenAL() : p(*new pAudioOpenAL(*this)) {}
  176. AudioOpenAL::~AudioOpenAL() { delete &p; }
  177. } //namespace ruby