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}