resource_manager.odin 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. package miniaudio
  2. import "core:c"
  3. foreign import lib { LIB }
  4. /************************************************************************************************************************************************************
  5. Resource Manager
  6. ************************************************************************************************************************************************************/
  7. resource_manager_data_source_flag :: enum c.int {
  8. STREAM = 0, /* When set, does not load the entire data source in memory. Disk I/O will happen on job threads. */
  9. DECODE = 1, /* Decode data before storing in memory. When set, decoding is done at the resource manager level rather than the mixing thread. Results in faster mixing, but higher memory usage. */
  10. ASYNC = 2, /* When set, the resource manager will load the data source asynchronously. */
  11. WAIT_INIT = 3, /* When set, waits for initialization of the underlying data source before returning from ma_resource_manager_data_source_init(). */
  12. UNKNOWN_LENGTH = 4, /* Gives the resource manager a hint that the length of the data source is unknown and calling `ma_data_source_get_length_in_pcm_frames()` should be avoided. */
  13. LOOPING = 5, /* When set, configures the data source to loop by default. */
  14. }
  15. resource_manager_data_source_flags :: bit_set[resource_manager_data_source_flag; u32]
  16. /*
  17. Pipeline notifications used by the resource manager. Made up of both an async notification and a fence, both of which are optional.
  18. */
  19. resource_manager_pipeline_stage_notification :: struct {
  20. pNotification: ^async_notification,
  21. pFence: ^fence,
  22. }
  23. resource_manager_pipeline_notifications :: struct {
  24. init: resource_manager_pipeline_stage_notification, /* Initialization of the decoder. */
  25. done: resource_manager_pipeline_stage_notification, /* Decoding fully completed. */
  26. }
  27. @(default_calling_convention="c", link_prefix="ma_")
  28. foreign lib {
  29. resource_manager_pipeline_notifications_init :: proc() -> resource_manager_pipeline_notifications ---
  30. }
  31. /* BEGIN BACKWARDS COMPATIBILITY */
  32. /* TODO: Remove this block in version 0.12. */
  33. resource_manager_job :: job
  34. resource_manager_job_init :: job_init
  35. JOB_TYPE_RESOURCE_MANAGER_QUEUE_FLAG_NON_BLOCKING :: job_queue_flags.NON_BLOCKING
  36. resource_manager_job_queue_config :: job_queue_config
  37. resource_manager_job_queue_config_init :: job_queue_config_init
  38. resource_manager_job_queue :: job_queue
  39. resource_manager_job_queue_get_heap_size :: job_queue_get_heap_size
  40. resource_manager_job_queue_init_preallocated :: job_queue_init_preallocated
  41. resource_manager_job_queue_init :: job_queue_init
  42. resource_manager_job_queue_uninit :: job_queue_uninit
  43. resource_manager_job_queue_post :: job_queue_post
  44. resource_manager_job_queue_next :: job_queue_next
  45. /* END BACKWARDS COMPATIBILITY */
  46. /* Maximum job thread count will be restricted to this, but this may be removed later and replaced with a heap allocation thereby removing any limitation. */
  47. RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT :: 64
  48. resource_manager_flag :: enum c.int {
  49. /* Indicates ma_resource_manager_next_job() should not block. Only valid when the job thread count is 0. */
  50. NON_BLOCKING = 0,
  51. /* Disables any kind of multithreading. Implicitly enables MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING. */
  52. NO_THREADING = 1,
  53. }
  54. resource_manager_flags :: bit_set[resource_manager_flag; u32]
  55. resource_manager_data_source_config :: struct {
  56. pFilePath: cstring,
  57. pFilePathW: [^]c.wchar_t,
  58. pNotifications: ^resource_manager_pipeline_notifications,
  59. initialSeekPointInPCMFrames: u64,
  60. rangeBegInPCMFrames: u64,
  61. rangeEndInPCMFrames: u64,
  62. loopPointBegInPCMFrames: u64,
  63. loopPointEndInPCMFrames: u64,
  64. flags: u32,
  65. isLooping: b32, /* Deprecated. Use the MA_RESOURCE_MANAGER_DATA_SOURCE_FLAG_LOOPING flag in `flags` instead. */
  66. }
  67. resource_manager_data_supply_type :: enum c.int {
  68. unknown = 0, /* Used for determining whether or the data supply has been initialized. */
  69. encoded, /* Data supply is an encoded buffer. Connector is ma_decoder. */
  70. decoded, /* Data supply is a decoded buffer. Connector is ma_audio_buffer. */
  71. decoded_paged, /* Data supply is a linked list of decoded buffers. Connector is ma_paged_audio_buffer. */
  72. }
  73. resource_manager_data_supply :: struct {
  74. type: resource_manager_data_supply_type, /*atomic*/ /* Read and written from different threads so needs to be accessed atomically. */
  75. backend: struct #raw_union {
  76. encoded: struct {
  77. pData: rawptr,
  78. sizeInBytes: c.size_t,
  79. },
  80. decoded: struct {
  81. pData: rawptr,
  82. totalFrameCount: u64,
  83. decodedFrameCount: u64,
  84. format: format,
  85. channels: u32,
  86. sampleRate: u32,
  87. },
  88. decodedPaged: struct {
  89. data: paged_audio_buffer_data,
  90. decodedFrameCount: u64,
  91. sampleRate: u32,
  92. },
  93. },
  94. }
  95. resource_manager_data_buffer_node :: struct {
  96. hashedName32: u32, /* The hashed name. This is the key. */
  97. refCount: u32,
  98. result: result, /*atomic*/ /* Result from asynchronous loading. When loading set to MA_BUSY. When fully loaded set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. */
  99. executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */
  100. executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
  101. isDataOwnedByResourceManager: b32, /* Set to true when the underlying data buffer was allocated the resource manager. Set to false if it is owned by the application (via ma_resource_manager_register_*()). */
  102. data: resource_manager_data_supply,
  103. pParent: ^resource_manager_data_buffer_node,
  104. pChildLo: ^resource_manager_data_buffer_node,
  105. pChildHi: ^resource_manager_data_buffer_node,
  106. }
  107. resource_manager_data_buffer :: struct {
  108. ds: data_source_base, /* Base data source. A data buffer is a data source. */
  109. pResourceManager: ^resource_manager, /* A pointer to the resource manager that owns this buffer. */
  110. pNode: ^resource_manager_data_buffer_node, /* The data node. This is reference counted and is what supplies the data. */
  111. flags: resource_manager_flags, /* The flags that were passed used to initialize the buffer. */
  112. executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */
  113. executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
  114. seekTargetInPCMFrames: u64, /* Only updated by the public API. Never written nor read from the job thread. */
  115. seekToCursorOnNextRead: b32, /* On the next read we need to seek to the frame cursor. */
  116. result: result, /*atomic*/ /* Keeps track of a result of decoding. Set to MA_BUSY while the buffer is still loading. Set to MA_SUCCESS when loading is finished successfully. Otherwise set to some other code. */
  117. isLooping: b32, /*atomic*/ /* Can be read and written by different threads at the same time. Must be used atomically. */
  118. isConnectorInitialized: b32, /* Used for asynchronous loading to ensure we don't try to initialize the connector multiple times while waiting for the node to fully load. */
  119. connector: struct #raw_union {
  120. decoder: decoder, /* Supply type is ma_resource_manager_data_supply_type_encoded */
  121. buffer: audio_buffer, /* Supply type is ma_resource_manager_data_supply_type_decoded */
  122. pagedBuffer: paged_audio_buffer, /* Supply type is ma_resource_manager_data_supply_type_decoded_paged */
  123. }, /* Connects this object to the node's data supply. */
  124. }
  125. resource_manager_data_stream :: struct {
  126. ds: data_source_base, /* Base data source. A data stream is a data source. */
  127. pResourceManager: ^resource_manager, /* A pointer to the resource manager that owns this data stream. */
  128. flags: u32, /* The flags that were passed used to initialize the stream. */
  129. decoder: decoder, /* Used for filling pages with data. This is only ever accessed by the job thread. The public API should never touch this. */
  130. isDecoderInitialized: b32, /* Required for determining whether or not the decoder should be uninitialized in MA_JOB_TYPE_RESOURCE_MANAGER_FREE_DATA_STREAM. */
  131. totalLengthInPCMFrames: u64, /* This is calculated when first loaded by the MA_JOB_TYPE_RESOURCE_MANAGER_LOAD_DATA_STREAM. */
  132. relativeCursor: u32, /* The playback cursor, relative to the current page. Only ever accessed by the public API. Never accessed by the job thread. */
  133. absoluteCursor: u64, /*atomic*/ /* The playback cursor, in absolute position starting from the start of the file. */
  134. currentPageIndex: u32, /* Toggles between 0 and 1. Index 0 is the first half of pPageData. Index 1 is the second half. Only ever accessed by the public API. Never accessed by the job thread. */
  135. executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */
  136. executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
  137. /* Written by the public API, read by the job thread. */
  138. isLooping: b32, /*atomic*/ /* Whether or not the stream is looping. It's important to set the looping flag at the data stream level for smooth loop transitions. */
  139. /* Written by the job thread, read by the public API. */
  140. pPageData: rawptr, /* Buffer containing the decoded data of each page. Allocated once at initialization time. */
  141. pageFrameCount: [2]u32, /*atomic*/ /* The number of valid PCM frames in each page. Used to determine the last valid frame. */
  142. /* Written and read by both the public API and the job thread. These must be atomic. */
  143. result: result, /*atomic*/ /* Result from asynchronous loading. When loading set to MA_BUSY. When initialized set to MA_SUCCESS. When deleting set to MA_UNAVAILABLE. If an error occurs when loading, set to an error code. */
  144. isDecoderAtEnd: b32, /*atomic*/ /* Whether or not the decoder has reached the end. */
  145. isPageValid: [2]b32, /*atomic*/ /* Booleans to indicate whether or not a page is valid. Set to false by the public API, set to true by the job thread. Set to false as the pages are consumed, true when they are filled. */
  146. seekCounter: b32, /*atomic*/ /* When 0, no seeking is being performed. When > 0, a seek is being performed and reading should be delayed with MA_BUSY. */
  147. }
  148. resource_manager_data_source :: struct {
  149. backend: struct #raw_union {
  150. buffer: resource_manager_data_buffer,
  151. stream: resource_manager_data_stream,
  152. }, /* Must be the first item because we need the first item to be the data source callbacks for the buffer or stream. */
  153. flags: u32, /* The flags that were passed in to ma_resource_manager_data_source_init(). */
  154. executionCounter: u32, /*atomic*/ /* For allocating execution orders for jobs. */
  155. executionPointer: u32, /*atomic*/ /* For managing the order of execution for asynchronous jobs relating to this object. Incremented as jobs complete processing. */
  156. }
  157. resource_manager_config :: struct {
  158. allocationCallbacks: allocation_callbacks,
  159. pLog: ^log,
  160. decodedFormat: format, /* The decoded format to use. Set to ma_format_unknown (default) to use the file's native format. */
  161. decodedChannels: u32, /* The decoded channel count to use. Set to 0 (default) to use the file's native channel count. */
  162. decodedSampleRate: u32, /* the decoded sample rate to use. Set to 0 (default) to use the file's native sample rate. */
  163. jobThreadCount: u32, /* Set to 0 if you want to self-manage your job threads. Defaults to 1. */
  164. jobThreadStackSize: uint,
  165. jobQueueCapacity: u32, /* The maximum number of jobs that can fit in the queue at a time. Defaults to MA_JOB_TYPE_RESOURCE_MANAGER_QUEUE_CAPACITY. Cannot be zero. */
  166. flags: u32,
  167. pVFS: ^vfs, /* Can be NULL in which case defaults will be used. */
  168. ppCustomDecodingBackendVTables: ^[^]decoding_backend_vtable,
  169. customDecodingBackendCount: u32,
  170. pCustomDecodingBackendUserData: rawptr,
  171. }
  172. resource_manager :: struct {
  173. config: resource_manager_config,
  174. pRootDataBufferNode: ^resource_manager_data_buffer_node, /* The root buffer in the binary tree. */
  175. dataBufferBSTLock: (struct {} when NO_THREADING else mutex), /* For synchronizing access to the data buffer binary tree. */
  176. jobThreads: (struct {} when NO_THREADING else [RESOURCE_MANAGER_MAX_JOB_THREAD_COUNT]thread), /* The threads for executing jobs. */
  177. jobQueue: job_queue, /* Multi-consumer, multi-producer job queue for managing jobs for asynchronous decoding and streaming. */
  178. defaultVFS: default_vfs, /* Only used if a custom VFS is not specified. */
  179. log: log, /* Only used if no log was specified in the config. */
  180. }
  181. @(default_calling_convention="c", link_prefix="ma_")
  182. foreign lib {
  183. resource_manager_data_source_config_init :: proc() -> resource_manager_data_source_config ---
  184. resource_manager_config_init :: proc() -> resource_manager_config ---
  185. /* Init. */
  186. resource_manager_init :: proc(pConfig: ^resource_manager_config, pResourceManager: ^resource_manager) -> result ---
  187. resource_manager_uninit :: proc(pResourceManager: ^resource_manager) ---
  188. resource_manager_get_log :: proc(pResourceManager: ^resource_manager) -> ^log ---
  189. /* Registration. */
  190. resource_manager_register_file :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32) -> result ---
  191. resource_manager_register_file_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32) -> result ---
  192. resource_manager_register_decoded_data :: proc(pResourceManager: ^resource_manager, pName: cstring, pData: rawptr, frameCount: u64, format: format, channels: u32, sampleRate: u32) -> result --- /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */
  193. resource_manager_register_decoded_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, pData: rawptr, frameCount: u64, format: format, channels: u32, sampleRate: u32) -> result ---
  194. resource_manager_register_encoded_data :: proc(pResourceManager: ^resource_manager, pName: cstring, pData: rawptr, sizeInBytes: c.size_t) -> result --- /* Does not copy. Increments the reference count if already exists and returns MA_SUCCESS. */
  195. resource_manager_register_encoded_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, pData: rawptr, sizeInBytes: c.size_t) -> result ---
  196. resource_manager_unregister_file :: proc(pResourceManager: ^resource_manager, pFilePath: cstring) -> result ---
  197. resource_manager_unregister_file_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t) -> result ---
  198. resource_manager_unregister_data :: proc(pResourceManager: ^resource_manager, pName: cstring) -> result ---
  199. resource_manager_unregister_data_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t) -> result ---
  200. /* Data Buffers. */
  201. resource_manager_data_buffer_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataBuffer: ^resource_manager_data_buffer) -> result ---
  202. resource_manager_data_buffer_init :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataBuffer: ^resource_manager_data_buffer) -> result ---
  203. resource_manager_data_buffer_init_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataBuffer: ^resource_manager_data_buffer) -> result ---
  204. resource_manager_data_buffer_init_copy :: proc(pResourceManager: ^resource_manager, pExistingDataBuffer, pDataBuffer: ^resource_manager_data_buffer) -> result ---
  205. resource_manager_data_buffer_uninit :: proc(pDataBuffer: ^resource_manager_data_buffer) -> result ---
  206. resource_manager_data_buffer_read_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
  207. resource_manager_data_buffer_seek_to_pcm_frame :: proc(pDataBuffer: ^resource_manager_data_buffer, frameIndex: u64) -> result ---
  208. resource_manager_data_buffer_get_data_format :: proc(pDataBuffer: ^resource_manager_data_buffer, pFormat: ^format, pChannels: ^u32, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
  209. resource_manager_data_buffer_get_cursor_in_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pCursor: ^u64) -> result ---
  210. resource_manager_data_buffer_get_length_in_pcm_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pLength: ^u64) -> result ---
  211. resource_manager_data_buffer_result :: proc(pDataBuffer: ^resource_manager_data_buffer) -> result ---
  212. resource_manager_data_buffer_set_looping :: proc(pDataBuffer: ^resource_manager_data_buffer, isLooping: b32) -> result ---
  213. resource_manager_data_buffer_is_looping :: proc(pDataBuffer: ^resource_manager_data_buffer) -> b32 ---
  214. resource_manager_data_buffer_get_available_frames :: proc(pDataBuffer: ^resource_manager_data_buffer, pAvailableFrames: ^u64) -> result ---
  215. /* Data Streams. */
  216. resource_manager_data_stream_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataStream: ^resource_manager_data_stream) -> result ---
  217. resource_manager_data_stream_init :: proc(pResourceManager: ^resource_manager, pFilePath: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataStream: ^resource_manager_data_stream) -> result ---
  218. resource_manager_data_stream_init_w :: proc(pResourceManager: ^resource_manager, pFilePath: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataStream: ^resource_manager_data_stream) -> result ---
  219. resource_manager_data_stream_uninit :: proc(pDataStream: ^resource_manager_data_stream) -> result ---
  220. resource_manager_data_stream_read_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
  221. resource_manager_data_stream_seek_to_pcm_frame :: proc(pDataStream: ^resource_manager_data_stream, frameIndex: u64) -> result ---
  222. resource_manager_data_stream_get_data_format :: proc(pDataStream: ^resource_manager_data_stream, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
  223. resource_manager_data_stream_get_cursor_in_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pCursor: ^u64) -> result ---
  224. resource_manager_data_stream_get_length_in_pcm_frames :: proc(pDataStream: ^resource_manager_data_stream, pLength: ^u64) -> result ---
  225. resource_manager_data_stream_result :: proc(pDataStream: ^resource_manager_data_stream) -> result ---
  226. resource_manager_data_stream_set_looping :: proc(pDataStream: ^resource_manager_data_stream, isLooping: b32) -> result ---
  227. resource_manager_data_stream_is_looping :: proc(pDataStream: ^resource_manager_data_stream) -> b32 ---
  228. resource_manager_data_stream_get_available_frames :: proc(pDataStream: ^resource_manager_data_stream, pAvailableFrames: ^u64) -> result ---
  229. /* Data Sources. */
  230. resource_manager_data_source_init_ex :: proc(pResourceManager: ^resource_manager, pConfig: ^resource_manager_data_source_config, pDataSource: ^resource_manager_data_source) -> result ---
  231. resource_manager_data_source_init :: proc(pResourceManager: ^resource_manager, pName: cstring, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataSource: ^resource_manager_data_source) -> result ---
  232. resource_manager_data_source_init_w :: proc(pResourceManager: ^resource_manager, pName: [^]c.wchar_t, flags: u32, pNotifications: ^resource_manager_pipeline_notifications, pDataSource: ^resource_manager_data_source) -> result ---
  233. resource_manager_data_source_init_copy :: proc(pResourceManager: ^resource_manager, pExistingDataSource, pDataSource: ^resource_manager_data_source) -> result ---
  234. resource_manager_data_source_uninit :: proc(pDataSource: ^resource_manager_data_source) -> result ---
  235. resource_manager_data_source_read_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pFramesOut: rawptr, frameCount: u64, pFramesRead: ^u64) -> result ---
  236. resource_manager_data_source_seek_to_pcm_frame :: proc(pDataSource: ^resource_manager_data_source, frameIndex: u64) -> result ---
  237. resource_manager_data_source_get_data_format :: proc(pDataSource: ^resource_manager_data_source, pFormat: ^format, pChannels, pSampleRate: ^u32, pChannelMap: [^]channel, channelMapCap: c.size_t) -> result ---
  238. resource_manager_data_source_get_cursor_in_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pCursor: ^u64) -> result ---
  239. resource_manager_data_source_get_length_in_pcm_frames :: proc(pDataSource: ^resource_manager_data_source, pLength: ^u64) -> result ---
  240. resource_manager_data_source_result :: proc(pDataSource: ^resource_manager_data_source) -> result ---
  241. resource_manager_data_source_set_looping :: proc(pDataSource: ^resource_manager_data_source, isLooping: b32) -> result ---
  242. resource_manager_data_source_is_looping :: proc(pDataSource: ^resource_manager_data_source) -> b32 ---
  243. resource_manager_data_source_get_available_frames :: proc(pDataSource: ^resource_manager_data_source, pAvailableFrames: ^u64) -> result ---
  244. /* Job management. */
  245. resource_manager_post_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result ---
  246. resource_manager_post_job_quit :: proc(pResourceManager: ^resource_manager) -> result --- /* Helper for posting a quit job. */
  247. resource_manager_next_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result ---
  248. resource_manager_process_job :: proc(pResourceManager: ^resource_manager, pJob: ^job) -> result --- /* DEPRECATED. Use ma_job_process(). Will be removed in version 0.12. */
  249. resource_manager_process_next_job :: proc(pResourceManager: ^resource_manager) -> result --- /* Returns MA_CANCELLED if a MA_JOB_TYPE_QUIT job is found. In non-blocking mode, returns MA_NO_DATA_AVAILABLE if no jobs are available. */
  250. }