Răsfoiți Sursa

Added new Audio Bus Chorus effect.
Added new Audio Bus Panner effect.

Juan Linietsky 8 ani în urmă
părinte
comite
eda739f414

+ 364 - 0
servers/audio/effects/audio_effect_chorus.cpp

@@ -0,0 +1,364 @@
+#include "audio_effect_chorus.h"
+#include "servers/audio_server.h"
+
+void AudioEffectChorusInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+	int todo = p_frame_count;
+
+	while(todo) {
+
+		int to_mix = MIN(todo,256); //can't mix too much
+
+		_process_chunk(p_src_frames,p_dst_frames,to_mix);
+
+		p_src_frames+=to_mix;
+		p_dst_frames+=to_mix;
+
+		todo-=to_mix;
+	}
+}
+
+void AudioEffectChorusInstance::_process_chunk(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+
+	//fill ringbuffer
+	for(int i=0;i<p_frame_count;i++) {
+		audio_buffer[(buffer_pos+i)&buffer_mask]=p_src_frames[i];
+		p_dst_frames[i]=p_src_frames[i]*base->dry;
+	}
+
+	float mix_rate = AudioServer::get_singleton()->get_mix_rate();
+
+	/* process voices */
+	for (int vc=0;vc<base->voice_count;vc++) {
+
+		AudioEffectChorus::Voice &v=base->voice[vc];
+
+
+		double time_to_mix=(float)p_frame_count/mix_rate;
+		double cycles_to_mix=time_to_mix*v.rate;
+
+		unsigned int local_rb_pos=buffer_pos;
+		AudioFrame *dst_buff=p_dst_frames;
+		AudioFrame *rb_buff=audio_buffer.ptr();
+
+		double delay_msec=v.delay;
+		unsigned int delay_frames=Math::fast_ftoi((delay_msec/1000.0)*mix_rate);
+		float max_depth_frames=(v.depth/1000.0)*mix_rate;
+
+		uint64_t local_cycles=cycles[vc];
+		uint64_t increment=llrint(cycles_to_mix/(double)p_frame_count*(double)(1<<AudioEffectChorus::CYCLES_FRAC));
+
+		//check the LFO doesnt read ahead of the write pos
+		if ((((int)max_depth_frames)+10)>delay_frames) { //10 as some threshold to avoid precision stuff
+			delay_frames+=(int)max_depth_frames-delay_frames;
+			delay_frames+=10; //threshold to avoid precision stuff
+
+		}
+
+
+
+		//low pass filter
+		if (v.cutoff==0)
+			continue;
+		float auxlp=expf(-2.0*M_PI*v.cutoff/mix_rate);
+		float c1=1.0-auxlp;
+		float c2=auxlp;
+		AudioFrame h=filter_h[vc];
+		if (v.cutoff>=AudioEffectChorus::MS_CUTOFF_MAX) {
+			c1=1.0; c2=0.0;
+		}
+
+		//vol modifier
+
+		AudioFrame vol_modifier=AudioFrame(base->wet,base->wet) * Math::db2linear(v.level);
+		vol_modifier.l*=CLAMP( 1.0 - v.pan, 0, 1);
+		vol_modifier.r*=CLAMP( 1.0 + v.pan, 0, 1);
+
+
+
+		for (int i=0;i<p_frame_count;i++) {
+
+			/** COMPUTE WAVEFORM **/
+
+			float phase=(float)(local_cycles&AudioEffectChorus::CYCLES_MASK)/(float)(1<<AudioEffectChorus::CYCLES_FRAC);
+
+			float wave_delay=sinf(phase*2.0*M_PI)*max_depth_frames;
+
+			int wave_delay_frames=lrint(floor(wave_delay));
+			float wave_delay_frac=wave_delay-(float)wave_delay_frames;
+
+			/** COMPUTE RINGBUFFER POS**/
+
+			unsigned int rb_source=local_rb_pos;
+			rb_source-=delay_frames;
+
+			rb_source-=wave_delay_frames;
+
+			/** READ FROM RINGBUFFER, LINEARLY INTERPOLATE */
+
+			AudioFrame val=rb_buff[rb_source&buffer_mask];
+			AudioFrame val_next=rb_buff[(rb_source-1)&buffer_mask];
+
+			val+=(val_next-val)*wave_delay_frac;
+
+			val=val*c1+h*c2;
+			h=val;
+
+			/** MIX VALUE TO OUTPUT **/
+
+			dst_buff[i]+=val*vol_modifier;
+
+			local_cycles+=increment;
+			local_rb_pos++;
+
+		}
+
+		filter_h[vc]=h;
+		cycles[vc]+=Math::fast_ftoi(cycles_to_mix*(double)(1<<AudioEffectChorus::CYCLES_FRAC));
+	}
+
+	buffer_pos+=p_frame_count;
+}
+
+
+Ref<AudioEffectInstance> AudioEffectChorus::instance() {
+
+	Ref<AudioEffectChorusInstance> ins;
+	ins.instance();
+	ins->base=Ref<AudioEffectChorus>(this);
+	for(int i=0;i<4;i++) {
+		ins->filter_h[i]=AudioFrame(0,0);
+		ins->cycles[i]=0;
+	}
+
+	float ring_buffer_max_size=AudioEffectChorus::MAX_DELAY_MS+AudioEffectChorus::MAX_DEPTH_MS+AudioEffectChorus::MAX_WIDTH_MS;
+
+	ring_buffer_max_size*=2; //just to avoid complications
+	ring_buffer_max_size/=1000.0;//convert to seconds
+	ring_buffer_max_size*=AudioServer::get_singleton()->get_mix_rate();
+
+	int ringbuff_size=ring_buffer_max_size;
+
+	int bits=0;
+
+	while(ringbuff_size>0) {
+		bits++;
+		ringbuff_size/=2;
+	}
+
+	ringbuff_size=1<<bits;
+	ins->buffer_mask=ringbuff_size-1;
+	ins->buffer_pos=0;
+	ins->audio_buffer.resize(ringbuff_size);
+	for(int i=0;i<ringbuff_size;i++) {
+		ins->audio_buffer[i]=AudioFrame(0,0);
+	}
+
+	return ins;
+}
+
+void AudioEffectChorus::set_voice_count(int p_voices) {
+
+	ERR_FAIL_COND(p_voices<1 || p_voices>=MAX_VOICES);
+	voice_count=p_voices;
+	_change_notify();
+}
+
+
+int AudioEffectChorus::get_voice_count() const{
+
+	return voice_count;
+}
+
+void AudioEffectChorus::set_voice_delay_ms(int p_voice,float p_delay_ms){
+
+	ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+	voice[p_voice].delay=p_delay_ms;
+
+}
+float AudioEffectChorus::get_voice_delay_ms(int p_voice) const{
+
+	ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+	return voice[p_voice].delay;
+}
+
+void AudioEffectChorus::set_voice_rate_hz(int p_voice,float p_rate_hz){
+	ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+	voice[p_voice].rate=p_rate_hz;
+}
+float AudioEffectChorus::get_voice_rate_hz(int p_voice) const{
+
+	ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+	return voice[p_voice].rate;
+}
+
+void AudioEffectChorus::set_voice_depth_ms(int p_voice,float p_depth_ms){
+
+	ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+	voice[p_voice].depth=p_depth_ms;
+}
+float AudioEffectChorus::get_voice_depth_ms(int p_voice) const{
+
+	ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+	return voice[p_voice].depth;
+}
+
+void AudioEffectChorus::set_voice_level_db(int p_voice,float p_level_db){
+
+	ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+	voice[p_voice].level=p_level_db;
+}
+float AudioEffectChorus::get_voice_level_db(int p_voice) const{
+
+	ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+	return voice[p_voice].level;
+}
+
+
+void AudioEffectChorus::set_voice_cutoff_hz(int p_voice,float p_cutoff_hz){
+
+	ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+	voice[p_voice].cutoff=p_cutoff_hz;
+}
+float AudioEffectChorus::get_voice_cutoff_hz(int p_voice) const{
+
+	ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+	return voice[p_voice].cutoff;
+}
+
+void AudioEffectChorus::set_voice_pan(int p_voice,float p_pan){
+
+	ERR_FAIL_INDEX(p_voice,MAX_VOICES);
+
+	voice[p_voice].pan=p_pan;
+}
+float AudioEffectChorus::get_voice_pan(int p_voice) const{
+
+	ERR_FAIL_INDEX_V(p_voice,MAX_VOICES,0);
+
+	return voice[p_voice].pan;
+}
+
+
+void AudioEffectChorus::set_wet(float amount){
+
+
+	wet=amount;
+}
+float AudioEffectChorus::get_wet() const{
+
+	return wet;
+}
+
+void AudioEffectChorus::set_dry(float amount){
+
+	dry=amount;
+
+}
+float AudioEffectChorus::get_dry() const{
+
+	return dry;
+}
+
+void AudioEffectChorus::_validate_property(PropertyInfo& property) const {
+
+	if (property.name.begins_with("voice/")) {
+		int voice_idx = property.name.get_slice("/",1).to_int();
+		if (voice_idx>voice_count) {
+			property.usage=0;
+		}
+	}
+}
+
+
+void AudioEffectChorus::_bind_methods() {
+
+	ClassDB::bind_method(_MD("set_voice_count","voices"),&AudioEffectChorus::set_voice_count);
+	ClassDB::bind_method(_MD("get_voice_count"),&AudioEffectChorus::get_voice_count);
+
+
+	ClassDB::bind_method(_MD("set_voice_delay_ms","voice_idx","delay_ms"),&AudioEffectChorus::set_voice_delay_ms);
+	ClassDB::bind_method(_MD("get_voice_delay_ms","voice_idx"),&AudioEffectChorus::get_voice_delay_ms);
+
+	ClassDB::bind_method(_MD("set_voice_rate_hz","voice_idx","rate_hz"),&AudioEffectChorus::set_voice_rate_hz);
+	ClassDB::bind_method(_MD("get_voice_rate_hz","voice_idx"),&AudioEffectChorus::get_voice_rate_hz);
+
+	ClassDB::bind_method(_MD("set_voice_depth_ms","voice_idx","depth_ms"),&AudioEffectChorus::set_voice_depth_ms);
+	ClassDB::bind_method(_MD("get_voice_depth_ms","voice_idx"),&AudioEffectChorus::get_voice_depth_ms);
+
+	ClassDB::bind_method(_MD("set_voice_level_db","voice_idx","level_db"),&AudioEffectChorus::set_voice_level_db);
+	ClassDB::bind_method(_MD("get_voice_level_db","voice_idx"),&AudioEffectChorus::get_voice_level_db);
+
+	ClassDB::bind_method(_MD("set_voice_cutoff_hz","voice_idx","cutoff_hz"),&AudioEffectChorus::set_voice_cutoff_hz);
+	ClassDB::bind_method(_MD("get_voice_cutoff_hz","voice_idx"),&AudioEffectChorus::get_voice_cutoff_hz);
+
+	ClassDB::bind_method(_MD("set_voice_pan","voice_idx","pan"),&AudioEffectChorus::set_voice_pan);
+	ClassDB::bind_method(_MD("get_voice_pan","voice_idx"),&AudioEffectChorus::get_voice_pan);
+
+	ClassDB::bind_method(_MD("set_wet","amount"),&AudioEffectChorus::set_wet);
+	ClassDB::bind_method(_MD("get_wet"),&AudioEffectChorus::get_wet);
+
+	ClassDB::bind_method(_MD("set_dry","amount"),&AudioEffectChorus::set_dry);
+	ClassDB::bind_method(_MD("get_dry"),&AudioEffectChorus::get_dry);
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT,"voice_count",PROPERTY_HINT_RANGE,"1,4,1"),_SCS("set_voice_count"),_SCS("get_voice_count"));
+	ADD_PROPERTY(PropertyInfo(Variant::REAL,"dry",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_dry"),_SCS("get_dry"));
+	ADD_PROPERTY(PropertyInfo(Variant::REAL,"wet",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_wet"),_SCS("get_wet"));
+
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/delay_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_voice_delay_ms"),_SCS("get_voice_delay_ms"),0);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/rate_hz",PROPERTY_HINT_RANGE,"0.1,20,0.1"),_SCS("set_voice_rate_hz"),_SCS("get_voice_rate_hz"),0);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/depth_ms",PROPERTY_HINT_RANGE,"0,20,0.01"),_SCS("set_voice_depth_ms"),_SCS("get_voice_depth_ms"),0);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/level_db",PROPERTY_HINT_RANGE,"-60,24,0.1"),_SCS("set_voice_level_db"),_SCS("get_voice_level_db"),0);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/cutoff_hz",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_voice_cutoff_hz"),_SCS("get_voice_cutoff_hz"),0);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/1/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_voice_pan"),_SCS("get_voice_pan"),0);
+
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/delay_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_voice_delay_ms"),_SCS("get_voice_delay_ms"),1);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/rate_hz",PROPERTY_HINT_RANGE,"0.1,20,0.1"),_SCS("set_voice_rate_hz"),_SCS("get_voice_rate_hz"),1);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/depth_ms",PROPERTY_HINT_RANGE,"0,20,0.01"),_SCS("set_voice_depth_ms"),_SCS("get_voice_depth_ms"),1);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/level_db",PROPERTY_HINT_RANGE,"-60,24,0.1"),_SCS("set_voice_level_db"),_SCS("get_voice_level_db"),1);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/cutoff_hz",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_voice_cutoff_hz"),_SCS("get_voice_cutoff_hz"),1);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/2/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_voice_pan"),_SCS("get_voice_pan"),1);
+
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/delay_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_voice_delay_ms"),_SCS("get_voice_delay_ms"),2);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/rate_hz",PROPERTY_HINT_RANGE,"0.1,20,0.1"),_SCS("set_voice_rate_hz"),_SCS("get_voice_rate_hz"),2);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/depth_ms",PROPERTY_HINT_RANGE,"0,20,0.01"),_SCS("set_voice_depth_ms"),_SCS("get_voice_depth_ms"),2);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/level_db",PROPERTY_HINT_RANGE,"-60,24,0.1"),_SCS("set_voice_level_db"),_SCS("get_voice_level_db"),2);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/cutoff_hz",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_voice_cutoff_hz"),_SCS("get_voice_cutoff_hz"),2);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/3/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_voice_pan"),_SCS("get_voice_pan"),2);
+
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/delay_ms",PROPERTY_HINT_RANGE,"0,50,0.01"),_SCS("set_voice_delay_ms"),_SCS("get_voice_delay_ms"),3);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/rate_hz",PROPERTY_HINT_RANGE,"0.1,20,0.1"),_SCS("set_voice_rate_hz"),_SCS("get_voice_rate_hz"),3);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/depth_ms",PROPERTY_HINT_RANGE,"0,20,0.01"),_SCS("set_voice_depth_ms"),_SCS("get_voice_depth_ms"),3);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/level_db",PROPERTY_HINT_RANGE,"-60,24,0.1"),_SCS("set_voice_level_db"),_SCS("get_voice_level_db"),3);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/cutoff_hz",PROPERTY_HINT_RANGE,"1,16000,1"),_SCS("set_voice_cutoff_hz"),_SCS("get_voice_cutoff_hz"),3);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL,"voice/4/pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_voice_pan"),_SCS("get_voice_pan"),3);
+
+}
+
+AudioEffectChorus::AudioEffectChorus()
+{
+	voice_count=2;
+	voice[0].delay=15;
+	voice[1].delay=20;
+	voice[0].rate=0.8;
+	voice[1].rate=1.2;
+	voice[0].depth=2;
+	voice[1].depth=3;
+	voice[0].cutoff=8000;
+	voice[1].cutoff=8000;
+	voice[0].pan=-0.5;
+	voice[1].pan=0.5;
+
+	wet=0.5;
+	dry=1.0;
+}

