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