rhino/demo/c/dr_libs/old/dr_audio_ancient.h
Go to the documentation of this file.
1 // Public domain. See "unlicense" statement at the end of this file.
2 
3 //
4 // QUICK NOTES
5 //
6 // If you've stumbled across this library, be aware that this is very, very early in development. A lot of APIs
7 // are very temporary, in particular the effects API which at the moment are tied very closely to DirectSound.
8 //
9 // Currently, the only backend available is DirectSound while I figure out the API.
10 //
11 // General
12 // - This library is NOT thread safe. Functions can be called from any thread, but it is up to the host application
13 // to do synchronization.
14 // - This library is only concerned with playback and recording of raw audio data. It does not load audio files
15 // such as WAV, OGG and MP3.
16 // - Before you can create an output (playback) or input (recording) device you need to first create a context.
17 // - Each backend (DirectSound, ALSA, etc.) has it's own context. Using draudio_create_context() will find
18 // a backend implementation based on the platform dr_audio has been compiled for.
19 // - A context for a specific backend can be created as well. For example, draudio_create_context_dsound() will
20 // create a context which uses DirectSound as it's backend.
21 // - Currently, devices are enumerated once when the context is created. Thus, when a device is plugged in or
22 // unplugged it will not be detected by dr_audio and the context will need to be deleted and re-created.
23 // - Currently, dr_audio will only consider the first DRAUDIO_MAX_DEVICE_COUNT output and input devices, which
24 // is currently set to 16 and should be plenty for the vast majority of cases. Feel free to increase (or decrease)
25 // this number to suit your own requirements.
26 //
27 // Events
28 // - Events are handled via callbacks. The different types of events include stop, pause, play and markers.
29 // - The Stop event is fired when an output buffer is stopped, either from finishing it's playback or if it was
30 // stopped manually.
31 // - The Pause event is fired when the output buffer is paused.
32 // - The Play event is fired when the output buffer begins being played from either a stopped or paused state.
33 // - A Marker event is fired when the playback position of an output buffer reaches a certain point within the
34 // buffer. This is useful for streaming audio data because it can tell you when a particular section of the
35 // buffer can be filled with new data.
36 // - Due to the inherent multi-threaded nature of audio playback, events can be fired from any thread. It is up
37 // to the application to ensure events are handled safely.
38 // - Currently, the maximum number of markers is set by DRAUDIO_MAX_MARKER_COUNT which is set to 4 by default. This
39 // can be increased, however doing so increases memory usage for each sound buffer.
40 //
41 // Performance Considerations
42 // - Creating and deleting buffers should be considered an expensive operation because there is quite a bit of thread
43 // management being performed under the hood. Prefer caching sound buffers.
44 //
45 
46 //
47 // OPTIONS
48 //
49 // #define DRAUDIO_NO_DIRECTSOUND
50 // Disables support for the DirectSound backend. Note that at the moment this is the only backend available for
51 // Windows platforms, so you will likely not want to set this. DirectSound will only be compiled on Win32 builds.
52 //
53 
54 //
55 // TODO
56 //
57 // - DirectSound: Consider using Win32 critical sections instead of events where possible.
58 // - DirectSound: Remove the semaphore and replace with an auto-reset event.
59 // - Implement a better error handling API.
60 // - Implement effects
61 // - Implement velocity
62 // - Implement cones
63 // - Implement attenuation min/max distances
64 //
65 
66 #ifndef dr_audio_h
67 #define dr_audio_h
68 
69 #ifdef __cplusplus
70 extern "C" {
71 #endif
72 
73 #include <stdbool.h>
74 #include <stdint.h>
75 
76 
77 #define DRAUDIO_MAX_DEVICE_COUNT 16
78 #define DRAUDIO_MAX_MARKER_COUNT 4
79 #define DRAUDIO_MAX_MESSAGE_QUEUE_SIZE 1024 // The maximum number of messages that can be cached in the internal message queues.
80 
81 
82 #if defined(_WIN32) && !defined(DRAUDIO_NO_DIRECTSOUND)
83 #define DRAUDIO_BUILD_DSOUND
84 #endif
85 
86 
87 #define DRAUDIO_EVENT_ID_STOP 0xFFFFFFFF
88 #define DRAUDIO_EVENT_ID_PAUSE 0xFFFFFFFE
89 #define DRAUDIO_EVENT_ID_PLAY 0xFFFFFFFD
90 #define DRAUDIO_EVENT_ID_MARKER 0
91 
92 #define DRAUDIO_ENABLE_3D (1 << 0)
93 #define DRAUDIO_RELATIVE_3D (1 << 1) // <-- Uses relative 3D positioning by default instead of absolute. Only used if DRAUDIO_ENABLE_3D is also specified.
94 
95 
96 // Data formats.
97 typedef enum
98 {
101 
103 
104 // Playback states.
105 typedef enum
106 {
110 
112 
113 // Effect types.
114 typedef enum
115 {
123 
125 
126 // 3D processing modes.
127 typedef enum
128 {
132 
134 
135 
139 
140 typedef void (* draudio_event_callback_proc)(draudio_buffer* pBuffer, unsigned int eventID, void *pUserData);
141 
142 typedef struct
143 {
146 
148  void* pUserData;
149 
151 
152 typedef struct
153 {
155  char description[256];
156 
158 
159 typedef struct
160 {
163  unsigned int flags;
164 
166  draudio_format format;
167 
169  unsigned int channels;
170 
172  unsigned int sampleRate;
173 
175  unsigned int bitsPerSample;
176 
178  size_t sizeInBytes;
179 
181  void* pData;
182 
184 
185 typedef struct
186 {
188  draudio_effect_type type;
189 
190  struct
191  {
192  float room;
193  float roomHF;
194  float roomRolloffFactor;
195  float decayTime;
196  float reflections;
197  float reflectionsDelay;
198  float reverb;
199  float reverbDelay;
200  float diffusion;
201  float density;
202  float hfReference;
203  } i3dl2reverb;
204 
205  struct
206  {
207  int waveform;
208  int phase;
209  float depth;
210  float feedback;
211  float frequency;
212  float delay;
213  } chorus;
214 
215  struct
216  {
217  float gain;
218  float attack;
219  float release;
220  float threshold;
221  float ratio;
222  float predelay;
223  } compressor;
224 
225  struct
226  {
227  float gain;
228  float edge;
229  float postEQCenterFrequency;
230  float postEQBandwidth;
231  float preLowpassCutoff;
232  } distortion;
233 
234  struct
235  {
236  float wetDryMix;
237  float feedback;
238  float leftDelay;
239  float rightDelay;
240  float panDelay;
241  } echo;
242 
243  struct
244  {
245  float wetDryMix;
246  float depth;
247  float feedback;
248  float frequency;
249  float waveform;
250  float delay;
251  float phase;
252  } flanger;
253 
255 
256 
259 
260 #ifdef DRAUDIO_BUILD_DSOUND
261 draudio_context* draudio_create_context_dsound();
263 #endif
264 
267 
268 
269 
270 
273 //
274 // OUTPUT / PLAYBACK
275 //
278 
280 unsigned int draudio_get_output_device_count(draudio_context* pContext);
281 
283 bool draudio_get_output_device_info(draudio_context* pContext, unsigned int deviceIndex, draudio_device_info* pInfoOut);
284 
285 
293 draudio_device* draudio_create_output_device(draudio_context* pContext, unsigned int deviceIndex);
294 
297 
298 
303 draudio_buffer* draudio_create_buffer(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, size_t extraDataSize);
304 
307 
308 
311 
314 
315 
317 void draudio_set_buffer_data(draudio_buffer* pBuffer, size_t offset, const void* pData, size_t dataSizeInBytes);
318 
319 
325 void draudio_play(draudio_buffer* pBuffer, bool loop);
326 
328 void draudio_pause(draudio_buffer* pBuffer);
329 
331 void draudio_stop(draudio_buffer* pBuffer);
332 
335 
337 bool draudio_is_looping(draudio_buffer* pBuffer);
338 
339 
341 void draudio_set_playback_position(draudio_buffer* pBuffer, unsigned int position);
342 
344 unsigned int draudio_get_playback_position(draudio_buffer* pBuffer);
345 
346 
351 void draudio_set_pan(draudio_buffer* pBuffer, float pan);
352 
354 float draudio_get_pan(draudio_buffer* pBuffer);
355 
356 
364 void draudio_set_volume(draudio_buffer* pBuffer, float volume);
365 
367 float draudio_get_volume(draudio_buffer* pBuffer);
368 
369 
372 
381 bool draudio_register_marker_callback(draudio_buffer* pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void* pUserData);
382 
390 bool draudio_register_stop_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData);
391 
399 bool draudio_register_pause_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData);
400 
408 bool draudio_register_play_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData);
409 
410 
413 
416 
419 
420 
425 void draudio_set_position(draudio_buffer* pBuffer, float x, float y, float z);
426 
428 void draudio_get_position(draudio_buffer* pBuffer, float* pPosOut);
429 
431 void draudio_set_listener_position(draudio_device* pDevice, float x, float y, float z);
432 
434 void draudio_get_listener_position(draudio_device* pDevice, float* pPosOut);
435 
437 void draudio_set_listener_orientation(draudio_device* pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ);
438 
440 void draudio_get_listener_orientation(draudio_device* pDevice, float* pForwardOut, float* pUpOut);
441 
442 
448 
451 
452 
453 
456 //
457 // INPUT / RECORDING
458 //
461 
462 
463 
464 
465 
468 //
469 // HIGH-LEVEL API
470 //
473 
475 
476 typedef void* draudio_mutex;
477 
480 
483 
486 
489 
490 
491 
492 
494 typedef int draudio_bool;
495 
496 typedef draudio_bool (* draudio_stream_read_proc)(void* pUserData, void* pDataOut, size_t bytesToRead, size_t* bytesReadOut);
497 typedef draudio_bool (* draudio_stream_seek_proc)(void* pUserData, size_t offsetInBytesFromStart);
498 
499 typedef struct
500 {
502  void* pUserData;
503 
506 
509 
511 
512 
528 draudio_buffer* draudio_create_streaming_buffer(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, draudio_streaming_callbacks callbacks, unsigned int extraDataSize);
529 
532 
535 
537 bool draudio_play_streaming_buffer(draudio_buffer* pBuffer, bool loop);
538 
541 
542 
543 
544 
545 
547 //
548 // Sound World
549 //
550 // When a sound is created, whether or not it will be streamed is determined by
551 // whether or not a pointer to some initial data is specified when creating the
552 // sound. When initial data is specified, the sound data will be loaded into
553 // buffer once at creation time. If no data is specified, sound data will be
554 // loaded dynamically at playback time.
555 //
557 
560 
561 typedef void (* draudio_on_sound_delete_proc) (draudio_sound* pSound);
562 typedef bool (* draudio_on_sound_read_data_proc)(draudio_sound* pSound, void* pDataOut, size_t bytesToRead, size_t* bytesReadOut);
563 typedef bool (* draudio_on_sound_seek_data_proc)(draudio_sound* pSound, size_t offsetInBytesFromStart);
564 
566 typedef struct
567 {
570  unsigned int flags;
571 
573  draudio_format format;
574 
576  unsigned int channels;
577 
579  unsigned int sampleRate;
580 
582  unsigned int bitsPerSample;
583 
586  size_t sizeInBytes;
587 
590  void* pData;
591 
592 
596 
600 
604 
605 
608  unsigned int extraDataSize;
609 
612  const void* pExtraData;
613 
615 
616 struct draudio_sound
617 {
620 
623 
624 
627 
630 
633 
636 
641  bool markedForDeletion;
642 
645 
648 
651 };
652 
653 struct draudio_world
654 {
657 
660 
663 
666 };
667 
668 
671 
673 void draudio_delete_world(draudio_world* pWorld);
674 
675 
678 
680 void draudio_delete_sound(draudio_sound* pSound);
681 
684 
685 
688 
691 
692 
694 void draudio_play_sound(draudio_sound* pSound, bool loop);
695 
697 void draudio_pause_sound(draudio_sound* pSound);
698 
700 void draudio_stop_sound(draudio_sound* pSound);
701 
704 
707 
708 
711 
713 void draudio_play_inline_sound_3f(draudio_world* pWorld, draudio_sound_desc desc, float posX, float posY, float posZ);
714 
715 
718 
721 
724 
725 
727 void draudio_set_sound_stop_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData);
728 
730 void draudio_set_sound_pause_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData);
731 
733 void draudio_set_sound_play_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData);
734 
735 
737 void draudio_set_sound_position(draudio_sound* pSound, float posX, float posY, float posZ);
738 
739 
742 
745 
746 
747 
748 #ifdef __cplusplus
749 }
750 #endif
751 
752 #endif //dr_audio_h
753 
755 //
756 // IMPLEMENTATION
757 //
759 #ifdef DR_AUDIO_IMPLEMENTATION
760 #include <assert.h>
761 #include <stdlib.h>
762 #include <string.h>
763 #include <math.h>
764 #include <errno.h>
765 
766 
767 // Annotations
768 #ifndef DRAUDIO_PRIVATE
769 #define DRAUDIO_PRIVATE
770 #endif
771 
772 
774 // Utilities
775 
776 // strcpy()
777 int draudio_strcpy(char* dst, size_t dstSizeInBytes, const char* src)
778 {
779 #if defined(_MSC_VER)
780  return strcpy_s(dst, dstSizeInBytes, src);
781 #else
782  if (dst == 0) {
783  return EINVAL;
784  }
785  if (dstSizeInBytes == 0) {
786  return ERANGE;
787  }
788  if (src == 0) {
789  dst[0] = '\0';
790  return EINVAL;
791  }
792 
793  char* iDst = dst;
794  const char* iSrc = src;
795  size_t remainingSizeInBytes = dstSizeInBytes;
796  while (remainingSizeInBytes > 0 && iSrc[0] != '\0')
797  {
798  iDst[0] = iSrc[0];
799 
800  iDst += 1;
801  iSrc += 1;
802  remainingSizeInBytes -= 1;
803  }
804 
805  if (remainingSizeInBytes > 0) {
806  iDst[0] = '\0';
807  } else {
808  dst[0] = '\0';
809  return ERANGE;
810  }
811 
812  return 0;
813 #endif
814 }
815 
816 
817 typedef void (* draudio_delete_context_proc)(draudio_context* pContext);
818 typedef draudio_device* (* draudio_create_output_device_proc)(draudio_context* pContext, unsigned int deviceIndex);
819 typedef void (* draudio_delete_output_device_proc)(draudio_device* pDevice);
820 typedef unsigned int (* draudio_get_output_device_count_proc)(draudio_context* pContext);
821 typedef bool (* draudio_get_output_device_info_proc)(draudio_context* pContext, unsigned int deviceIndex, draudio_device_info* pInfoOut);
822 typedef draudio_buffer* (* draudio_create_buffer_proc)(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, size_t extraDataSize);
823 typedef void (* draudio_delete_buffer_proc)(draudio_buffer* pBuffer);
824 typedef unsigned int (* draudio_get_buffer_extra_data_size_proc)(draudio_buffer* pBuffer);
825 typedef void* (* draudio_get_buffer_extra_data_proc)(draudio_buffer* pBuffer);
826 typedef void (* draudio_set_buffer_data_proc)(draudio_buffer* pBuffer, size_t offset, const void* pData, size_t dataSizeInBytes);
827 typedef void (* draudio_play_proc)(draudio_buffer* pBuffer, bool loop);
828 typedef void (* draudio_pause_proc)(draudio_buffer* pBuffer);
829 typedef void (* draudio_stop_proc)(draudio_buffer* pBuffer);
830 typedef draudio_playback_state (* draudio_get_playback_state_proc)(draudio_buffer* pBuffer);
831 typedef void (* draudio_set_playback_position_proc)(draudio_buffer* pBuffer, unsigned int position);
832 typedef unsigned int (* draudio_get_playback_position_proc)(draudio_buffer* pBuffer);
833 typedef void (* draudio_set_pan_proc)(draudio_buffer* pBuffer, float pan);
834 typedef float (* draudio_get_pan_proc)(draudio_buffer* pBuffer);
835 typedef void (* draudio_set_volume_proc)(draudio_buffer* pBuffer, float volume);
836 typedef float (* draudio_get_volume_proc)(draudio_buffer* pBuffer);
837 typedef void (* draudio_remove_markers_proc)(draudio_buffer* pBuffer);
838 typedef bool (* draudio_register_marker_callback_proc)(draudio_buffer* pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void* pUserData);
839 typedef bool (* draudio_register_stop_callback_proc)(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData);
840 typedef bool (* draudio_register_pause_callback_proc)(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData);
841 typedef bool (* draudio_register_play_callback_proc)(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData);
842 typedef void (* draudio_set_position_proc)(draudio_buffer* pBuffer, float x, float y, float z);
843 typedef void (* draudio_get_position_proc)(draudio_buffer* pBuffer, float* pPosOut);
844 typedef void (* draudio_set_listener_position_proc)(draudio_device* pDevice, float x, float y, float z);
845 typedef void (* draudio_get_listener_position_proc)(draudio_device* pDevice, float* pPosOut);
846 typedef void (* draudio_set_listener_orientation_proc)(draudio_device* pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ);
847 typedef void (* draudio_get_listener_orientation_proc)(draudio_device* pDevice, float* pForwardOut, float* pUpOut);
848 typedef void (* draudio_set_3d_mode_proc)(draudio_buffer* pBuffer, draudio_3d_mode mode);
849 typedef draudio_3d_mode (* draudio_get_3d_mode_proc)(draudio_buffer* pBuffer);
850 
851 struct draudio_context
852 {
853  // Callbacks.
854  draudio_delete_context_proc delete_context;
855  draudio_create_output_device_proc create_output_device;
856  draudio_delete_output_device_proc delete_output_device;
857  draudio_get_output_device_count_proc get_output_device_count;
858  draudio_get_output_device_info_proc get_output_device_info;
859  draudio_create_buffer_proc create_buffer;
860  draudio_delete_buffer_proc delete_buffer;
861  draudio_get_buffer_extra_data_size_proc get_buffer_extra_data_size;
862  draudio_get_buffer_extra_data_proc get_buffer_extra_data;
863  draudio_set_buffer_data_proc set_buffer_data;
864  draudio_play_proc play;
865  draudio_pause_proc pause;
866  draudio_stop_proc stop;
867  draudio_get_playback_state_proc get_playback_state;
868  draudio_set_playback_position_proc set_playback_position;
869  draudio_get_playback_position_proc get_playback_position;
870  draudio_set_pan_proc set_pan;
871  draudio_get_pan_proc get_pan;
872  draudio_set_volume_proc set_volume;
873  draudio_get_volume_proc get_volume;
874  draudio_remove_markers_proc remove_markers;
875  draudio_register_marker_callback_proc register_marker_callback;
876  draudio_register_stop_callback_proc register_stop_callback;
877  draudio_register_pause_callback_proc register_pause_callback;
878  draudio_register_play_callback_proc register_play_callback;
879  draudio_set_position_proc set_position;
880  draudio_get_position_proc get_position;
881  draudio_set_listener_position_proc set_listener_position;
882  draudio_get_listener_position_proc get_listener_position;
883  draudio_set_listener_orientation_proc set_listener_orientation;
884  draudio_get_listener_orientation_proc get_listener_orientation;
885  draudio_set_3d_mode_proc set_3d_mode;
886  draudio_get_3d_mode_proc get_3d_mode;
887 };
888 
889 struct draudio_device
890 {
892  draudio_context* pContext;
893 
896  bool markedForDeletion;
897 };
898 
899 struct draudio_buffer
900 {
902  draudio_device* pDevice;
903 
905  draudio_event_callback stopCallback;
906 
908  draudio_event_callback pauseCallback;
909 
911  draudio_event_callback playCallback;
912 
914  bool isLooping;
915 
918  bool markedForDeletion;
919 };
920 
921 
923 {
924  draudio_context* pContext = NULL;
925 
926 #ifdef DRAUDIO_BUILD_DSOUND
927  pContext = draudio_create_context_dsound();
928  if (pContext != NULL) {
929  return pContext;
930  }
931 #endif
932 
933 
934  // If we get here it means we weren't able to create a context, so return NULL. Later on we're going to have a null implementation so that
935  // we don't ever need to return NULL here.
936  assert(pContext == NULL);
937  return pContext;
938 }
939 
941 {
942  if (pContext == NULL) {
943  return;
944  }
945 
946  pContext->delete_context(pContext);
947 }
948 
949 
950 
951 
952 
955 //
956 // OUTPUT
957 //
960 
961 unsigned int draudio_get_output_device_count(draudio_context* pContext)
962 {
963  if (pContext == NULL) {
964  return 0;
965  }
966 
967  return pContext->get_output_device_count(pContext);
968 }
969 
970 bool draudio_get_output_device_info(draudio_context* pContext, unsigned int deviceIndex, draudio_device_info* pInfoOut)
971 {
972  if (pContext == NULL) {
973  return false;
974  }
975 
976  if (pInfoOut == NULL) {
977  return false;
978  }
979 
980  return pContext->get_output_device_info(pContext, deviceIndex, pInfoOut);
981 }
982 
983 
984 draudio_device* draudio_create_output_device(draudio_context* pContext, unsigned int deviceIndex)
985 {
986  if (pContext == NULL) {
987  return NULL;
988  }
989 
990  draudio_device* pDevice = pContext->create_output_device(pContext, deviceIndex);
991  if (pDevice != NULL)
992  {
993  pDevice->markedForDeletion = false;
994  }
995 
996  return pDevice;
997 }
998 
1000 {
1001  if (pDevice == NULL) {
1002  return;
1003  }
1004 
1005  // If the device is already marked for deletion we just return straight away. However, this is an erroneous case so we trigger a failed assertion in this case.
1006  if (pDevice->markedForDeletion) {
1007  assert(false);
1008  return;
1009  }
1010 
1011  pDevice->markedForDeletion = true;
1012 
1013  assert(pDevice->pContext != NULL);
1014  pDevice->pContext->delete_output_device(pDevice);
1015 }
1016 
1017 
1018 draudio_buffer* draudio_create_buffer(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, size_t extraDataSize)
1019 {
1020  if (pDevice == NULL) {
1021  return NULL;
1022  }
1023 
1024  if (pBufferDesc == NULL) {
1025  return NULL;
1026  }
1027 
1028  assert(pDevice->pContext != NULL);
1029 
1030  draudio_buffer* pBuffer = pDevice->pContext->create_buffer(pDevice, pBufferDesc, extraDataSize);
1031  if (pBuffer != NULL)
1032  {
1033  draudio_event_callback nullcb = {NULL, NULL};
1034 
1035  pBuffer->pDevice = pDevice;
1036  pBuffer->stopCallback = nullcb;
1037  pBuffer->pauseCallback = nullcb;
1038  pBuffer->playCallback = nullcb;
1039  pBuffer->isLooping = false;
1040  pBuffer->markedForDeletion = false;
1041  }
1042 
1043  return pBuffer;
1044 }
1045 
1047 {
1048  if (pBuffer == NULL) {
1049  return;
1050  }
1051 
1052  // We don't want to do anything if the buffer is marked for deletion.
1053  if (pBuffer->markedForDeletion) {
1054  assert(false);
1055  return;
1056  }
1057 
1058  pBuffer->markedForDeletion = true;
1059 
1060 
1061  // The sound needs to be stopped first.
1062  draudio_stop(pBuffer);
1063 
1064  // Now we need to remove every event.
1065  draudio_remove_markers(pBuffer);
1069 
1070 
1071  assert(pBuffer->pDevice != NULL);
1072  assert(pBuffer->pDevice->pContext != NULL);
1073  pBuffer->pDevice->pContext->delete_buffer(pBuffer);
1074 }
1075 
1076 
1078 {
1079  if (pBuffer == NULL) {
1080  return 0;
1081  }
1082 
1083  assert(pBuffer->pDevice != NULL);
1084  assert(pBuffer->pDevice->pContext != NULL);
1085  return pBuffer->pDevice->pContext->get_buffer_extra_data_size(pBuffer);
1086 }
1087 
1089 {
1090  if (pBuffer == NULL) {
1091  return NULL;
1092  }
1093 
1094  assert(pBuffer->pDevice != NULL);
1095  assert(pBuffer->pDevice->pContext != NULL);
1096  return pBuffer->pDevice->pContext->get_buffer_extra_data(pBuffer);
1097 }
1098 
1099 
1100 void draudio_set_buffer_data(draudio_buffer* pBuffer, size_t offset, const void* pData, size_t dataSizeInBytes)
1101 {
1102  if (pBuffer == NULL) {
1103  return;
1104  }
1105 
1106  if (pData == NULL) {
1107  return;
1108  }
1109 
1110  assert(pBuffer->pDevice != NULL);
1111  assert(pBuffer->pDevice->pContext != NULL);
1112  pBuffer->pDevice->pContext->set_buffer_data(pBuffer, offset, pData, dataSizeInBytes);
1113 }
1114 
1115 void draudio_play(draudio_buffer* pBuffer, bool loop)
1116 {
1117  if (pBuffer == NULL) {
1118  return;
1119  }
1120 
1121  pBuffer->isLooping = loop;
1122 
1123  assert(pBuffer->pDevice != NULL);
1124  assert(pBuffer->pDevice->pContext != NULL);
1125  pBuffer->pDevice->pContext->play(pBuffer, loop);
1126 }
1127 
1128 void draudio_pause(draudio_buffer* pBuffer)
1129 {
1130  if (pBuffer == NULL) {
1131  return;
1132  }
1133 
1134  assert(pBuffer->pDevice != NULL);
1135  assert(pBuffer->pDevice->pContext != NULL);
1136  pBuffer->pDevice->pContext->pause(pBuffer);
1137 }
1138 
1139 void draudio_stop(draudio_buffer* pBuffer)
1140 {
1141  if (pBuffer == NULL) {
1142  return;
1143  }
1144 
1145  assert(pBuffer->pDevice != NULL);
1146  assert(pBuffer->pDevice->pContext != NULL);
1147  pBuffer->pDevice->pContext->stop(pBuffer);
1148 }
1149 
1151 {
1152  if (pBuffer == NULL) {
1153  return draudio_stopped;
1154  }
1155 
1156  assert(pBuffer->pDevice != NULL);
1157  assert(pBuffer->pDevice->pContext != NULL);
1158  return pBuffer->pDevice->pContext->get_playback_state(pBuffer);
1159 }
1160 
1161 bool draudio_is_looping(draudio_buffer* pBuffer)
1162 {
1163  if (pBuffer == NULL) {
1164  return false;
1165  }
1166 
1167  return pBuffer->isLooping;
1168 }
1169 
1170 
1171 void draudio_set_playback_position(draudio_buffer* pBuffer, unsigned int position)
1172 {
1173  if (pBuffer == NULL) {
1174  return;
1175  }
1176 
1177  assert(pBuffer->pDevice != NULL);
1178  assert(pBuffer->pDevice->pContext != NULL);
1179  pBuffer->pDevice->pContext->set_playback_position(pBuffer, position);
1180 }
1181 
1182 unsigned int draudio_get_playback_position(draudio_buffer* pBuffer)
1183 {
1184  if (pBuffer == NULL) {
1185  return 0;
1186  }
1187 
1188  assert(pBuffer->pDevice != NULL);
1189  assert(pBuffer->pDevice->pContext != NULL);
1190  return pBuffer->pDevice->pContext->get_playback_position(pBuffer);
1191 }
1192 
1193 
1194 void draudio_set_pan(draudio_buffer* pBuffer, float pan)
1195 {
1196  if (pBuffer == NULL) {
1197  return;
1198  }
1199 
1200  assert(pBuffer->pDevice != NULL);
1201  assert(pBuffer->pDevice->pContext != NULL);
1202  pBuffer->pDevice->pContext->set_pan(pBuffer, pan);
1203 }
1204 
1205 float draudio_get_pan(draudio_buffer* pBuffer)
1206 {
1207  if (pBuffer == NULL) {
1208  return 0.0f;
1209  }
1210 
1211  assert(pBuffer->pDevice != NULL);
1212  assert(pBuffer->pDevice->pContext != NULL);
1213  return pBuffer->pDevice->pContext->get_pan(pBuffer);
1214 }
1215 
1216 
1217 void draudio_set_volume(draudio_buffer* pBuffer, float volume)
1218 {
1219  if (pBuffer == NULL) {
1220  return;
1221  }
1222 
1223  assert(pBuffer->pDevice != NULL);
1224  assert(pBuffer->pDevice->pContext != NULL);
1225  pBuffer->pDevice->pContext->set_volume(pBuffer, volume);
1226 }
1227 
1228 float draudio_get_volume(draudio_buffer* pBuffer)
1229 {
1230  if (pBuffer == NULL) {
1231  return 1.0f;
1232  }
1233 
1234  assert(pBuffer->pDevice != NULL);
1235  assert(pBuffer->pDevice->pContext != NULL);
1236  return pBuffer->pDevice->pContext->get_volume(pBuffer);
1237 }
1238 
1239 
1241 {
1242  if (pBuffer == NULL) {
1243  return;
1244  }
1245 
1246  assert(pBuffer->pDevice != NULL);
1247  assert(pBuffer->pDevice->pContext != NULL);
1248  pBuffer->pDevice->pContext->remove_markers(pBuffer);
1249 }
1250 
1251 bool draudio_register_marker_callback(draudio_buffer* pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void* pUserData)
1252 {
1253  if (pBuffer == NULL) {
1254  return false;
1255  }
1256 
1257  if (eventID == DRAUDIO_EVENT_ID_STOP ||
1258  eventID == DRAUDIO_EVENT_ID_PAUSE ||
1259  eventID == DRAUDIO_EVENT_ID_PLAY)
1260  {
1261  return false;
1262  }
1263 
1264  if (draudio_get_playback_state(pBuffer) != draudio_stopped) {
1265  return false;
1266  }
1267 
1268  assert(pBuffer->pDevice != NULL);
1269  assert(pBuffer->pDevice->pContext != NULL);
1270  return pBuffer->pDevice->pContext->register_marker_callback(pBuffer, offsetInBytes, callback, eventID, pUserData);
1271 }
1272 
1273 bool draudio_register_stop_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData)
1274 {
1275  if (pBuffer == NULL) {
1276  return false;
1277  }
1278 
1279  if (callback != NULL && draudio_get_playback_state(pBuffer) != draudio_stopped) {
1280  return false;
1281  }
1282 
1283  pBuffer->stopCallback.callback = callback;
1284  pBuffer->stopCallback.pUserData = pUserData;
1285 
1286  assert(pBuffer->pDevice != NULL);
1287  assert(pBuffer->pDevice->pContext != NULL);
1288  return pBuffer->pDevice->pContext->register_stop_callback(pBuffer, callback, pUserData);
1289 }
1290 
1291 bool draudio_register_pause_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData)
1292 {
1293  if (pBuffer == NULL) {
1294  return false;
1295  }
1296 
1297  if (callback != NULL && draudio_get_playback_state(pBuffer) != draudio_stopped) {
1298  return false;
1299  }
1300 
1301  pBuffer->pauseCallback.callback = callback;
1302  pBuffer->pauseCallback.pUserData = pUserData;
1303 
1304  assert(pBuffer->pDevice != NULL);
1305  assert(pBuffer->pDevice->pContext != NULL);
1306  return pBuffer->pDevice->pContext->register_pause_callback(pBuffer, callback, pUserData);
1307 }
1308 
1309 bool draudio_register_play_callback(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData)
1310 {
1311  if (pBuffer == NULL) {
1312  return false;
1313  }
1314 
1315  if (callback != NULL && draudio_get_playback_state(pBuffer) != draudio_stopped) {
1316  return false;
1317  }
1318 
1319  pBuffer->playCallback.callback = callback;
1320  pBuffer->playCallback.pUserData = pUserData;
1321 
1322  assert(pBuffer->pDevice != NULL);
1323  assert(pBuffer->pDevice->pContext != NULL);
1324  return pBuffer->pDevice->pContext->register_play_callback(pBuffer, callback, pUserData);
1325 }
1326 
1327 
1329 {
1330  if (pBuffer != NULL) {
1331  return pBuffer->stopCallback;
1332  } else {
1333  draudio_event_callback result = {NULL, NULL};
1334  return result;
1335  }
1336 }
1337 
1339 {
1340  if (pBuffer != NULL) {
1341  return pBuffer->pauseCallback;
1342  } else {
1343  draudio_event_callback result = {NULL, NULL};
1344  return result;
1345  }
1346 }
1347 
1349 {
1350  if (pBuffer != NULL) {
1351  return pBuffer->playCallback;
1352  } else {
1353  draudio_event_callback result = {NULL, NULL};
1354  return result;
1355  }
1356 }
1357 
1358 
1359 void draudio_set_position(draudio_buffer* pBuffer, float x, float y, float z)
1360 {
1361  if (pBuffer == NULL) {
1362  return;
1363  }
1364 
1365  assert(pBuffer->pDevice != NULL);
1366  assert(pBuffer->pDevice->pContext != NULL);
1367  pBuffer->pDevice->pContext->set_position(pBuffer, x, y, z);
1368 }
1369 
1370 void draudio_get_position(draudio_buffer* pBuffer, float* pPosOut)
1371 {
1372  if (pBuffer == NULL) {
1373  return;
1374  }
1375 
1376  if (pPosOut == NULL) {
1377  return;
1378  }
1379 
1380  assert(pBuffer->pDevice != NULL);
1381  assert(pBuffer->pDevice->pContext != NULL);
1382  pBuffer->pDevice->pContext->get_position(pBuffer, pPosOut);
1383 }
1384 
1385 
1386 void draudio_set_listener_position(draudio_device* pDevice, float x, float y, float z)
1387 {
1388  if (pDevice == NULL) {
1389  return;
1390  }
1391 
1392  pDevice->pContext->set_listener_position(pDevice, x, y, z);
1393 }
1394 
1395 void draudio_get_listener_position(draudio_device* pDevice, float* pPosOut)
1396 {
1397  if (pDevice == NULL || pPosOut == NULL) {
1398  return;
1399  }
1400 
1401  pDevice->pContext->get_listener_position(pDevice, pPosOut);
1402 }
1403 
1404 void draudio_set_listener_orientation(draudio_device* pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ)
1405 {
1406  if (pDevice == NULL) {
1407  return;
1408  }
1409 
1410  pDevice->pContext->set_listener_orientation(pDevice, forwardX, forwardY, forwardZ, upX, upY, upZ);
1411 }
1412 
1413 void draudio_get_listener_orientation(draudio_device* pDevice, float* pForwardOut, float* pUpOut)
1414 {
1415  if (pDevice == NULL) {
1416  return;
1417  }
1418 
1419  pDevice->pContext->get_listener_orientation(pDevice, pForwardOut, pUpOut);
1420 }
1421 
1422 
1424 {
1425  if (pBuffer == NULL) {
1426  return;
1427  }
1428 
1429  assert(pBuffer->pDevice != NULL);
1430  assert(pBuffer->pDevice->pContext != NULL);
1431  pBuffer->pDevice->pContext->set_3d_mode(pBuffer, mode);
1432 }
1433 
1435 {
1436  if (pBuffer == NULL) {
1437  return draudio_3d_mode_disabled;
1438  }
1439 
1440  assert(pBuffer->pDevice != NULL);
1441  assert(pBuffer->pDevice->pContext != NULL);
1442  return pBuffer->pDevice->pContext->get_3d_mode(pBuffer);
1443 }
1444 
1445 
1446 
1447 
1450 //
1451 // INPUT
1452 //
1455 
1456 
1457 
1458 
1459 
1460 
1461 
1462 
1465 //
1466 // HIGH-LEVEL API
1467 //
1470 
1472 
1473 #if defined(_WIN32)
1474 #include <windows.h>
1475 
1477 {
1478  draudio_mutex mutex = malloc(sizeof(CRITICAL_SECTION));
1479  if (mutex != NULL)
1480  {
1481  InitializeCriticalSection((LPCRITICAL_SECTION)mutex);
1482  }
1483 
1484  return mutex;
1485 }
1486 
1488 {
1489  DeleteCriticalSection((LPCRITICAL_SECTION)mutex);
1490  free(mutex);
1491 }
1492 
1494 {
1495  EnterCriticalSection((LPCRITICAL_SECTION)mutex);
1496 }
1497 
1499 {
1500  LeaveCriticalSection((LPCRITICAL_SECTION)mutex);
1501 }
1502 #else
1503 #include <pthread.h>
1504 
1506 {
1507  pthread_mutex_t* mutex = malloc(sizeof(pthread_mutex_t));
1508  if (pthread_mutex_init(mutex, NULL) != 0) {
1509  free(mutex);
1510  mutex = NULL;
1511  }
1512 
1513  return mutex;
1514 }
1515 
1517 {
1518  pthread_mutex_destroy(mutex);
1519 }
1520 
1522 {
1523  pthread_mutex_lock(mutex);
1524 }
1525 
1527 {
1528  pthread_mutex_unlock(mutex);
1529 }
1530 #endif
1531 
1532 
1533 
1535 
1536 #define DRAUDIO_STREAMING_MARKER_0 DRAUDIO_EVENT_ID_MARKER + 0
1537 #define DRAUDIO_STREAMING_MARKER_1 DRAUDIO_EVENT_ID_MARKER + 1
1538 
1539 #define DRAUDIO_STREAMING_CHUNK_INVALID 0
1540 
1541 typedef struct
1542 {
1544  draudio_streaming_callbacks callbacks;
1545 
1547  bool atStart;
1548 
1550  bool stopAtEndOfCurrentChunk;
1551 
1553  bool isLoopingEnabled;
1554 
1556  size_t extraDataSize;
1557 
1559  size_t chunkSize;
1560 
1562  unsigned char pTempChunkData[1];
1563 
1564 } ea_streaming_buffer_data;
1565 
1566 
1567 bool ea_streaming_buffer_load_next_chunk(draudio_buffer* pBuffer, ea_streaming_buffer_data* pStreamingData, size_t offset, size_t chunkSize)
1568 {
1569  assert(pStreamingData != NULL);
1570  assert(pStreamingData->callbacks.read != NULL);
1571  assert(pStreamingData->callbacks.seek != NULL);
1572  assert(pStreamingData->chunkSize >= chunkSize);
1573 
1574  // A chunk size of 0 is valid, but we just return immediately.
1575  if (chunkSize == 0) {
1576  return true;
1577  }
1578 
1579  size_t bytesRead;
1580  if (!pStreamingData->callbacks.read(pStreamingData->callbacks.pUserData, pStreamingData->pTempChunkData, chunkSize, &bytesRead))
1581  {
1582  // There was an error reading the data. We might have run out of data.
1583  return false;
1584  }
1585 
1586 
1587  pStreamingData->stopAtEndOfCurrentChunk = false;
1588 
1589  draudio_set_buffer_data(pBuffer, offset, pStreamingData->pTempChunkData, bytesRead);
1590 
1591  if (chunkSize > bytesRead)
1592  {
1593  // The number of bytes read is less than our chunk size. This is our cue that we've reached the end of the steam. If we're looping, we
1594  // just seek back to the start and read more data. There is a chance the data total size of the streaming data is smaller than our
1595  // chunk, so we actually want to do this recursively.
1596  //
1597  // If we're not looping, we fill the remaining data with silence.
1598  if (pStreamingData->isLoopingEnabled)
1599  {
1600  pStreamingData->callbacks.seek(pStreamingData->callbacks.pUserData, 0);
1601  return ea_streaming_buffer_load_next_chunk(pBuffer, pStreamingData, offset + bytesRead, chunkSize - bytesRead);
1602  }
1603  else
1604  {
1605  memset(pStreamingData->pTempChunkData + bytesRead, 0, chunkSize - bytesRead);
1606  draudio_set_buffer_data(pBuffer, offset + bytesRead, pStreamingData->pTempChunkData + bytesRead, chunkSize - bytesRead);
1607 
1608  pStreamingData->stopAtEndOfCurrentChunk = true;
1609  }
1610  }
1611 
1612  return true;
1613 }
1614 
1615 void ea_steaming_buffer_marker_callback(draudio_buffer* pBuffer, unsigned int eventID, void *pUserData)
1616 {
1617  ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)pUserData;
1618  assert(pStreamingData != NULL);
1619 
1620  size_t offset = 0;
1621  if (eventID == DRAUDIO_STREAMING_MARKER_0) {
1622  offset = pStreamingData->chunkSize;
1623  }
1624 
1625  if (pStreamingData->stopAtEndOfCurrentChunk)
1626  {
1627  if (!pStreamingData->atStart) {
1628  draudio_stop(pBuffer);
1629  }
1630  }
1631  else
1632  {
1633  ea_streaming_buffer_load_next_chunk(pBuffer, pStreamingData, offset, pStreamingData->chunkSize);
1634  }
1635 
1636  pStreamingData->atStart = false;
1637 }
1638 
1639 
1640 draudio_buffer* draudio_create_streaming_buffer(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, draudio_streaming_callbacks callbacks, unsigned int extraDataSize)
1641 {
1642  if (callbacks.read == NULL) {
1643  return NULL;
1644  }
1645 
1646  if (pBufferDesc == NULL) {
1647  return NULL;
1648  }
1649 
1650 
1651  // We are determining for ourselves what the size of the buffer should be. We need to create our own copy rather than modify the input descriptor.
1652  draudio_buffer_desc bufferDesc = *pBufferDesc;
1653  bufferDesc.sizeInBytes = pBufferDesc->sampleRate * pBufferDesc->channels * (pBufferDesc->bitsPerSample / 8);
1654  bufferDesc.pData = NULL;
1655 
1656  size_t chunkSize = bufferDesc.sizeInBytes / 2;
1657 
1658  draudio_buffer* pBuffer = draudio_create_buffer(pDevice, &bufferDesc, sizeof(ea_streaming_buffer_data) - sizeof(unsigned char) + chunkSize + extraDataSize);
1659  if (pBuffer == NULL) {
1660  return NULL;
1661  }
1662 
1663 
1664  ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer);
1665  assert(pStreamingData != NULL);
1666 
1667  pStreamingData->callbacks = callbacks;
1668  pStreamingData->atStart = true;
1669  pStreamingData->stopAtEndOfCurrentChunk = false;
1670  pStreamingData->isLoopingEnabled = false;
1671  pStreamingData->chunkSize = chunkSize;
1672 
1673  // Register two markers - one for the first half and another for the second half. When a half is finished playing we need to
1674  // replace it with new data.
1675  draudio_register_marker_callback(pBuffer, 0, ea_steaming_buffer_marker_callback, DRAUDIO_STREAMING_MARKER_0, pStreamingData);
1676  draudio_register_marker_callback(pBuffer, chunkSize, ea_steaming_buffer_marker_callback, DRAUDIO_STREAMING_MARKER_1, pStreamingData);
1677 
1678 
1679  return pBuffer;
1680 }
1681 
1682 
1684 {
1685  if (pBuffer == NULL) {
1686  return 0;
1687  }
1688 
1689  ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer);
1690  assert(pStreamingData != NULL);
1691 
1692  return pStreamingData->extraDataSize;
1693 }
1694 
1696 {
1697  if (pBuffer == NULL) {
1698  return NULL;
1699  }
1700 
1701  ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer);
1702  assert(pStreamingData != NULL);
1703 
1704  return ((char*)pStreamingData->pTempChunkData) + pStreamingData->chunkSize;
1705 }
1706 
1707 
1708 bool draudio_play_streaming_buffer(draudio_buffer* pBuffer, bool loop)
1709 {
1710  if (pBuffer == NULL) {
1711  return false;
1712  }
1713 
1714 
1715  ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer);
1716  assert(pStreamingData != NULL);
1717 
1718  // If the buffer was previously in a paused state, we just play like normal. If it was in a stopped state we need to start from the beginning.
1720  {
1721  // We need to load some initial data into the first chunk.
1722  pStreamingData->atStart = true;
1723  pStreamingData->callbacks.seek(pStreamingData->callbacks.pUserData, 0);
1724 
1725  if (!ea_streaming_buffer_load_next_chunk(pBuffer, pStreamingData, 0, pStreamingData->chunkSize))
1726  {
1727  // There was an error loading the initial data.
1728  return false;
1729  }
1730  }
1731 
1732 
1733  pStreamingData->isLoopingEnabled = loop;
1734  draudio_play(pBuffer, true); // <-- Always loop on a streaming buffer. Actual looping is done a bit differently for streaming buffers.
1735 
1736  return true;
1737 }
1738 
1740 {
1741  if (pBuffer == NULL) {
1742  return false;
1743  }
1744 
1745  ea_streaming_buffer_data* pStreamingData = (ea_streaming_buffer_data*)draudio_get_buffer_extra_data(pBuffer);
1746  assert(pStreamingData != NULL);
1747 
1748  return pStreamingData->isLoopingEnabled;
1749 }
1750 
1751 
1752 
1754 //
1755 // Sound World
1756 //
1758 
1759 DRAUDIO_PRIVATE draudio_bool draudio_on_sound_read_callback(void* pUserData, void* pDataOut, size_t bytesToRead, size_t* bytesReadOut)
1760 {
1761  draudio_sound* pSound = (draudio_sound*)pUserData;
1762  assert(pSound != NULL);
1763  assert(pSound->onRead != NULL);
1764 
1765  bool result = false;
1766  draudio_lock_mutex(pSound->pWorld->lock);
1767  {
1768  if (!pSound->markedForDeletion) {
1769  result = pSound->onRead(pSound, pDataOut, bytesToRead, bytesReadOut);
1770  }
1771  }
1772  draudio_unlock_mutex(pSound->pWorld->lock);
1773 
1774  return result;
1775 }
1776 
1777 DRAUDIO_PRIVATE static draudio_bool draudio_on_sound_seek_callback(void* pUserData, size_t offsetInBytesFromStart)
1778 {
1779  draudio_sound* pSound = (draudio_sound*)pUserData;
1780  assert(pSound != NULL);
1781  assert(pSound->onRead != NULL);
1782 
1783  bool result = false;
1784  draudio_lock_mutex(pSound->pWorld->lock);
1785  {
1786  if (!pSound->markedForDeletion) {
1787  result = pSound->onSeek(pSound, offsetInBytesFromStart);
1788  }
1789  }
1790  draudio_unlock_mutex(pSound->pWorld->lock);
1791 
1792  return result;
1793 }
1794 
1795 
1796 DRAUDIO_PRIVATE static void draudio_inline_sound_stop_callback(draudio_buffer* pBuffer, unsigned int eventID, void *pUserData)
1797 {
1798  (void)pBuffer;
1799  (void)eventID;
1800 
1801  assert(pBuffer != NULL);
1802  assert(eventID == DRAUDIO_EVENT_ID_STOP);
1803  assert(pUserData != NULL);
1804 
1805  draudio_sound* pSound = (draudio_sound*)pUserData;
1806  draudio_delete_sound(pSound);
1807 }
1808 
1809 
1810 DRAUDIO_PRIVATE void draudio_prepend_sound(draudio_sound* pSound)
1811 {
1812  assert(pSound != NULL);
1813  assert(pSound->pWorld != NULL);
1814  assert(pSound->pPrevSound == NULL);
1815 
1816  draudio_lock_mutex(pSound->pWorld->lock);
1817  {
1818  pSound->pNextSound = pSound->pWorld->pFirstSound;
1819 
1820  if (pSound->pNextSound != NULL) {
1821  pSound->pNextSound->pPrevSound = pSound;
1822  }
1823 
1824  pSound->pWorld->pFirstSound = pSound;
1825  }
1826  draudio_unlock_mutex(pSound->pWorld->lock);
1827 }
1828 
1829 DRAUDIO_PRIVATE void draudio_remove_sound_nolock(draudio_sound* pSound)
1830 {
1831  assert(pSound != NULL);
1832  assert(pSound->pWorld != NULL);
1833 
1834  if (pSound == pSound->pWorld->pFirstSound) {
1835  pSound->pWorld->pFirstSound = pSound->pNextSound;
1836  }
1837 
1838  if (pSound->pNextSound != NULL) {
1839  pSound->pNextSound->pPrevSound = pSound->pPrevSound;
1840  }
1841 
1842  if (pSound->pPrevSound != NULL) {
1843  pSound->pPrevSound->pNextSound = pSound->pNextSound;
1844  }
1845 }
1846 
1847 
1848 DRAUDIO_PRIVATE bool draudio_is_inline_sound(draudio_sound* pSound)
1849 {
1850  assert(pSound != NULL);
1851  return draudio_get_stop_callback(pSound->pBuffer).callback == draudio_inline_sound_stop_callback;
1852 }
1853 
1854 
1856 {
1857  draudio_world* pWorld = (draudio_world*)malloc(sizeof(*pWorld));
1858  if (pWorld != NULL)
1859  {
1860  pWorld->pDevice = pDevice;
1861  pWorld->playbackState = draudio_playing;
1862  pWorld->pFirstSound = NULL;
1863  pWorld->lock = draudio_create_mutex();
1864  }
1865 
1866  return pWorld;
1867 }
1868 
1869 void draudio_delete_world(draudio_world* pWorld)
1870 {
1871  if (pWorld == NULL) {
1872  return;
1873  }
1874 
1875  // Delete every sound first.
1876  draudio_delete_all_sounds(pWorld);
1877 
1878  // Delete the lock after deleting every sound because we still need thread-safety at this point.
1879  draudio_delete_mutex(pWorld->lock);
1880 
1881  // Free the world last.
1882  free(pWorld);
1883 }
1884 
1885 
1887 {
1888  if (pWorld == NULL) {
1889  return NULL;
1890  }
1891 
1892  if ((desc.pData == NULL || desc.sizeInBytes == 0) && (desc.onRead == NULL || desc.onSeek == NULL)) {
1893  // When streaming is not being used, the initial data must be valid at creation time.
1894  return NULL;
1895  }
1896 
1897  draudio_sound* pSound = (draudio_sound*)malloc(sizeof(*pSound));
1898  if (pSound == NULL) {
1899  return NULL;
1900  }
1901 
1902  pSound->pWorld = pWorld;
1904  pSound->pNextSound = NULL;
1905  pSound->pPrevSound = NULL;
1906  pSound->isUsingStreamingBuffer = desc.sizeInBytes == 0 || desc.pData == NULL;
1907  pSound->markedForDeletion = false;
1908  pSound->onDelete = desc.onDelete;
1909  pSound->onRead = desc.onRead;
1910  pSound->onSeek = desc.onSeek;
1911 
1912  draudio_buffer_desc bufferDesc;
1913  bufferDesc.flags = desc.flags;
1914  bufferDesc.format = desc.format;
1915  bufferDesc.channels = desc.channels;
1916  bufferDesc.sampleRate = desc.sampleRate;
1917  bufferDesc.bitsPerSample = desc.bitsPerSample;
1918  bufferDesc.sizeInBytes = desc.sizeInBytes;
1919  bufferDesc.pData = desc.pData;
1920 
1921  if (pSound->isUsingStreamingBuffer)
1922  {
1923  draudio_streaming_callbacks streamingCallbacks;
1924  streamingCallbacks.pUserData = pSound;
1925  streamingCallbacks.read = draudio_on_sound_read_callback;
1926  streamingCallbacks.seek = draudio_on_sound_seek_callback;
1927 
1928  pSound->pBuffer = draudio_create_streaming_buffer(pWorld->pDevice, &bufferDesc, streamingCallbacks, desc.extraDataSize);
1929  if (pSound->pBuffer != NULL && desc.pExtraData != NULL)
1930  {
1932  }
1933  }
1934  else
1935  {
1936  pSound->pBuffer = draudio_create_buffer(pWorld->pDevice, &bufferDesc, desc.extraDataSize);
1937  if (pSound->pBuffer != NULL && desc.pExtraData != NULL)
1938  {
1939  memcpy(draudio_get_buffer_extra_data(pSound->pBuffer), desc.pExtraData, desc.extraDataSize);
1940  }
1941  }
1942 
1943 
1944  // Return NULL if we failed to create the internal audio buffer.
1945  if (pSound->pBuffer == NULL) {
1946  free(pSound);
1947  return NULL;
1948  }
1949 
1950 
1951  // Only attach the sound to the internal list at the end when we know everything has worked.
1952  draudio_prepend_sound(pSound);
1953 
1954  return pSound;
1955 }
1956 
1957 void draudio_delete_sound(draudio_sound* pSound)
1958 {
1959  if (pSound == NULL) {
1960  return;
1961  }
1962 
1963 
1964  draudio_lock_mutex(pSound->pWorld->lock);
1965  {
1966  if (pSound->markedForDeletion) {
1967  assert(false);
1968  return;
1969  }
1970 
1971  pSound->markedForDeletion = true;
1972 
1973 
1974  // Remove the sound from the internal list first.
1975  draudio_remove_sound_nolock(pSound);
1976 
1977 
1978  // If we're deleting an inline sound, we want to remove the stop event callback. If we don't do this, we'll end up trying to delete
1979  // the sound twice.
1980  if (draudio_is_inline_sound(pSound)) {
1982  }
1983 
1984 
1985  // Let the application know that the sound is being deleted. We want to do this after removing the stop event just to be sure the
1986  // application doesn't try to explicitly stop the sound in this callback - that would be a problem for inlined sounds because they
1987  // are configured to delete themselves upon stopping which we are already in the process of doing.
1988  if (pSound->onDelete != NULL) {
1989  pSound->onDelete(pSound);
1990  }
1991 
1992 
1993  // Delete the internal audio buffer before letting the host application know about the deletion.
1994  draudio_delete_buffer(pSound->pBuffer);
1995  }
1996  draudio_unlock_mutex(pSound->pWorld->lock);
1997 
1998 
1999  // Only free the sound after the application has been made aware the sound is being deleted.
2000  free(pSound);
2001 }
2002 
2004 {
2005  if (pWorld == NULL) {
2006  return;
2007  }
2008 
2009  while (pWorld->pFirstSound != NULL) {
2011  }
2012 }
2013 
2014 
2016 {
2017  if (pSound == NULL) {
2018  return 0;
2019  }
2020 
2021  if (pSound->isUsingStreamingBuffer) {
2023  } else {
2025  }
2026 }
2027 
2029 {
2030  if (pSound == NULL) {
2031  return NULL;
2032  }
2033 
2034  if (pSound->isUsingStreamingBuffer) {
2036  } else {
2037  return draudio_get_buffer_extra_data(pSound->pBuffer);
2038  }
2039 }
2040 
2041 
2042 void draudio_play_sound(draudio_sound* pSound, bool loop)
2043 {
2044  if (pSound != NULL) {
2045  if (pSound->isUsingStreamingBuffer) {
2046  draudio_play_streaming_buffer(pSound->pBuffer, loop);
2047  } else {
2048  draudio_play(pSound->pBuffer, loop);
2049  }
2050  }
2051 }
2052 
2053 void draudio_pause_sound(draudio_sound* pSound)
2054 {
2055  if (pSound != NULL) {
2056  draudio_pause(pSound->pBuffer);
2057  }
2058 }
2059 
2060 void draudio_stop_sound(draudio_sound* pSound)
2061 {
2062  if (pSound != NULL) {
2063  draudio_stop(pSound->pBuffer);
2064  }
2065 }
2066 
2068 {
2069  if (pSound == NULL) {
2070  return draudio_stopped;
2071  }
2072 
2073  return draudio_get_playback_state(pSound->pBuffer);
2074 }
2075 
2077 {
2078  if (pSound == NULL) {
2079  return false;
2080  }
2081 
2082  if (pSound->isUsingStreamingBuffer) {
2084  } else {
2085  return draudio_is_looping(pSound->pBuffer);
2086  }
2087 }
2088 
2089 
2090 
2092 {
2093  if (pWorld == NULL) {
2094  return;
2095  }
2096 
2097  // We need to explicitly ensure 3D positioning is disabled.
2098  desc.flags &= ~DRAUDIO_ENABLE_3D;
2099 
2100  draudio_sound* pSound = draudio_create_sound(pWorld, desc);
2101  if (pSound != NULL)
2102  {
2103  // For inline sounds we set a callback for when the sound is stopped. When this callback is fired, the sound is deleted.
2104  draudio_set_sound_stop_callback(pSound, draudio_inline_sound_stop_callback, pSound);
2105 
2106  // Start playing the sound once everything else has been set up.
2107  draudio_play_sound(pSound, false);
2108  }
2109 }
2110 
2111 void draudio_play_inline_sound_3f(draudio_world* pWorld, draudio_sound_desc desc, float posX, float posY, float posZ)
2112 {
2113  if (pWorld == NULL) {
2114  return;
2115  }
2116 
2117  draudio_sound* pSound = draudio_create_sound(pWorld, desc);
2118  if (pSound != NULL)
2119  {
2120  // For inline sounds we set a callback for when the sound is stopped. When this callback is fired, the sound is deleted.
2121  draudio_set_sound_stop_callback(pSound, draudio_inline_sound_stop_callback, pSound);
2122 
2123  // Set the position before playing anything.
2124  draudio_set_sound_position(pSound, posX, posY, posZ);
2125 
2126  // Start playing the sound once everything else has been set up.
2127  draudio_play_sound(pSound, false);
2128  }
2129 }
2130 
2131 
2133 {
2134  if (pWorld == NULL) {
2135  return;
2136  }
2137 
2138  bool wasPlaying = pWorld->playbackState == draudio_playing;
2139  if (pWorld->playbackState != draudio_stopped)
2140  {
2141  // We need to loop over every sound and stop them. We also need to keep track of their previous playback state
2142  // so that when resume_all_sounds() is called, it can be restored correctly.
2143  for (draudio_sound* pSound = pWorld->pFirstSound; pSound != NULL; pSound = pSound->pNextSound)
2144  {
2145  if (wasPlaying) {
2147  }
2148 
2149  draudio_stop_sound(pSound);
2150  }
2151  }
2152 }
2153 
2155 {
2156  if (pWorld == NULL) {
2157  return;
2158  }
2159 
2160  if (pWorld->playbackState == draudio_playing)
2161  {
2162  // We need to loop over every sound and stop them. We also need to keep track of their previous playback state
2163  // so that when resume_all_sounds() is called, it can be restored correctly.
2164  for (draudio_sound* pSound = pWorld->pFirstSound; pSound != NULL; pSound = pSound->pNextSound)
2165  {
2167  draudio_pause_sound(pSound);
2168  }
2169  }
2170 }
2171 
2173 {
2174  if (pWorld == NULL) {
2175  return;
2176  }
2177 
2178  if (pWorld->playbackState != draudio_playing)
2179  {
2180  // When resuming playback, we use the previous playback state to determine how to resume.
2181  for (draudio_sound* pSound = pWorld->pFirstSound; pSound != NULL; pSound = pSound->pNextSound)
2182  {
2183  if (pSound->prevPlaybackState == draudio_playing) {
2185  }
2186  }
2187  }
2188 }
2189 
2190 
2191 void draudio_set_sound_stop_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData)
2192 {
2193  if (pSound != NULL) {
2194  draudio_register_stop_callback(pSound->pBuffer, callback, pUserData);
2195  }
2196 }
2197 
2198 void draudio_set_sound_pause_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData)
2199 {
2200  if (pSound != NULL) {
2201  draudio_register_pause_callback(pSound->pBuffer, callback, pUserData);
2202  }
2203 }
2204 
2205 void draudio_set_sound_play_callback(draudio_sound* pSound, draudio_event_callback_proc callback, void* pUserData)
2206 {
2207  if (pSound != NULL) {
2208  draudio_register_play_callback(pSound->pBuffer, callback, pUserData);
2209  }
2210 }
2211 
2212 
2213 void draudio_set_sound_position(draudio_sound* pSound, float posX, float posY, float posZ)
2214 {
2215  if (pSound != NULL) {
2216  draudio_set_position(pSound->pBuffer, posX, posY, posZ);
2217  }
2218 }
2219 
2220 
2222 {
2223  if (pSound != NULL) {
2224  draudio_set_3d_mode(pSound->pBuffer, mode);
2225  }
2226 }
2227 
2229 {
2230  if (pSound == NULL) {
2231  return draudio_3d_mode_disabled;
2232  }
2233 
2234  return draudio_get_3d_mode(pSound->pBuffer);
2235 }
2236 
2237 
2238 
2239 
2240 
2243 //
2244 // BACKENDS
2245 //
2248 
2250 //
2251 // DirectSound
2252 //
2253 // The DirectSound backend is mostly simple, except for event handling. Events
2254 // are achieved through the use of Win32 event objects and waiting on them to
2255 // be put into a signaled state by DirectSound. Due to this mechanic we need to
2256 // create a worker thread that waits on each event.
2257 //
2258 // The worker thread waits on three general types of events. The first is an
2259 // event that is signaled when the thread needs to be terminated. The second
2260 // is an event that is signaled when a new set of events need to be waited on.
2261 // The third is a set of events that correspond to an output buffer event (such
2262 // as stop, pause, play and marker events.)
2263 //
2265 #ifdef DRAUDIO_BUILD_DSOUND
2266 #include <windows.h>
2267 #include <dsound.h>
2268 #include <mmreg.h>
2269 #include <stdio.h> // For testing and debugging with printf(). Delete this later.
2270 
2271 // Define a NULL GUID for use later on. If we don't do this and use GUID_NULL we'll end
2272 // up with a link error.
2273 GUID DRAUDIO_GUID_NULL = {0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
2274 
2275 
2277 
2278 #define DRAUDIO_MESSAGE_ID_UNKNOWN 0
2279 #define DRAUDIO_MESSAGE_ID_EVENT 1
2280 #define DRAUDIO_MESSAGE_ID_DELETE_BUFFER 2
2281 #define DRAUDIO_MESSAGE_ID_DELETE_DEVICE 3
2282 #define DRAUDIO_MESSAGE_ID_TERMINATE_THREAD 4
2283 
2285 typedef struct
2286 {
2288  int id;
2289 
2291  draudio_buffer* pBuffer;
2292 
2293 
2294  // The message-specific data.
2295  union
2296  {
2297  struct
2298  {
2300  draudio_event_callback_proc callback;
2301 
2303  unsigned int eventID;
2304 
2306  void* pUserData;
2307 
2308  } callback_event;
2309 
2310 
2311  struct
2312  {
2314  LPDIRECTSOUNDBUFFER8 pDSBuffer;
2315 
2317  LPDIRECTSOUND3DBUFFER pDSBuffer3D;
2318 
2320  LPDIRECTSOUNDNOTIFY pDSNotify;
2321 
2322  } delete_buffer;
2323 
2324 
2325  struct
2326  {
2328  LPDIRECTSOUND8 pDS;
2329 
2331  LPDIRECTSOUNDBUFFER pDSPrimaryBuffer;
2332 
2334  LPDIRECTSOUND3DLISTENER pDSListener;
2335 
2337  draudio_device* pDevice;
2338 
2339  } delete_device;
2340 
2341  } data;
2342 
2343 } draudio_message_dsound;
2344 
2345 
2350 typedef struct
2351 {
2353  draudio_message_dsound messages[DRAUDIO_MAX_MESSAGE_QUEUE_SIZE];
2354 
2356  unsigned int messageCount;
2357 
2359  unsigned int iFirstMessage;
2360 
2362  draudio_mutex queueLock;
2363 
2365  HANDLE hMessageSemaphore;
2366 
2368  HANDLE hMessageHandlingThread;
2369 
2371  bool isDeleted;
2372 
2373 } draudio_message_queue_dsound;
2374 
2375 
2377 DWORD WINAPI MessageHandlingThread_DSound(draudio_message_queue_dsound* pQueue);
2378 
2380 void draudio_post_message_dsound(draudio_message_queue_dsound* pQueue, draudio_message_dsound msg);
2381 
2382 
2383 
2385 bool draudio_init_message_queue_dsound(draudio_message_queue_dsound* pQueue)
2386 {
2387  if (pQueue == NULL) {
2388  return false;
2389  }
2390 
2391  pQueue->messageCount = 0;
2392  pQueue->iFirstMessage = 0;
2393 
2394  pQueue->queueLock = draudio_create_mutex();
2395  if (pQueue->queueLock == NULL) {
2396  return false;
2397  }
2398 
2399  pQueue->hMessageSemaphore = CreateSemaphoreA(NULL, 0, DRAUDIO_MAX_MESSAGE_QUEUE_SIZE, NULL);
2400  if (pQueue->hMessageSemaphore == NULL)
2401  {
2402  draudio_delete_mutex(pQueue->queueLock);
2403  return false;
2404  }
2405 
2406  pQueue->hMessageHandlingThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MessageHandlingThread_DSound, pQueue, 0, NULL);
2407  if (pQueue->hMessageHandlingThread == NULL)
2408  {
2409  CloseHandle(pQueue->hMessageSemaphore);
2410  draudio_delete_mutex(pQueue->queueLock);
2411  return false;
2412  }
2413 
2414  pQueue->isDeleted = false;
2415 
2416  return true;
2417 }
2418 
2420 void draudio_uninit_message_queue_dsound(draudio_message_queue_dsound* pQueue)
2421 {
2422  // We need to make sure the thread is closed properly before returning from here. To do this we just post an DRAUDIO_MESSAGE_ID_TERMINATE_THREAD
2423  // event to the message queue and wait for the thread to finish.
2424  draudio_message_dsound msg;
2425  msg.id = DRAUDIO_MESSAGE_ID_TERMINATE_THREAD;
2426  draudio_post_message_dsound(pQueue, msg);
2427 
2428 
2429  // Once we posted the event we just wait for the thread to process it and terminate.
2430  WaitForSingleObject(pQueue->hMessageHandlingThread, INFINITE);
2431 
2432  // At this point the thread has been terminated and we can clear everything.
2433  CloseHandle(pQueue->hMessageHandlingThread);
2434  pQueue->hMessageHandlingThread = NULL;
2435 
2436  CloseHandle(pQueue->hMessageSemaphore);
2437  pQueue->hMessageSemaphore = NULL;
2438 
2439 
2440  pQueue->isDeleted = true;
2441  draudio_lock_mutex(pQueue->queueLock);
2442  {
2443  pQueue->messageCount = 0;
2444  pQueue->iFirstMessage = 0;
2445  }
2446  draudio_unlock_mutex(pQueue->queueLock);
2447 
2448  draudio_delete_mutex(pQueue->queueLock);
2449  pQueue->queueLock = NULL;
2450 }
2451 
2452 
2453 void draudio_post_message_dsound(draudio_message_queue_dsound* pQueue, draudio_message_dsound msg)
2454 {
2455  assert(pQueue != NULL);
2456 
2457  if (pQueue->isDeleted) {
2458  return;
2459  }
2460 
2461  draudio_lock_mutex(pQueue->queueLock);
2462  {
2463  if (pQueue->messageCount < DRAUDIO_MAX_MESSAGE_QUEUE_SIZE)
2464  {
2465  pQueue->messages[(pQueue->iFirstMessage + pQueue->messageCount) % DRAUDIO_MAX_MESSAGE_QUEUE_SIZE] = msg;
2466  pQueue->messageCount += 1;
2467 
2468  ReleaseSemaphore(pQueue->hMessageSemaphore, 1, NULL);
2469  }
2470  }
2471  draudio_unlock_mutex(pQueue->queueLock);
2472 }
2473 
2474 
2479 bool draudio_next_message_dsound(draudio_message_queue_dsound* pQueue, draudio_message_dsound* pMsgOut)
2480 {
2481  if (WaitForSingleObject(pQueue->hMessageSemaphore, INFINITE) == WAIT_OBJECT_0) // Wait for a message to become available.
2482  {
2483  draudio_message_dsound msg;
2484  msg.id = DRAUDIO_MESSAGE_ID_UNKNOWN;
2485 
2486  draudio_lock_mutex(pQueue->queueLock);
2487  {
2488  assert(pQueue->messageCount > 0);
2489 
2490  msg = pQueue->messages[pQueue->iFirstMessage];
2491 
2492  pQueue->iFirstMessage = (pQueue->iFirstMessage + 1) % DRAUDIO_MAX_MESSAGE_QUEUE_SIZE;
2493  pQueue->messageCount -= 1;
2494  }
2495  draudio_unlock_mutex(pQueue->queueLock);
2496 
2497 
2498  if (pMsgOut != NULL) {
2499  pMsgOut[0] = msg;
2500  }
2501 
2502  return msg.id != DRAUDIO_MESSAGE_ID_TERMINATE_THREAD;
2503  }
2504 
2505  return false;
2506 }
2507 
2508 
2509 DWORD WINAPI MessageHandlingThread_DSound(draudio_message_queue_dsound* pQueue)
2510 {
2511  assert(pQueue != NULL);
2512 
2513  draudio_message_dsound msg;
2514  while (draudio_next_message_dsound(pQueue, &msg))
2515  {
2516  assert(msg.id != DRAUDIO_MESSAGE_ID_TERMINATE_THREAD); // <-- draudio_next_message_dsound() will return false when it receives DRAUDIO_MESSAGE_ID_TERMINATE_THREAD.
2517 
2518  switch (msg.id)
2519  {
2520  case DRAUDIO_MESSAGE_ID_EVENT:
2521  {
2522  assert(msg.data.callback_event.callback != NULL);
2523 
2524  msg.data.callback_event.callback(msg.pBuffer, msg.data.callback_event.eventID, msg.data.callback_event.pUserData);
2525  break;
2526  }
2527 
2528  case DRAUDIO_MESSAGE_ID_DELETE_BUFFER:
2529  {
2530  if (msg.data.delete_buffer.pDSNotify != NULL) {
2531  IDirectSoundNotify_Release(msg.data.delete_buffer.pDSNotify);
2532  }
2533 
2534  if (msg.data.delete_buffer.pDSBuffer3D != NULL) {
2535  IDirectSound3DBuffer_Release(msg.data.delete_buffer.pDSBuffer3D);
2536  }
2537 
2538  if (msg.data.delete_buffer.pDSBuffer != NULL) {
2539  IDirectSoundBuffer8_Release(msg.data.delete_buffer.pDSBuffer);
2540  }
2541 
2542  free(msg.pBuffer);
2543  break;
2544  }
2545 
2546  case DRAUDIO_MESSAGE_ID_DELETE_DEVICE:
2547  {
2548  if (msg.data.delete_device.pDSListener != NULL) {
2549  IDirectSound3DListener_Release(msg.data.delete_device.pDSListener);
2550  }
2551 
2552  if (msg.data.delete_device.pDSPrimaryBuffer != NULL) {
2553  IDirectSoundBuffer_Release(msg.data.delete_device.pDSPrimaryBuffer);
2554  }
2555 
2556  if (msg.data.delete_device.pDS != NULL) {
2557  IDirectSound_Release(msg.data.delete_device.pDS);
2558  }
2559 
2560  free(msg.data.delete_device.pDevice);
2561  break;
2562  }
2563 
2564  default:
2565  {
2566  // Should never hit this.
2567  assert(false);
2568  break;
2569  }
2570  }
2571  }
2572 
2573  return 0;
2574 }
2575 
2576 
2577 
2578 
2580 void draudio_deactivate_buffer_events_dsound(draudio_buffer* pBuffer);
2581 
2582 
2584 
2585 typedef struct draudio_event_manager_dsound draudio_event_manager_dsound;
2586 typedef struct draudio_event_dsound draudio_event_dsound;
2587 
2588 struct draudio_event_dsound
2589 {
2591  draudio_event_manager_dsound* pEventManager;
2592 
2594  HANDLE hEvent;
2595 
2597  draudio_event_callback_proc callback;
2598 
2600  draudio_buffer* pBuffer;
2601 
2603  unsigned int eventID;
2604 
2606  void* pUserData;
2607 
2609  DWORD markerOffset;
2610 
2612  draudio_event_dsound* pNextEvent;
2613 
2615  draudio_event_dsound* pPrevEvent;
2616 };
2617 
2618 struct draudio_event_manager_dsound
2619 {
2621  draudio_message_queue_dsound* pMessageQueue;
2622 
2623 
2625  HANDLE hThread;
2626 
2628  HANDLE hTerminateEvent;
2629 
2631  HANDLE hRefreshEvent;
2632 
2634  draudio_mutex refreshMutex;
2635 
2637  draudio_mutex mainLock;
2638 
2640  HANDLE hEventCompletionLock;
2641 
2642 
2644  draudio_event_dsound* pFirstEvent;
2645 
2647  draudio_event_dsound* pLastEvent;
2648 };
2649 
2650 
2652 void draudio_lock_events_dsound(draudio_event_manager_dsound* pEventManager)
2653 {
2654  draudio_lock_mutex(pEventManager->mainLock);
2655 }
2656 
2658 void draudio_unlock_events_dsound(draudio_event_manager_dsound* pEventManager)
2659 {
2660  draudio_unlock_mutex(pEventManager->mainLock);
2661 }
2662 
2663 
2668 void draudio_remove_event_dsound_nolock(draudio_event_dsound* pEvent)
2669 {
2670  assert(pEvent != NULL);
2671 
2672  draudio_event_manager_dsound* pEventManager = pEvent->pEventManager;
2673  assert(pEventManager != NULL);
2674 
2675  if (pEventManager->pFirstEvent == pEvent) {
2676  pEventManager->pFirstEvent = pEvent->pNextEvent;
2677  }
2678 
2679  if (pEventManager->pLastEvent == pEvent) {
2680  pEventManager->pLastEvent = pEvent->pPrevEvent;
2681  }
2682 
2683 
2684  if (pEvent->pPrevEvent != NULL) {
2685  pEvent->pPrevEvent->pNextEvent = pEvent->pNextEvent;
2686  }
2687 
2688  if (pEvent->pNextEvent != NULL) {
2689  pEvent->pNextEvent->pPrevEvent = pEvent->pPrevEvent;
2690  }
2691 
2692  pEvent->pNextEvent = NULL;
2693  pEvent->pPrevEvent = NULL;
2694 }
2695 
2697 void draudio_remove_event_dsound(draudio_event_dsound* pEvent)
2698 {
2699  assert(pEvent != NULL);
2700 
2701  draudio_event_manager_dsound* pEventManager = pEvent->pEventManager;
2702  draudio_lock_events_dsound(pEventManager);
2703  {
2704  draudio_remove_event_dsound_nolock(pEvent);
2705  }
2706  draudio_unlock_events_dsound(pEventManager);
2707 }
2708 
2710 void draudio_append_event_dsound(draudio_event_dsound* pEvent)
2711 {
2712  assert(pEvent != NULL);
2713 
2714  draudio_event_manager_dsound* pEventManager = pEvent->pEventManager;
2715  draudio_lock_events_dsound(pEventManager);
2716  {
2717  draudio_remove_event_dsound_nolock(pEvent);
2718 
2719  assert(pEvent->pNextEvent == NULL);
2720 
2721  if (pEventManager->pLastEvent != NULL) {
2722  pEvent->pPrevEvent = pEventManager->pLastEvent;
2723  pEvent->pPrevEvent->pNextEvent = pEvent;
2724  }
2725 
2726  if (pEventManager->pFirstEvent == NULL) {
2727  pEventManager->pFirstEvent = pEvent;
2728  }
2729 
2730  pEventManager->pLastEvent = pEvent;
2731  }
2732  draudio_unlock_events_dsound(pEventManager);
2733 }
2734 
2735 void draudio_refresh_worker_thread_event_queue(draudio_event_manager_dsound* pEventManager)
2736 {
2737  assert(pEventManager != NULL);
2738 
2739  // To refresh the worker thread we just need to signal the refresh event. We then just need to wait for
2740  // processing to finish which we can do by waiting on another event to become signaled.
2741 
2742  draudio_lock_mutex(pEventManager->refreshMutex);
2743  {
2744  // Signal a refresh.
2745  SetEvent(pEventManager->hRefreshEvent);
2746 
2747  // Wait for refreshing to complete.
2748  WaitForSingleObject(pEventManager->hEventCompletionLock, INFINITE);
2749  }
2750  draudio_unlock_mutex(pEventManager->refreshMutex);
2751 }
2752 
2753 
2755 void draudio_close_win32_event_handle_dsound(draudio_event_dsound* pEvent)
2756 {
2757  assert(pEvent != NULL);
2758  assert(pEvent->pEventManager != NULL);
2759 
2760 
2761  // At the time of calling this function, pEvent should have been removed from the internal list. The issue is that
2762  // the event notification thread is waiting on it. Thus, we need to refresh the worker thread to ensure the event
2763  // have been flushed from that queue. To do this we just signal a special event that's used to trigger a refresh.
2764  draudio_refresh_worker_thread_event_queue(pEvent->pEventManager);
2765 
2766  // The worker thread should not be waiting on the event so we can go ahead and close the handle now.
2767  CloseHandle(pEvent->hEvent);
2768  pEvent->hEvent = NULL;
2769 }
2770 
2771 
2773 void draudio_update_event_dsound(draudio_event_dsound* pEvent, draudio_event_callback_proc callback, void* pUserData)
2774 {
2775  assert(pEvent != NULL);
2776 
2777  pEvent->callback = callback;
2778  pEvent->pUserData = pUserData;
2779 
2780  draudio_refresh_worker_thread_event_queue(pEvent->pEventManager);
2781 }
2782 
2788 draudio_event_dsound* draudio_create_event_dsound(draudio_event_manager_dsound* pEventManager, draudio_event_callback_proc callback, draudio_buffer* pBuffer, unsigned int eventID, void* pUserData)
2789 {
2790  draudio_event_dsound* pEvent = (draudio_event_dsound*)malloc(sizeof(draudio_event_dsound));
2791  if (pEvent != NULL)
2792  {
2793  pEvent->pEventManager = pEventManager;
2794  pEvent->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2795  pEvent->callback = NULL;
2796  pEvent->pBuffer = pBuffer;
2797  pEvent->eventID = eventID;
2798  pEvent->pUserData = NULL;
2799  pEvent->markerOffset = 0;
2800  pEvent->pNextEvent = NULL;
2801  pEvent->pPrevEvent = NULL;
2802 
2803  // Append the event to the internal list.
2804  draudio_append_event_dsound(pEvent);
2805 
2806  // This roundabout way of setting the callback and user data is to ensure the worker thread is made aware that it needs
2807  // to refresh it's local event data.
2808  draudio_update_event_dsound(pEvent, callback, pUserData);
2809  }
2810 
2811  return pEvent;
2812 }
2813 
2818 void draudio_delete_event_dsound(draudio_event_dsound* pEvent)
2819 {
2820  assert(pEvent != NULL);
2821 
2822  // Set everything to NULL so the worker thread is aware that the event is about to get deleted.
2823  pEvent->pBuffer = NULL;
2824  pEvent->callback = NULL;
2825  pEvent->eventID = 0;
2826  pEvent->pUserData = NULL;
2827  pEvent->markerOffset = 0;
2828 
2829  // Remove the event from the list.
2830  draudio_remove_event_dsound(pEvent);
2831 
2832  // Close the Win32 event handle.
2833  if (pEvent->hEvent != NULL) {
2834  draudio_close_win32_event_handle_dsound(pEvent);
2835  }
2836 
2837 
2838  // At this point everything has been closed so we can safely free the memory and return.
2839  free(pEvent);
2840 }
2841 
2842 
2844 unsigned int draudio_gather_events_dsound(draudio_event_manager_dsound *pEventManager, HANDLE* pHandlesOut, draudio_event_dsound** ppEventsOut, unsigned int outputBufferSize)
2845 {
2846  assert(pEventManager != NULL);
2847  assert(pHandlesOut != NULL);
2848  assert(ppEventsOut != NULL);
2849  assert(outputBufferSize >= 2);
2850 
2851  unsigned int i = 2;
2852  draudio_lock_events_dsound(pEventManager);
2853  {
2854  pHandlesOut[0] = pEventManager->hTerminateEvent;
2855  ppEventsOut[0] = NULL;
2856 
2857  pHandlesOut[1] = pEventManager->hRefreshEvent;
2858  ppEventsOut[1] = NULL;
2859 
2860 
2861  draudio_event_dsound* pEvent = pEventManager->pFirstEvent;
2862  while (i < outputBufferSize && pEvent != NULL)
2863  {
2864  if (pEvent->hEvent != NULL)
2865  {
2866  pHandlesOut[i] = pEvent->hEvent;
2867  ppEventsOut[i] = pEvent;
2868 
2869  i += 1;
2870  }
2871 
2872  pEvent = pEvent->pNextEvent;
2873  }
2874  }
2875  draudio_unlock_events_dsound(pEventManager);
2876 
2877  return i;
2878 }
2879 
2881 DWORD WINAPI DSound_EventWorkerThreadProc(draudio_event_manager_dsound *pEventManager)
2882 {
2883  if (pEventManager != NULL)
2884  {
2885  HANDLE hTerminateEvent = pEventManager->hTerminateEvent;
2886  HANDLE hRefreshEvent = pEventManager->hRefreshEvent;
2887 
2888  HANDLE eventHandles[1024];
2889  draudio_event_dsound* events[1024];
2890  unsigned int eventCount = draudio_gather_events_dsound(pEventManager, eventHandles, events, 1024); // <-- Initial gather.
2891 
2892  bool requestedRefresh = false;
2893  for (;;)
2894  {
2895  if (requestedRefresh)
2896  {
2897  eventCount = draudio_gather_events_dsound(pEventManager, eventHandles, events, 1024);
2898 
2899  // Refreshing is done, so now we need to let other threads know about it.
2900  SetEvent(pEventManager->hEventCompletionLock);
2901  requestedRefresh = false;
2902  }
2903 
2904 
2905 
2906  DWORD rc = WaitForMultipleObjects(eventCount, eventHandles, FALSE, INFINITE);
2907  if (rc >= WAIT_OBJECT_0 && rc < eventCount)
2908  {
2909  const unsigned int eventIndex = rc - WAIT_OBJECT_0;
2910  HANDLE hEvent = eventHandles[eventIndex];
2911 
2912  if (hEvent == hTerminateEvent)
2913  {
2914  // The terminator event was signaled. We just return from the thread immediately.
2915  return 0;
2916  }
2917 
2918  if (hEvent == hRefreshEvent)
2919  {
2920  assert(hRefreshEvent == pEventManager->hRefreshEvent);
2921 
2922  // This event will get signaled when a new set of events need to be waited on, such as when a new event has been registered on a buffer.
2923  requestedRefresh = true;
2924  continue;
2925  }
2926 
2927 
2928  // If we get here if means we have hit a callback event.
2929  draudio_event_dsound* pEvent = events[eventIndex];
2930  if (pEvent->callback != NULL)
2931  {
2932  assert(pEvent->hEvent == hEvent);
2933 
2934  // The stop event will be signaled by DirectSound when IDirectSoundBuffer::Stop() is called. The problem is that we need to call that when the
2935  // sound is paused as well. Thus, we need to check if we got the stop event, and if so DON'T call the callback function if it is in a non-stopped
2936  // state.
2937  bool isStopEventButNotStopped = pEvent->eventID == DRAUDIO_EVENT_ID_STOP && draudio_get_playback_state(pEvent->pBuffer) != draudio_stopped;
2938  if (!isStopEventButNotStopped)
2939  {
2940  // We don't call the callback directly. Instead we post a message to the message handling thread for processing later.
2941  draudio_message_dsound msg;
2942  msg.id = DRAUDIO_MESSAGE_ID_EVENT;
2943  msg.pBuffer = pEvent->pBuffer;
2944  msg.data.callback_event.callback = pEvent->callback;
2945  msg.data.callback_event.eventID = pEvent->eventID;
2946  msg.data.callback_event.pUserData = pEvent->pUserData;
2947  draudio_post_message_dsound(pEventManager->pMessageQueue, msg);
2948  }
2949  }
2950  }
2951  }
2952  }
2953 
2954  return 0;
2955 }
2956 
2957 
2959 bool draudio_init_event_manager_dsound(draudio_event_manager_dsound* pEventManager, draudio_message_queue_dsound* pMessageQueue)
2960 {
2961  assert(pEventManager != NULL);
2962  assert(pMessageQueue != NULL);
2963 
2964  pEventManager->pMessageQueue = pMessageQueue;
2965 
2966  HANDLE hTerminateEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2967  if (hTerminateEvent == NULL) {
2968  return false;
2969  }
2970 
2971  HANDLE hRefreshEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
2972  if (hRefreshEvent == NULL)
2973  {
2974  CloseHandle(hTerminateEvent);
2975  return false;
2976  }
2977 
2978  draudio_mutex refreshMutex = draudio_create_mutex();
2979  if (refreshMutex == NULL)
2980  {
2981  CloseHandle(hTerminateEvent);
2982  CloseHandle(hRefreshEvent);
2983  return false;
2984  }
2985 
2986  draudio_mutex mainLock = draudio_create_mutex();
2987  if (mainLock == NULL)
2988  {
2989  CloseHandle(hTerminateEvent);
2990  CloseHandle(hRefreshEvent);
2991  draudio_delete_mutex(refreshMutex);
2992  return false;
2993  }
2994 
2995  HANDLE hEventCompletionLock = CreateEventA(NULL, FALSE, FALSE, NULL);
2996  if (hEventCompletionLock == NULL)
2997  {
2998  CloseHandle(hTerminateEvent);
2999  CloseHandle(hRefreshEvent);
3000  draudio_delete_mutex(refreshMutex);
3001  draudio_delete_mutex(mainLock);
3002  return false;
3003  }
3004 
3005 
3006  HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DSound_EventWorkerThreadProc, pEventManager, 0, NULL);
3007  if (hThread == NULL)
3008  {
3009  CloseHandle(hTerminateEvent);
3010  CloseHandle(hRefreshEvent);
3011  draudio_delete_mutex(refreshMutex);
3012  draudio_delete_mutex(mainLock);
3013  CloseHandle(hEventCompletionLock);
3014  return false;
3015  }
3016 
3017 
3018  pEventManager->hTerminateEvent = hTerminateEvent;
3019  pEventManager->hRefreshEvent = hRefreshEvent;
3020  pEventManager->refreshMutex = refreshMutex;
3021  pEventManager->mainLock = mainLock;
3022  pEventManager->hEventCompletionLock = hEventCompletionLock;
3023  pEventManager->hThread = hThread;
3024 
3025  pEventManager->pFirstEvent = NULL;
3026  pEventManager->pLastEvent = NULL;
3027 
3028  return true;
3029 }
3030 
3037 void draudio_uninit_event_manager_dsound(draudio_event_manager_dsound* pEventManager)
3038 {
3039  assert(pEventManager != NULL);
3040 
3041 
3042  // Cleanly delete every event first.
3043  while (pEventManager->pFirstEvent != NULL) {
3044  draudio_delete_event_dsound(pEventManager->pFirstEvent);
3045  }
3046 
3047 
3048 
3049  // Terminate the thread and wait for the thread to finish executing before freeing the context for real.
3050  SignalObjectAndWait(pEventManager->hTerminateEvent, pEventManager->hThread, INFINITE, FALSE);
3051 
3052  // Only delete the thread after it has returned naturally.
3053  CloseHandle(pEventManager->hThread);
3054  pEventManager->hThread = NULL;
3055 
3056 
3057  // Once the thread has been terminated we can delete the terminator and refresher events.
3058  CloseHandle(pEventManager->hTerminateEvent);
3059  pEventManager->hTerminateEvent = NULL;
3060 
3061  CloseHandle(pEventManager->hRefreshEvent);
3062  pEventManager->hRefreshEvent = NULL;
3063 
3064  draudio_delete_mutex(pEventManager->refreshMutex);
3065  pEventManager->refreshMutex = NULL;
3066 
3067  draudio_delete_mutex(pEventManager->mainLock);
3068  pEventManager->mainLock = NULL;
3069 
3070 
3071  CloseHandle(pEventManager->hEventCompletionLock);
3072  pEventManager->hEventCompletionLock = NULL;
3073 }
3074 
3075 
3077 
3078 static GUID _g_DSListenerGUID = {0x279AFA84, 0x4981, 0x11CE, {0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60}};
3079 static GUID _g_DirectSoundBuffer8GUID = {0x6825a449, 0x7524, 0x4d82, {0x92, 0x0f, 0x50, 0xe3, 0x6a, 0xb3, 0xab, 0x1e}};
3080 static GUID _g_DirectSound3DBuffer8GUID = {0x279AFA86, 0x4981, 0x11CE, {0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60}};
3081 static GUID _g_DirectSoundNotifyGUID = {0xb0210783, 0x89cd, 0x11d0, {0xaf, 0x08, 0x00, 0xa0, 0xc9, 0x25, 0xcd, 0x16}};
3082 static GUID _g_KSDATAFORMAT_SUBTYPE_PCM_GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
3083 static GUID _g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID = {0x00000003, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
3084 
3085 #ifdef __cplusplus
3086 static GUID g_DSListenerGUID = _g_DSListenerGUID;
3087 static GUID g_DirectSoundBuffer8GUID = _g_DirectSoundBuffer8GUID;
3088 static GUID g_DirectSound3DBuffer8GUID = _g_DirectSound3DBuffer8GUID;
3089 static GUID g_DirectSoundNotifyGUID = _g_DirectSoundNotifyGUID;
3090 static GUID g_KSDATAFORMAT_SUBTYPE_PCM_GUID = _g_KSDATAFORMAT_SUBTYPE_PCM_GUID;
3091 static GUID g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID = _g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID;
3092 #else
3093 static GUID* g_DSListenerGUID = &_g_DSListenerGUID;
3094 static GUID* g_DirectSoundBuffer8GUID = &_g_DirectSoundBuffer8GUID;
3095 static GUID* g_DirectSound3DBuffer8GUID = &_g_DirectSound3DBuffer8GUID;
3096 static GUID* g_DirectSoundNotifyGUID = &_g_DirectSoundNotifyGUID;
3097 static GUID* g_KSDATAFORMAT_SUBTYPE_PCM_GUID = &_g_KSDATAFORMAT_SUBTYPE_PCM_GUID;
3098 static GUID* g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID = &_g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID;
3099 #endif
3100 
3101 
3102 typedef HRESULT (WINAPI * pDirectSoundCreate8Proc)(LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter);
3103 typedef HRESULT (WINAPI * pDirectSoundEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
3104 typedef HRESULT (WINAPI * pDirectSoundCaptureCreate8Proc)(LPCGUID pcGuidDevice, LPDIRECTSOUNDCAPTURE8 *ppDSC8, LPUNKNOWN pUnkOuter);
3105 typedef HRESULT (WINAPI * pDirectSoundCaptureEnumerateAProc)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
3106 
3107 typedef struct
3108 {
3110  GUID guid;
3111 
3113  char description[256];
3114 
3116  char moduleName[256];
3117 
3118 } draudio_device_info_dsound;
3119 
3120 typedef struct
3121 {
3123  draudio_context base;
3124 
3126  HMODULE hDSoundDLL;
3127 
3128  // DirectSound APIs.
3129  pDirectSoundCreate8Proc pDirectSoundCreate8;
3130  pDirectSoundEnumerateAProc pDirectSoundEnumerateA;
3131  pDirectSoundCaptureCreate8Proc pDirectSoundCaptureCreate8;
3132  pDirectSoundCaptureEnumerateAProc pDirectSoundCaptureEnumerateA;
3133 
3134 
3137  unsigned int outputDeviceCount;
3138 
3140  draudio_device_info_dsound outputDeviceInfo[DRAUDIO_MAX_DEVICE_COUNT];
3141 
3142 
3145  unsigned int inputDeviceCount;
3146 
3148  draudio_device_info_dsound inputDeviceInfo[DRAUDIO_MAX_DEVICE_COUNT];
3149 
3150 
3152  draudio_event_manager_dsound eventManager;
3153 
3154 
3156  draudio_message_queue_dsound messageQueue;
3157 
3158 } draudio_context_dsound;
3159 
3160 typedef struct
3161 {
3163  draudio_device base;
3164 
3166  LPDIRECTSOUND8 pDS;
3167 
3169  LPDIRECTSOUNDBUFFER pDSPrimaryBuffer;
3170 
3172  LPDIRECTSOUND3DLISTENER pDSListener;
3173 
3174 } draudio_device_dsound;
3175 
3176 typedef struct
3177 {
3179  draudio_buffer base;
3180 
3182  LPDIRECTSOUNDBUFFER8 pDSBuffer;
3183 
3185  LPDIRECTSOUND3DBUFFER pDSBuffer3D;
3186 
3188  LPDIRECTSOUNDNOTIFY pDSNotify;
3189 
3191  draudio_playback_state playbackState;
3192 
3193 
3195  unsigned int markerEventCount;
3196 
3198  draudio_event_dsound* pMarkerEvents[DRAUDIO_MAX_MARKER_COUNT];
3199 
3201  draudio_event_dsound* pStopEvent;
3202 
3204  draudio_event_dsound* pPauseEvent;
3205 
3207  draudio_event_dsound* pPlayEvent;
3208 
3209 
3211  unsigned int extraDataSize;
3212 
3214  unsigned char pExtraData[1];
3215 
3216 } draudio_buffer_dsound;
3217 
3218 
3219 void draudio_activate_buffer_events_dsound(draudio_buffer* pBuffer)
3220 {
3221  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3222  assert(pBufferDS != NULL);
3223 
3224  unsigned int dwPositionNotifies = 0;
3225  DSBPOSITIONNOTIFY n[DRAUDIO_MAX_MARKER_COUNT + 1]; // +1 because we use this array for the markers + stop event.
3226 
3227  // Stop
3228  if (pBufferDS->pStopEvent != NULL)
3229  {
3230  LPDSBPOSITIONNOTIFY pN = n + dwPositionNotifies;
3231  pN->dwOffset = DSBPN_OFFSETSTOP;
3232  pN->hEventNotify = pBufferDS->pStopEvent->hEvent;
3233 
3234  dwPositionNotifies += 1;
3235  }
3236 
3237  // Markers
3238  for (unsigned int iMarker = 0; iMarker < pBufferDS->markerEventCount; ++iMarker)
3239  {
3240  LPDSBPOSITIONNOTIFY pN = n + dwPositionNotifies;
3241  pN->dwOffset = pBufferDS->pMarkerEvents[iMarker]->markerOffset;
3242  pN->hEventNotify = pBufferDS->pMarkerEvents[iMarker]->hEvent;
3243 
3244  dwPositionNotifies += 1;
3245  }
3246 
3247 
3248  HRESULT hr = IDirectSoundNotify_SetNotificationPositions(pBufferDS->pDSNotify, dwPositionNotifies, n);
3249 #if 0
3250  if (FAILED(hr)) {
3251  printf("WARNING: FAILED TO CREATE DIRECTSOUND NOTIFIERS\n");
3252  }
3253 #else
3254  (void)hr;
3255 #endif
3256 }
3257 
3258 void draudio_deactivate_buffer_events_dsound(draudio_buffer* pBuffer)
3259 {
3260  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3261  assert(pBufferDS != NULL);
3262 
3263 
3264  HRESULT hr = IDirectSoundNotify_SetNotificationPositions(pBufferDS->pDSNotify, 0, NULL);
3265 #if 0
3266  if (FAILED(hr)) {
3267  printf("WARNING: FAILED TO CLEAR DIRECTSOUND NOTIFIERS\n");
3268  }
3269 #else
3270  (void)hr;
3271 #endif
3272 }
3273 
3274 
3275 void draudio_delete_context_dsound(draudio_context* pContext)
3276 {
3277  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pContext;
3278  assert(pContextDS != NULL);
3279 
3280  draudio_uninit_event_manager_dsound(&pContextDS->eventManager);
3281 
3282  // The message queue needs to uninitialized after the DirectSound marker notification thread.
3283  draudio_uninit_message_queue_dsound(&pContextDS->messageQueue);
3284 
3285  FreeLibrary(pContextDS->hDSoundDLL);
3286  free(pContextDS);
3287 }
3288 
3289 
3290 unsigned int draudio_get_output_device_count_dsound(draudio_context* pContext)
3291 {
3292  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pContext;
3293  assert(pContextDS != NULL);
3294 
3295  return pContextDS->outputDeviceCount;
3296 }
3297 
3298 bool draudio_get_output_device_info_dsound(draudio_context* pContext, unsigned int deviceIndex, draudio_device_info* pInfoOut)
3299 {
3300  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pContext;
3301  assert(pContextDS != NULL);
3302  assert(pInfoOut != NULL);
3303 
3304  if (deviceIndex >= pContextDS->outputDeviceCount) {
3305  return false;
3306  }
3307 
3308 
3309  draudio_strcpy(pInfoOut->description, sizeof(pInfoOut->description), pContextDS->outputDeviceInfo[deviceIndex].description);
3310 
3311  return true;
3312 }
3313 
3314 
3315 draudio_device* draudio_create_output_device_dsound(draudio_context* pContext, unsigned int deviceIndex)
3316 {
3317  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pContext;
3318  assert(pContextDS != NULL);
3319 
3320  if (deviceIndex >= pContextDS->outputDeviceCount) {
3321  return NULL;
3322  }
3323 
3324 
3325  LPDIRECTSOUND8 pDS;
3326 
3327  // Create the device.
3328  HRESULT hr;
3329  if (deviceIndex == 0) {
3330  hr = pContextDS->pDirectSoundCreate8(NULL, &pDS, NULL);
3331  } else {
3332  hr = pContextDS->pDirectSoundCreate8(&pContextDS->outputDeviceInfo[deviceIndex].guid, &pDS, NULL);
3333  }
3334 
3335  if (FAILED(hr)) {
3336  return NULL;
3337  }
3338 
3339 
3340  // Set the cooperative level. Must be done before anything else.
3341  hr = IDirectSound_SetCooperativeLevel(pDS, GetForegroundWindow(), DSSCL_EXCLUSIVE);
3342  if (FAILED(hr)) {
3343  IDirectSound_Release(pDS);
3344  return NULL;
3345  }
3346 
3347 
3348  // Primary buffer.
3349  DSBUFFERDESC descDSPrimary;
3350  memset(&descDSPrimary, 0, sizeof(DSBUFFERDESC));
3351  descDSPrimary.dwSize = sizeof(DSBUFFERDESC);
3352  descDSPrimary.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRL3D;
3353  descDSPrimary.guid3DAlgorithm = DRAUDIO_GUID_NULL;
3354 
3355  LPDIRECTSOUNDBUFFER pDSPrimaryBuffer;
3356  hr = IDirectSound_CreateSoundBuffer(pDS, &descDSPrimary, &pDSPrimaryBuffer, NULL);
3357  if (FAILED(hr)) {
3358  IDirectSound_Release(pDS);
3359  return NULL;
3360  }
3361 
3362 
3363  WAVEFORMATIEEEFLOATEX wf = {0};
3364  wf.Format.cbSize = sizeof(wf);
3365  wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
3366  wf.Format.nChannels = 2;
3367  wf.Format.nSamplesPerSec = 48000;
3368  wf.Format.wBitsPerSample = 32;
3369  wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8;
3370  wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
3371  wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
3372  wf.dwChannelMask = 0;
3373  wf.SubFormat = _g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID;
3374  hr = IDirectSoundBuffer_SetFormat(pDSPrimaryBuffer, (WAVEFORMATEX*)&wf);
3375  if (FAILED(hr)) {
3376  IDirectSoundBuffer_Release(pDSPrimaryBuffer);
3377  IDirectSound_Release(pDS);
3378  return NULL;
3379  }
3380 
3381 
3382  // Listener.
3383  LPDIRECTSOUND3DLISTENER pDSListener = NULL;
3384  hr = IDirectSound3DListener_QueryInterface(pDSPrimaryBuffer, g_DSListenerGUID, (LPVOID*)&pDSListener);
3385  if (FAILED(hr)) {
3386  IDirectSoundBuffer_Release(pDSPrimaryBuffer);
3387  IDirectSound_Release(pDS);
3388  return NULL;
3389  }
3390 
3391 
3392  draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)malloc(sizeof(draudio_device_dsound));
3393  if (pDeviceDS != NULL)
3394  {
3395  pDeviceDS->base.pContext = pContext;
3396  pDeviceDS->pDS = pDS;
3397  pDeviceDS->pDSPrimaryBuffer = pDSPrimaryBuffer;
3398  pDeviceDS->pDSListener = pDSListener;
3399 
3400  return (draudio_device*)pDeviceDS;
3401  }
3402  else
3403  {
3404  IDirectSound3DListener_Release(pDSListener);
3405  IDirectSoundBuffer_Release(pDeviceDS->pDSPrimaryBuffer);
3406  IDirectSound_Release(pDS);
3407  return NULL;
3408  }
3409 }
3410 
3411 void draudio_delete_output_device_dsound(draudio_device* pDevice)
3412 {
3413  draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice;
3414  assert(pDeviceDS != NULL);
3415 
3416  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pDevice->pContext;
3417  assert(pContextDS != NULL);
3418 
3419  // The device id not deleted straight away. Instead we post a message to the message for delayed processing. The reason for this is that buffer
3420  // deletion is also delayed which means we want to ensure any delayed processing of buffers is handled before deleting the device.
3421  draudio_message_dsound msg;
3422  msg.id = DRAUDIO_MESSAGE_ID_DELETE_DEVICE;
3423  msg.pBuffer = NULL;
3424  msg.data.delete_device.pDSListener = pDeviceDS->pDSListener;
3425  msg.data.delete_device.pDSPrimaryBuffer = pDeviceDS->pDSPrimaryBuffer;
3426  msg.data.delete_device.pDS = pDeviceDS->pDS;
3427  msg.data.delete_device.pDevice = pDevice;
3428  draudio_post_message_dsound(&pContextDS->messageQueue, msg);
3429 
3430 #if 0
3431  IDirectSound3DListener_Release(pDeviceDS->pDSListener);
3432  IDirectSoundBuffer_Release(pDeviceDS->pDSPrimaryBuffer);
3433  IDirectSound_Release(pDeviceDS->pDS);
3434  free(pDeviceDS);
3435 #endif
3436 }
3437 
3438 
3439 draudio_buffer* draudio_create_buffer_dsound(draudio_device* pDevice, draudio_buffer_desc* pBufferDesc, size_t extraDataSize)
3440 {
3441  draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice;
3442  assert(pDeviceDS != NULL);
3443  assert(pBufferDesc != NULL);
3444 
3445  // 3D is only valid for mono sounds.
3446  if (pBufferDesc->channels > 1 && (pBufferDesc->flags & DRAUDIO_ENABLE_3D) != 0) {
3447  return NULL;
3448  }
3449 
3450  WAVEFORMATIEEEFLOATEX wf = {0};
3451  wf.Format.cbSize = sizeof(wf);
3452  wf.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
3453  wf.Format.nChannels = (WORD)pBufferDesc->channels;
3454  wf.Format.nSamplesPerSec = pBufferDesc->sampleRate;
3455  wf.Format.wBitsPerSample = (WORD)pBufferDesc->bitsPerSample;
3456  wf.Format.nBlockAlign = (wf.Format.nChannels * wf.Format.wBitsPerSample) / 8;
3457  wf.Format.nAvgBytesPerSec = wf.Format.nBlockAlign * wf.Format.nSamplesPerSec;
3458  wf.Samples.wValidBitsPerSample = wf.Format.wBitsPerSample;
3459  wf.dwChannelMask = 0;
3460 
3461  if (pBufferDesc->format == draudio_format_pcm) {
3462  wf.SubFormat = _g_KSDATAFORMAT_SUBTYPE_PCM_GUID;
3463  } else if (pBufferDesc->format == draudio_format_float) {
3464  wf.SubFormat = _g_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_GUID;
3465  } else {
3466  return NULL;
3467  }
3468 
3469 
3470 
3471  // We want to try and create a 3D enabled buffer, however this will fail whenever the number of channels is > 1. In this case
3472  // we do not want to attempt to create a 3D enabled buffer because it will just fail anyway. Instead we'll just create a normal
3473  // buffer with panning enabled.
3474  DSBUFFERDESC descDS;
3475  memset(&descDS, 0, sizeof(DSBUFFERDESC));
3476  descDS.dwSize = sizeof(DSBUFFERDESC);
3477  descDS.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
3478  descDS.dwBufferBytes = (DWORD)pBufferDesc->sizeInBytes;
3479  descDS.lpwfxFormat = (WAVEFORMATEX*)&wf;
3480 
3481  LPDIRECTSOUNDBUFFER8 pDSBuffer = NULL;
3482  LPDIRECTSOUND3DBUFFER pDSBuffer3D = NULL;
3483  if ((pBufferDesc->flags & DRAUDIO_ENABLE_3D) == 0)
3484  {
3485  // 3D Disabled.
3486  descDS.dwFlags |= DSBCAPS_CTRLPAN;
3487 
3488  LPDIRECTSOUNDBUFFER pDSBufferTemp;
3489  HRESULT hr = IDirectSound_CreateSoundBuffer(pDeviceDS->pDS, &descDS, &pDSBufferTemp, NULL);
3490  if (FAILED(hr)) {
3491  return NULL;
3492  }
3493 
3494  hr = IDirectSoundBuffer_QueryInterface(pDSBufferTemp, g_DirectSoundBuffer8GUID, (void**)&pDSBuffer);
3495  if (FAILED(hr)) {
3496  IDirectSoundBuffer_Release(pDSBufferTemp);
3497  return NULL;
3498  }
3499  IDirectSoundBuffer_Release(pDSBufferTemp);
3500  }
3501  else
3502  {
3503  // 3D Enabled.
3504  descDS.dwFlags |= DSBCAPS_CTRL3D;
3505  descDS.guid3DAlgorithm = DS3DALG_DEFAULT;
3506 
3507  LPDIRECTSOUNDBUFFER pDSBufferTemp;
3508  HRESULT hr = IDirectSound_CreateSoundBuffer(pDeviceDS->pDS, &descDS, &pDSBufferTemp, NULL);
3509  if (FAILED(hr)) {
3510  return NULL;
3511  }
3512 
3513  hr = IDirectSoundBuffer_QueryInterface(pDSBufferTemp, g_DirectSoundBuffer8GUID, (void**)&pDSBuffer);
3514  if (FAILED(hr)) {
3515  IDirectSoundBuffer_Release(pDSBufferTemp);
3516  return NULL;
3517  }
3518  IDirectSoundBuffer_Release(pDSBufferTemp);
3519 
3520 
3521  hr = IDirectSoundBuffer_QueryInterface(pDSBuffer, g_DirectSound3DBuffer8GUID, (void**)&pDSBuffer3D);
3522  if (FAILED(hr)) {
3523  return NULL;
3524  }
3525 
3526  IDirectSound3DBuffer_SetPosition(pDSBuffer3D, 0, 0, 0, DS3D_IMMEDIATE);
3527 
3528  if ((pBufferDesc->flags & DRAUDIO_RELATIVE_3D) != 0) {
3529  IDirectSound3DBuffer_SetMode(pDSBuffer3D, DS3DMODE_HEADRELATIVE, DS3D_IMMEDIATE);
3530  }
3531  }
3532 
3533 
3534 
3535  // We need to create a notification object so we can notify the host application when the playback buffer hits a certain point.
3536  LPDIRECTSOUNDNOTIFY pDSNotify;
3537  HRESULT hr = IDirectSoundBuffer8_QueryInterface(pDSBuffer, g_DirectSoundNotifyGUID, (void**)&pDSNotify);
3538  if (FAILED(hr)) {
3539  IDirectSound3DBuffer_Release(pDSBuffer3D);
3540  IDirectSoundBuffer8_Release(pDSBuffer);
3541  return NULL;
3542  }
3543 
3544 
3545  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)malloc(sizeof(draudio_buffer_dsound) - sizeof(pBufferDS->pExtraData) + extraDataSize);
3546  if (pBufferDS == NULL) {
3547  IDirectSound3DBuffer_Release(pDSBuffer3D);
3548  IDirectSoundBuffer8_Release(pDSBuffer);
3549  return NULL;
3550  }
3551 
3552  pBufferDS->base.pDevice = pDevice;
3553  pBufferDS->pDSBuffer = pDSBuffer;
3554  pBufferDS->pDSBuffer3D = pDSBuffer3D;
3555  pBufferDS->pDSNotify = pDSNotify;
3556  pBufferDS->playbackState = draudio_stopped;
3557 
3558  pBufferDS->markerEventCount = 0;
3559  memset(pBufferDS->pMarkerEvents, 0, sizeof(pBufferDS->pMarkerEvents));
3560  pBufferDS->pStopEvent = NULL;
3561  pBufferDS->pPauseEvent = NULL;
3562  pBufferDS->pPlayEvent = NULL;
3563 
3564 
3565 
3566  // Fill with initial data, if applicable.
3567  if (pBufferDesc->pData != NULL) {
3568  draudio_set_buffer_data((draudio_buffer*)pBufferDS, 0, pBufferDesc->pData, pBufferDesc->sizeInBytes);
3569  }
3570 
3571  return (draudio_buffer*)pBufferDS;
3572 }
3573 
3574 void draudio_delete_buffer_dsound(draudio_buffer* pBuffer)
3575 {
3576  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3577  assert(pBufferDS != NULL);
3578  assert(pBuffer->pDevice != NULL);
3579 
3580  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext;
3581  assert(pContextDS != NULL);
3582 
3583 
3584  // Deactivate the DirectSound notify events for sanity.
3585  draudio_deactivate_buffer_events_dsound(pBuffer);
3586 
3587 
3588  draudio_message_dsound msg;
3589  msg.id = DRAUDIO_MESSAGE_ID_DELETE_BUFFER;
3590  msg.pBuffer = pBuffer;
3591  msg.data.delete_buffer.pDSNotify = pBufferDS->pDSNotify;
3592  msg.data.delete_buffer.pDSBuffer3D = pBufferDS->pDSBuffer3D;
3593  msg.data.delete_buffer.pDSBuffer = pBufferDS->pDSBuffer;
3594  draudio_post_message_dsound(&pContextDS->messageQueue, msg);
3595 
3596 #if 0
3597  if (pBufferDS->pDSNotify != NULL) {
3598  IDirectSoundNotify_Release(pBufferDS->pDSNotify);
3599  }
3600 
3601  if (pBufferDS->pDSBuffer3D != NULL) {
3602  IDirectSound3DBuffer_Release(pBufferDS->pDSBuffer3D);
3603  }
3604 
3605  if (pBufferDS->pDSBuffer != NULL) {
3606  IDirectSoundBuffer8_Release(pBufferDS->pDSBuffer);
3607  }
3608 
3609  free(pBufferDS);
3610 #endif
3611 }
3612 
3613 
3614 unsigned int draudio_get_buffer_extra_data_size_dsound(draudio_buffer* pBuffer)
3615 {
3616  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3617  assert(pBufferDS != NULL);
3618 
3619  return pBufferDS->extraDataSize;
3620 }
3621 
3622 void* draudio_get_buffer_extra_data_dsound(draudio_buffer* pBuffer)
3623 {
3624  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3625  assert(pBufferDS != NULL);
3626 
3627  return pBufferDS->pExtraData;
3628 }
3629 
3630 
3631 void draudio_set_buffer_data_dsound(draudio_buffer* pBuffer, size_t offset, const void* pData, size_t dataSizeInBytes)
3632 {
3633  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3634  assert(pBufferDS != NULL);
3635  assert(pData != NULL);
3636 
3637  LPVOID lpvWrite;
3638  DWORD dwLength;
3639  HRESULT hr = IDirectSoundBuffer8_Lock(pBufferDS->pDSBuffer, (DWORD)offset, (DWORD)dataSizeInBytes, &lpvWrite, &dwLength, NULL, NULL, 0);
3640  if (FAILED(hr)) {
3641  return;
3642  }
3643 
3644  assert(dataSizeInBytes <= dwLength);
3645  memcpy(lpvWrite, pData, dataSizeInBytes);
3646 
3647  hr = IDirectSoundBuffer8_Unlock(pBufferDS->pDSBuffer, lpvWrite, dwLength, NULL, 0);
3648  if (FAILED(hr)) {
3649  return;
3650  }
3651 }
3652 
3653 
3654 void draudio_play_dsound(draudio_buffer* pBuffer, bool loop)
3655 {
3656  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3657  assert(pBufferDS != NULL);
3658 
3659  bool postEvent = true;
3660  if (pBufferDS->playbackState == draudio_playing) {
3661  postEvent = false;
3662  }
3663 
3664 
3665  // Events need to be activated.
3666  if (pBufferDS->playbackState == draudio_stopped) {
3667  draudio_activate_buffer_events_dsound(pBuffer);
3668  }
3669 
3670 
3671  DWORD dwFlags = 0;
3672  if (loop) {
3673  dwFlags |= DSBPLAY_LOOPING;
3674  }
3675 
3676  pBufferDS->playbackState = draudio_playing;
3677  IDirectSoundBuffer8_Play(pBufferDS->pDSBuffer, 0, 0, dwFlags);
3678 
3679  // If we have a play event we need to signal the event which will cause the worker thread to call the callback function.
3680  if (pBufferDS->pPlayEvent != NULL && postEvent) {
3681  SetEvent(pBufferDS->pPlayEvent->hEvent);
3682  }
3683 }
3684 
3685 void draudio_pause_dsound(draudio_buffer* pBuffer)
3686 {
3687  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3688  assert(pBufferDS != NULL);
3689 
3690  if (pBufferDS->playbackState == draudio_playing)
3691  {
3692  pBufferDS->playbackState = draudio_paused;
3693  IDirectSoundBuffer8_Stop(pBufferDS->pDSBuffer);
3694 
3695  // If we have a pause event we need to signal the event which will cause the worker thread to call the callback function.
3696  if (pBufferDS->pPlayEvent != NULL) {
3697  SetEvent(pBufferDS->pPauseEvent->hEvent);
3698  }
3699  }
3700 }
3701 
3702 void draudio_stop_dsound(draudio_buffer* pBuffer)
3703 {
3704  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3705  assert(pBufferDS != NULL);
3706 
3707  if (pBufferDS->playbackState == draudio_playing)
3708  {
3709  pBufferDS->playbackState = draudio_stopped;
3710  IDirectSoundBuffer8_Stop(pBufferDS->pDSBuffer);
3711  IDirectSoundBuffer8_SetCurrentPosition(pBufferDS->pDSBuffer, 0);
3712  }
3713  else if (pBufferDS->playbackState == draudio_paused)
3714  {
3715  pBufferDS->playbackState = draudio_stopped;
3716  IDirectSoundBuffer8_SetCurrentPosition(pBufferDS->pDSBuffer, 0);
3717 
3718  if (pBufferDS->pStopEvent != NULL) {
3719  SetEvent(pBufferDS->pStopEvent->hEvent);
3720  }
3721  }
3722 }
3723 
3724 draudio_playback_state draudio_get_playback_state_dsound(draudio_buffer* pBuffer)
3725 {
3726  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3727  assert(pBufferDS != NULL);
3728 
3729  return pBufferDS->playbackState;
3730 }
3731 
3732 
3733 void draudio_set_playback_position_dsound(draudio_buffer* pBuffer, unsigned int position)
3734 {
3735  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3736  assert(pBufferDS != NULL);
3737 
3738  IDirectSoundBuffer8_SetCurrentPosition(pBufferDS->pDSBuffer, position);
3739 }
3740 
3741 unsigned int draudio_get_playback_position_dsound(draudio_buffer* pBuffer)
3742 {
3743  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3744  assert(pBufferDS != NULL);
3745 
3746  DWORD position;
3747  HRESULT hr = IDirectSoundBuffer8_GetCurrentPosition(pBufferDS->pDSBuffer, &position, NULL);
3748  if (FAILED(hr)) {
3749  return 0;
3750  }
3751 
3752  return position;
3753 }
3754 
3755 
3756 void draudio_set_pan_dsound(draudio_buffer* pBuffer, float pan)
3757 {
3758  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3759  assert(pBufferDS != NULL);
3760 
3761  LONG panDB;
3762  if (pan == 0) {
3763  panDB = DSBPAN_CENTER;
3764  } else {
3765  if (pan > 1) {
3766  panDB = DSBPAN_RIGHT;
3767  } else if (pan < -1) {
3768  panDB = DSBPAN_LEFT;
3769  } else {
3770  if (pan < 0) {
3771  panDB = (LONG)((20*log10f(1 + pan)) * 100);
3772  } else {
3773  panDB = -(LONG)((20*log10f(1 - pan)) * 100);
3774  }
3775  }
3776  }
3777 
3778  IDirectSoundBuffer_SetPan(pBufferDS->pDSBuffer, panDB);
3779 }
3780 
3781 float draudio_get_pan_dsound(draudio_buffer* pBuffer)
3782 {
3783  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3784  assert(pBufferDS != NULL);
3785 
3786  LONG panDB;
3787  HRESULT hr = IDirectSoundBuffer_GetPan(pBufferDS->pDSBuffer, &panDB);
3788  if (FAILED(hr)) {
3789  return 0;
3790  }
3791 
3792 
3793  if (panDB < 0) {
3794  return -(1 - (float)(1.0f / powf(10.0f, -panDB / (20.0f*100.0f))));
3795  }
3796 
3797  if (panDB > 0) {
3798  return (1 - (float)(1.0f / powf(10.0f, panDB / (20.0f*100.0f))));
3799  }
3800 
3801  return 0;
3802 }
3803 
3804 
3805 void draudio_set_volume_dsound(draudio_buffer* pBuffer, float volume)
3806 {
3807  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3808  assert(pBufferDS != NULL);
3809 
3810  LONG volumeDB;
3811  if (volume > 0) {
3812  if (volume < 1) {
3813  volumeDB = (LONG)((20*log10f(volume)) * 100);
3814  } else {
3815  volumeDB = DSBVOLUME_MAX;
3816  }
3817  } else {
3818  volumeDB = DSBVOLUME_MIN;
3819  }
3820 
3821  IDirectSoundBuffer_SetVolume(pBufferDS->pDSBuffer, volumeDB);
3822 }
3823 
3824 float draudio_get_volume_dsound(draudio_buffer* pBuffer)
3825 {
3826  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3827  assert(pBufferDS != NULL);
3828 
3829  LONG volumeDB;
3830  HRESULT hr = IDirectSoundBuffer_GetVolume(pBufferDS->pDSBuffer, &volumeDB);
3831  if (FAILED(hr)) {
3832  return 1;
3833  }
3834 
3835  return (float)(1.0f / powf(10.0f, -volumeDB / (20.0f*100.0f)));
3836 }
3837 
3838 
3839 void draudio_remove_markers_dsound(draudio_buffer* pBuffer)
3840 {
3841  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3842  assert(pBufferDS != NULL);
3843 
3844  for (unsigned int iMarker = 0; iMarker < pBufferDS->markerEventCount; ++iMarker)
3845  {
3846  if (pBufferDS->pMarkerEvents[iMarker] != NULL) {
3847  draudio_delete_event_dsound(pBufferDS->pMarkerEvents[iMarker]);
3848  pBufferDS->pMarkerEvents[iMarker] = NULL;
3849  }
3850  }
3851 
3852  pBufferDS->markerEventCount = 0;
3853 }
3854 
3855 bool draudio_register_marker_callback_dsound(draudio_buffer* pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void* pUserData)
3856 {
3857  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3858  assert(pBufferDS != NULL);
3859  assert(pBufferDS->markerEventCount <= DRAUDIO_MAX_MARKER_COUNT);
3860 
3861  if (pBufferDS->markerEventCount == DRAUDIO_MAX_MARKER_COUNT) {
3862  // Too many markers.
3863  return false;
3864  }
3865 
3866  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext;
3867  assert(pContextDS != NULL);
3868 
3869  draudio_event_dsound* pEvent = draudio_create_event_dsound(&pContextDS->eventManager, callback, pBuffer, eventID, pUserData);
3870  if (pEvent == NULL) {
3871  return false;
3872  }
3873 
3874  // draudio_create_event_dsound() will initialize the marker offset to 0, so we'll need to set it manually here.
3875  pEvent->markerOffset = (DWORD)offsetInBytes;
3876 
3877  pBufferDS->pMarkerEvents[pBufferDS->markerEventCount] = pEvent;
3878  pBufferDS->markerEventCount += 1;
3879 
3880  return true;
3881 }
3882 
3883 bool draudio_register_stop_callback_dsound(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData)
3884 {
3885  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3886  assert(pBufferDS != NULL);
3887 
3888  if (callback == NULL)
3889  {
3890  if (pBufferDS->pStopEvent != NULL) {
3891  draudio_delete_event_dsound(pBufferDS->pStopEvent);
3892  pBufferDS->pStopEvent = NULL;
3893  }
3894 
3895  return true;
3896  }
3897  else
3898  {
3899  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext;
3900 
3901  // If we already have a stop event, just replace the existing one.
3902  if (pBufferDS->pStopEvent != NULL) {
3903  draudio_update_event_dsound(pBufferDS->pStopEvent, callback, pUserData);
3904  } else {
3905  pBufferDS->pStopEvent = draudio_create_event_dsound(&pContextDS->eventManager, callback, pBuffer, DRAUDIO_EVENT_ID_STOP, pUserData);
3906  }
3907 
3908  return pBufferDS->pStopEvent != NULL;
3909  }
3910 }
3911 
3912 bool draudio_register_pause_callback_dsound(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData)
3913 {
3914  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3915  assert(pBufferDS != NULL);
3916 
3917  if (callback == NULL)
3918  {
3919  if (pBufferDS->pPauseEvent != NULL) {
3920  draudio_delete_event_dsound(pBufferDS->pPauseEvent);
3921  pBufferDS->pPauseEvent = NULL;
3922  }
3923 
3924  return true;
3925  }
3926  else
3927  {
3928  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext;
3929 
3930  // If we already have a stop event, just replace the existing one.
3931  if (pBufferDS->pPauseEvent != NULL) {
3932  draudio_update_event_dsound(pBufferDS->pPauseEvent, callback, pUserData);
3933  } else {
3934  pBufferDS->pPauseEvent = draudio_create_event_dsound(&pContextDS->eventManager, callback, pBuffer, DRAUDIO_EVENT_ID_PAUSE, pUserData);
3935  }
3936 
3937  return pBufferDS->pPauseEvent != NULL;
3938  }
3939 }
3940 
3941 bool draudio_register_play_callback_dsound(draudio_buffer* pBuffer, draudio_event_callback_proc callback, void* pUserData)
3942 {
3943  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3944  assert(pBufferDS != NULL);
3945 
3946  if (callback == NULL)
3947  {
3948  if (pBufferDS->pPlayEvent != NULL) {
3949  draudio_delete_event_dsound(pBufferDS->pPlayEvent);
3950  pBufferDS->pPlayEvent = NULL;
3951  }
3952 
3953  return true;
3954  }
3955  else
3956  {
3957  draudio_context_dsound* pContextDS = (draudio_context_dsound*)pBuffer->pDevice->pContext;
3958 
3959  // If we already have a stop event, just replace the existing one.
3960  if (pBufferDS->pPlayEvent != NULL) {
3961  draudio_update_event_dsound(pBufferDS->pPlayEvent, callback, pUserData);
3962  } else {
3963  pBufferDS->pPlayEvent = draudio_create_event_dsound(&pContextDS->eventManager, callback, pBuffer, DRAUDIO_EVENT_ID_PLAY, pUserData);
3964  }
3965 
3966  return pBufferDS->pPlayEvent != NULL;
3967  }
3968 }
3969 
3970 
3971 
3972 void draudio_set_position_dsound(draudio_buffer* pBuffer, float x, float y, float z)
3973 {
3974  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3975  assert(pBufferDS != NULL);
3976 
3977  if (pBufferDS->pDSBuffer3D != NULL) {
3978  IDirectSound3DBuffer_SetPosition(pBufferDS->pDSBuffer3D, x, y, z, DS3D_IMMEDIATE);
3979  }
3980 }
3981 
3982 void draudio_get_position_dsound(draudio_buffer* pBuffer, float* pPosOut)
3983 {
3984  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
3985  assert(pBufferDS != NULL);
3986  assert(pPosOut != NULL);
3987 
3988  if (pBufferDS->pDSBuffer3D != NULL)
3989  {
3990  D3DVECTOR pos;
3991  IDirectSound3DBuffer_GetPosition(pBufferDS->pDSBuffer3D, &pos);
3992 
3993  pPosOut[0] = pos.x;
3994  pPosOut[1] = pos.y;
3995  pPosOut[2] = pos.z;
3996  }
3997  else
3998  {
3999  pPosOut[0] = 0;
4000  pPosOut[1] = 1;
4001  pPosOut[2] = 2;
4002  }
4003 }
4004 
4005 
4006 void draudio_set_listener_position_dsound(draudio_device* pDevice, float x, float y, float z)
4007 {
4008  draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice;
4009  assert(pDeviceDS != NULL);
4010 
4011  IDirectSound3DListener_SetPosition(pDeviceDS->pDSListener, x, y, z, DS3D_IMMEDIATE);
4012 }
4013 
4014 void draudio_get_listener_position_dsound(draudio_device* pDevice, float* pPosOut)
4015 {
4016  draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice;
4017  assert(pDeviceDS != NULL);
4018  assert(pPosOut != NULL);
4019 
4020  D3DVECTOR pos;
4021  IDirectSound3DListener_GetPosition(pDeviceDS->pDSListener, &pos);
4022 
4023  pPosOut[0] = pos.x;
4024  pPosOut[1] = pos.y;
4025  pPosOut[2] = pos.z;
4026 }
4027 
4028 
4029 void draudio_set_listener_orientation_dsound(draudio_device* pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ)
4030 {
4031  draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice;
4032  assert(pDeviceDS != NULL);
4033 
4034  IDirectSound3DListener_SetOrientation(pDeviceDS->pDSListener, forwardX, forwardY, forwardZ, upX, upY, upZ, DS3D_IMMEDIATE);
4035 }
4036 
4037 void draudio_get_listener_orientation_dsound(draudio_device* pDevice, float* pForwardOut, float* pUpOut)
4038 {
4039  draudio_device_dsound* pDeviceDS = (draudio_device_dsound*)pDevice;
4040  assert(pDeviceDS != NULL);
4041  assert(pForwardOut != NULL);
4042  assert(pUpOut != NULL);
4043 
4044  D3DVECTOR forward;
4045  D3DVECTOR up;
4046  IDirectSound3DListener_GetOrientation(pDeviceDS->pDSListener, &forward, &up);
4047 
4048  pForwardOut[0] = forward.x;
4049  pForwardOut[1] = forward.y;
4050  pForwardOut[2] = forward.z;
4051 
4052  pUpOut[0] = up.x;
4053  pUpOut[1] = up.y;
4054  pUpOut[2] = up.z;
4055 }
4056 
4057 void draudio_set_3d_mode_dsound(draudio_buffer* pBuffer, draudio_3d_mode mode)
4058 {
4059  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
4060  assert(pBufferDS != NULL);
4061 
4062  if (pBufferDS->pDSBuffer3D == NULL) {
4063  return;
4064  }
4065 
4066 
4067  DWORD dwMode = DS3DMODE_NORMAL;
4068  if (mode == draudio_3d_mode_relative) {
4069  dwMode = DS3DMODE_HEADRELATIVE;
4070  } else if (mode == draudio_3d_mode_disabled) {
4071  dwMode = DS3DMODE_DISABLE;
4072  }
4073 
4074  IDirectSound3DBuffer_SetMode(pBufferDS->pDSBuffer3D, dwMode, DS3D_IMMEDIATE);
4075 }
4076 
4077 draudio_3d_mode draudio_get_3d_mode_dsound(draudio_buffer* pBuffer)
4078 {
4079  draudio_buffer_dsound* pBufferDS = (draudio_buffer_dsound*)pBuffer;
4080  assert(pBufferDS != NULL);
4081 
4082  if (pBufferDS->pDSBuffer3D == NULL) {
4083  return draudio_3d_mode_disabled;
4084  }
4085 
4086 
4087  DWORD dwMode;
4088  if (FAILED(IDirectSound3DBuffer_GetMode(pBufferDS->pDSBuffer3D, &dwMode))) {
4089  return draudio_3d_mode_disabled;
4090  }
4091 
4092 
4093  if (dwMode == DS3DMODE_NORMAL) {
4094  return draudio_3d_mode_absolute;
4095  }
4096 
4097  if (dwMode == DS3DMODE_HEADRELATIVE) {
4098  return draudio_3d_mode_relative;
4099  }
4100 
4101  return draudio_3d_mode_disabled;
4102 }
4103 
4104 
4105 static BOOL CALLBACK DSEnumCallback_OutputDevices(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
4106 {
4107  // From MSDN:
4108  //
4109  // The first device enumerated is always called the Primary Sound Driver, and the lpGUID parameter of the callback is
4110  // NULL. This device represents the preferred output device set by the user in Control Panel.
4111 
4112  draudio_context_dsound* pContextDS = (draudio_context_dsound*)lpContext;
4113  assert(pContextDS != NULL);
4114 
4115  if (pContextDS->outputDeviceCount < DRAUDIO_MAX_DEVICE_COUNT)
4116  {
4117  if (lpGuid != NULL) {
4118  memcpy(&pContextDS->outputDeviceInfo[pContextDS->outputDeviceCount].guid, lpGuid, sizeof(GUID));
4119  } else {
4120  memset(&pContextDS->outputDeviceInfo[pContextDS->outputDeviceCount].guid, 0, sizeof(GUID));
4121  }
4122 
4123  draudio_strcpy(pContextDS->outputDeviceInfo[pContextDS->outputDeviceCount].description, 256, lpcstrDescription);
4124  draudio_strcpy(pContextDS->outputDeviceInfo[pContextDS->outputDeviceCount].moduleName, 256, lpcstrModule);
4125 
4126  pContextDS->outputDeviceCount += 1;
4127  return TRUE;
4128  }
4129  else
4130  {
4131  // Ran out of device slots.
4132  return FALSE;
4133  }
4134 }
4135 
4136 static BOOL CALLBACK DSEnumCallback_InputDevices(LPGUID lpGuid, LPCSTR lpcstrDescription, LPCSTR lpcstrModule, LPVOID lpContext)
4137 {
4138  // From MSDN:
4139  //
4140  // The first device enumerated is always called the Primary Sound Driver, and the lpGUID parameter of the callback is
4141  // NULL. This device represents the preferred output device set by the user in Control Panel.
4142 
4143  draudio_context_dsound* pContextDS = (draudio_context_dsound*)lpContext;
4144  assert(pContextDS != NULL);
4145 
4146  if (pContextDS->inputDeviceCount < DRAUDIO_MAX_DEVICE_COUNT)
4147  {
4148  if (lpGuid != NULL) {
4149  memcpy(&pContextDS->inputDeviceInfo[pContextDS->inputDeviceCount].guid, lpGuid, sizeof(GUID));
4150  } else {
4151  memset(&pContextDS->inputDeviceInfo[pContextDS->inputDeviceCount].guid, 0, sizeof(GUID));
4152  }
4153 
4154  draudio_strcpy(pContextDS->inputDeviceInfo[pContextDS->inputDeviceCount].description, 256, lpcstrDescription);
4155  draudio_strcpy(pContextDS->inputDeviceInfo[pContextDS->inputDeviceCount].moduleName, 256, lpcstrModule);
4156 
4157  pContextDS->inputDeviceCount += 1;
4158  return TRUE;
4159  }
4160  else
4161  {
4162  // Ran out of device slots.
4163  return FALSE;
4164  }
4165 }
4166 
4167 draudio_context* draudio_create_context_dsound()
4168 {
4169  // Load the DLL.
4170  HMODULE hDSoundDLL = LoadLibraryW(L"dsound.dll");
4171  if (hDSoundDLL == NULL) {
4172  return NULL;
4173  }
4174 
4175 
4176  // Retrieve the APIs.
4177  pDirectSoundCreate8Proc pDirectSoundCreate8 = (pDirectSoundCreate8Proc)GetProcAddress(hDSoundDLL, "DirectSoundCreate8");
4178  if (pDirectSoundCreate8 == NULL){
4179  FreeLibrary(hDSoundDLL);
4180  return NULL;
4181  }
4182 
4183  pDirectSoundEnumerateAProc pDirectSoundEnumerateA = (pDirectSoundEnumerateAProc)GetProcAddress(hDSoundDLL, "DirectSoundEnumerateA");
4184  if (pDirectSoundEnumerateA == NULL){
4185  FreeLibrary(hDSoundDLL);
4186  return NULL;
4187  }
4188 
4189  pDirectSoundCaptureCreate8Proc pDirectSoundCaptureCreate8 = (pDirectSoundCaptureCreate8Proc)GetProcAddress(hDSoundDLL, "DirectSoundCaptureCreate8");
4190  if (pDirectSoundCaptureCreate8 == NULL) {
4191  FreeLibrary(hDSoundDLL);
4192  return NULL;
4193  }
4194 
4195  pDirectSoundCaptureEnumerateAProc pDirectSoundCaptureEnumerateA = (pDirectSoundCaptureEnumerateAProc)GetProcAddress(hDSoundDLL, "DirectSoundCaptureEnumerateA");
4196  if (pDirectSoundCaptureEnumerateA == NULL ){
4197  FreeLibrary(hDSoundDLL);
4198  return NULL;
4199  }
4200 
4201 
4202 
4203  // At this point we can almost certainly assume DirectSound is usable so we'll now go ahead and create the context.
4204  draudio_context_dsound* pContext = (draudio_context_dsound*)malloc(sizeof(draudio_context_dsound));
4205  if (pContext != NULL)
4206  {
4207  pContext->base.delete_context = draudio_delete_context_dsound;
4208  pContext->base.create_output_device = draudio_create_output_device_dsound;
4209  pContext->base.delete_output_device = draudio_delete_output_device_dsound;
4210  pContext->base.get_output_device_count = draudio_get_output_device_count_dsound;
4211  pContext->base.get_output_device_info = draudio_get_output_device_info_dsound;
4212  pContext->base.create_buffer = draudio_create_buffer_dsound;
4213  pContext->base.delete_buffer = draudio_delete_buffer_dsound;
4214  pContext->base.get_buffer_extra_data_size = draudio_get_buffer_extra_data_size_dsound;
4215  pContext->base.get_buffer_extra_data = draudio_get_buffer_extra_data_dsound;
4216  pContext->base.set_buffer_data = draudio_set_buffer_data_dsound;
4217  pContext->base.play = draudio_play_dsound;
4218  pContext->base.pause = draudio_pause_dsound;
4219  pContext->base.stop = draudio_stop_dsound;
4220  pContext->base.get_playback_state = draudio_get_playback_state_dsound;
4221  pContext->base.set_playback_position = draudio_set_playback_position_dsound;
4222  pContext->base.get_playback_position = draudio_get_playback_position_dsound;
4223  pContext->base.set_pan = draudio_set_pan_dsound;
4224  pContext->base.get_pan = draudio_get_pan_dsound;
4225  pContext->base.set_volume = draudio_set_volume_dsound;
4226  pContext->base.get_volume = draudio_get_volume_dsound;
4227  pContext->base.remove_markers = draudio_remove_markers_dsound;
4228  pContext->base.register_marker_callback = draudio_register_marker_callback_dsound;
4229  pContext->base.register_stop_callback = draudio_register_stop_callback_dsound;
4230  pContext->base.register_pause_callback = draudio_register_pause_callback_dsound;
4231  pContext->base.register_play_callback = draudio_register_play_callback_dsound;
4232  pContext->base.set_position = draudio_set_position_dsound;
4233  pContext->base.get_position = draudio_get_position_dsound;
4234  pContext->base.set_listener_position = draudio_set_listener_position_dsound;
4235  pContext->base.get_listener_position = draudio_get_listener_position_dsound;
4236  pContext->base.set_listener_orientation = draudio_set_listener_orientation_dsound;
4237  pContext->base.get_listener_orientation = draudio_get_listener_orientation_dsound;
4238  pContext->base.set_3d_mode = draudio_set_3d_mode_dsound;
4239  pContext->base.get_3d_mode = draudio_get_3d_mode_dsound;
4240 
4241  pContext->hDSoundDLL = hDSoundDLL;
4242  pContext->pDirectSoundCreate8 = pDirectSoundCreate8;
4243  pContext->pDirectSoundEnumerateA = pDirectSoundEnumerateA;
4244  pContext->pDirectSoundCaptureCreate8 = pDirectSoundCaptureCreate8;
4245  pContext->pDirectSoundCaptureEnumerateA = pDirectSoundCaptureEnumerateA;
4246 
4247  // Enumerate output devices.
4248  pContext->outputDeviceCount = 0;
4249  pContext->pDirectSoundEnumerateA(DSEnumCallback_OutputDevices, pContext);
4250 
4251  // Enumerate input devices.
4252  pContext->inputDeviceCount = 0;
4253  pContext->pDirectSoundCaptureEnumerateA(DSEnumCallback_InputDevices, pContext);
4254 
4255  // The message queue and marker notification thread.
4256  if (!draudio_init_message_queue_dsound(&pContext->messageQueue) || !draudio_init_event_manager_dsound(&pContext->eventManager, &pContext->messageQueue))
4257  {
4258  // Failed to initialize the event manager.
4259  FreeLibrary(hDSoundDLL);
4260  free(pContext);
4261 
4262  return NULL;
4263  }
4264  }
4265 
4266  return (draudio_context*)pContext;
4267 }
4268 #endif // !DRAUDIO_BUILD_DSOUND
4269 
4270 
4272 //
4273 // XAudio2
4274 //
4276 
4277 #if 0
4278 #define uuid(x)
4279 #define DX_BUILD
4280 #define INITGUID 1
4281 #include <xaudio2.h>
4282 #endif
4283 #endif
4284 
4285 /*
4286 This is free and unencumbered software released into the public domain.
4287 
4288 Anyone is free to copy, modify, publish, use, compile, sell, or
4289 distribute this software, either in source code form or as a compiled
4290 binary, for any purpose, commercial or non-commercial, and by any
4291 means.
4292 
4293 In jurisdictions that recognize copyright laws, the author or authors
4294 of this software dedicate any and all copyright interest in the
4295 software to the public domain. We make this dedication for the benefit
4296 of the public at large and to the detriment of our heirs and
4297 successors. We intend this dedication to be an overt act of
4298 relinquishment in perpetuity of all present and future rights to this
4299 software under copyright law.
4300 
4301 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4302 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4303 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
4304 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
4305 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
4306 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
4307 OTHER DEALINGS IN THE SOFTWARE.
4308 
4309 For more information, please refer to <http://unlicense.org/>
4310 */
draudio_paused
@ draudio_paused
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:108
draudio_streaming_callbacks::read
draudio_stream_read_proc read
A pointer to the function to call when more data needs to be read.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:505
draudio_effect_type_none
@ draudio_effect_type_none
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:116
draudio_sound_desc::onRead
draudio_on_sound_read_data_proc onRead
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:599
draudio_get_streaming_buffer_extra_data_size
size_t draudio_get_streaming_buffer_extra_data_size(draudio_buffer *pBuffer)
Retrieves the size of the extra data of the given streaming buffer..
draudio_sound_desc::extraDataSize
unsigned int extraDataSize
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:608
draudio_format
draudio_format
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:97
draudio_effect
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:185
draudio_delete_mutex
void draudio_delete_mutex(draudio_mutex mutex)
Deletes a mutex object.
draudio_sound_desc::onDelete
draudio_on_sound_delete_proc onDelete
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:595
draudio_set_3d_mode
void draudio_set_3d_mode(draudio_buffer *pBuffer, draudio_3d_mode mode)
draudio_pause_all_sounds
void draudio_pause_all_sounds(draudio_world *pWorld)
Pauses playback of all sounds in the given world.
NULL
#define NULL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:92
draudio_sound
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:616
draudio_set_buffer_data
void draudio_set_buffer_data(draudio_buffer *pBuffer, size_t offset, const void *pData, size_t dataSizeInBytes)
Sets the audio data of the given buffer.
draudio_effect_type_chorus
@ draudio_effect_type_chorus
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:118
draudio_get_sound_playback_state
draudio_playback_state draudio_get_sound_playback_state(draudio_sound *pSound)
Retrieves the playback state of the given sound.
draudio_get_playback_position
unsigned int draudio_get_playback_position(draudio_buffer *pBuffer)
Retrieves hte playback position of the given buffer.
draudio_buffer_desc::sampleRate
unsigned int sampleRate
The sample rate.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:172
draudio_effect_type
draudio_effect_type
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:114
draudio_delete_all_sounds
void draudio_delete_all_sounds(draudio_world *pWorld)
Deletes every sound from the given world.
draudio_play_streaming_buffer
bool draudio_play_streaming_buffer(draudio_buffer *pBuffer, bool loop)
Begins playing the given streaming buffer.
draudio_sound_desc::channels
unsigned int channels
The number of channels. This should be 1 for mono, 2 for stereo.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:576
draudio_buffer_desc::bitsPerSample
unsigned int bitsPerSample
The number of bits per sample.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:175
draudio_on_sound_seek_data_proc
bool(* draudio_on_sound_seek_data_proc)(draudio_sound *pSound, size_t offsetInBytesFromStart)
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:563
draudio_streaming_callbacks::seek
draudio_stream_seek_proc seek
Seeks source data from the beginning of the file.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:508
DRAUDIO_MAX_MARKER_COUNT
#define DRAUDIO_MAX_MARKER_COUNT
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:78
draudio_stream_seek_proc
draudio_bool(* draudio_stream_seek_proc)(void *pUserData, size_t offsetInBytesFromStart)
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:497
DRAUDIO_EVENT_ID_PLAY
#define DRAUDIO_EVENT_ID_PLAY
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:89
FALSE
#define FALSE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:642
draudio_stop_sound
void draudio_stop_sound(draudio_sound *pSound)
Stops playback of the given sound.
draudio_sound::pBuffer
draudio_buffer * pBuffer
A pointer to the audio buffer for playback.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:622
draudio_effect_type
draudio_effect_type
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:114
draudio_stop_all_sounds
void draudio_stop_all_sounds(draudio_world *pWorld)
Stops playback of all sounds in the given world.
draudio_stream_read_proc
draudio_bool(* draudio_stream_read_proc)(void *pUserData, void *pDataOut, size_t bytesToRead, size_t *bytesReadOut)
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:496
draudio_3d_mode
draudio_3d_mode
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:127
draudio_3d_mode_absolute
@ draudio_3d_mode_absolute
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:129
draudio_resume_all_sounds
void draudio_resume_all_sounds(draudio_world *pWorld)
Resumes playback of all sounds in the given world.
draudio_sound_desc
The structure that is used for creating a sound object.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:566
draudio_stopped
@ draudio_stopped
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:107
draudio_playback_state
draudio_playback_state
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:105
draudio_3d_mode_disabled
@ draudio_3d_mode_disabled
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:131
draudio_unlock_mutex
void draudio_unlock_mutex(draudio_mutex mutex)
Unlocks the given mutex.
draudio_set_sound_play_callback
void draudio_set_sound_play_callback(draudio_sound *pSound, draudio_event_callback_proc callback, void *pUserData)
Sets the callback for the play event for the given sound.
draudio_sound::onRead
draudio_on_sound_read_data_proc onRead
[Internal Use Only] The onRead streaming function. Can be null, in which case streaming will not be u...
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:647
draudio_sound::prevPlaybackState
draudio_playback_state prevPlaybackState
[Internal Use Only] The state of the buffer's playback at the time the associated world overwrote it.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:626
draudio_get_pan
float draudio_get_pan(draudio_buffer *pBuffer)
Retrieves the pan of the given buffer.
draudio_play
void draudio_play(draudio_buffer *pBuffer, bool loop)
draudio_sound::pPrevSound
draudio_sound * pPrevSound
[Internal Use Only] A pointer ot the previous sound in the local list.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:632
draudio_get_volume
float draudio_get_volume(draudio_buffer *pBuffer)
Retrieves the volume of the sound.
draudio_get_sound_3d_mode
draudio_3d_mode draudio_get_sound_3d_mode(draudio_sound *pSound)
Retrieves the 3D mode of the given sound.
draudio_buffer_desc
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:159
draudio_device
struct draudio_device draudio_device
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:137
draudio_delete_buffer
void draudio_delete_buffer(draudio_buffer *pBuffer)
Deletes the given buffer.
draudio_sound::markedForDeletion
bool markedForDeletion
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:641
draudio_get_sound_extra_data
void * draudio_get_sound_extra_data(draudio_sound *pSound)
Retrieves a pointer to the buffer containing the given sound's extra data.
draudio_create_buffer
draudio_buffer * draudio_create_buffer(draudio_device *pDevice, draudio_buffer_desc *pBufferDesc, size_t extraDataSize)
draudio_delete_sound
void draudio_delete_sound(draudio_sound *pSound)
Deletes a sound that was previously created with draudio_create_sound().
draudio_sound_desc::onSeek
draudio_on_sound_seek_data_proc onSeek
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:603
draudio_delete_output_device
void draudio_delete_output_device(draudio_device *pDevice)
Deletes the given output device.
draudio_pause
void draudio_pause(draudio_buffer *pBuffer)
Pauses playback of the given buffer.
draudio_on_sound_delete_proc
void(* draudio_on_sound_delete_proc)(draudio_sound *pSound)
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:561
draudio_sound_desc::bitsPerSample
unsigned int bitsPerSample
The number of bits per sample.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:582
draudio_sound_desc::sampleRate
unsigned int sampleRate
The sample rate.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:579
draudio_bool
int draudio_bool
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:494
DRAUDIO_EVENT_ID_PAUSE
#define DRAUDIO_EVENT_ID_PAUSE
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:88
draudio_create_mutex
draudio_mutex draudio_create_mutex()
Creates a mutex object.
draudio_play_inline_sound
void draudio_play_inline_sound(draudio_world *pWorld, draudio_sound_desc desc)
Begins playing a sound using the given streaming callbacks.
draudio_get_output_device_info
bool draudio_get_output_device_info(draudio_context *pContext, unsigned int deviceIndex, draudio_device_info *pInfoOut)
Retrieves information about the device at the given index.
draudio_set_volume
void draudio_set_volume(draudio_buffer *pBuffer, float volume)
draudio_get_listener_position
void draudio_get_listener_position(draudio_device *pDevice, float *pPosOut)
Retrieves the position of the listner for the given output device.
draudio_get_3d_mode
draudio_3d_mode draudio_get_3d_mode(draudio_buffer *pBuffer)
Retrieves the 3D processing mode (absolute, relative or disabled).
draudio_play_inline_sound_3f
void draudio_play_inline_sound_3f(draudio_world *pWorld, draudio_sound_desc desc, float posX, float posY, float posZ)
Begins playing the given sound at the given position.
draudio_device_info::description
char description[256]
The description of the device.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:155
draudio_create_streaming_buffer
draudio_buffer * draudio_create_streaming_buffer(draudio_device *pDevice, draudio_buffer_desc *pBufferDesc, draudio_streaming_callbacks callbacks, unsigned int extraDataSize)
draudio_remove_markers
void draudio_remove_markers(draudio_buffer *pBuffer)
Removes every marker.
draudio_get_sound_extra_data_size
size_t draudio_get_sound_extra_data_size(draudio_sound *pSound)
Retrieves the size in bytes of the given sound's extra data.
TRUE
#define TRUE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:641
draudio_sound::isUsingStreamingBuffer
bool isUsingStreamingBuffer
[Internal Use Only] Keeps track of whether or not a streaming buffer is being used.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:635
draudio_sound::pWorld
draudio_world * pWorld
A pointer to the world that owns the sound.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:619
draudio_world::lock
draudio_mutex lock
Mutex for thread-safety.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:665
strcpy_s
DR_INLINE int strcpy_s(char *dst, size_t dstSizeInBytes, const char *src)
Definition: porcupine/demo/c/dr_libs/old/dr.h:157
draudio_format_pcm
@ draudio_format_pcm
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:99
draudio_event_callback
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:142
DRAUDIO_MAX_MESSAGE_QUEUE_SIZE
#define DRAUDIO_MAX_MESSAGE_QUEUE_SIZE
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:79
draudio_get_streaming_buffer_extra_data
void * draudio_get_streaming_buffer_extra_data(draudio_buffer *pBuffer)
Retrieves a pointer to the extra data of the given streaming buffer.
DRAUDIO_RELATIVE_3D
#define DRAUDIO_RELATIVE_3D
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:93
draudio_sound_desc::pExtraData
const void * pExtraData
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:612
draudio_bool
int draudio_bool
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:494
draudio_set_listener_orientation
void draudio_set_listener_orientation(draudio_device *pDevice, float forwardX, float forwardY, float forwardZ, float upX, float upY, float upZ)
Sets the orientation of the listener for the given output device.
draudio_get_buffer_extra_data
void * draudio_get_buffer_extra_data(draudio_buffer *pBuffer)
Retrieves a pointer to the given buffer's extra data.
draudio_sound::onSeek
draudio_on_sound_seek_data_proc onSeek
[Internal Use Only] The onSeek streaming function. Can be null, in which case streaming will not be u...
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:650
draudio_set_sound_position
void draudio_set_sound_position(draudio_sound *pSound, float posX, float posY, float posZ)
Sets the position of the given sound.
draudio_sound::pNextSound
draudio_sound * pNextSound
[Internal Use Only] A pointer to the next sound in the local list.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:629
DRAUDIO_ENABLE_3D
#define DRAUDIO_ENABLE_3D
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:92
draudio_world
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:653
draudio_world::pFirstSound
draudio_sound * pFirstSound
A pointer to the first sound in the local list of sounds.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:662
draudio_world::pDevice
draudio_device * pDevice
A pointer to the dr_audio device to output audio to.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:656
draudio_buffer
struct draudio_buffer draudio_buffer
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:138
python.setup.description
description
Definition: porcupine/binding/python/setup.py:73
draudio_world::playbackState
draudio_playback_state playbackState
The global playback state of the world.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:659
draudio_get_output_device_count
unsigned int draudio_get_output_device_count(draudio_context *pContext)
Retrieves the number of output devices that were enumerated when the context was created.
draudio_get_position
void draudio_get_position(draudio_buffer *pBuffer, float *pPosOut)
Retrieves the position of the given buffer in 3D space.
L
#define L
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:5102
draudio_set_position
void draudio_set_position(draudio_buffer *pBuffer, float x, float y, float z)
draudio_effect_type_distortion
@ draudio_effect_type_distortion
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:120
waveform
ma_waveform waveform
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/tests/test_deviceio/ma_test_deviceio.c:59
draudio_buffer_desc::flags
unsigned int flags
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:163
draudio_buffer_desc::pData
void * pData
A pointer to the initial data.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:181
draudio_event_callback::callback
draudio_event_callback_proc callback
The callback function.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:145
draudio_is_looping
bool draudio_is_looping(draudio_buffer *pBuffer)
Determines whether or not the given audio buffer is looping.
draudio_streaming_callbacks
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:499
python.pvrecorder.CALLBACK
CALLBACK
Definition: porcupine/demo/c/pvrecorder/sdk/python/pvrecorder.py:17
draudio_sound_desc::format
draudio_format format
The data format.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:573
draudio_effect_type_i3dl2reverb
@ draudio_effect_type_i3dl2reverb
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:117
draudio_sound_desc::sizeInBytes
size_t sizeInBytes
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:586
draudio_register_stop_callback
bool draudio_register_stop_callback(draudio_buffer *pBuffer, draudio_event_callback_proc callback, void *pUserData)
draudio_mutex
void * draudio_mutex
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:476
draudio_get_listener_orientation
void draudio_get_listener_orientation(draudio_device *pDevice, float *pForwardOut, float *pUpOut)
Retrieves the orientation of the listener for the given output device.
draudio_lock_mutex
void draudio_lock_mutex(draudio_mutex mutex)
Locks the given mutex.
draudio_sound_desc::flags
unsigned int flags
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:570
draudio_set_pan
void draudio_set_pan(draudio_buffer *pBuffer, float pan)
draudio_device_info
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:152
DRAUDIO_MAX_DEVICE_COUNT
#define DRAUDIO_MAX_DEVICE_COUNT
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:77
draudio_3d_mode_relative
@ draudio_3d_mode_relative
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:130
draudio_format_float
@ draudio_format_float
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:100
draudio_set_sound_pause_callback
void draudio_set_sound_pause_callback(draudio_sound *pSound, draudio_event_callback_proc callback, void *pUserData)
Sets the callback for the pause event for the given sound.
draudio_create_world
draudio_world * draudio_create_world(draudio_device *pDevice)
Creates a new sound world which will output audio from the given device.
draudio_streaming_callbacks::pUserData
void * pUserData
A pointer to the user data to pass to each callback.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:502
draudio_stop
void draudio_stop(draudio_buffer *pBuffer)
Stops playback of the given buffer.
draudio_mutex
void * draudio_mutex
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:476
draudio_get_stop_callback
draudio_event_callback draudio_get_stop_callback(draudio_buffer *pBuffer)
Retrieves the callback that is currently set for the stop event.
draudio_get_pause_callback
draudio_event_callback draudio_get_pause_callback(draudio_buffer *pBuffer)
Retrieves the callback that is currently set for the pause event.
draudio_play_sound
void draudio_play_sound(draudio_sound *pSound, bool loop)
Plays or resumes the given sound.
draudio_pause_sound
void draudio_pause_sound(draudio_sound *pSound)
Pauses playback the given sound.
draudio_effect_type_echo
@ draudio_effect_type_echo
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:121
draudio_get_buffer_extra_data_size
unsigned int draudio_get_buffer_extra_data_size(draudio_buffer *pBuffer)
Retrieves the size in bytes of the given buffer's extra data.
draudio_get_playback_state
draudio_playback_state draudio_get_playback_state(draudio_buffer *pBuffer)
Retrieves the playback state of the given buffer.
draudio_on_sound_read_data_proc
bool(* draudio_on_sound_read_data_proc)(draudio_sound *pSound, void *pDataOut, size_t bytesToRead, size_t *bytesReadOut)
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:562
draudio_register_play_callback
bool draudio_register_play_callback(draudio_buffer *pBuffer, draudio_event_callback_proc callback, void *pUserData)
draudio_get_play_callback
draudio_event_callback draudio_get_play_callback(draudio_buffer *pBuffer)
Retrieves the callback that is currently set for the play event.
draudio_is_sound_looping
bool draudio_is_sound_looping(draudio_sound *pSound)
Determines if the given sound is looping.
draudio_event_callback_proc
void(* draudio_event_callback_proc)(draudio_buffer *pBuffer, unsigned int eventID, void *pUserData)
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:140
draudio_effect_type_compressor
@ draudio_effect_type_compressor
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:119
draudio_playing
@ draudio_playing
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:109
draudio_create_output_device
draudio_device * draudio_create_output_device(draudio_context *pContext, unsigned int deviceIndex)
draudio_set_listener_position
void draudio_set_listener_position(draudio_device *pDevice, float x, float y, float z)
Sets the position of the listener for the given output device.
draudio_3d_mode
draudio_3d_mode
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:127
draudio_buffer_desc::format
draudio_format format
The data format.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:166
assert.h
draudio_sound::onDelete
draudio_on_sound_delete_proc onDelete
[Internal Use Only] the onDelete function. Can be null.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:644
draudio_delete_world
void draudio_delete_world(draudio_world *pWorld)
Deletes a sound world that was previously created with draudio_create_world().
DRAUDIO_EVENT_ID_STOP
#define DRAUDIO_EVENT_ID_STOP
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:87
draudio_set_sound_stop_callback
void draudio_set_sound_stop_callback(draudio_sound *pSound, draudio_event_callback_proc callback, void *pUserData)
Sets the callback for the stop event for the given sound.
draudio_is_streaming_buffer_looping
bool draudio_is_streaming_buffer_looping(draudio_buffer *pBuffer)
Determines whether or not the given streaming buffer is looping.
draudio_delete_context
void draudio_delete_context(draudio_context *pContext)
Deletes the given context.
draudio_buffer_desc::channels
unsigned int channels
The number of channels. This should be 1 for mono, 2 for stereo.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:169
draudio_register_marker_callback
bool draudio_register_marker_callback(draudio_buffer *pBuffer, size_t offsetInBytes, draudio_event_callback_proc callback, unsigned int eventID, void *pUserData)
draudio_set_sound_3d_mode
void draudio_set_sound_3d_mode(draudio_sound *pSound, draudio_3d_mode mode)
Sets the 3D mode of the given sound (absolute positioning, relative positioning, no positioning).
draudio_set_playback_position
void draudio_set_playback_position(draudio_buffer *pBuffer, unsigned int position)
Sets the playback position for the given buffer.
draudio_effect_type_flanger
@ draudio_effect_type_flanger
Definition: rhino/demo/c/dr_libs/old/dr_audio_ancient.h:122
draudio_create_sound
draudio_sound * draudio_create_sound(draudio_world *pWorld, draudio_sound_desc desc)
Creates a sound in 3D space.
draudio_create_context
draudio_context * draudio_create_context()
Creates a context which chooses an appropriate backend based on the given platform.
draudio_register_pause_callback
bool draudio_register_pause_callback(draudio_buffer *pBuffer, draudio_event_callback_proc callback, void *pUserData)
draudio_context
struct draudio_context draudio_context
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:136
draudio_buffer_desc::sizeInBytes
size_t sizeInBytes
The size in bytes of the data.
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:178
draudio_sound_desc::pData
void * pData
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:590
draudio_format
draudio_format
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:97
draudio_playback_state
draudio_playback_state
Definition: porcupine/demo/c/dr_libs/old/dr_audio_ancient.h:105


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:13:49