您可以使用原生数字信号处理 (DSP) 插件来处理音频,并暴露参数供用户尝试音频效果。Unity 提供的示例插件非常适合试用插件和了解所需的参数。
要为 Unity 开发原生音频插件,请执行以下操作:
卸载插件。
要创建音频插件文件,请执行以下操作:
下载最新音频插件 SDK。
在该文件夹中,转到 NativeAudioPlugins > NativeCode。原生示例插件 .cpp 文件位于此处。
您可以复制其中一个插件 .cpp 文件,以便将其用作您自己的插件的模板,直接在其中一个示例插件文件(例如 Plugin_Equalizer.cpp)中工作,或创建您自己的 .cpp 文件。
在文件中包含 AudioPluginUtil.h(如果尚未包含)。
创建一个参数列表,供用户在使用插件时进行交互,这将非常实用。要将参数添加到插件中,请执行以下操作:
在插件 .cpp 文件中,将参数定义为枚举值。例如:
enum Param
{
P_FREQ, //Frequency parameter
P_MIX, //Mix parameter
P_NUM //An extra value to keep track of length of the enum
};
创建一个 UnityAudioParameterDefinitions 数组并将其大小设置为您拥有的参数数量:
int numparams = P_NUM;
definition.paramdefs = new UnityAudioParameterDefinition [numparams];
使用 RegisterParameter 函数注册每个枚举值。
int InternalRegisterEffectDefinition(UnityAudioEffectDefinition& definition)
{
int numparams = P_NUM;
definition.paramdefs = new UnityAudioParameterDefinition [numparams];
RegisterParameter(definition, "Frequency", "Hz",
0.0f, kMaxSampleRate, 1000.0f,
1.0f, 3.0f,
P_FREQ);
RegisterParameter(definition, "Mix amount", "%",
0.0f, 1.0f, 0.5f,
100.0f, 1.0f,
P_MIX);
return numparams;
}
下表概述了 RegisterParameter 函数、其参数以及在上方代码示例中的用法:
| 参数类型和名称 | 示例代码中的变量 | 描述 |
|---|---|---|
UnityAudioEffectDefinition definition |
definition |
UnityAudioEffectDefinition 结构包含 UnityAudioParameterDefinition 数组。RegisterParameter 函数将参数定义作为条目插入到此数组中。 |
char* name |
“Frequency”、“Mix Amount”
|
要为参数提供的显示名称。 |
char* unit |
“Hz”、“%”
|
值的类型。 |
float minval |
0.0f |
参数的最小值。 |
float maxval |
kMaxSampleRate、1.0f
|
参数的最大值。 |
float defaultval |
1000.0f、0.5f
|
参数的默认值和初始值。 |
float displayscale |
1.0f、100.0f
|
仅用于显示参数的缩放系数。例如,示例代码中的百分比具有最小值 0、最大值 1 和缩放系数 100.0f。这意味着,虽然实际值介于 0 和 1 之间,但在 Unity 中的 GUI 中显示的值介于 0% 和 100% 之间。 |
float displayexponent |
3.0f、1.0f
|
将参数映射到滑动条。 |
int enumvalue |
P_FREQ、P_MIX
|
要将这些值分配到的枚举值。 |
Unity 会从这些基本参数定义中生成默认 GUI。
要创建插件的实例,请使用 CreateCallback 函数。Unity 在创建插件后会立即调用 CreateCallback 函数。可为 null。
struct EffectData
{
struct Data
{
float p[P_NUM]; // Parameters
float s; // Sine output of oscillator
float c; // Cosine output of oscillator
};
union
{
Data data;
unsigned char pad[(sizeof(Data) + 15) & ~15];
};
};
UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK CreateCallback(
UnityAudioEffectState* state)
{
EffectData* effectdata = new EffectData;
memset(effectdata, 0, sizeof(EffectData));
effectdata->data.c = 1.0f;
state->effectdata = effectdata;
InitParametersFromDefinitions(
InternalRegisterEffectDefinition, effectdata->data.p);
return UNITY_AUDIODSP_OK;
}
UnityAudioEffectState 对象将存储从主机接收的数据,并将数据传递给所有回调函数。它存储的数据包括:
采样率
处理的样本总数(用于计时)
是否绕过插件
要释放插件实例,请使用 ReleaseCallback 函数。Unity 会在释放插件之前调用 ReleaseCallback 函数,还会释放与此插件特定实例关联的所有数据。此后,不再发生与此实例相关的回调。
UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ReleaseCallback(
UnityAudioEffectState* state)
{
EffectData::Data* data = &state->GetEffectData<EffectData>()->data;
delete data;
return UNITY_AUDIODSP_OK;
}
要解决音频处理,请使用 ProcessCallback 函数。Unity 将反复调用 ProcessCallback 函数,同时提供要读取的输入音频块和要写入的输出块。
以下代码提供了正弦波乘以所有声道的示例:
UNITY_AUDIODSP_RESULT UNITY_AUDIODSP_CALLBACK ProcessCallback(
UnityAudioEffectState* state,
float* inbuffer, float* outbuffer,
unsigned int length,
int inchannels, int outchannels)
{
EffectData::Data* data = &state->GetEffectData<EffectData>()->data;
float w = 2.0f * sinf(kPI * data->p[P_FREQ] / state->samplerate);
for(unsigned int n = 0; n < length; n++)
{
for(int i = 0; i < outchannels; i++)
{
outbuffer[n * outchannels + i] =
inbuffer[n * outchannels + i] *
(1.0f - data->p[P_MIX] + data->p[P_MIX] * data->s);
}
data->s += data->c * w; // cheap way to calculate a sine-wave
data->c -= data->s * w;
}
return UNITY_AUDIODSP_OK;
}
GetEffectData 函数是一个辅助函数,它会将状态变量的 effectdata 字段转换为结构中的 EffectData::Data。
如果要自定义 Unity 显示插件参数的方式,请参阅自定义音频插件的 GUI。
要将插件导入 Unity,请参阅在 Unity 中使用原生 DSP 插件和 GUI。