This commit is contained in:
Crizomb 2025-06-10 17:40:16 +02:00
commit f698a38c7e
585 changed files with 118338 additions and 0 deletions

View file

@ -0,0 +1,133 @@
/*===============================================================================================
Raw Codec Plugin Example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2025.
This example shows how to create a codec that reads raw PCM data.
1. The codec can be compiled as a DLL, using the reserved function name 'FMODGetCodecDescription'
as the only export symbol, and at runtime, the dll can be loaded in with System::loadPlugin.
2. Alternatively a codec of this type can be compiled directly into the program that uses it, and
you just register the codec into FMOD with System::registerCodec. This puts the codec into
the FMOD system, just the same way System::loadPlugin would if it was an external file.
3. The 'open' callback is the first thing called, and FMOD already has a file handle open for it.
In the open callback you can use FMOD_CODEC_STATE::fileread / FMOD_CODEC_STATE::fileseek to parse
your own file format, and return FMOD_ERR_FORMAT if it is not the format you support. Return
FMOD_OK if it succeeds your format test.
4. When an FMOD user calls System::createSound or System::createStream, the 'open' callback is called
once after FMOD tries to open it as many other types of file. If you want to override FMOD's
internal codecs then use the 'priority' parameter of System::loadPlugin or System::registerCodec.
5. In the open callback, tell FMOD what sort of PCM format the sound will produce with the
FMOD_CODEC_STATE::waveformat member.
6. The 'close' callback is called when Sound::release is called by the FMOD user.
7. The 'read' callback is called when System::createSound or System::createStream wants to receive
PCM data, in the format that you specified with FMOD_CODEC_STATE::waveformat. Data is
interleaved as decribed in the terminology section of the FMOD API documentation.
When a stream is being used, the read callback will be called repeatedly, using a size value
determined by the decode buffer size of the stream. See FMOD_CREATESOUNDEXINFO or
FMOD_ADVANCEDSETTINGS.
8. The 'seek' callback is called when Channel::setPosition is called, or when looping a sound
when it is a stream.
===============================================================================================*/
#include <stdio.h>
#include "fmod.h"
FMOD_RESULT F_CALL rawopen(FMOD_CODEC_STATE *codec, FMOD_MODE usermode, FMOD_CREATESOUNDEXINFO *userexinfo);
FMOD_RESULT F_CALL rawclose(FMOD_CODEC_STATE *codec);
FMOD_RESULT F_CALL rawread(FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read);
FMOD_RESULT F_CALL rawsetposition(FMOD_CODEC_STATE *codec, int subsound, unsigned int position, FMOD_TIMEUNIT postype);
FMOD_CODEC_DESCRIPTION rawcodec =
{
FMOD_CODEC_PLUGIN_VERSION, // Plugin version.
"FMOD Raw player plugin example", // Name.
0x00010000, // Version 0xAAAABBBB A = major, B = minor.
0, // Don't force everything using this codec to be a stream
FMOD_TIMEUNIT_PCMBYTES, // The time format we would like to accept into setposition/getposition.
&rawopen, // Open callback.
&rawclose, // Close callback.
&rawread, // Read callback.
0, // Getlength callback. (If not specified FMOD return the length in FMOD_TIMEUNIT_PCM, FMOD_TIMEUNIT_MS or FMOD_TIMEUNIT_PCMBYTES units based on the lengthpcm member of the FMOD_CODEC structure).
&rawsetposition, // Setposition callback.
0, // Getposition callback. (only used for timeunit types that are not FMOD_TIMEUNIT_PCM, FMOD_TIMEUNIT_MS and FMOD_TIMEUNIT_PCMBYTES).
0 // Sound create callback (don't need it)
};
/*
FMODGetCodecDescription is mandatory for every fmod plugin. This is the symbol the registerplugin function searches for.
Must be declared with F_CALL to make it export as stdcall.
MUST BE EXTERN'ED AS C! C++ functions will be mangled incorrectly and not load in fmod.
*/
#ifdef __cplusplus
extern "C" {
#endif
F_EXPORT FMOD_CODEC_DESCRIPTION * F_CALL FMODGetCodecDescription()
{
return &rawcodec;
}
#ifdef __cplusplus
}
#endif
static FMOD_CODEC_WAVEFORMAT rawwaveformat;
/*
The actual codec code.
Note that the callbacks uses FMOD's supplied file system callbacks.
This is important as even though you might want to open the file yourself, you would lose the following benefits.
1. Automatic support of memory files, CDDA based files, and HTTP/TCPIP based files.
2. "fileoffset" / "length" support when user calls System::createSound with FMOD_CREATESOUNDEXINFO structure.
3. Buffered file access.
FMOD files are high level abstracts that support all sorts of 'file', they are not just disk file handles.
If you want FMOD to use your own filesystem (and potentially lose the above benefits) use System::setFileSystem.
*/
FMOD_RESULT F_CALL rawopen(FMOD_CODEC_STATE *codec, FMOD_MODE /*usermode*/, FMOD_CREATESOUNDEXINFO * /*userexinfo*/)
{
rawwaveformat.channels = 2;
rawwaveformat.format = FMOD_SOUND_FORMAT_PCM16;
rawwaveformat.frequency = 44100;
rawwaveformat.pcmblocksize = 0;
unsigned int size;
FMOD_CODEC_FILE_SIZE(codec, &size);
rawwaveformat.lengthpcm = size / (rawwaveformat.channels * sizeof(short)); /* bytes converted to PCM samples */;
codec->numsubsounds = 0; /* number of 'subsounds' in this sound. For most codecs this is 0, only multi sound codecs such as FSB or CDDA have subsounds. */
codec->waveformat = &rawwaveformat;
codec->plugindata = 0; /* user data value */
/* If your file format needs to read data to determine the format and load metadata, do so here with codec->fileread/fileseek function pointers. This will handle reading from disk/memory or internet. */
return FMOD_OK;
}
FMOD_RESULT F_CALL rawclose(FMOD_CODEC_STATE * /*codec*/)
{
return FMOD_OK;
}
FMOD_RESULT F_CALL rawread(FMOD_CODEC_STATE *codec, void *buffer, unsigned int size, unsigned int *read)
{
return FMOD_CODEC_FILE_READ(codec, buffer, size, read);
}
FMOD_RESULT F_CALL rawsetposition(FMOD_CODEC_STATE *codec, int /*subsound*/, unsigned int position, FMOD_TIMEUNIT /*postype*/)
{
return FMOD_CODEC_FILE_SEEK(codec, position, 0);
}

View file

@ -0,0 +1,466 @@
/*==============================================================================
Distance Filter DSP Plugin Example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2025.
This example shows how to create a distance filter DSP effect.
==============================================================================*/
#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "fmod.hpp"
extern "C"
{
F_EXPORT FMOD_DSP_DESCRIPTION* F_CALL FMODGetDSPDescription();
}
const float FMOD_DISTANCE_FILTER_PARAM_MAX_DISTANCE_MIN = 0.0f;
const float FMOD_DISTANCE_FILTER_PARAM_MAX_DISTANCE_MAX = 10000.0f;
const float FMOD_DISTANCE_FILTER_PARAM_MAX_DISTANCE_DEFAULT = 20.0f;
const float FMOD_DISTANCE_FILTER_PARAM_BANDPASS_FREQUENCY_MIN = 10.0f;
const float FMOD_DISTANCE_FILTER_PARAM_BANDPASS_FREQUENCY_MAX = 22000.0f;
const float FMOD_DISTANCE_FILTER_PARAM_BANDPASS_FREQUENCY_DEFAULT = 1500.0f;
enum
{
FMOD_DISTANCE_FILTER_MAX_DISTANCE,
FMOD_DISTANCE_FILTER_BANDPASS_FREQUENCY,
FMOD_DISTANCE_FILTER_3D_ATTRIBUTES,
FMOD_DISTANCE_FILTER_NUM_PARAMETERS
};
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspcreate (FMOD_DSP_STATE *dsp_state);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dsprelease (FMOD_DSP_STATE *dsp_state);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspreset (FMOD_DSP_STATE *dsp_state);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspread (FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspprocess (FMOD_DSP_STATE *dsp_state, unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inbufferarray, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL inputsidle, FMOD_DSP_PROCESS_OPERATION op);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspsetparamfloat(FMOD_DSP_STATE *dsp_state, int index, float value);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspsetparamint (FMOD_DSP_STATE *dsp_state, int index, int value);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspsetparambool (FMOD_DSP_STATE *dsp_state, int index, FMOD_BOOL value);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspsetparamdata (FMOD_DSP_STATE *dsp_state, int index, void *data, unsigned int length);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspgetparamfloat(FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspgetparamint (FMOD_DSP_STATE *dsp_state, int index, int *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspgetparambool (FMOD_DSP_STATE *dsp_state, int index, FMOD_BOOL *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspgetparamdata (FMOD_DSP_STATE *dsp_state, int index, void **value, unsigned int *length, char *valuestr);
FMOD_RESULT F_CALL FMOD_DistanceFilter_shouldiprocess (FMOD_DSP_STATE *dsp_state, FMOD_BOOL inputsidle, unsigned int length, FMOD_CHANNELMASK inmask, int inchannels, FMOD_SPEAKERMODE speakermode);
static FMOD_DSP_PARAMETER_DESC p_max_distance;
static FMOD_DSP_PARAMETER_DESC p_bandpass_frequency;
static FMOD_DSP_PARAMETER_DESC p_3d_attributes;
FMOD_DSP_PARAMETER_DESC *FMOD_DistanceFilter_dspparam[FMOD_DISTANCE_FILTER_NUM_PARAMETERS] =
{
&p_max_distance,
&p_bandpass_frequency,
&p_3d_attributes
};
FMOD_DSP_DESCRIPTION FMOD_DistanceFilter_Desc =
{
FMOD_PLUGIN_SDK_VERSION,
"FMOD Distance Filter", // name
0x00010000, // plugin version
1, // number of input buffers to process
1, // number of output buffers to process
FMOD_DistanceFilter_dspcreate,
FMOD_DistanceFilter_dsprelease,
FMOD_DistanceFilter_dspreset,
FMOD_DistanceFilter_dspread,
0, // FMOD_DistanceFilter_dspprocess, // *** declare this callback instead of FMOD_DistanceFilter_dspread if the plugin sets the output channel count ***
0,
FMOD_DISTANCE_FILTER_NUM_PARAMETERS,
FMOD_DistanceFilter_dspparam,
FMOD_DistanceFilter_dspsetparamfloat,
0, // FMOD_DistanceFilter_dspsetparamint,
0, // FMOD_DistanceFilter_dspsetparambool,
FMOD_DistanceFilter_dspsetparamdata,
FMOD_DistanceFilter_dspgetparamfloat,
0, // FMOD_DistanceFilter_dspgetparamint,
0, // FMOD_DistanceFilter_dspgetparambool,
FMOD_DistanceFilter_dspgetparamdata,
FMOD_DistanceFilter_shouldiprocess,
0, // userdata
0, // sys_register
0, // sys_deregister
0 // sys_mix
};
extern "C"
{
F_EXPORT FMOD_DSP_DESCRIPTION* F_CALL FMODGetDSPDescription()
{
static float distance_mapping_values[] = { 0, 1, 5, 20, 100, 500, 10000 };
static float distance_mapping_scale[] = { 0, 1, 2, 3, 4, 4.5, 5 };
FMOD_DSP_INIT_PARAMDESC_FLOAT_WITH_MAPPING(p_max_distance, "Max Dist", "", "Distance at which bandpass stops narrowing. 0 to 1000000000. Default = 100", FMOD_DISTANCE_FILTER_PARAM_MAX_DISTANCE_DEFAULT, distance_mapping_values, distance_mapping_scale);
FMOD_DSP_INIT_PARAMDESC_FLOAT(p_bandpass_frequency, "Frequency", "Hz", "Bandpass target frequency. 100 to 10,000Hz. Default = 2000Hz", FMOD_DISTANCE_FILTER_PARAM_BANDPASS_FREQUENCY_MIN, FMOD_DISTANCE_FILTER_PARAM_BANDPASS_FREQUENCY_MAX, FMOD_DISTANCE_FILTER_PARAM_BANDPASS_FREQUENCY_DEFAULT);
FMOD_DSP_INIT_PARAMDESC_DATA(p_3d_attributes, "3D Attributes", "", "", FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES);
return &FMOD_DistanceFilter_Desc;
}
}
class FMODDistanceFilterState
{
public:
FMODDistanceFilterState() { }
void init (FMOD_DSP_STATE *dsp_state);
void release (FMOD_DSP_STATE *dsp_state);
FMOD_RESULT process (float *inbuffer, float *outbuffer, unsigned int length, int channels);
FMOD_RESULT process (unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inbufferarray, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL inputsidle, FMOD_DSP_PROCESS_OPERATION op);
void reset ();
void setMaxDistance (float);
void setBandpassFrequency(float);
void setDistance (float);
float maxDistance () const { return m_max_distance; }
float bandpassFrequency () const { return m_bandpass_frequency; }
private:
void updateTimeConstants ();
float m_max_distance;
float m_bandpass_frequency;
float m_distance;
float m_target_highpass_time_const;
float m_current_highpass_time_const;
float m_target_lowpass_time_const;
float m_current_lowpass_time_const;
int m_ramp_samples_left;
float *m_previous_lp1_out;
float *m_previous_lp2_out;
float *m_previous_hp_out;
int m_sample_rate;
int m_max_channels;
};
void FMODDistanceFilterState::init(FMOD_DSP_STATE *dsp_state)
{
FMOD_DSP_GETSAMPLERATE(dsp_state, &m_sample_rate);
m_max_channels = 8;
m_max_distance = FMOD_DISTANCE_FILTER_PARAM_MAX_DISTANCE_DEFAULT;
m_bandpass_frequency = FMOD_DISTANCE_FILTER_PARAM_BANDPASS_FREQUENCY_DEFAULT;
m_distance = 0;
m_previous_lp1_out = (float*)FMOD_DSP_ALLOC(dsp_state, m_max_channels * sizeof(float));
m_previous_lp2_out = (float*)FMOD_DSP_ALLOC(dsp_state, m_max_channels * sizeof(float));
m_previous_hp_out = (float*)FMOD_DSP_ALLOC(dsp_state, m_max_channels * sizeof(float));
updateTimeConstants();
reset();
}
void FMODDistanceFilterState::release(FMOD_DSP_STATE *dsp_state)
{
FMOD_DSP_FREE(dsp_state, m_previous_lp1_out);
FMOD_DSP_FREE(dsp_state, m_previous_lp2_out);
FMOD_DSP_FREE(dsp_state, m_previous_hp_out);
}
FMOD_RESULT FMODDistanceFilterState::process(float *inbuffer, float *outbuffer, unsigned int length, int channels)
{
if(channels > m_max_channels)
{
return FMOD_ERR_INVALID_PARAM;
}
// Note: buffers are interleaved
static float jitter = (float)1E-20;
float lp1_out, lp2_out;
int ch;
float lp_tc = m_current_lowpass_time_const;
float hp_tc = m_current_highpass_time_const;
if (m_ramp_samples_left)
{
float lp_delta = (m_target_lowpass_time_const - m_current_lowpass_time_const) / m_ramp_samples_left;
float hp_delta = (m_target_highpass_time_const - m_current_highpass_time_const) / m_ramp_samples_left;
while (length)
{
if (--m_ramp_samples_left)
{
lp_tc += lp_delta;
hp_tc += hp_delta;
for (ch = 0; ch < channels; ++ch)
{
lp1_out = m_previous_lp1_out[ch] + lp_tc * (*inbuffer++ + jitter - m_previous_lp1_out[ch]);
lp2_out = m_previous_lp2_out[ch] + lp_tc * (lp1_out - m_previous_lp2_out[ch]);
*outbuffer = hp_tc * (m_previous_hp_out[ch] + lp2_out - m_previous_lp2_out[ch]);
m_previous_lp1_out[ch] = lp1_out;
m_previous_lp2_out[ch] = lp2_out;
m_previous_hp_out[ch] = *outbuffer++;
}
jitter = -jitter;
}
else
{
lp_tc = m_target_lowpass_time_const;
hp_tc = m_target_highpass_time_const;
break;
}
--length;
}
}
while (length--)
{
for (ch = 0; ch < channels; ++ch)
{
lp1_out = m_previous_lp1_out[ch] + lp_tc * (*inbuffer++ + jitter - m_previous_lp1_out[ch]);
lp2_out = m_previous_lp2_out[ch] + lp_tc * (lp1_out - m_previous_lp2_out[ch]);
*outbuffer = hp_tc * (m_previous_hp_out[ch] + lp2_out - m_previous_lp2_out[ch]);
m_previous_lp1_out[ch] = lp1_out;
m_previous_lp2_out[ch] = lp2_out;
m_previous_hp_out[ch] = *outbuffer++;
}
jitter = -jitter;
}
m_current_lowpass_time_const = lp_tc;
m_current_highpass_time_const = hp_tc;
return FMOD_OK;
}
FMOD_RESULT FMODDistanceFilterState::process(unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inbufferarray, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL inputsidle, FMOD_DSP_PROCESS_OPERATION op)
{
if (op == FMOD_DSP_PROCESS_QUERY)
{
FMOD_SPEAKERMODE outmode;
int outchannels;
#if 1 // For stereo output
{
outmode = FMOD_SPEAKERMODE_STEREO;
outchannels = 2;
}
#else // For 5.1 output
{
outmode = FMOD_SPEAKERMODE_5POINT1;
outchannels = 6;
}
#endif
if (outbufferarray)
{
outbufferarray->speakermode = outmode;
outbufferarray->buffernumchannels[0] = outchannels;
}
if (inputsidle)
{
return FMOD_ERR_DSP_DONTPROCESS;
}
return FMOD_OK;
}
// Do processing here
float *inbuffer = inbufferarray->buffers[0];
float *outbuffer = outbufferarray->buffers[0];
int inchannels = inbufferarray->buffernumchannels[0];
int outchannels = outbufferarray->buffernumchannels[0];
while(length--)
{
// MAIN DSP LOOP...
}
return FMOD_OK;
}
void FMODDistanceFilterState::reset()
{
m_current_lowpass_time_const = m_target_lowpass_time_const;
m_current_highpass_time_const = m_target_highpass_time_const;
m_ramp_samples_left = 0;
memset(m_previous_lp1_out, 0, m_max_channels * sizeof(float));
memset(m_previous_lp2_out, 0, m_max_channels * sizeof(float));
memset(m_previous_hp_out, 0, m_max_channels * sizeof(float));
}
void FMODDistanceFilterState::setMaxDistance(float distance)
{
m_max_distance = distance;
updateTimeConstants();
}
void FMODDistanceFilterState::setBandpassFrequency(float frequency)
{
m_bandpass_frequency = frequency;
updateTimeConstants();
}
void FMODDistanceFilterState::setDistance(float distance)
{
m_distance = distance;
updateTimeConstants();
}
void FMODDistanceFilterState::updateTimeConstants()
{
#define PI (3.14159265358979323846f)
#define MIN_CUTOFF (10.0f)
#define MAX_CUTOFF (22000.0f)
float dist_factor = m_distance >= m_max_distance ? 1.0f : m_distance / m_max_distance;
float lp_cutoff = m_bandpass_frequency + (1.0f - dist_factor) * (1.0f - dist_factor) * (MAX_CUTOFF - m_bandpass_frequency);
float hp_cutoff = MIN_CUTOFF + dist_factor * dist_factor * (m_bandpass_frequency - MIN_CUTOFF);
float dt = 1.0f / m_sample_rate;
float threshold = m_sample_rate / PI;
if (lp_cutoff >= MAX_CUTOFF)
{
m_target_lowpass_time_const = 1.0f;
}
else if (lp_cutoff <= threshold)
{
float RC = 1.0f / (2.0f * PI * lp_cutoff);
m_target_lowpass_time_const = dt / (RC + dt);
}
else
{
m_target_lowpass_time_const = 0.666666667f + (lp_cutoff - threshold) / (3.0f * (MAX_CUTOFF - threshold));
}
if (hp_cutoff >= MAX_CUTOFF)
{
m_target_highpass_time_const = 0.0f;
}
else if (hp_cutoff <= threshold)
{
float RC = 1.0f / (2.0f * PI * hp_cutoff);
m_target_highpass_time_const = RC / (RC + dt);
}
else
{
m_target_highpass_time_const = (MAX_CUTOFF - hp_cutoff) / (3.0f * (MAX_CUTOFF - threshold));
}
m_ramp_samples_left = 256;
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspcreate(FMOD_DSP_STATE *dsp_state)
{
FMODDistanceFilterState* state = (FMODDistanceFilterState *)FMOD_DSP_ALLOC(dsp_state, sizeof(FMODDistanceFilterState));
state->init(dsp_state);
dsp_state->plugindata = state;
if (!state)
{
return FMOD_ERR_MEMORY;
}
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dsprelease(FMOD_DSP_STATE *dsp_state)
{
FMODDistanceFilterState *state = (FMODDistanceFilterState *)dsp_state->plugindata;
state->release(dsp_state);
FMOD_DSP_FREE(dsp_state, state);
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspread(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int * /*outchannels*/)
{
FMODDistanceFilterState *state = (FMODDistanceFilterState *)dsp_state->plugindata;
return state->process(inbuffer, outbuffer, length, inchannels); // input and output channels count match for this effect
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspprocess(FMOD_DSP_STATE *dsp_state, unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inbufferarray, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL inputsidle, FMOD_DSP_PROCESS_OPERATION op)
{
FMODDistanceFilterState *state = (FMODDistanceFilterState *)dsp_state->plugindata;
return state->process(length, inbufferarray, outbufferarray, inputsidle, op); // as an example for plugins which set the output channel count
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspreset(FMOD_DSP_STATE *dsp_state)
{
FMODDistanceFilterState *state = (FMODDistanceFilterState *)dsp_state->plugindata;
state->reset();
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspsetparamfloat(FMOD_DSP_STATE *dsp_state, int index, float value)
{
FMODDistanceFilterState *state = (FMODDistanceFilterState *)dsp_state->plugindata;
switch (index)
{
case FMOD_DISTANCE_FILTER_MAX_DISTANCE:
state->setMaxDistance(value);
return FMOD_OK;
case FMOD_DISTANCE_FILTER_BANDPASS_FREQUENCY:
state->setBandpassFrequency(value);
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspgetparamfloat(FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr)
{
FMODDistanceFilterState *state = (FMODDistanceFilterState *)dsp_state->plugindata;
switch (index)
{
case FMOD_DISTANCE_FILTER_MAX_DISTANCE:
*value = state->maxDistance();
if (valuestr) snprintf(valuestr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%.1f", state->maxDistance());
return FMOD_OK;
case FMOD_DISTANCE_FILTER_BANDPASS_FREQUENCY:
*value = state->bandpassFrequency();
if (valuestr) snprintf(valuestr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%.1f Hz", state->bandpassFrequency());
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspsetparamdata(FMOD_DSP_STATE *dsp_state, int index, void *data, unsigned int /*length*/)
{
FMODDistanceFilterState *state = (FMODDistanceFilterState *)dsp_state->plugindata;
switch (index)
{
case FMOD_DISTANCE_FILTER_3D_ATTRIBUTES:
FMOD_DSP_PARAMETER_3DATTRIBUTES* param = (FMOD_DSP_PARAMETER_3DATTRIBUTES*)data;
state->setDistance(sqrtf(param->relative.position.x * param->relative.position.x + param->relative.position.y * param->relative.position.y + param->relative.position.z * param->relative.position.z));
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_dspgetparamdata(FMOD_DSP_STATE * /*dsp_state*/, int index, void ** /*value*/, unsigned int * /*length*/, char * /*valuestr*/)
{
switch (index)
{
case FMOD_DISTANCE_FILTER_3D_ATTRIBUTES:
return FMOD_ERR_INVALID_PARAM;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_DistanceFilter_shouldiprocess(FMOD_DSP_STATE * /*dsp_state*/, FMOD_BOOL inputsidle, unsigned int /*length*/, FMOD_CHANNELMASK /*inmask*/, int /*inchannels*/, FMOD_SPEAKERMODE /*speakermode*/)
{
if (inputsidle)
{
return FMOD_ERR_DSP_DONTPROCESS;
}
return FMOD_OK;
}

View file

@ -0,0 +1,360 @@
/*==============================================================================
Gain DSP Plugin Example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2025.
This example shows how to create a simple gain DSP effect.
==============================================================================*/
#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "fmod.hpp"
#define FMOD_GAIN_USEPROCESSCALLBACK /* FMOD plugins have 2 methods of processing data.
1. via a 'read' callback which is compatible with FMOD Ex but limited in functionality, or
2. via a 'process' callback which exposes more functionality, like masks and query before process early out logic. */
extern "C" {
F_EXPORT FMOD_DSP_DESCRIPTION* F_CALL FMODGetDSPDescription();
}
const float FMOD_GAIN_PARAM_GAIN_MIN = -80.0f;
const float FMOD_GAIN_PARAM_GAIN_MAX = 10.0f;
const float FMOD_GAIN_PARAM_GAIN_DEFAULT = 0.0f;
#define FMOD_GAIN_RAMPCOUNT 256
enum
{
FMOD_GAIN_PARAM_GAIN = 0,
FMOD_GAIN_PARAM_INVERT,
FMOD_GAIN_NUM_PARAMETERS
};
#define DECIBELS_TO_LINEAR(__dbval__) ((__dbval__ <= FMOD_GAIN_PARAM_GAIN_MIN) ? 0.0f : powf(10.0f, __dbval__ / 20.0f))
#define LINEAR_TO_DECIBELS(__linval__) ((__linval__ <= 0.0f) ? FMOD_GAIN_PARAM_GAIN_MIN : 20.0f * log10f((float)__linval__))
FMOD_RESULT F_CALL FMOD_Gain_dspcreate (FMOD_DSP_STATE *dsp_state);
FMOD_RESULT F_CALL FMOD_Gain_dsprelease (FMOD_DSP_STATE *dsp_state);
FMOD_RESULT F_CALL FMOD_Gain_dspreset (FMOD_DSP_STATE *dsp_state);
#ifdef FMOD_GAIN_USEPROCESSCALLBACK
FMOD_RESULT F_CALL FMOD_Gain_dspprocess (FMOD_DSP_STATE *dsp_state, unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inbufferarray, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL inputsidle, FMOD_DSP_PROCESS_OPERATION op);
#else
FMOD_RESULT F_CALL FMOD_Gain_dspread (FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
#endif
FMOD_RESULT F_CALL FMOD_Gain_dspsetparamfloat(FMOD_DSP_STATE *dsp_state, int index, float value);
FMOD_RESULT F_CALL FMOD_Gain_dspsetparamint (FMOD_DSP_STATE *dsp_state, int index, int value);
FMOD_RESULT F_CALL FMOD_Gain_dspsetparambool (FMOD_DSP_STATE *dsp_state, int index, FMOD_BOOL value);
FMOD_RESULT F_CALL FMOD_Gain_dspsetparamdata (FMOD_DSP_STATE *dsp_state, int index, void *data, unsigned int length);
FMOD_RESULT F_CALL FMOD_Gain_dspgetparamfloat(FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_Gain_dspgetparamint (FMOD_DSP_STATE *dsp_state, int index, int *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_Gain_dspgetparambool (FMOD_DSP_STATE *dsp_state, int index, FMOD_BOOL *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_Gain_dspgetparamdata (FMOD_DSP_STATE *dsp_state, int index, void **value, unsigned int *length, char *valuestr);
FMOD_RESULT F_CALL FMOD_Gain_shouldiprocess (FMOD_DSP_STATE *dsp_state, FMOD_BOOL inputsidle, unsigned int length, FMOD_CHANNELMASK inmask, int inchannels, FMOD_SPEAKERMODE speakermode);
FMOD_RESULT F_CALL FMOD_Gain_sys_register (FMOD_DSP_STATE *dsp_state);
FMOD_RESULT F_CALL FMOD_Gain_sys_deregister (FMOD_DSP_STATE *dsp_state);
FMOD_RESULT F_CALL FMOD_Gain_sys_mix (FMOD_DSP_STATE *dsp_state, int stage);
static bool FMOD_Gain_Running = false;
static FMOD_DSP_PARAMETER_DESC p_gain;
static FMOD_DSP_PARAMETER_DESC p_invert;
FMOD_DSP_PARAMETER_DESC *FMOD_Gain_dspparam[FMOD_GAIN_NUM_PARAMETERS] =
{
&p_gain,
&p_invert
};
FMOD_DSP_DESCRIPTION FMOD_Gain_Desc =
{
FMOD_PLUGIN_SDK_VERSION,
"FMOD Gain", // name
0x00010000, // plug-in version
1, // number of input buffers to process
1, // number of output buffers to process
FMOD_Gain_dspcreate,
FMOD_Gain_dsprelease,
FMOD_Gain_dspreset,
#ifndef FMOD_GAIN_USEPROCESSCALLBACK
FMOD_Gain_dspread,
#else
0,
#endif
#ifdef FMOD_GAIN_USEPROCESSCALLBACK
FMOD_Gain_dspprocess,
#else
0,
#endif
0,
FMOD_GAIN_NUM_PARAMETERS,
FMOD_Gain_dspparam,
FMOD_Gain_dspsetparamfloat,
0, // FMOD_Gain_dspsetparamint,
FMOD_Gain_dspsetparambool,
0, // FMOD_Gain_dspsetparamdata,
FMOD_Gain_dspgetparamfloat,
0, // FMOD_Gain_dspgetparamint,
FMOD_Gain_dspgetparambool,
0, // FMOD_Gain_dspgetparamdata,
FMOD_Gain_shouldiprocess,
0, // userdata
FMOD_Gain_sys_register,
FMOD_Gain_sys_deregister,
FMOD_Gain_sys_mix
};
extern "C"
{
F_EXPORT FMOD_DSP_DESCRIPTION* F_CALL FMODGetDSPDescription()
{
static float gain_mapping_values[] = { -80, -50, -30, -10, 10 };
static float gain_mapping_scale[] = { 0, 2, 4, 7, 11 };
FMOD_DSP_INIT_PARAMDESC_FLOAT_WITH_MAPPING(p_gain, "Gain", "dB", "Gain in dB. -80 to 10. Default = 0", FMOD_GAIN_PARAM_GAIN_DEFAULT, gain_mapping_values, gain_mapping_scale);
FMOD_DSP_INIT_PARAMDESC_BOOL(p_invert, "Invert", "", "Invert signal. Default = off", false, 0);
return &FMOD_Gain_Desc;
}
}
class FMODGainState
{
public:
FMODGainState();
void read(float *inbuffer, float *outbuffer, unsigned int length, int channels);
void reset();
void setGain(float);
void setInvert(bool);
float gain() const { return LINEAR_TO_DECIBELS(m_invert ? -m_target_gain : m_target_gain); }
FMOD_BOOL invert() const { return m_invert; }
private:
float m_target_gain;
float m_current_gain;
int m_ramp_samples_left;
bool m_invert;
};
FMODGainState::FMODGainState()
{
m_target_gain = DECIBELS_TO_LINEAR(FMOD_GAIN_PARAM_GAIN_DEFAULT);
m_invert = 0;
reset();
}
void FMODGainState::read(float *inbuffer, float *outbuffer, unsigned int length, int channels)
{
// Note: buffers are interleaved
float gain = m_current_gain;
if (m_ramp_samples_left)
{
float target = m_target_gain;
float delta = (target - gain) / m_ramp_samples_left;
while (length)
{
if (--m_ramp_samples_left)
{
gain += delta;
for (int i = 0; i < channels; ++i)
{
*outbuffer++ = *inbuffer++ * gain;
}
}
else
{
gain = target;
break;
}
--length;
}
}
unsigned int samples = length * channels;
while (samples--)
{
*outbuffer++ = *inbuffer++ * gain;
}
m_current_gain = gain;
}
void FMODGainState::reset()
{
m_current_gain = m_target_gain;
m_ramp_samples_left = 0;
}
void FMODGainState::setGain(float gain)
{
m_target_gain = m_invert ? -DECIBELS_TO_LINEAR(gain) : DECIBELS_TO_LINEAR(gain);
m_ramp_samples_left = FMOD_GAIN_RAMPCOUNT;
}
void FMODGainState::setInvert(bool invert)
{
if (invert != m_invert)
{
m_target_gain = -m_target_gain;
m_ramp_samples_left = FMOD_GAIN_RAMPCOUNT;
}
m_invert = invert;
}
FMOD_RESULT F_CALL FMOD_Gain_dspcreate(FMOD_DSP_STATE *dsp_state)
{
dsp_state->plugindata = (FMODGainState *)FMOD_DSP_ALLOC(dsp_state, sizeof(FMODGainState));
if (!dsp_state->plugindata)
{
return FMOD_ERR_MEMORY;
}
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Gain_dsprelease(FMOD_DSP_STATE *dsp_state)
{
FMODGainState *state = (FMODGainState *)dsp_state->plugindata;
FMOD_DSP_FREE(dsp_state, state);
return FMOD_OK;
}
#ifdef FMOD_GAIN_USEPROCESSCALLBACK
FMOD_RESULT F_CALL FMOD_Gain_dspprocess(FMOD_DSP_STATE *dsp_state, unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inbufferarray, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL inputsidle, FMOD_DSP_PROCESS_OPERATION op)
{
FMODGainState *state = (FMODGainState *)dsp_state->plugindata;
if (op == FMOD_DSP_PROCESS_QUERY)
{
if (outbufferarray && inbufferarray)
{
outbufferarray[0].buffernumchannels[0] = inbufferarray[0].buffernumchannels[0];
outbufferarray[0].speakermode = inbufferarray[0].speakermode;
}
if (inputsidle)
{
return FMOD_ERR_DSP_DONTPROCESS;
}
}
else
{
state->read(inbufferarray[0].buffers[0], outbufferarray[0].buffers[0], length, inbufferarray[0].buffernumchannels[0]); // input and output channels count match for this effect
}
return FMOD_OK;
}
#else
FMOD_RESULT F_CALL FMOD_Gain_dspread(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int * /*outchannels*/)
{
FMODGainState *state = (FMODGainState *)dsp_state->plugindata;
state->read(inbuffer, outbuffer, length, inchannels); // input and output channels count match for this effect
return FMOD_OK;
}
#endif
FMOD_RESULT F_CALL FMOD_Gain_dspreset(FMOD_DSP_STATE *dsp_state)
{
FMODGainState *state = (FMODGainState *)dsp_state->plugindata;
state->reset();
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Gain_dspsetparamfloat(FMOD_DSP_STATE *dsp_state, int index, float value)
{
FMODGainState *state = (FMODGainState *)dsp_state->plugindata;
switch (index)
{
case FMOD_GAIN_PARAM_GAIN:
state->setGain(value);
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_Gain_dspgetparamfloat(FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr)
{
FMODGainState *state = (FMODGainState *)dsp_state->plugindata;
switch (index)
{
case FMOD_GAIN_PARAM_GAIN:
*value = state->gain();
if (valuestr) snprintf(valuestr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%.1f dB", state->gain());
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_Gain_dspsetparambool(FMOD_DSP_STATE *dsp_state, int index, FMOD_BOOL value)
{
FMODGainState *state = (FMODGainState *)dsp_state->plugindata;
switch (index)
{
case FMOD_GAIN_PARAM_INVERT:
state->setInvert(value ? true : false);
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_Gain_dspgetparambool(FMOD_DSP_STATE *dsp_state, int index, FMOD_BOOL *value, char *valuestr)
{
FMODGainState *state = (FMODGainState *)dsp_state->plugindata;
switch (index)
{
case FMOD_GAIN_PARAM_INVERT:
*value = state->invert();
if (valuestr) snprintf(valuestr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, state->invert() ? "Inverted" : "Off" );
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_Gain_shouldiprocess(FMOD_DSP_STATE * /*dsp_state*/, FMOD_BOOL inputsidle, unsigned int /*length*/, FMOD_CHANNELMASK /*inmask*/, int /*inchannels*/, FMOD_SPEAKERMODE /*speakermode*/)
{
if (inputsidle)
{
return FMOD_ERR_DSP_DONTPROCESS;
}
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Gain_sys_register(FMOD_DSP_STATE * /*dsp_state*/)
{
FMOD_Gain_Running = true;
// called once for this type of dsp being loaded or registered (it is not per instance)
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Gain_sys_deregister(FMOD_DSP_STATE * /*dsp_state*/)
{
FMOD_Gain_Running = false;
// called once for this type of dsp being unloaded or de-registered (it is not per instance)
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Gain_sys_mix(FMOD_DSP_STATE * /*dsp_state*/, int /*stage*/)
{
// stage == 0 , before all dsps are processed/mixed, this callback is called once for this type.
// stage == 1 , after all dsps are processed/mixed, this callback is called once for this type.
return FMOD_OK;
}

View file

@ -0,0 +1,302 @@
/*==============================================================================
Plugin Example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2025.
This example shows how to created a plugin effect.
==============================================================================*/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "fmod.hpp"
extern "C" {
F_EXPORT FMOD_DSP_DESCRIPTION* F_CALL FMODGetDSPDescription();
}
const float FMOD_NOISE_PARAM_GAIN_MIN = -80.0f;
const float FMOD_NOISE_PARAM_GAIN_MAX = 10.0f;
const float FMOD_NOISE_PARAM_GAIN_DEFAULT = 0.0f;
#define FMOD_NOISE_RAMPCOUNT 256
enum
{
FMOD_NOISE_PARAM_LEVEL = 0,
FMOD_NOISE_PARAM_FORMAT,
FMOD_NOISE_NUM_PARAMETERS
};
enum FMOD_NOISE_FORMAT
{
FMOD_NOISE_FORMAT_MONO = 0,
FMOD_NOISE_FORMAT_STEREO,
FMOD_NOISE_FORMAT_5POINT1
};
#define DECIBELS_TO_LINEAR(__dbval__) ((__dbval__ <= FMOD_NOISE_PARAM_GAIN_MIN) ? 0.0f : powf(10.0f, __dbval__ / 20.0f))
#define LINEAR_TO_DECIBELS(__linval__) ((__linval__ <= 0.0f) ? FMOD_NOISE_PARAM_GAIN_MIN : 20.0f * log10f((float)__linval__))
FMOD_RESULT F_CALL FMOD_Noise_dspcreate (FMOD_DSP_STATE *dsp);
FMOD_RESULT F_CALL FMOD_Noise_dsprelease (FMOD_DSP_STATE *dsp);
FMOD_RESULT F_CALL FMOD_Noise_dspreset (FMOD_DSP_STATE *dsp);
FMOD_RESULT F_CALL FMOD_Noise_dspprocess (FMOD_DSP_STATE *dsp, unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inbufferarray, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL inputsidle, FMOD_DSP_PROCESS_OPERATION op);
FMOD_RESULT F_CALL FMOD_Noise_dspsetparamfloat(FMOD_DSP_STATE *dsp, int index, float value);
FMOD_RESULT F_CALL FMOD_Noise_dspsetparamint (FMOD_DSP_STATE *dsp, int index, int value);
FMOD_RESULT F_CALL FMOD_Noise_dspsetparambool (FMOD_DSP_STATE *dsp, int index, bool value);
FMOD_RESULT F_CALL FMOD_Noise_dspsetparamdata (FMOD_DSP_STATE *dsp, int index, void *data, unsigned int length);
FMOD_RESULT F_CALL FMOD_Noise_dspgetparamfloat(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_Noise_dspgetparamint (FMOD_DSP_STATE *dsp, int index, int *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_Noise_dspgetparambool (FMOD_DSP_STATE *dsp, int index, bool *value, char *valuestr);
FMOD_RESULT F_CALL FMOD_Noise_dspgetparamdata (FMOD_DSP_STATE *dsp, int index, void **value, unsigned int *length, char *valuestr);
static FMOD_DSP_PARAMETER_DESC p_level;
static FMOD_DSP_PARAMETER_DESC p_format;
FMOD_DSP_PARAMETER_DESC *FMOD_Noise_dspparam[FMOD_NOISE_NUM_PARAMETERS] =
{
&p_level,
&p_format
};
const char* FMOD_Noise_Format_Names[3] = {"Mono", "Stereo", "5.1"};
FMOD_DSP_DESCRIPTION FMOD_Noise_Desc =
{
FMOD_PLUGIN_SDK_VERSION,
"FMOD Noise", // name
0x00010000, // plug-in version
0, // number of input buffers to process
1, // number of output buffers to process
FMOD_Noise_dspcreate,
FMOD_Noise_dsprelease,
FMOD_Noise_dspreset,
0,
FMOD_Noise_dspprocess,
0,
FMOD_NOISE_NUM_PARAMETERS,
FMOD_Noise_dspparam,
FMOD_Noise_dspsetparamfloat,
FMOD_Noise_dspsetparamint,
0,
0,
FMOD_Noise_dspgetparamfloat,
FMOD_Noise_dspgetparamint,
0,
0,
0,
0, // userdata
0, // Register
0, // Deregister
0 // Mix
};
extern "C"
{
F_EXPORT FMOD_DSP_DESCRIPTION* F_CALL FMODGetDSPDescription()
{
FMOD_DSP_INIT_PARAMDESC_FLOAT(p_level, "Level", "dB", "Gain in dB. -80 to 10. Default = 0", FMOD_NOISE_PARAM_GAIN_MIN, FMOD_NOISE_PARAM_GAIN_MAX, FMOD_NOISE_PARAM_GAIN_DEFAULT);
FMOD_DSP_INIT_PARAMDESC_INT(p_format, "Format", "", "Mono, stereo or 5.1. Default = 0 (mono)", FMOD_NOISE_FORMAT_MONO, FMOD_NOISE_FORMAT_5POINT1, FMOD_NOISE_FORMAT_MONO, false, FMOD_Noise_Format_Names);
return &FMOD_Noise_Desc;
}
}
class FMODNoiseState
{
public:
FMODNoiseState();
void generate(float *outbuffer, unsigned int length, int channels);
void reset();
void setLevel(float);
void setFormat(FMOD_NOISE_FORMAT format) { m_format = format; }
float level() const { return LINEAR_TO_DECIBELS(m_target_level); }
FMOD_NOISE_FORMAT format() const { return m_format; }
private:
float m_target_level;
float m_current_level;
int m_ramp_samples_left;
FMOD_NOISE_FORMAT m_format;
};
FMODNoiseState::FMODNoiseState()
{
m_target_level = DECIBELS_TO_LINEAR(FMOD_NOISE_PARAM_GAIN_DEFAULT);
m_format = FMOD_NOISE_FORMAT_MONO;
reset();
}
void FMODNoiseState::generate(float *outbuffer, unsigned int length, int channels)
{
// Note: buffers are interleaved
float gain = m_current_level;
if (m_ramp_samples_left)
{
float target = m_target_level;
float delta = (target - gain) / m_ramp_samples_left;
while (length)
{
if (--m_ramp_samples_left)
{
gain += delta;
for (int i = 0; i < channels; ++i)
{
*outbuffer++ = (((float)(rand()%32768) / 16384.0f) - 1.0f) * gain;
}
}
else
{
gain = target;
break;
}
--length;
}
}
unsigned int samples = length * channels;
while (samples--)
{
*outbuffer++ = (((float)(rand()%32768) / 16384.0f) - 1.0f) * gain;
}
m_current_level = gain;
}
void FMODNoiseState::reset()
{
m_current_level = m_target_level;
m_ramp_samples_left = 0;
}
void FMODNoiseState::setLevel(float level)
{
m_target_level = DECIBELS_TO_LINEAR(level);
m_ramp_samples_left = FMOD_NOISE_RAMPCOUNT;
}
FMOD_RESULT F_CALL FMOD_Noise_dspcreate(FMOD_DSP_STATE *dsp)
{
dsp->plugindata = (FMODNoiseState *)FMOD_DSP_ALLOC(dsp, sizeof(FMODNoiseState));
if (!dsp->plugindata)
{
return FMOD_ERR_MEMORY;
}
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Noise_dsprelease(FMOD_DSP_STATE *dsp)
{
FMODNoiseState *state = (FMODNoiseState *)dsp->plugindata;
FMOD_DSP_FREE(dsp, state);
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Noise_dspprocess(FMOD_DSP_STATE *dsp, unsigned int length, const FMOD_DSP_BUFFER_ARRAY * /*inbufferarray*/, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL /*inputsidle*/, FMOD_DSP_PROCESS_OPERATION op)
{
FMODNoiseState *state = (FMODNoiseState *)dsp->plugindata;
if (op == FMOD_DSP_PROCESS_QUERY)
{
FMOD_SPEAKERMODE outmode = FMOD_SPEAKERMODE_DEFAULT;
int outchannels = 0;
switch(state->format())
{
case FMOD_NOISE_FORMAT_MONO:
outmode = FMOD_SPEAKERMODE_MONO;
outchannels = 1;
break;
case FMOD_NOISE_FORMAT_STEREO:
outmode = FMOD_SPEAKERMODE_STEREO;
outchannels = 2;
break;
case FMOD_NOISE_FORMAT_5POINT1:
outmode = FMOD_SPEAKERMODE_5POINT1;
outchannels = 6;
}
if (outbufferarray)
{
outbufferarray->speakermode = outmode;
outbufferarray->buffernumchannels[0] = outchannels;
}
return FMOD_OK;
}
state->generate(outbufferarray->buffers[0], length, outbufferarray->buffernumchannels[0]);
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Noise_dspreset(FMOD_DSP_STATE *dsp)
{
FMODNoiseState *state = (FMODNoiseState *)dsp->plugindata;
state->reset();
return FMOD_OK;
}
FMOD_RESULT F_CALL FMOD_Noise_dspsetparamfloat(FMOD_DSP_STATE *dsp, int index, float value)
{
FMODNoiseState *state = (FMODNoiseState *)dsp->plugindata;
switch (index)
{
case FMOD_NOISE_PARAM_LEVEL:
state->setLevel(value);
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_Noise_dspgetparamfloat(FMOD_DSP_STATE *dsp, int index, float *value, char *valuestr)
{
FMODNoiseState *state = (FMODNoiseState *)dsp->plugindata;
switch (index)
{
case FMOD_NOISE_PARAM_LEVEL:
*value = state->level();
if (valuestr) snprintf(valuestr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%.1f dB", state->level());
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_Noise_dspsetparamint(FMOD_DSP_STATE *dsp, int index, int value)
{
FMODNoiseState *state = (FMODNoiseState *)dsp->plugindata;
switch (index)
{
case FMOD_NOISE_PARAM_FORMAT:
state->setFormat((FMOD_NOISE_FORMAT)value);
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}
FMOD_RESULT F_CALL FMOD_Noise_dspgetparamint(FMOD_DSP_STATE *dsp, int index, int *value, char *valuestr)
{
FMODNoiseState *state = (FMODNoiseState *)dsp->plugindata;
switch (index)
{
case FMOD_NOISE_PARAM_FORMAT:
*value = state->format();
if (valuestr) snprintf(valuestr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%s", FMOD_Noise_Format_Names[state->format()]);
return FMOD_OK;
}
return FMOD_ERR_INVALID_PARAM;
}

View file

@ -0,0 +1,184 @@
/*==============================================================================
RNBO DSP Plugin Example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2025.
This example shows how to integrate RNBO C++ source code into an FMOD effect.
1. Add the rnbo and rnbo/common directories to your include paths.
2. Add the generated RNBO source .cpp file and rnbo/RNBO.cpp files to your list
of source files.
3. Build and copy the generated library into your FMOD Studio script directory:
https://fmod.com/docs/2.02/studio/plugin-reference.html#loading-plug-ins
==============================================================================*/
#if __has_include("RNBO.h")
#include "RNBO.h"
#include <math.h>
#include <stdio.h>
#include <atomic>
#include <string.h>
#include "fmod.hpp"
static FMOD_DSP_PARAMETER_DESC** params = nullptr;
static int numParams;
static int numInputs;
static int numOutputs;
static std::atomic<int> gSysCount = 0;
static FMOD_RESULT F_CALL FMOD_RNBO_Create(FMOD_DSP_STATE *dsp_state)
{
dsp_state->plugindata = FMOD_DSP_ALLOC(dsp_state, sizeof(RNBO::CoreObject));
if (!dsp_state->plugindata)
{
return FMOD_ERR_MEMORY;
}
RNBO::CoreObject *rnboObject = (RNBO::CoreObject *)dsp_state->plugindata;
int sampleRate;
unsigned int blockSize;
FMOD_DSP_GETSAMPLERATE(dsp_state, &sampleRate);
FMOD_DSP_GETBLOCKSIZE(dsp_state, &blockSize);
new (rnboObject) RNBO::CoreObject();
rnboObject->prepareToProcess(sampleRate, blockSize);
return FMOD_OK;
}
static FMOD_RESULT F_CALL FMOD_RNBO_Release(FMOD_DSP_STATE *dsp_state)
{
RNBO::CoreObject *rnboObject = (RNBO::CoreObject *)dsp_state->plugindata;
rnboObject->~CoreObject();
FMOD_DSP_FREE(dsp_state, rnboObject);
return FMOD_OK;
}
static FMOD_RESULT F_CALL FMOD_RNBO_Process(FMOD_DSP_STATE *dsp_state, unsigned int length, const FMOD_DSP_BUFFER_ARRAY *inbufferarray, FMOD_DSP_BUFFER_ARRAY *outbufferarray, FMOD_BOOL inputsidle, FMOD_DSP_PROCESS_OPERATION op)
{
RNBO::CoreObject *rnboObject = (RNBO::CoreObject *)dsp_state->plugindata;
if (op == FMOD_DSP_PROCESS_QUERY)
{
if (numInputs > 0)
{
if (inputsidle)
{
return FMOD_ERR_DSP_SILENCE;
}
}
else
{
if (outbufferarray && outbufferarray[0].buffernumchannels)
{
outbufferarray[0].buffernumchannels[0] = numOutputs;
}
}
}
else
{
rnboObject->process(inbufferarray[0].buffers[0], inbufferarray[0].buffernumchannels[0],
outbufferarray[0].buffers[0], outbufferarray[0].buffernumchannels[0], length);
}
return FMOD_OK;
}
static FMOD_RESULT F_CALL FMOD_RNBO_SetParamFloat(FMOD_DSP_STATE *dsp_state, int index, float value)
{
RNBO::CoreObject *rnboObject = (RNBO::CoreObject *)dsp_state->plugindata;
rnboObject->setParameterValue(index, value);
return FMOD_OK;
}
static FMOD_RESULT F_CALL FMOD_RNBO_GetParamFloat(FMOD_DSP_STATE *dsp_state, int index, float *value, char *valuestr)
{
RNBO::CoreObject *rnboObject = (RNBO::CoreObject *)dsp_state->plugindata;
*value = (float)rnboObject->getParameterValue(index);
if (valuestr) snprintf(valuestr, FMOD_DSP_GETPARAM_VALUESTR_LENGTH, "%s", rnboObject->getParameterName(index));
return FMOD_OK;
}
static FMOD_RESULT F_CALL FMOD_RNBO_SysRegister(FMOD_DSP_STATE* dsp_state)
{
RNBO::CoreObject* rnboObject = (RNBO::CoreObject*)dsp_state->plugindata;
gSysCount++;
return FMOD_OK;
}
static FMOD_RESULT F_CALL FMOD_RNBO_SysDeregister(FMOD_DSP_STATE* dsp_state)
{
RNBO::CoreObject* rnboObject = (RNBO::CoreObject*)dsp_state->plugindata;
gSysCount--;
if (gSysCount == 0)
{
for (int i = 0; i < numParams; ++i)
{
free(params[i]);
}
free(params);
params = nullptr;
}
return FMOD_OK;
}
extern "C" F_EXPORT FMOD_DSP_DESCRIPTION *F_CALL FMODGetDSPDescription()
{
static FMOD_DSP_DESCRIPTION desc = { FMOD_PLUGIN_SDK_VERSION, "FMOD RNBO", 0x00010000 };
desc.create = FMOD_RNBO_Create;
desc.release = FMOD_RNBO_Release;
desc.process = FMOD_RNBO_Process;
desc.setparameterfloat = FMOD_RNBO_SetParamFloat;
desc.getparameterfloat = FMOD_RNBO_GetParamFloat;
desc.sys_register = FMOD_RNBO_SysRegister;
desc.sys_deregister = FMOD_RNBO_SysDeregister;
if (!params)
{
RNBO::CoreObject tmpRnboObject;
numParams = tmpRnboObject.getNumParameters();
numInputs = tmpRnboObject.getNumInputChannels();
numOutputs = tmpRnboObject.getNumOutputChannels();
desc.numparameters = numParams;
desc.numinputbuffers = numInputs > 0;
desc.numoutputbuffers = numOutputs > 0;
params = (FMOD_DSP_PARAMETER_DESC**)malloc(desc.numparameters * sizeof(FMOD_DSP_PARAMETER_DESC*));
for (int i = 0; i < numParams; ++i)
{
RNBO::ParameterInfo info = {};
tmpRnboObject.getParameterInfo(i, &info);
params[i] = (FMOD_DSP_PARAMETER_DESC *)malloc(sizeof(FMOD_DSP_PARAMETER_DESC));
memset(params[i], 0, sizeof(FMOD_DSP_PARAMETER_DESC));
snprintf(params[i]->name, sizeof(params[i]->name), "%s", tmpRnboObject.getParameterId(i));
snprintf(params[i]->label, sizeof(params[i]->label), "%s", info.unit);
params[i]->type = FMOD_DSP_PARAMETER_TYPE_FLOAT;
params[i]->floatdesc.defaultval = info.initialValue;
params[i]->floatdesc.min = info.min;
params[i]->floatdesc.max = info.max;
}
desc.paramdesc = params;
}
return &desc;
}
#endif