Added Audio Limiter bus effect, and sidechain ability to compressor.
This commit is contained in:
parent
4d944b4996
commit
4d9bc8b00c
6 changed files with 239 additions and 3 deletions
|
@ -19,10 +19,19 @@ void AudioEffectCompressorInstance::process(const AudioFrame *p_src_frames,Audio
|
||||||
float mix = base->mix;
|
float mix = base->mix;
|
||||||
float gr_meter_decay = exp(1 / (1 * sample_rate));
|
float gr_meter_decay = exp(1 / (1 * sample_rate));
|
||||||
|
|
||||||
|
const AudioFrame *src = p_src_frames;
|
||||||
|
|
||||||
|
if (base->sidechain!=StringName() && current_channel!=-1) {
|
||||||
|
|
||||||
|
int bus = AudioServer::get_singleton()->thread_find_bus_index(base->sidechain);
|
||||||
|
if (bus>=0) {
|
||||||
|
src = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus,current_channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(int i=0;i<p_frame_count;i++) {
|
for(int i=0;i<p_frame_count;i++) {
|
||||||
|
|
||||||
AudioFrame s = p_src_frames[i];
|
AudioFrame s = src[i];
|
||||||
//convert to positive
|
//convert to positive
|
||||||
s.l = Math::abs(s.l);
|
s.l = Math::abs(s.l);
|
||||||
s.r = Math::abs(s.r);
|
s.r = Math::abs(s.r);
|
||||||
|
@ -88,6 +97,7 @@ Ref<AudioEffectInstance> AudioEffectCompressor::instance() {
|
||||||
ins->runmax=0;
|
ins->runmax=0;
|
||||||
ins->maxover=0;
|
ins->maxover=0;
|
||||||
ins->gr_meter=1.0;
|
ins->gr_meter=1.0;
|
||||||
|
ins->current_channel=-1;
|
||||||
return ins;
|
return ins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +157,31 @@ float AudioEffectCompressor::get_mix() const {
|
||||||
return mix;
|
return mix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioEffectCompressor::set_sidechain(const StringName& p_sidechain) {
|
||||||
|
|
||||||
|
AudioServer::get_singleton()->lock();
|
||||||
|
sidechain=p_sidechain;
|
||||||
|
AudioServer::get_singleton()->unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName AudioEffectCompressor::get_sidechain() const {
|
||||||
|
|
||||||
|
return sidechain;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioEffectCompressor::_validate_property(PropertyInfo& property) const {
|
||||||
|
|
||||||
|
if (property.name=="sidechain") {
|
||||||
|
|
||||||
|
String buses="";
|
||||||
|
for(int i=0;i<AudioServer::get_singleton()->get_bus_count();i++) {
|
||||||
|
buses+=",";
|
||||||
|
buses+=AudioServer::get_singleton()->get_bus_name(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
property.hint_string=buses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudioEffectCompressor::_bind_methods() {
|
void AudioEffectCompressor::_bind_methods() {
|
||||||
|
|
||||||
|
@ -168,12 +203,16 @@ void AudioEffectCompressor::_bind_methods() {
|
||||||
ClassDB::bind_method(_MD("set_mix","mix"),&AudioEffectCompressor::set_mix);
|
ClassDB::bind_method(_MD("set_mix","mix"),&AudioEffectCompressor::set_mix);
|
||||||
ClassDB::bind_method(_MD("get_mix"),&AudioEffectCompressor::get_mix);
|
ClassDB::bind_method(_MD("get_mix"),&AudioEffectCompressor::get_mix);
|
||||||
|
|
||||||
|
ClassDB::bind_method(_MD("set_sidechain","sidechain"),&AudioEffectCompressor::set_sidechain);
|
||||||
|
ClassDB::bind_method(_MD("get_sidechain"),&AudioEffectCompressor::get_sidechain);
|
||||||
|
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL,"treshold",PROPERTY_HINT_RANGE,"-60,0,0.1"),_SCS("set_treshold"),_SCS("get_treshold"));
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"treshold",PROPERTY_HINT_RANGE,"-60,0,0.1"),_SCS("set_treshold"),_SCS("get_treshold"));
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL,"ratio",PROPERTY_HINT_RANGE,"1,48,0.1"),_SCS("set_ratio"),_SCS("get_ratio"));
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"ratio",PROPERTY_HINT_RANGE,"1,48,0.1"),_SCS("set_ratio"),_SCS("get_ratio"));
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL,"gain",PROPERTY_HINT_RANGE,"-20,20,0.1"),_SCS("set_gain"),_SCS("get_gain"));
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"gain",PROPERTY_HINT_RANGE,"-20,20,0.1"),_SCS("set_gain"),_SCS("get_gain"));
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL,"attack_us",PROPERTY_HINT_RANGE,"20,2000,1"),_SCS("set_attack_us"),_SCS("get_attack_us"));
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"attack_us",PROPERTY_HINT_RANGE,"20,2000,1"),_SCS("set_attack_us"),_SCS("get_attack_us"));
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL,"release_ms",PROPERTY_HINT_RANGE,"20,2000,1"),_SCS("set_release_ms"),_SCS("get_release_ms"));
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"release_ms",PROPERTY_HINT_RANGE,"20,2000,1"),_SCS("set_release_ms"),_SCS("get_release_ms"));
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::REAL,"mix",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_mix"),_SCS("get_mix"));
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"mix",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_mix"),_SCS("get_mix"));
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"sidechain",PROPERTY_HINT_ENUM),_SCS("set_sidechain"),_SCS("get_sidechain"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,10 @@ friend class AudioEffectCompressor;
|
||||||
Ref<AudioEffectCompressor> base;
|
Ref<AudioEffectCompressor> base;
|
||||||
|
|
||||||
float rundb,averatio,runratio,runmax,maxover,gr_meter;
|
float rundb,averatio,runratio,runmax,maxover,gr_meter;
|
||||||
|
int current_channel;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
void set_current_channel(int p_channel) { current_channel=p_channel; }
|
||||||
virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
|
virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -29,10 +31,11 @@ friend class AudioEffectCompressorInstance;
|
||||||
float attack_us;
|
float attack_us;
|
||||||
float release_ms;
|
float release_ms;
|
||||||
float mix;
|
float mix;
|
||||||
|
StringName sidechain;
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void _validate_property(PropertyInfo& property) const;
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -58,6 +61,9 @@ public:
|
||||||
void set_mix(float p_mix);
|
void set_mix(float p_mix);
|
||||||
float get_mix() const;
|
float get_mix() const;
|
||||||
|
|
||||||
|
void set_sidechain(const StringName& p_sidechain);
|
||||||
|
StringName get_sidechain() const;
|
||||||
|
|
||||||
AudioEffectCompressor();
|
AudioEffectCompressor();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
124
servers/audio/effects/audio_effect_limiter.cpp
Normal file
124
servers/audio/effects/audio_effect_limiter.cpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#include "audio_effect_limiter.h"
|
||||||
|
|
||||||
|
void AudioEffectLimiterInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
|
||||||
|
|
||||||
|
float thresh = Math::db2linear(base->treshold);
|
||||||
|
float threshdb = base->treshold;
|
||||||
|
float ceiling = Math::db2linear(base->ceiling);
|
||||||
|
float ceildb = base->ceiling;
|
||||||
|
float makeup = Math::db2linear(ceildb - threshdb);
|
||||||
|
float makeupdb = ceildb - threshdb;
|
||||||
|
float sc = -base->soft_clip;
|
||||||
|
float scv = Math::db2linear(sc);
|
||||||
|
float sccomp = Math::db2linear(-sc);
|
||||||
|
float peakdb = ceildb + 25;
|
||||||
|
float peaklvl = Math::db2linear(peakdb);
|
||||||
|
float scratio = base->soft_clip_ratio;
|
||||||
|
float scmult = Math::abs((ceildb - sc) / (peakdb - sc));
|
||||||
|
|
||||||
|
for(int i=0;i<p_frame_count;i++) {
|
||||||
|
|
||||||
|
float spl0 = p_src_frames[i].l;
|
||||||
|
float spl1 = p_src_frames[i].r;
|
||||||
|
spl0 = spl0 * makeup;
|
||||||
|
spl1 = spl1 * makeup;
|
||||||
|
float sign0 = (spl0 < 0.0 ? -1.0 : 1.0 );
|
||||||
|
float sign1 = (spl1 < 0.0 ? -1.0 : 1.0 );
|
||||||
|
float abs0 = Math::abs(spl0);
|
||||||
|
float abs1 = Math::abs(spl1);
|
||||||
|
float overdb0 = Math::linear2db(abs0) - ceildb;
|
||||||
|
float overdb1 = Math::linear2db(abs1) - ceildb;
|
||||||
|
|
||||||
|
if (abs0 > scv)
|
||||||
|
{
|
||||||
|
spl0 = sign0 * (scv + Math::db2linear(overdb0 * scmult));
|
||||||
|
}
|
||||||
|
if (abs1 > scv)
|
||||||
|
{
|
||||||
|
spl1 = sign1 * (scv + Math::db2linear(overdb1 * scmult));
|
||||||
|
}
|
||||||
|
|
||||||
|
spl0 = MIN(ceiling, Math::abs(spl0)) * (spl0 < 0.0 ? -1.0 : 1.0);
|
||||||
|
spl1 = MIN(ceiling, Math::abs(spl1)) * (spl1 < 0.0 ? -1.0 : 1.0);
|
||||||
|
|
||||||
|
p_dst_frames[i].l = spl0;
|
||||||
|
p_dst_frames[i].r = spl1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ref<AudioEffectInstance> AudioEffectLimiter::instance() {
|
||||||
|
Ref<AudioEffectLimiterInstance> ins;
|
||||||
|
ins.instance();
|
||||||
|
ins->base=Ref<AudioEffectLimiter>(this);
|
||||||
|
|
||||||
|
return ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioEffectLimiter::set_treshold_db(float p_treshold) {
|
||||||
|
|
||||||
|
treshold=p_treshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AudioEffectLimiter::get_treshold_db() const{
|
||||||
|
|
||||||
|
return treshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioEffectLimiter::set_ceiling_db(float p_ceiling){
|
||||||
|
|
||||||
|
ceiling=p_ceiling;
|
||||||
|
}
|
||||||
|
float AudioEffectLimiter::get_ceiling_db() const{
|
||||||
|
|
||||||
|
return ceiling;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioEffectLimiter::set_soft_clip_db(float p_soft_clip){
|
||||||
|
|
||||||
|
soft_clip=p_soft_clip;
|
||||||
|
}
|
||||||
|
float AudioEffectLimiter::get_soft_clip_db() const{
|
||||||
|
|
||||||
|
return soft_clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioEffectLimiter::set_soft_clip_ratio(float p_soft_clip){
|
||||||
|
|
||||||
|
soft_clip_ratio=p_soft_clip;
|
||||||
|
}
|
||||||
|
float AudioEffectLimiter::get_soft_clip_ratio() const{
|
||||||
|
|
||||||
|
return soft_clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioEffectLimiter::_bind_methods() {
|
||||||
|
|
||||||
|
ClassDB::bind_method(_MD("set_ceiling_db","ceiling"),&AudioEffectLimiter::set_ceiling_db);
|
||||||
|
ClassDB::bind_method(_MD("get_ceiling_db"),&AudioEffectLimiter::get_ceiling_db);
|
||||||
|
|
||||||
|
ClassDB::bind_method(_MD("set_treshold_db","treshold"),&AudioEffectLimiter::set_treshold_db);
|
||||||
|
ClassDB::bind_method(_MD("get_treshold_db"),&AudioEffectLimiter::get_treshold_db);
|
||||||
|
|
||||||
|
ClassDB::bind_method(_MD("set_soft_clip_db","soft_clip"),&AudioEffectLimiter::set_soft_clip_db);
|
||||||
|
ClassDB::bind_method(_MD("get_soft_clip_db"),&AudioEffectLimiter::get_soft_clip_db);
|
||||||
|
|
||||||
|
ClassDB::bind_method(_MD("set_soft_clip_ratio","soft_clip"),&AudioEffectLimiter::set_soft_clip_ratio);
|
||||||
|
ClassDB::bind_method(_MD("get_soft_clip_ratio"),&AudioEffectLimiter::get_soft_clip_ratio);
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"ceiling_db",PROPERTY_HINT_RANGE,"-20,-0.1,0.1"),_SCS("set_ceiling_db"),_SCS("get_ceiling_db"));
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"treshold_db",PROPERTY_HINT_RANGE,"-30,0,0.1"),_SCS("set_treshold_db"),_SCS("get_treshold_db"));
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"soft_clip_db",PROPERTY_HINT_RANGE,"0,6,0.1"),_SCS("set_soft_clip_db"),_SCS("get_soft_clip_db"));
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::REAL,"soft_clip_ratio",PROPERTY_HINT_RANGE,"3,20,0.1"),_SCS("set_soft_clip_ratio"),_SCS("get_soft_clip_ratio"));
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioEffectLimiter::AudioEffectLimiter()
|
||||||
|
{
|
||||||
|
treshold=0;
|
||||||
|
ceiling=-0.1;
|
||||||
|
soft_clip=2;
|
||||||
|
soft_clip_ratio=10;
|
||||||
|
}
|
58
servers/audio/effects/audio_effect_limiter.h
Normal file
58
servers/audio/effects/audio_effect_limiter.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef AUDIO_EFFECT_LIMITER_H
|
||||||
|
#define AUDIO_EFFECT_LIMITER_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "servers/audio/audio_effect.h"
|
||||||
|
|
||||||
|
class AudioEffectLimiter;
|
||||||
|
|
||||||
|
class AudioEffectLimiterInstance : public AudioEffectInstance {
|
||||||
|
GDCLASS(AudioEffectLimiterInstance,AudioEffectInstance)
|
||||||
|
friend class AudioEffectLimiter;
|
||||||
|
Ref<AudioEffectLimiter> base;
|
||||||
|
|
||||||
|
float mix_volume_db;
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AudioEffectLimiter : public AudioEffect {
|
||||||
|
GDCLASS(AudioEffectLimiter,AudioEffect)
|
||||||
|
|
||||||
|
friend class AudioEffectLimiterInstance;
|
||||||
|
float treshold;
|
||||||
|
float ceiling;
|
||||||
|
float soft_clip;
|
||||||
|
float soft_clip_ratio;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
static void _bind_methods();
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
void set_treshold_db(float p_treshold);
|
||||||
|
float get_treshold_db() const;
|
||||||
|
|
||||||
|
void set_ceiling_db(float p_ceiling);
|
||||||
|
float get_ceiling_db() const;
|
||||||
|
|
||||||
|
void set_soft_clip_db(float p_soft_clip);
|
||||||
|
float get_soft_clip_db() const;
|
||||||
|
|
||||||
|
void set_soft_clip_ratio(float p_soft_clip);
|
||||||
|
float get_soft_clip_ratio() const;
|
||||||
|
|
||||||
|
|
||||||
|
Ref<AudioEffectInstance> instance();
|
||||||
|
void set_volume_db(float p_volume);
|
||||||
|
float get_volume_db() const;
|
||||||
|
|
||||||
|
AudioEffectLimiter();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // AUDIO_EFFECT_LIMITER_H
|
|
@ -29,6 +29,8 @@
|
||||||
#include "audio_server.h"
|
#include "audio_server.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "os/os.h"
|
#include "os/os.h"
|
||||||
|
#include "servers/audio/effects/audio_effect_compressor.h"
|
||||||
|
|
||||||
AudioDriver *AudioDriver::singleton=NULL;
|
AudioDriver *AudioDriver::singleton=NULL;
|
||||||
AudioDriver *AudioDriver::get_singleton() {
|
AudioDriver *AudioDriver::get_singleton() {
|
||||||
|
|
||||||
|
@ -514,7 +516,12 @@ void AudioServer::_update_bus_effects(int p_bus) {
|
||||||
for(int i=0;i<buses[p_bus]->channels.size();i++) {
|
for(int i=0;i<buses[p_bus]->channels.size();i++) {
|
||||||
buses[p_bus]->channels[i].effect_instances.resize(buses[p_bus]->effects.size());
|
buses[p_bus]->channels[i].effect_instances.resize(buses[p_bus]->effects.size());
|
||||||
for(int j=0;j<buses[p_bus]->effects.size();j++) {
|
for(int j=0;j<buses[p_bus]->effects.size();j++) {
|
||||||
buses[p_bus]->channels[i].effect_instances[j]=buses[p_bus]->effects[j].effect->instance();
|
Ref<AudioEffectInstance> fx = buses[p_bus]->effects[j].effect->instance();
|
||||||
|
if (fx->cast_to<AudioEffectCompressorInstance>()) {
|
||||||
|
fx->cast_to<AudioEffectCompressorInstance>()->set_current_channel(i);
|
||||||
|
}
|
||||||
|
buses[p_bus]->channels[i].effect_instances[j]=fx;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "audio/effects/audio_effect_chorus.h"
|
#include "audio/effects/audio_effect_chorus.h"
|
||||||
#include "audio/effects/audio_effect_delay.h"
|
#include "audio/effects/audio_effect_delay.h"
|
||||||
#include "audio/effects/audio_effect_compressor.h"
|
#include "audio/effects/audio_effect_compressor.h"
|
||||||
|
#include "audio/effects/audio_effect_limiter.h"
|
||||||
|
|
||||||
static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsage>* r_usage) {
|
static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsage>* r_usage) {
|
||||||
|
|
||||||
|
@ -109,6 +110,7 @@ void register_server_types() {
|
||||||
ClassDB::register_class<AudioEffectChorus>();
|
ClassDB::register_class<AudioEffectChorus>();
|
||||||
ClassDB::register_class<AudioEffectDelay>();
|
ClassDB::register_class<AudioEffectDelay>();
|
||||||
ClassDB::register_class<AudioEffectCompressor>();
|
ClassDB::register_class<AudioEffectCompressor>();
|
||||||
|
ClassDB::register_class<AudioEffectLimiter>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue