Path: blob/master/servers/audio/effects/audio_effect_compressor.cpp
10278 views
/**************************************************************************/1/* audio_effect_compressor.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "audio_effect_compressor.h"31#include "servers/audio_server.h"3233void AudioEffectCompressorInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {34float threshold = Math::db_to_linear(base->threshold);35float sample_rate = AudioServer::get_singleton()->get_mix_rate();3637float ratatcoef = std::exp(-1 / (0.00001f * sample_rate));38float ratrelcoef = std::exp(-1 / (0.5f * sample_rate));39float attime = base->attack_us / 1000000.0;40float reltime = base->release_ms / 1000.0;41float atcoef = std::exp(-1 / (attime * sample_rate));42float relcoef = std::exp(-1 / (reltime * sample_rate));4344float makeup = Math::db_to_linear(base->gain);4546float mix = base->mix;47float gr_meter_decay = std::exp(1 / (1 * sample_rate));4849const AudioFrame *src = p_src_frames;5051if (base->sidechain != StringName() && current_channel != -1) {52int bus = AudioServer::get_singleton()->thread_find_bus_index(base->sidechain);53if (bus >= 0) {54src = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus, current_channel);55}56}5758for (int i = 0; i < p_frame_count; i++) {59AudioFrame s = src[i];60//convert to positive61s.left = Math::abs(s.left);62s.right = Math::abs(s.right);6364float peak = MAX(s.left, s.right);6566float overdb = 2.08136898f * Math::linear_to_db(peak / threshold);6768if (overdb < 0.0) { //we only care about what goes over to compress69overdb = 0.0;70}7172if (overdb - rundb > 5) { // diffeence is too large73averatio = 4;74}7576if (overdb > rundb) {77rundb = overdb + atcoef * (rundb - overdb);78runratio = averatio + ratatcoef * (runratio - averatio);79} else {80rundb = overdb + relcoef * (rundb - overdb);81runratio = averatio + ratrelcoef * (runratio - averatio);82}8384overdb = rundb;85averatio = runratio;8687float cratio;8889if (false) { //rato all-in90cratio = 12 + averatio;91} else {92cratio = base->ratio;93}9495float gr = -overdb * (cratio - 1) / cratio;96float grv = Math::db_to_linear(gr);9798runmax = maxover + relcoef * (runmax - maxover); // highest peak for setting att/rel decays in reltime99maxover = runmax;100101if (grv < gr_meter) {102gr_meter = grv;103} else {104gr_meter *= gr_meter_decay;105if (gr_meter > 1) {106gr_meter = 1;107}108}109110p_dst_frames[i] = p_src_frames[i] * grv * makeup * mix + p_src_frames[i] * (1.0 - mix);111}112}113114Ref<AudioEffectInstance> AudioEffectCompressor::instantiate() {115Ref<AudioEffectCompressorInstance> ins;116ins.instantiate();117ins->base = Ref<AudioEffectCompressor>(this);118ins->rundb = 0;119ins->runratio = 0;120ins->averatio = 0;121ins->runmax = 0;122ins->maxover = 0;123ins->gr_meter = 1.0;124ins->current_channel = -1;125return ins;126}127128void AudioEffectCompressor::set_threshold(float p_threshold) {129threshold = p_threshold;130}131132float AudioEffectCompressor::get_threshold() const {133return threshold;134}135136void AudioEffectCompressor::set_ratio(float p_ratio) {137ratio = p_ratio;138}139140float AudioEffectCompressor::get_ratio() const {141return ratio;142}143144void AudioEffectCompressor::set_gain(float p_gain) {145gain = p_gain;146}147148float AudioEffectCompressor::get_gain() const {149return gain;150}151152void AudioEffectCompressor::set_attack_us(float p_attack_us) {153attack_us = p_attack_us;154}155156float AudioEffectCompressor::get_attack_us() const {157return attack_us;158}159160void AudioEffectCompressor::set_release_ms(float p_release_ms) {161release_ms = p_release_ms;162}163164float AudioEffectCompressor::get_release_ms() const {165return release_ms;166}167168void AudioEffectCompressor::set_mix(float p_mix) {169mix = p_mix;170}171172float AudioEffectCompressor::get_mix() const {173return mix;174}175176void AudioEffectCompressor::set_sidechain(const StringName &p_sidechain) {177AudioServer::get_singleton()->lock();178sidechain = p_sidechain;179AudioServer::get_singleton()->unlock();180}181182StringName AudioEffectCompressor::get_sidechain() const {183return sidechain;184}185186void AudioEffectCompressor::_validate_property(PropertyInfo &p_property) const {187if (!Engine::get_singleton()->is_editor_hint()) {188return;189}190if (p_property.name == "sidechain") {191String buses = "";192for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {193buses += ",";194buses += AudioServer::get_singleton()->get_bus_name(i);195}196197p_property.hint_string = buses;198}199}200201void AudioEffectCompressor::_bind_methods() {202ClassDB::bind_method(D_METHOD("set_threshold", "threshold"), &AudioEffectCompressor::set_threshold);203ClassDB::bind_method(D_METHOD("get_threshold"), &AudioEffectCompressor::get_threshold);204205ClassDB::bind_method(D_METHOD("set_ratio", "ratio"), &AudioEffectCompressor::set_ratio);206ClassDB::bind_method(D_METHOD("get_ratio"), &AudioEffectCompressor::get_ratio);207208ClassDB::bind_method(D_METHOD("set_gain", "gain"), &AudioEffectCompressor::set_gain);209ClassDB::bind_method(D_METHOD("get_gain"), &AudioEffectCompressor::get_gain);210211ClassDB::bind_method(D_METHOD("set_attack_us", "attack_us"), &AudioEffectCompressor::set_attack_us);212ClassDB::bind_method(D_METHOD("get_attack_us"), &AudioEffectCompressor::get_attack_us);213214ClassDB::bind_method(D_METHOD("set_release_ms", "release_ms"), &AudioEffectCompressor::set_release_ms);215ClassDB::bind_method(D_METHOD("get_release_ms"), &AudioEffectCompressor::get_release_ms);216217ClassDB::bind_method(D_METHOD("set_mix", "mix"), &AudioEffectCompressor::set_mix);218ClassDB::bind_method(D_METHOD("get_mix"), &AudioEffectCompressor::get_mix);219220ClassDB::bind_method(D_METHOD("set_sidechain", "sidechain"), &AudioEffectCompressor::set_sidechain);221ClassDB::bind_method(D_METHOD("get_sidechain"), &AudioEffectCompressor::get_sidechain);222223ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "threshold", PROPERTY_HINT_RANGE, "-60,0,0.1"), "set_threshold", "get_threshold");224ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ratio", PROPERTY_HINT_RANGE, "1,48,0.1"), "set_ratio", "get_ratio");225ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gain", PROPERTY_HINT_RANGE, "-20,20,0.1"), "set_gain", "get_gain");226ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attack_us", PROPERTY_HINT_RANGE, U"20,2000,1,suffix:\u00B5s"), "set_attack_us", "get_attack_us");227ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "release_ms", PROPERTY_HINT_RANGE, "20,2000,1,suffix:ms"), "set_release_ms", "get_release_ms");228ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mix", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_mix", "get_mix");229ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "sidechain", PROPERTY_HINT_ENUM), "set_sidechain", "get_sidechain");230}231232AudioEffectCompressor::AudioEffectCompressor() {233threshold = 0;234ratio = 4;235gain = 0;236attack_us = 20;237release_ms = 250;238mix = 1;239}240241242