fmod/core/system/plugin.rs
1// Copyright (c) 2024 Melody Madeline 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, Utf8CString};
9use std::ffi::{c_int, c_uint};
10
11use crate::{Dsp, PluginType, System, get_string};
12use crate::{FmodResultExt, Result};
13
14impl System {
15 /// Specify a base search path for plugins so they can be placed somewhere else than the directory of the main executable.
16 pub fn set_plugin_path(&self, path: &Utf8CStr) -> Result<()> {
17 unsafe { FMOD_System_SetPluginPath(self.inner.as_ptr(), path.as_ptr()).to_result() }
18 }
19
20 /// Loads an FMOD (DSP, Output or Codec) plugin from file.
21 ///
22 /// Once loaded DSP plugins can be used via `System::createDSPByPlugin`, output plugins can be use via `System::setOutputByPlugin` and codec plugins will be used automatically.
23 ///
24 /// When opening a file each codec tests whether it can support the file format in priority order.
25 ///
26 /// The format of the plugin is dependant on the operating system:
27 /// - Windows / UWP / Xbox One: .dll
28 /// - Linux / Android: .so
29 /// - Macintosh: .dylib
30 /// - PS4: .prx
31 ///
32 /// # Safety
33 ///
34 /// THIS CALLS INTO NON-RUST CODE! There is no guarantee that the plugin is safe to load, use, or unload.
35 pub unsafe fn load_plugin(&self, filename: &Utf8CStr, priority: c_uint) -> Result<c_uint> {
36 let mut handle = 0;
37 unsafe {
38 FMOD_System_LoadPlugin(
39 self.inner.as_ptr(),
40 filename.as_ptr(),
41 &raw mut handle,
42 priority,
43 )
44 .to_result()?;
45 }
46 Ok(handle)
47 }
48
49 /// Unloads an FMOD (DSP, Output or Codec) plugin.
50 pub fn unload_plugin(&self, handle: c_uint) -> Result<()> {
51 unsafe { FMOD_System_UnloadPlugin(self.inner.as_ptr(), handle).to_result() }
52 }
53
54 /// Retrieves the number of nested plugins from the selected plugin.
55 ///
56 /// Most plugins contain a single definition, in which case the count is 1, however some have a list of definitions.
57 /// his function returns the number of plugins that have been defined.
58 ///
59 /// See the DSP Plug-in API guide for more information.
60 pub fn get_nested_plugin_count(&self, handle: c_uint) -> Result<c_int> {
61 let mut count = 0;
62 unsafe {
63 FMOD_System_GetNumNestedPlugins(self.inner.as_ptr(), handle, &raw mut count)
64 .to_result()?;
65 }
66 Ok(count)
67 }
68
69 /// Retrieves the handle of a nested plugin.
70 ///
71 /// This function is used to iterate handles for plugins that have a list of definitions.
72 ///
73 /// Most plugins contain a single definition.
74 /// If this is the case, only index 0 is valid, and the returned handle is the same as the handle passed in.
75 ///
76 /// See the DSP Plug-in API guide for more information.
77 pub fn get_nested_plugin(&self, handle: c_uint, index: c_int) -> Result<c_uint> {
78 let mut nested_handle = 0;
79 unsafe {
80 FMOD_System_GetNestedPlugin(self.inner.as_ptr(), handle, index, &raw mut nested_handle)
81 .to_result()?;
82 }
83 Ok(nested_handle)
84 }
85
86 /// Retrieves the number of loaded plugins.
87 pub fn get_plugin_count(&self, kind: PluginType) -> Result<c_int> {
88 let mut count = 0;
89 unsafe {
90 FMOD_System_GetNumPlugins(self.inner.as_ptr(), kind.into(), &raw mut count)
91 .to_result()?;
92 }
93 Ok(count)
94 }
95
96 /// Retrieves the handle of a plugin based on its type and relative index.
97 ///
98 /// All plugins whether built in or loaded can be enumerated using this and [`System::get_plugin_count`].
99 pub fn get_plugin_handle(&self, kind: PluginType, index: c_int) -> Result<c_uint> {
100 let mut handle = 0;
101 unsafe {
102 FMOD_System_GetPluginHandle(self.inner.as_ptr(), kind.into(), index, &raw mut handle)
103 .to_result()?;
104 }
105 Ok(handle)
106 }
107
108 /// Retrieves information for the selected plugin.
109 pub fn get_plugin_info(&self, handle: c_uint) -> Result<(PluginType, Utf8CString, c_uint)> {
110 let mut plugin_type = 0;
111 let mut version = 0;
112
113 let name = get_string(|name| unsafe {
114 FMOD_System_GetPluginInfo(
115 self.inner.as_ptr(),
116 handle,
117 &raw mut plugin_type,
118 name.as_mut_ptr().cast(),
119 name.len() as c_int,
120 &raw mut version,
121 )
122 })?;
123
124 let plugin_type = plugin_type.try_into()?;
125 Ok((plugin_type, name, version))
126 }
127
128 /// Selects an output type given a plugin handle.
129 pub fn set_output_by_plugin(&self, handle: c_uint) -> Result<()> {
130 unsafe { FMOD_System_SetOutputByPlugin(self.inner.as_ptr(), handle).to_result() }
131 }
132
133 /// Retrieves the plugin handle for the currently selected output type.
134 pub fn get_output_by_plugin(&self) -> Result<c_uint> {
135 let mut handle = 0;
136 unsafe {
137 FMOD_System_GetOutputByPlugin(self.inner.as_ptr(), &raw mut handle).to_result()?;
138 }
139 Ok(handle)
140 }
141
142 /// Create a DSP object given a plugin handle.
143 ///
144 /// A DSP object is a module that can be inserted into the mixing graph to allow sound filtering or sound generation.
145 /// See the DSP architecture guide for more information.
146 ///
147 /// A handle can come from a newly loaded plugin with `System::loadPlugin` or an existing plugin with `System::getPluginHandle`.
148 ///
149 /// DSPs must be attached to the DSP graph before they become active, either via `ChannelControl::addDSP` or `DSP::addInput`.
150 pub fn create_dsp_by_plugin(&self, handle: c_uint) -> Result<Dsp> {
151 let mut dsp = std::ptr::null_mut();
152 unsafe {
153 FMOD_System_CreateDSPByPlugin(self.inner.as_ptr(), handle, &raw mut dsp).to_result()?;
154 Ok(Dsp::from_ffi(dsp))
155 }
156 }
157
158 /// Retrieve the description structure for a pre-existing DSP plugin.
159 // this is safe, but dereferencing the pointer is not
160 pub fn get_dsp_info_by_plugin(&self, handle: c_uint) -> Result<*const FMOD_DSP_DESCRIPTION> {
161 let mut dsp_description = std::ptr::null();
162 unsafe {
163 FMOD_System_GetDSPInfoByPlugin(self.inner.as_ptr(), handle, &raw mut dsp_description)
164 .to_result()?;
165 }
166 Ok(dsp_description)
167 }
168
169 /// Register a Codec plugin description structure for later use.
170 ///
171 /// To create an instances of this plugin use `System::create_sound` and `System::create_stream`.
172 ///
173 /// When opening a file each Codec tests whether it can support the file format in priority order.
174 /// The priority for each `FMOD_SOUND_TYPE` are as follows:
175 /// - `FMOD_SOUND_TYPE_FSB` : 250
176 /// - `FMOD_SOUND_TYPE_XMA` : 250
177 /// - `FMOD_SOUND_TYPE_AT9` : 250
178 /// - `FMOD_SOUND_TYPE_VORBIS` : 250
179 /// - `FMOD_SOUND_TYPE_OPUS` : 250
180 /// - `FMOD_SOUND_TYPE_FADPCM` : 250
181 /// - `FMOD_SOUND_TYPE_WAV` : 600
182 /// - `FMOD_SOUND_TYPE_OGGVORBIS` : 800
183 /// - `FMOD_SOUND_TYPE_AIFF` : 1000
184 /// - `FMOD_SOUND_TYPE_FLAC` : 1100
185 /// - `FMOD_SOUND_TYPE_MOD` : 1200
186 /// - `FMOD_SOUND_TYPE_S3M` : 1300
187 /// - `FMOD_SOUND_TYPE_XM` : 1400
188 /// - `FMOD_SOUND_TYPE_IT` : 1500
189 /// - `FMOD_SOUND_TYPE_MIDI` : 1600
190 /// - `FMOD_SOUND_TYPE_DLS` : 1700
191 /// - `FMOD_SOUND_TYPE_ASF` : 1900
192 /// - `FMOD_SOUND_TYPE_AUDIOQUEUE` : 2200
193 /// - `FMOD_SOUND_TYPE_MEDIACODEC` : 2250
194 /// - `FMOD_SOUND_TYPE_MPEG` : 2400
195 /// - `FMOD_SOUND_TYPE_PLAYLIST` : 2450
196 /// - `FMOD_SOUND_TYPE_RAW` : 2500
197 /// - `FMOD_SOUND_TYPE_USER` : 2600
198 /// - `FMOD_SOUND_TYPE_MEDIA_FOUNDATION` : 2600
199 ///
200 /// XMA, AT9, Vorbis, Opus and FADPCM are supported through the FSB format, and therefore have the same priority as FSB.
201 ///
202 /// Media Foundation is supported through the User codec, and therefore has the same priority as User.
203 ///
204 /// Raw and User are only accesible if `FMOD_OPENRAW` or `FMOD_OPENUSER` is specified as the mode in `System::create_sound`.
205 ///
206 /// # Safety
207 ///
208 /// This function provides no gaurdrails or safe API for registering a codec.
209 /// It can call into non-rust external code.
210 /// Codec descriptions are intended to be retrieved from a plugin's C API, so it's not feasible to provide a safe API for this function.
211 pub unsafe fn register_codec(
212 &self,
213 description: *mut FMOD_CODEC_DESCRIPTION,
214 priority: c_uint,
215 ) -> Result<c_uint> {
216 let mut handle = 0;
217 unsafe {
218 FMOD_System_RegisterCodec(self.inner.as_ptr(), description, &raw mut handle, priority)
219 .to_result()?;
220 }
221 Ok(handle)
222 }
223
224 /// Register a DSP plugin description structure for later use.
225 ///
226 /// To create an instances of this plugin use `System::createDSPByPlugin`.
227 ///
228 /// # Safety
229 ///
230 /// This function provides no gaurdrails or safe API for registering a plugin.
231 /// It can call into non-rust external code.
232 /// Dsp descriptions are intended to be retrieved from a plugin's C API, so it's not feasible to provide a safe API for this function.
233 pub unsafe fn register_plugin(
234 &self,
235 dsp_description: *mut FMOD_DSP_DESCRIPTION,
236 ) -> Result<c_uint> {
237 let mut handle = 0;
238 unsafe {
239 FMOD_System_RegisterDSP(self.inner.as_ptr(), dsp_description, &raw mut handle)
240 .to_result()?;
241 }
242 Ok(handle)
243 }
244
245 /// Register an Output plugin description structure for later use.
246 ///
247 /// To select this plugin for output use `System::setOutputByPlugin`.
248 ///
249 /// # Safety
250 ///
251 /// This function provides no gaurdrails or safe API for registering an output.
252 /// It can call into non-rust external code.
253 /// Output descriptions are intended to be retrieved from a plugin's C API, so it's not feasible to provide a safe API for this function.
254 pub unsafe fn register_output(
255 &self,
256 description: *mut FMOD_OUTPUT_DESCRIPTION,
257 ) -> Result<c_uint> {
258 let mut handle = 0;
259 unsafe {
260 FMOD_System_RegisterOutput(self.inner.as_ptr(), description, &raw mut handle)
261 .to_result()?;
262 }
263 Ok(handle)
264 }
265}