fmod/studio/system/bank.rs
1// Copyright (c) 2024 Lily Lyons
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use fmod_sys::*;
8use lanyard::Utf8CStr;
9use std::ffi::c_int;
10
11use crate::studio::{Bank, LoadBankFlags, System};
12use crate::Guid;
13
14impl System {
15 // TODO: load bank with callbacks
16 pub fn load_bank_custom(&self) -> Result<Bank> {
17 todo!()
18 }
19
20 /// Sample data must be loaded separately.
21 ///
22 /// By default this function will block until the file load finishes.
23 ///
24 /// Using the [`LoadBankFlags::NONBLOCKING`] flag will cause the bank to be loaded asynchronously.
25 /// In that case this function will always return [`Ok`] and bank will contain a valid bank handle.
26 /// Load errors for asynchronous banks can be detected by calling [`Bank::get_loading_state`].
27 /// Failed asynchronous banks should be released by calling [`Bank::unload`].
28 ///
29 /// If a bank has been split, separating out assets and optionally streams from the metadata bank, all parts must be loaded before any APIs that use the data are called.
30 /// It is recommended you load each part one after another (order is not important), then proceed with dependent API calls such as [`Bank::load_sample_data`] or [`System::get_event`].
31 pub fn load_bank_file(&self, filename: &Utf8CStr, load_flags: LoadBankFlags) -> Result<Bank> {
32 let mut bank = std::ptr::null_mut();
33 unsafe {
34 FMOD_Studio_System_LoadBankFile(
35 self.inner,
36 filename.as_ptr(),
37 load_flags.bits(),
38 &mut bank,
39 )
40 .to_result()?;
41 Ok(Bank::from(bank))
42 }
43 }
44
45 /// Sample data must be loaded separately.
46 ///
47 /// This function is the safe counterpart of [`System::load_bank_pointer`].
48 /// FMOD will allocate an internal buffer and copy the data from the passed in buffer before using it.
49 /// The buffer passed to this function may be cleaned up at any time after this function returns.
50 ///
51 /// By default this function will block until the load finishes.
52 ///
53 /// Using the [`LoadBankFlags::NONBLOCKING`] flag will cause the bank to be loaded asynchronously.
54 /// In that case this function will always return [`Ok`] and bank will contain a valid bank handle.
55 /// Load errors for asynchronous banks can be detected by calling [`Bank::get_loading_state`].
56 /// Failed asynchronous banks should be released by calling [`Bank::unload`].
57 ///
58 /// This function is not compatible with [`AdvancedSettings::encryption_key`], using them together will cause an error to be returned.
59 ///
60 /// If a bank has been split, separating out assets and optionally streams from the metadata bank, all parts must be loaded before any APIs that use the data are called.
61 /// It is recommended you load each part one after another (order is not important), then proceed with dependent API calls such as [`Bank::load_sample_data`] or [`System::get_event`].
62 pub fn load_bank_memory(&self, buffer: &[u8], flags: LoadBankFlags) -> Result<Bank> {
63 let mut bank = std::ptr::null_mut();
64 unsafe {
65 FMOD_Studio_System_LoadBankMemory(
66 self.inner,
67 buffer.as_ptr().cast::<i8>(),
68 buffer.len() as c_int,
69 FMOD_STUDIO_LOAD_MEMORY,
70 flags.bits(),
71 &mut bank,
72 )
73 .to_result()?;
74 Ok(Bank::from(bank))
75 }
76 }
77
78 /// Sample data must be loaded separately.
79 ///
80 /// This function is the unsafe counterpart of [`System::load_bank_memory`].
81 /// FMOD will use the passed memory buffer directly.
82 ///
83 /// By default this function will block until the load finishes.
84 ///
85 /// Using the [`LoadBankFlags::NONBLOCKING`] flag will cause the bank to be loaded asynchronously.
86 /// In that case this function will always return [`Ok`] and bank will contain a valid bank handle.
87 /// Load errors for asynchronous banks can be detected by calling [`Bank::get_loading_state`].
88 /// Failed asynchronous banks should be released by calling [`Bank::unload`].
89 ///
90 /// This function is not compatible with [`AdvancedSettings::encryption_key`], using them together will cause an error to be returned.
91 ///
92 /// If a bank has been split, separating out assets and optionally streams from the metadata bank, all parts must be loaded before any APIs that use the data are called.
93 /// It is recommended you load each part one after another (order is not important), then proceed with dependent API calls such as [`Bank::load_sample_data`] or [`System::get_event`].
94 ///
95 /// # Safety
96 /// When using this function the buffer must be aligned to [`FMOD_STUDIO_LOAD_MEMORY_ALIGNMENT`]
97 /// and the memory must persist until the bank has been fully unloaded, which can be some time after calling [`Bank::unload`] to unload the bank.
98 /// You can ensure the memory is not being freed prematurely by only freeing it after receiving the [`FMOD_STUDIO_SYSTEM_CALLBACK_BANK_UNLOAD`] callback.
99 pub unsafe fn load_bank_pointer(
100 &self,
101 buffer: *const [u8],
102 flags: LoadBankFlags,
103 ) -> Result<Bank> {
104 let mut bank = std::ptr::null_mut();
105 unsafe {
106 FMOD_Studio_System_LoadBankMemory(
107 self.inner,
108 buffer.cast::<i8>(),
109 (*buffer).len() as c_int,
110 FMOD_STUDIO_LOAD_MEMORY_POINT,
111 flags.bits(),
112 &mut bank,
113 )
114 .to_result()?;
115 Ok(Bank::from(bank))
116 }
117 }
118
119 /// Unloads all currently loaded banks.
120 pub fn unload_all_banks(&self) -> Result<()> {
121 unsafe { FMOD_Studio_System_UnloadAll(self.inner).to_result() }
122 }
123
124 /// Retrieves a loaded bank
125 ///
126 /// `path_or_id` may be a path, such as `bank:/Weapons` or an ID string such as `{793cddb6-7fa1-4e06-b805-4c74c0fd625b}`.
127 ///
128 /// Note that path lookups will only succeed if the strings bank has been loaded.
129 pub fn get_bank(&self, path_or_id: &Utf8CStr) -> Result<Bank> {
130 let mut bank = std::ptr::null_mut();
131 unsafe {
132 FMOD_Studio_System_GetBank(self.inner, path_or_id.as_ptr(), &mut bank).to_result()?;
133 Ok(Bank::from(bank))
134 }
135 }
136
137 /// Retrieves a loaded bank.
138 pub fn get_bank_by_id(&self, id: Guid) -> Result<Bank> {
139 let mut bank = std::ptr::null_mut();
140 unsafe {
141 FMOD_Studio_System_GetBankByID(self.inner, &id.into(), &mut bank).to_result()?;
142 Ok(Bank::from(bank))
143 }
144 }
145
146 /// Retrieves the number of loaded banks.
147 pub fn bank_count(&self) -> Result<c_int> {
148 let mut count = 0;
149 unsafe {
150 FMOD_Studio_System_GetBankCount(self.inner, &mut count).to_result()?;
151 }
152 Ok(count)
153 }
154
155 pub fn get_bank_list(&self) -> Result<Vec<Bank>> {
156 let expected_count = self.bank_count()?;
157 let mut count = 0;
158 let mut list = vec![std::ptr::null_mut(); expected_count as usize];
159
160 unsafe {
161 FMOD_Studio_System_GetBankList(
162 self.inner,
163 // bank is repr transparent and has the same layout as *mut FMOD_STUDIO_BANK, so this cast is ok
164 list.as_mut_ptr(),
165 list.capacity() as c_int,
166 &mut count,
167 )
168 .to_result()?;
169
170 debug_assert_eq!(count, expected_count);
171
172 Ok(std::mem::transmute::<
173 Vec<*mut fmod_sys::FMOD_STUDIO_BANK>,
174 Vec<Bank>,
175 >(list))
176 }
177 }
178}