+ 115 - 0
servers/audio/effects/audio_effect_chorus.h

@@ -0,0 +1,115 @@
+#ifndef AUDIOEFFECTCHORUS_H
+#define AUDIOEFFECTCHORUS_H
+
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectChorus;
+
+class AudioEffectChorusInstance : public AudioEffectInstance {
+	GDCLASS(AudioEffectChorusInstance,AudioEffectInstance)
+friend class AudioEffectChorus;
+	Ref<AudioEffectChorus> base;
+
+	Vector<AudioFrame> audio_buffer;
+	unsigned int buffer_pos;
+	unsigned int buffer_mask;
+
+	AudioFrame filter_h[4];
+	uint64_t cycles[4];
+
+	void _process_chunk(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+public:
+
+	virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectChorus : public AudioEffect {
+	GDCLASS(AudioEffectChorus,AudioEffect)
+
+friend class AudioEffectChorusInstance;
+public:
+	enum {
+
+		MAX_DELAY_MS=50,
+		MAX_DEPTH_MS=20,
+		MAX_WIDTH_MS=50,
+		MAX_VOICES=4,
+		CYCLES_FRAC=16,
+		CYCLES_MASK=(1<<CYCLES_FRAC)-1,
+		MAX_CHANNELS=4,
+		MS_CUTOFF_MAX=16000
+	};
+
+private:
+
+	struct Voice {
+
+		float delay;
+		float rate;
+		float depth;
+		float level;
+		float cutoff;
+		float pan;
+
+		Voice() {
+
+			delay=12.0;
+			rate=1;
+			depth=0;
+			level=0;
+			cutoff=MS_CUTOFF_MAX;
+			pan=0;
+
+		}
+
+	} voice[MAX_VOICES];
+
+	int voice_count;
+
+	float wet;
+	float dry;
+
+
+protected:
+	void _validate_property(PropertyInfo& property) const;
+
+	static void _bind_methods();
+public:
+
+	void set_voice_count(int p_voices);
+	int get_voice_count() const;
+
+	void set_voice_delay_ms(int p_voice,float p_delay_ms);
+	float get_voice_delay_ms(int p_voice) const;
+
+	void set_voice_rate_hz(int p_voice,float p_rate_hz);
+	float get_voice_rate_hz(int p_voice) const;
+
+	void set_voice_depth_ms(int p_voice,float p_depth_ms);
+	float get_voice_depth_ms(int p_voice) const;
+
+	void set_voice_level_db(int p_voice,float p_level_db);
+	float get_voice_level_db(int p_voice) const;
+
+	void set_voice_cutoff_hz(int p_voice,float p_cutoff_hz);
+	float get_voice_cutoff_hz(int p_voice) const;
+
+	void set_voice_pan(int p_voice,float p_pan);
+	float get_voice_pan(int p_voice) const;
+
+	void set_wet(float amount);
+	float get_wet() const;
+
+	void set_dry(float amount);
+	float get_dry() const;
+
+	Ref<AudioEffectInstance> instance();
+
+	AudioEffectChorus();
+};
+
+#endif // AUDIOEFFECTCHORUS_H

+ 47 - 0
servers/audio/effects/audio_effect_panner.cpp

@@ -0,0 +1,47 @@
+#include "audio_effect_panner.h"
+
+
+void AudioEffectPannerInstance::process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count) {
+
+
+	float lvol = CLAMP( 1.0 - base->pan, 0, 1);
+	float rvol = CLAMP( 1.0 + base->pan, 0, 1);
+
+	for(int i=0;i<p_frame_count;i++) {
+
+		p_dst_frames[i].l = p_src_frames[i].l * lvol + p_src_frames[i].r * (1.0 - rvol);
+		p_dst_frames[i].r = p_src_frames[i].r * rvol + p_src_frames[i].l * (1.0 - lvol);
+
+	}
+
+}
+
+
+Ref<AudioEffectInstance> AudioEffectPanner::instance() {
+	Ref<AudioEffectPannerInstance> ins;
+	ins.instance();
+	ins->base=Ref<AudioEffectPanner>(this);
+	return ins;
+}
+
+void AudioEffectPanner::set_pan(float p_cpanume) {
+	pan=p_cpanume;
+}
+
+float AudioEffectPanner::get_pan() const {
+
+	return pan;
+}
+
+void AudioEffectPanner::_bind_methods() {
+
+	ClassDB::bind_method(_MD("set_pan","cpanume"),&AudioEffectPanner::set_pan);
+	ClassDB::bind_method(_MD("get_pan"),&AudioEffectPanner::get_pan);
+
+	ADD_PROPERTY(PropertyInfo(Variant::REAL,"pan",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_pan"),_SCS("get_pan"));
+}
+
+AudioEffectPanner::AudioEffectPanner()
+{
+	pan=0;
+}

+ 40 - 0
servers/audio/effects/audio_effect_panner.h

@@ -0,0 +1,40 @@
+#ifndef AUDIOEFFECTPANNER_H
+#define AUDIOEFFECTPANNER_H
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectPanner;
+
+class AudioEffectPannerInstance : public AudioEffectInstance {
+	GDCLASS(AudioEffectPannerInstance,AudioEffectInstance)
+friend class AudioEffectPanner;
+	Ref<AudioEffectPanner> base;
+
+public:
+
+	virtual void process(const AudioFrame *p_src_frames,AudioFrame *p_dst_frames,int p_frame_count);
+
+};
+
+
+class AudioEffectPanner : public AudioEffect {
+	GDCLASS(AudioEffectPanner,AudioEffect)
+
+friend class AudioEffectPannerInstance;
+	float pan;
+
+protected:
+
+	static void _bind_methods();
+public:
+
+
+	Ref<AudioEffectInstance> instance();
+	void set_pan(float p_volume);
+	float get_pan() const;
+
+	AudioEffectPanner();
+};
+
+
+#endif // AUDIOEFFECTPANNER_H

+ 23 - 14
servers/register_server_types.cpp

@@ -43,6 +43,8 @@
 #include "audio/effects/audio_effect_eq.h"
 #include "audio/effects/audio_effect_distortion.h"
 #include "audio/effects/audio_effect_stereo_enhance.h"
+#include "audio/effects/audio_effect_panner.h"
+#include "audio/effects/audio_effect_chorus.h"
 
 static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsage>* r_usage) {
 
@@ -79,25 +81,32 @@ void register_server_types() {
 	ClassDB::register_virtual_class<AudioStreamPlayback>();
 	ClassDB::register_virtual_class<AudioEffect>();
 
-	ClassDB::register_class<AudioEffectAmplify>();
+	{
+		//audio effects
+		ClassDB::register_class<AudioEffectAmplify>();
 
-	ClassDB::register_class<AudioEffectReverb>();
+		ClassDB::register_class<AudioEffectReverb>();
 
-	ClassDB::register_class<AudioEffectLowPass>();
-	ClassDB::register_class<AudioEffectHighPass>();
-	ClassDB::register_class<AudioEffectBandPass>();
-	ClassDB::register_class<AudioEffectNotchPass>();
-	ClassDB::register_class<AudioEffectBandLimit>();
-	ClassDB::register_class<AudioEffectLowShelf>();
-	ClassDB::register_class<AudioEffectHighShelf>();
+		ClassDB::register_class<AudioEffectLowPass>();
+		ClassDB::register_class<AudioEffectHighPass>();
+		ClassDB::register_class<AudioEffectBandPass>();
+		ClassDB::register_class<AudioEffectNotchPass>();
+		ClassDB::register_class<AudioEffectBandLimit>();
+		ClassDB::register_class<AudioEffectLowShelf>();
+		ClassDB::register_class<AudioEffectHighShelf>();
 
-	ClassDB::register_class<AudioEffectEQ6>();
-	ClassDB::register_class<AudioEffectEQ10>();
-	ClassDB::register_class<AudioEffectEQ21>();
+		ClassDB::register_class<AudioEffectEQ6>();
+		ClassDB::register_class<AudioEffectEQ10>();
+		ClassDB::register_class<AudioEffectEQ21>();
 
-	ClassDB::register_class<AudioEffectDistortion>();
+		ClassDB::register_class<AudioEffectDistortion>();
+
+		ClassDB::register_class<AudioEffectStereoEnhance>();
+
+		ClassDB::register_class<AudioEffectPanner>();
+		ClassDB::register_class<AudioEffectChorus>();
+	}
 
-	ClassDB::register_class<AudioEffectStereoEnhance>();
 
 	ClassDB::register_virtual_class<Physics2DDirectBodyState>();
 	ClassDB::register_virtual_class<Physics2DDirectSpaceState>();