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}