| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  audio_stream_player_3d.cpp                                           */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							|  |  |  | /*                      https://godotengine.org                          */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2020-01-01 11:16:22 +01:00
										 |  |  | /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | #include "audio_stream_player_3d.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-11 18:13:45 +02:00
										 |  |  | #include "core/engine.h"
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | #include "scene/3d/area.h"
 | 
					
						
							|  |  |  | #include "scene/3d/camera.h"
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | #include "scene/3d/listener.h"
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | #include "scene/main/viewport.h"
 | 
					
						
							| 
									
										
										
										
											2019-01-17 01:41:36 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | // Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004)
 | 
					
						
							|  |  |  | // Speaker-Placement Correction Amplitude Panning (SPCAP)
 | 
					
						
							|  |  |  | class Spcap { | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  | 	struct Speaker { | 
					
						
							|  |  |  | 		Vector3 direction; | 
					
						
							|  |  |  | 		real_t effective_number_of_speakers; // precalculated
 | 
					
						
							|  |  |  | 		mutable real_t squared_gain; // temporary
 | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | 	Vector<Speaker> speakers; | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	Spcap(unsigned int speaker_count, const Vector3 *speaker_directions) { | 
					
						
							|  |  |  | 		this->speakers.resize(speaker_count); | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | 		Speaker *w = this->speakers.ptrw(); | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 		for (unsigned int speaker_num = 0; speaker_num < speaker_count; speaker_num++) { | 
					
						
							|  |  |  | 			w[speaker_num].direction = speaker_directions[speaker_num]; | 
					
						
							|  |  |  | 			w[speaker_num].squared_gain = 0.0; | 
					
						
							|  |  |  | 			w[speaker_num].effective_number_of_speakers = 0.0; | 
					
						
							|  |  |  | 			for (unsigned int other_speaker_num = 0; other_speaker_num < speaker_count; other_speaker_num++) { | 
					
						
							|  |  |  | 				w[speaker_num].effective_number_of_speakers += 0.5 * (1.0 + w[speaker_num].direction.dot(w[other_speaker_num].direction)); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	unsigned int get_speaker_count() const { | 
					
						
							|  |  |  | 		return (unsigned int)this->speakers.size(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Vector3 get_speaker_direction(unsigned int index) const { | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | 		return this->speakers.ptr()[index].direction; | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void calculate(const Vector3 &source_direction, real_t tightness, unsigned int volume_count, real_t *volumes) const { | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | 		const Speaker *r = this->speakers.ptr(); | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 		real_t sum_squared_gains = 0.0; | 
					
						
							|  |  |  | 		for (unsigned int speaker_num = 0; speaker_num < (unsigned int)this->speakers.size(); speaker_num++) { | 
					
						
							|  |  |  | 			real_t initial_gain = 0.5 * powf(1.0 + r[speaker_num].direction.dot(source_direction), tightness) / r[speaker_num].effective_number_of_speakers; | 
					
						
							|  |  |  | 			r[speaker_num].squared_gain = initial_gain * initial_gain; | 
					
						
							|  |  |  | 			sum_squared_gains += r[speaker_num].squared_gain; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (unsigned int speaker_num = 0; speaker_num < MIN(volume_count, (unsigned int)this->speakers.size()); speaker_num++) { | 
					
						
							|  |  |  | 			volumes[speaker_num] = sqrtf(r[speaker_num].squared_gain / sum_squared_gains); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //TODO: hardcoded main speaker directions for 2, 3.1, 5.1 and 7.1 setups - these are simplified and could also be made configurable
 | 
					
						
							|  |  |  | static const Vector3 speaker_directions[7] = { | 
					
						
							|  |  |  | 	Vector3(-1.0, 0.0, -1.0).normalized(), // front-left
 | 
					
						
							|  |  |  | 	Vector3(1.0, 0.0, -1.0).normalized(), // front-right
 | 
					
						
							|  |  |  | 	Vector3(0.0, 0.0, -1.0).normalized(), // center
 | 
					
						
							|  |  |  | 	Vector3(-1.0, 0.0, 1.0).normalized(), // rear-left
 | 
					
						
							|  |  |  | 	Vector3(1.0, 0.0, 1.0).normalized(), // rear-right
 | 
					
						
							|  |  |  | 	Vector3(-1.0, 0.0, 0.0).normalized(), // side-left
 | 
					
						
							|  |  |  | 	Vector3(1.0, 0.0, 0.0).normalized(), // side-right
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tightness, AudioStreamPlayer3D::Output &output) { | 
					
						
							|  |  |  | 	unsigned int speaker_count; // only main speakers (no LFE)
 | 
					
						
							|  |  |  | 	switch (AudioServer::get_singleton()->get_speaker_mode()) { | 
					
						
							| 
									
										
										
										
											2020-02-22 20:47:50 +01:00
										 |  |  | 		case AudioServer::SPEAKER_MODE_STEREO: | 
					
						
							|  |  |  | 			speaker_count = 2; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioServer::SPEAKER_SURROUND_31: | 
					
						
							|  |  |  | 			speaker_count = 3; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioServer::SPEAKER_SURROUND_51: | 
					
						
							|  |  |  | 			speaker_count = 5; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioServer::SPEAKER_SURROUND_71: | 
					
						
							|  |  |  | 			speaker_count = 7; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Spcap spcap(speaker_count, speaker_directions); //TODO: should only be created/recreated once the speaker mode / speaker positions changes
 | 
					
						
							|  |  |  | 	real_t volumes[7]; | 
					
						
							|  |  |  | 	spcap.calculate(source_dir, tightness, speaker_count, volumes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (AudioServer::get_singleton()->get_speaker_mode()) { | 
					
						
							|  |  |  | 		case AudioServer::SPEAKER_SURROUND_71: | 
					
						
							|  |  |  | 			output.vol[3].l = volumes[5]; // side-left
 | 
					
						
							|  |  |  | 			output.vol[3].r = volumes[6]; // side-right
 | 
					
						
							| 
									
										
										
										
											2020-02-22 20:47:50 +01:00
										 |  |  | 			[[fallthrough]]; | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 		case AudioServer::SPEAKER_SURROUND_51: | 
					
						
							|  |  |  | 			output.vol[2].l = volumes[3]; // rear-left
 | 
					
						
							|  |  |  | 			output.vol[2].r = volumes[4]; // rear-right
 | 
					
						
							| 
									
										
										
										
											2020-02-22 20:47:50 +01:00
										 |  |  | 			[[fallthrough]]; | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 		case AudioServer::SPEAKER_SURROUND_31: | 
					
						
							|  |  |  | 			output.vol[1].r = 1.0; // LFE - always full power
 | 
					
						
							|  |  |  | 			output.vol[1].l = volumes[2]; // center
 | 
					
						
							| 
									
										
										
										
											2020-02-22 20:47:50 +01:00
										 |  |  | 			[[fallthrough]]; | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 		case AudioServer::SPEAKER_MODE_STEREO: | 
					
						
							|  |  |  | 			output.vol[0].r = volumes[1]; // front-right
 | 
					
						
							|  |  |  | 			output.vol[0].l = volumes[0]; // front-left
 | 
					
						
							| 
									
										
										
										
											2020-02-22 20:47:50 +01:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | void AudioStreamPlayer3D::_mix_audio() { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | 	if (!stream_playback.is_valid() || !active || | 
					
						
							| 
									
										
										
										
											2019-04-27 12:17:54 -03:00
										 |  |  | 			(stream_paused && !stream_paused_fade_out)) { | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool started = false; | 
					
						
							|  |  |  | 	if (setseek >= 0.0) { | 
					
						
							|  |  |  | 		stream_playback->start(setseek); | 
					
						
							|  |  |  | 		setseek = -1.0; //reset seek
 | 
					
						
							|  |  |  | 		started = true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//get data
 | 
					
						
							| 
									
										
										
										
											2017-11-25 00:07:54 -03:00
										 |  |  | 	AudioFrame *buffer = mix_buffer.ptrw(); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	int buffer_size = mix_buffer.size(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 12:17:54 -03:00
										 |  |  | 	if (stream_paused_fade_out) { | 
					
						
							| 
									
										
										
										
											2018-07-08 21:30:26 -03:00
										 |  |  | 		// Short fadeout ramp
 | 
					
						
							|  |  |  | 		buffer_size = MIN(buffer_size, 128); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | 	// Mix if we're not paused or we're fading out
 | 
					
						
							| 
									
										
										
										
											2018-07-08 21:30:26 -03:00
										 |  |  | 	if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) { | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | 		float output_pitch_scale = 0.0; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		if (output_count) { | 
					
						
							|  |  |  | 			//used for doppler, not realistic but good enough
 | 
					
						
							|  |  |  | 			for (int i = 0; i < output_count; i++) { | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | 				output_pitch_scale += outputs[i].pitch_scale; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | 			output_pitch_scale /= float(output_count); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | 			output_pitch_scale = 1.0; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | 		stream_playback->mix(buffer, pitch_scale * output_pitch_scale, buffer_size); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//write all outputs
 | 
					
						
							|  |  |  | 	for (int i = 0; i < output_count; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Output current = outputs[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		//see if current output exists, to keep volume ramp
 | 
					
						
							|  |  |  | 		bool found = false; | 
					
						
							|  |  |  | 		for (int j = i; j < prev_output_count; j++) { | 
					
						
							|  |  |  | 			if (prev_outputs[j].viewport == current.viewport) { | 
					
						
							|  |  |  | 				if (j != i) { | 
					
						
							|  |  |  | 					SWAP(prev_outputs[j], prev_outputs[i]); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				found = true; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bool interpolate_filter = !started; | 
					
						
							| 
									
										
										
										
											2019-06-26 15:08:25 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		if (!found) { | 
					
						
							|  |  |  | 			//create new if was not used before
 | 
					
						
							|  |  |  | 			if (prev_output_count < MAX_OUTPUTS) { | 
					
						
							|  |  |  | 				prev_outputs[prev_output_count] = prev_outputs[i]; //may be owned by another viewport
 | 
					
						
							|  |  |  | 				prev_output_count++; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			prev_outputs[i] = current; | 
					
						
							|  |  |  | 			interpolate_filter = false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		//mix!
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:27:17 -03:00
										 |  |  | 		int buffers = AudioServer::get_singleton()->get_channel_count(); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for (int k = 0; k < buffers; k++) { | 
					
						
							| 
									
										
										
										
											2019-04-27 12:17:54 -03:00
										 |  |  | 			AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol[k]; | 
					
						
							|  |  |  | 			AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol[k]; | 
					
						
							| 
									
										
										
										
											2018-07-08 21:30:26 -03:00
										 |  |  | 			AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size); | 
					
						
							| 
									
										
										
										
											2019-04-27 12:17:54 -03:00
										 |  |  | 			AudioFrame vol = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : current.vol[k]; | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-13 18:16:33 -03:00
										 |  |  | 			if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, k)) | 
					
						
							|  |  |  | 				continue; //may have been deleted, will be updated on process
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-13 18:16:33 -03:00
										 |  |  | 			AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 			current.filter.set_mode(AudioFilterSW::HIGHSHELF); | 
					
						
							|  |  |  | 			current.filter.set_sampling_rate(AudioServer::get_singleton()->get_mix_rate()); | 
					
						
							|  |  |  | 			current.filter.set_cutoff(attenuation_filter_cutoff_hz); | 
					
						
							|  |  |  | 			current.filter.set_resonance(1); | 
					
						
							|  |  |  | 			current.filter.set_stages(1); | 
					
						
							|  |  |  | 			current.filter.set_gain(current.filter_gain); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (interpolate_filter) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 0] = prev_outputs[i].filter_process[k * 2 + 0]; | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 1] = prev_outputs[i].filter_process[k * 2 + 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 0].set_filter(¤t.filter, false); | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 1].set_filter(¤t.filter, false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 0].update_coeffs(buffer_size); | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 1].update_coeffs(buffer_size); | 
					
						
							|  |  |  | 				for (int j = 0; j < buffer_size; j++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					AudioFrame f = buffer[j] * vol; | 
					
						
							|  |  |  | 					current.filter_process[k * 2 + 0].process_one_interp(f.l); | 
					
						
							|  |  |  | 					current.filter_process[k * 2 + 1].process_one_interp(f.r); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					target[j] += f; | 
					
						
							|  |  |  | 					vol += vol_inc; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 0].set_filter(¤t.filter); | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 1].set_filter(¤t.filter); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 0].update_coeffs(); | 
					
						
							|  |  |  | 				current.filter_process[k * 2 + 1].update_coeffs(); | 
					
						
							|  |  |  | 				for (int j = 0; j < buffer_size; j++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					AudioFrame f = buffer[j] * vol; | 
					
						
							|  |  |  | 					current.filter_process[k * 2 + 0].process_one(f.l); | 
					
						
							|  |  |  | 					current.filter_process[k * 2 + 1].process_one(f.r); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					target[j] += f; | 
					
						
							|  |  |  | 					vol += vol_inc; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (current.reverb_bus_index >= 0) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-13 18:16:33 -03:00
										 |  |  | 				if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.reverb_bus_index, k)) | 
					
						
							|  |  |  | 					continue; //may have been deleted, will be updated on process
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:27:17 -03:00
										 |  |  | 				AudioFrame *rtarget = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.reverb_bus_index, k); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (current.reverb_bus_index == prev_outputs[i].reverb_bus_index) { | 
					
						
							|  |  |  | 					AudioFrame rvol_inc = (current.reverb_vol[k] - prev_outputs[i].reverb_vol[k]) / float(buffer_size); | 
					
						
							|  |  |  | 					AudioFrame rvol = prev_outputs[i].reverb_vol[k]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					for (int j = 0; j < buffer_size; j++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						rtarget[j] += buffer[j] * rvol; | 
					
						
							|  |  |  | 						rvol += rvol_inc; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					AudioFrame rvol = current.reverb_vol[k]; | 
					
						
							|  |  |  | 					for (int j = 0; j < buffer_size; j++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						rtarget[j] += buffer[j] * rvol; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		prev_outputs[i] = current; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	prev_output_count = output_count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//stream is no longer active, disable this.
 | 
					
						
							|  |  |  | 	if (!stream_playback->is_playing()) { | 
					
						
							|  |  |  | 		active = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	output_ready = false; | 
					
						
							| 
									
										
										
										
											2019-04-27 12:17:54 -03:00
										 |  |  | 	stream_paused_fade_in = false; | 
					
						
							|  |  |  | 	stream_paused_fade_out = false; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 22:33:39 +02:00
										 |  |  | 	float att = 0; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	switch (attenuation_model) { | 
					
						
							|  |  |  | 		case ATTENUATION_INVERSE_DISTANCE: { | 
					
						
							| 
									
										
										
										
											2019-01-17 01:41:36 +03:00
										 |  |  | 			att = Math::linear2db(1.0 / ((p_distance / unit_size) + CMP_EPSILON)); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case ATTENUATION_INVERSE_SQUARE_DISTANCE: { | 
					
						
							|  |  |  | 			float d = (p_distance / unit_size); | 
					
						
							|  |  |  | 			d *= d; | 
					
						
							| 
									
										
										
										
											2019-01-17 01:41:36 +03:00
										 |  |  | 			att = Math::linear2db(1.0 / (d + CMP_EPSILON)); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case ATTENUATION_LOGARITHMIC: { | 
					
						
							| 
									
										
										
										
											2019-01-17 01:41:36 +03:00
										 |  |  | 			att = -20 * Math::log(p_distance / unit_size + CMP_EPSILON); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		} break; | 
					
						
							| 
									
										
										
										
											2019-03-10 13:25:54 +00:00
										 |  |  | 		case ATTENUATION_DISABLED: break; | 
					
						
							| 
									
										
										
										
											2017-09-01 22:33:39 +02:00
										 |  |  | 		default: { | 
					
						
							|  |  |  | 			ERR_PRINT("Unknown attenuation type"); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	att += unit_db; | 
					
						
							|  |  |  | 	if (att > max_db) { | 
					
						
							|  |  |  | 		att = max_db; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return att; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void _update_sound() { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::_notification(int p_what) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_what == NOTIFICATION_ENTER_TREE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		velocity_tracker->reset(get_global_transform().origin); | 
					
						
							|  |  |  | 		AudioServer::get_singleton()->add_callback(_mix_audios, this); | 
					
						
							| 
									
										
										
										
											2017-08-19 01:02:56 +02:00
										 |  |  | 		if (autoplay && !Engine::get_singleton()->is_editor_hint()) { | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 			play(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_what == NOTIFICATION_EXIT_TREE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		AudioServer::get_singleton()->remove_callback(_mix_audios, this); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (p_what == NOTIFICATION_PAUSED) { | 
					
						
							|  |  |  | 		if (!can_process()) { | 
					
						
							|  |  |  | 			// Node can't process so we start fading out to silence
 | 
					
						
							|  |  |  | 			set_stream_paused(true); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_what == NOTIFICATION_UNPAUSED) { | 
					
						
							|  |  |  | 		set_stream_paused(false); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { | 
					
						
							|  |  |  | 			velocity_tracker->update_position(get_global_transform().origin); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-30 16:19:07 +02:00
										 |  |  | 	if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		//update anything related to position first, if possible of course
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!output_ready) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Vector3 linear_velocity; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			//compute linear velocity for doppler
 | 
					
						
							|  |  |  | 			if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { | 
					
						
							|  |  |  | 				linear_velocity = velocity_tracker->get_tracked_linear_velocity(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Ref<World> world = get_world(); | 
					
						
							|  |  |  | 			ERR_FAIL_COND(world.is_null()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			int new_output_count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Vector3 global_pos = get_global_transform().origin; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			//check if any area is diverting sound into a bus
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			PhysicsDirectSpaceState *space_state = PhysicsServer::get_singleton()->space_get_direct_state(world->get_space()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			PhysicsDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 05:15:22 +02:00
										 |  |  | 			int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 			Area *area = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for (int i = 0; i < areas; i++) { | 
					
						
							|  |  |  | 				if (!sr[i].collider) | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-24 22:58:51 +02:00
										 |  |  | 				Area *tarea = Object::cast_to<Area>(sr[i].collider); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 				if (!tarea) | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (!tarea->is_overriding_audio_bus() && !tarea->is_using_reverb_bus()) | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				area = tarea; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			List<Camera *> cameras; | 
					
						
							|  |  |  | 			world->get_camera_list(&cameras); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for (List<Camera *>::Element *E = cameras.front(); E; E = E->next()) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				Camera *camera = E->get(); | 
					
						
							|  |  |  | 				Viewport *vp = camera->get_viewport(); | 
					
						
							|  |  |  | 				if (!vp->is_audio_listener()) | 
					
						
							|  |  |  | 					continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 				bool listener_is_camera = true; | 
					
						
							|  |  |  | 				Spatial *listener_node = camera; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				Listener *listener = vp->get_listener(); | 
					
						
							|  |  |  | 				if (listener) { | 
					
						
							|  |  |  | 					listener_node = listener; | 
					
						
							|  |  |  | 					listener_is_camera = false; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				Vector3 local_pos = listener_node->get_global_transform().orthonormalized().affine_inverse().xform(global_pos); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				float dist = local_pos.length(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				Vector3 area_sound_pos; | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 				Vector3 listener_area_pos; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) { | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 					area_sound_pos = space_state->get_closest_point_to_object_volume(area->get_rid(), listener_node->get_global_transform().origin); | 
					
						
							|  |  |  | 					listener_area_pos = listener_node->get_global_transform().affine_inverse().xform(area_sound_pos); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (max_distance > 0) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					float total_max = max_distance; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) { | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 						total_max = MAX(total_max, listener_area_pos.length()); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					if (total_max > max_distance) { | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 						continue; //can't hear this sound in this listener
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				float multiplier = Math::db2linear(_get_attenuation_db(dist)); | 
					
						
							|  |  |  | 				if (max_distance > 0) { | 
					
						
							|  |  |  | 					multiplier *= MAX(0, 1.0 - (dist / max_distance)); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				Output output; | 
					
						
							|  |  |  | 				output.bus_index = bus_index; | 
					
						
							|  |  |  | 				output.reverb_bus_index = -1; //no reverb by default
 | 
					
						
							|  |  |  | 				output.viewport = vp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				float db_att = (1.0 - MIN(1.0, multiplier)) * attenuation_filter_db; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (emission_angle_enabled) { | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 					Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin; | 
					
						
							|  |  |  | 					float c = listenertopos.normalized().dot(get_global_transform().basis.get_axis(2).normalized()); //it's z negative
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 					float angle = Math::rad2deg(Math::acos(c)); | 
					
						
							|  |  |  | 					if (angle > emission_angle) | 
					
						
							|  |  |  | 						db_att -= -emission_angle_filter_attenuation_db; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				output.filter_gain = Math::db2linear(db_att); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-01 22:35:07 +02:00
										 |  |  | 				//TODO: The lower the second parameter (tightness) the more the sound will "enclose" the listener (more undirected / playing from
 | 
					
						
							|  |  |  | 				//      speakers not facing the source) - this could be made distance dependent.
 | 
					
						
							|  |  |  | 				_calc_output_vol(local_pos.normalized(), 4.0, output); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:27:17 -03:00
										 |  |  | 				unsigned int cc = AudioServer::get_singleton()->get_channel_count(); | 
					
						
							| 
									
										
										
										
											2018-09-26 17:38:02 +02:00
										 |  |  | 				for (unsigned int k = 0; k < cc; k++) { | 
					
						
							| 
									
										
										
										
											2017-08-22 18:27:17 -03:00
										 |  |  | 					output.vol[k] *= multiplier; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 18:40:47 -03:00
										 |  |  | 				bool filled_reverb = false; | 
					
						
							|  |  |  | 				int vol_index_max = AudioServer::get_singleton()->get_speaker_mode() + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 				if (area) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if (area->is_overriding_audio_bus()) { | 
					
						
							|  |  |  | 						//override audio bus
 | 
					
						
							|  |  |  | 						StringName bus_name = area->get_audio_bus(); | 
					
						
							|  |  |  | 						output.bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if (area->is_using_reverb_bus()) { | 
					
						
							| 
									
										
										
										
											2017-07-15 18:40:47 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						filled_reverb = true; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 						StringName bus_name = area->get_reverb_bus(); | 
					
						
							|  |  |  | 						output.reverb_bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						float uniformity = area->get_reverb_uniformity(); | 
					
						
							|  |  |  | 						float area_send = area->get_reverb_amount(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if (uniformity > 0.0) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 							float distance = listener_area_pos.length(); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 							float attenuation = Math::db2linear(_get_attenuation_db(distance)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							//float dist_att_db = -20 * Math::log(dist + 0.00001); //logarithmic attenuation, like in real life
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 14:38:52 +01:00
										 |  |  | 							float center_val[3] = { 0.5f, 0.25f, 0.16666f }; | 
					
						
							| 
									
										
										
										
											2017-07-15 18:40:47 -03:00
										 |  |  | 							AudioFrame center_frame(center_val[vol_index_max - 1], center_val[vol_index_max - 1]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 							if (attenuation < 1.0) { | 
					
						
							|  |  |  | 								//pan the uniform sound
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 								Vector3 rev_pos = listener_area_pos; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 								rev_pos.y = 0; | 
					
						
							|  |  |  | 								rev_pos.normalize(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:27:17 -03:00
										 |  |  | 								if (cc >= 1) { | 
					
						
							|  |  |  | 									// Stereo pair
 | 
					
						
							|  |  |  | 									float c = rev_pos.x * 0.5 + 0.5; | 
					
						
							|  |  |  | 									output.reverb_vol[0].l = 1.0 - c; | 
					
						
							|  |  |  | 									output.reverb_vol[0].r = c; | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:27:17 -03:00
										 |  |  | 								if (cc >= 3) { | 
					
						
							|  |  |  | 									// Center pair + Side pair
 | 
					
						
							|  |  |  | 									float xl = Vector3(-1, 0, -1).normalized().dot(rev_pos) * 0.5 + 0.5; | 
					
						
							|  |  |  | 									float xr = Vector3(1, 0, -1).normalized().dot(rev_pos) * 0.5 + 0.5; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:27:17 -03:00
										 |  |  | 									output.reverb_vol[1].l = xl; | 
					
						
							|  |  |  | 									output.reverb_vol[1].r = xr; | 
					
						
							|  |  |  | 									output.reverb_vol[2].l = 1.0 - xr; | 
					
						
							|  |  |  | 									output.reverb_vol[2].r = 1.0 - xl; | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:27:17 -03:00
										 |  |  | 								if (cc >= 4) { | 
					
						
							|  |  |  | 									// Rear pair
 | 
					
						
							|  |  |  | 									// FIXME: Not sure what math should be done here
 | 
					
						
							|  |  |  | 									float c = rev_pos.x * 0.5 + 0.5; | 
					
						
							|  |  |  | 									output.reverb_vol[3].l = 1.0 - c; | 
					
						
							|  |  |  | 									output.reverb_vol[3].r = c; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 								} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 18:40:47 -03:00
										 |  |  | 								for (int i = 0; i < vol_index_max; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									output.reverb_vol[i] = output.reverb_vol[i].linear_interpolate(center_frame, attenuation); | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} else { | 
					
						
							|  |  |  | 								for (int i = 0; i < vol_index_max; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									output.reverb_vol[i] = center_frame; | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							for (int i = 0; i < vol_index_max; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								output.reverb_vol[i] = output.vol[i].linear_interpolate(output.reverb_vol[i] * attenuation, uniformity); | 
					
						
							|  |  |  | 								output.reverb_vol[i] *= area_send; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							for (int i = 0; i < vol_index_max; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								output.reverb_vol[i] = output.vol[i] * area_send; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 					Vector3 listener_velocity; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if (listener_is_camera) { | 
					
						
							|  |  |  | 						listener_velocity = camera->get_doppler_tracked_velocity(); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 20:35:32 +11:00
										 |  |  | 					Vector3 local_velocity = listener_node->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - listener_velocity); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					if (local_velocity == Vector3()) { | 
					
						
							|  |  |  | 						output.pitch_scale = 1.0; | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						float approaching = local_pos.normalized().dot(local_velocity.normalized()); | 
					
						
							|  |  |  | 						float velocity = local_velocity.length(); | 
					
						
							|  |  |  | 						float speed_of_sound = 343.0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						output.pitch_scale = speed_of_sound / (speed_of_sound + velocity * approaching); | 
					
						
							|  |  |  | 						output.pitch_scale = CLAMP(output.pitch_scale, (1 / 8.0), 8.0); //avoid crazy stuff
 | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					output.pitch_scale = 1.0; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 18:40:47 -03:00
										 |  |  | 				if (!filled_reverb) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					for (int i = 0; i < vol_index_max; i++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						output.reverb_vol[i] = AudioFrame(0, 0); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 				outputs[new_output_count] = output; | 
					
						
							|  |  |  | 				new_output_count++; | 
					
						
							|  |  |  | 				if (new_output_count == MAX_OUTPUTS) | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			output_count = new_output_count; | 
					
						
							|  |  |  | 			output_ready = true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		//start playing if requested
 | 
					
						
							|  |  |  | 		if (setplay >= 0.0) { | 
					
						
							|  |  |  | 			setseek = setplay; | 
					
						
							|  |  |  | 			active = true; | 
					
						
							|  |  |  | 			setplay = -1; | 
					
						
							| 
									
										
										
										
											2018-02-21 11:30:55 -05:00
										 |  |  | 			//do not update, this makes it easier to animate (will shut off otherwise)
 | 
					
						
							| 
									
										
										
										
											2017-09-06 22:03:04 -03:00
										 |  |  | 			///_change_notify("playing"); //update property in editor
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		//stop playing if no longer active
 | 
					
						
							|  |  |  | 		if (!active) { | 
					
						
							| 
									
										
										
										
											2017-09-30 16:19:07 +02:00
										 |  |  | 			set_physics_process_internal(false); | 
					
						
							| 
									
										
										
										
											2018-05-13 21:37:08 +02:00
										 |  |  | 			//do not update, this makes it easier to animate (will shut off otherwise)
 | 
					
						
							| 
									
										
										
										
											2017-09-06 22:03:04 -03:00
										 |  |  | 			//_change_notify("playing"); //update property in editor
 | 
					
						
							| 
									
										
										
										
											2017-08-25 11:58:21 -03:00
										 |  |  | 			emit_signal("finished"); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AudioServer::get_singleton()->lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stream_playback.is_valid()) { | 
					
						
							|  |  |  | 		stream_playback.unref(); | 
					
						
							|  |  |  | 		stream.unref(); | 
					
						
							|  |  |  | 		active = false; | 
					
						
							|  |  |  | 		setseek = -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 18:56:05 +07:00
										 |  |  | 	if (p_stream.is_valid()) { | 
					
						
							|  |  |  | 		stream = p_stream; | 
					
						
							|  |  |  | 		stream_playback = p_stream->instance_playback(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 16:42:50 -03:00
										 |  |  | 	AudioServer::get_singleton()->unlock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-19 18:56:05 +07:00
										 |  |  | 	if (p_stream.is_valid() && stream_playback.is_null()) { | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		stream.unref(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Ref<AudioStream> AudioStreamPlayer3D::get_stream() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return stream; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_unit_db(float p_volume) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	unit_db = p_volume; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_unit_db() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return unit_db; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_unit_size(float p_volume) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	unit_size = p_volume; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_unit_size() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return unit_size; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_max_db(float p_boost) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	max_db = p_boost; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_max_db() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return max_db; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | void AudioStreamPlayer3D::set_pitch_scale(float p_pitch_scale) { | 
					
						
							| 
									
										
										
										
											2018-08-20 11:25:48 +03:00
										 |  |  | 	ERR_FAIL_COND(p_pitch_scale <= 0.0); | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | 	pitch_scale = p_pitch_scale; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_pitch_scale() const { | 
					
						
							|  |  |  | 	return pitch_scale; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | void AudioStreamPlayer3D::play(float p_from_pos) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stream_playback.is_valid()) { | 
					
						
							| 
									
										
										
										
											2018-11-17 11:47:11 -03:00
										 |  |  | 		active = true; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 		setplay = p_from_pos; | 
					
						
							|  |  |  | 		output_ready = false; | 
					
						
							| 
									
										
										
										
											2017-09-30 16:19:07 +02:00
										 |  |  | 		set_physics_process_internal(true); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::seek(float p_seconds) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stream_playback.is_valid()) { | 
					
						
							|  |  |  | 		setseek = p_seconds; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::stop() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stream_playback.is_valid()) { | 
					
						
							| 
									
										
										
										
											2019-04-27 12:17:54 -03:00
										 |  |  | 		active = false; | 
					
						
							|  |  |  | 		set_physics_process_internal(false); | 
					
						
							|  |  |  | 		setplay = -1; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AudioStreamPlayer3D::is_playing() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stream_playback.is_valid()) { | 
					
						
							|  |  |  | 		return active; // && stream_playback->is_playing();
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 00:31:36 -03:00
										 |  |  | float AudioStreamPlayer3D::get_playback_position() { | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (stream_playback.is_valid()) { | 
					
						
							| 
									
										
										
										
											2017-09-21 00:31:36 -03:00
										 |  |  | 		return stream_playback->get_playback_position(); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_bus(const StringName &p_bus) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//if audio is active, must lock this
 | 
					
						
							|  |  |  | 	AudioServer::get_singleton()->lock(); | 
					
						
							|  |  |  | 	bus = p_bus; | 
					
						
							|  |  |  | 	AudioServer::get_singleton()->unlock(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | StringName AudioStreamPlayer3D::get_bus() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { | 
					
						
							|  |  |  | 		if (AudioServer::get_singleton()->get_bus_name(i) == bus) { | 
					
						
							|  |  |  | 			return bus; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return "Master"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_autoplay(bool p_enable) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	autoplay = p_enable; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | bool AudioStreamPlayer3D::is_autoplay_enabled() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return autoplay; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::_set_playing(bool p_enable) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_enable) | 
					
						
							|  |  |  | 		play(); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		stop(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | bool AudioStreamPlayer3D::_is_active() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return active; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (property.name == "bus") { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		String options; | 
					
						
							|  |  |  | 		for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { | 
					
						
							|  |  |  | 			if (i > 0) | 
					
						
							|  |  |  | 				options += ","; | 
					
						
							|  |  |  | 			String name = AudioServer::get_singleton()->get_bus_name(i); | 
					
						
							|  |  |  | 			options += name; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		property.hint_string = options; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::_bus_layout_changed() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_change_notify(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_max_distance(float p_metres) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND(p_metres < 0.0); | 
					
						
							|  |  |  | 	max_distance = p_metres; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_max_distance() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return max_distance; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_area_mask(uint32_t p_mask) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	area_mask = p_mask; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint32_t AudioStreamPlayer3D::get_area_mask() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return area_mask; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_emission_angle_enabled(bool p_enable) { | 
					
						
							|  |  |  | 	emission_angle_enabled = p_enable; | 
					
						
							|  |  |  | 	update_gizmo(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AudioStreamPlayer3D::is_emission_angle_enabled() const { | 
					
						
							|  |  |  | 	return emission_angle_enabled; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_emission_angle(float p_angle) { | 
					
						
							|  |  |  | 	ERR_FAIL_COND(p_angle < 0 || p_angle > 90); | 
					
						
							|  |  |  | 	emission_angle = p_angle; | 
					
						
							|  |  |  | 	update_gizmo(); | 
					
						
							| 
									
										
										
										
											2019-07-10 20:06:59 +02:00
										 |  |  | 	_change_notify("emission_angle"); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_emission_angle() const { | 
					
						
							|  |  |  | 	return emission_angle; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_emission_angle_filter_attenuation_db(float p_angle_attenuation_db) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	emission_angle_filter_attenuation_db = p_angle_attenuation_db; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_emission_angle_filter_attenuation_db() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return emission_angle_filter_attenuation_db; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_attenuation_filter_cutoff_hz(float p_hz) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	attenuation_filter_cutoff_hz = p_hz; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_attenuation_filter_cutoff_hz() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return attenuation_filter_cutoff_hz; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_attenuation_filter_db(float p_db) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	attenuation_filter_db = p_db; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | float AudioStreamPlayer3D::get_attenuation_filter_db() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return attenuation_filter_db; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_attenuation_model(AttenuationModel p_model) { | 
					
						
							| 
									
										
										
										
											2019-03-10 13:25:54 +00:00
										 |  |  | 	ERR_FAIL_INDEX((int)p_model, 4); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	attenuation_model = p_model; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioStreamPlayer3D::AttenuationModel AudioStreamPlayer3D::get_attenuation_model() const { | 
					
						
							|  |  |  | 	return attenuation_model; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_out_of_range_mode(OutOfRangeMode p_mode) { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-04 09:17:59 +02:00
										 |  |  | 	ERR_FAIL_INDEX((int)p_mode, 2); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	out_of_range_mode = p_mode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioStreamPlayer3D::OutOfRangeMode AudioStreamPlayer3D::get_out_of_range_mode() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return out_of_range_mode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlayer3D::set_doppler_tracking(DopplerTracking p_tracking) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (doppler_tracking == p_tracking) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	doppler_tracking = p_tracking; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { | 
					
						
							|  |  |  | 		set_notify_transform(true); | 
					
						
							| 
									
										
										
										
											2017-09-30 16:19:07 +02:00
										 |  |  | 		velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP); | 
					
						
							| 
									
										
										
										
											2019-02-26 09:15:51 -03:00
										 |  |  | 		if (is_inside_tree()) { | 
					
						
							|  |  |  | 			velocity_tracker->reset(get_global_transform().origin); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		set_notify_transform(false); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioStreamPlayer3D::DopplerTracking AudioStreamPlayer3D::get_doppler_tracking() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return doppler_tracking; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | void AudioStreamPlayer3D::set_stream_paused(bool p_pause) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_pause != stream_paused) { | 
					
						
							|  |  |  | 		stream_paused = p_pause; | 
					
						
							| 
									
										
										
										
											2019-06-26 15:08:25 +02:00
										 |  |  | 		stream_paused_fade_in = !stream_paused; | 
					
						
							|  |  |  | 		stream_paused_fade_out = stream_paused; | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AudioStreamPlayer3D::get_stream_paused() const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return stream_paused; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 12:57:03 -03:00
										 |  |  | Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() { | 
					
						
							|  |  |  | 	return stream_playback; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | void AudioStreamPlayer3D::_bind_methods() { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-09 13:19:41 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer3D::get_stream); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_unit_db", "unit_db"), &AudioStreamPlayer3D::set_unit_db); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_unit_db"), &AudioStreamPlayer3D::get_unit_db); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_unit_size", "unit_size"), &AudioStreamPlayer3D::set_unit_size); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_unit_size"), &AudioStreamPlayer3D::get_unit_size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_max_db", "max_db"), &AudioStreamPlayer3D::set_max_db); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_max_db"), &AudioStreamPlayer3D::get_max_db); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer3D::set_pitch_scale); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer3D::get_pitch_scale); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer3D::play, DEFVAL(0.0)); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer3D::seek); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer3D::stop); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer3D::is_playing); | 
					
						
							| 
									
										
										
										
											2017-09-21 00:31:36 -03:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("get_playback_position"), &AudioStreamPlayer3D::get_playback_position); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioStreamPlayer3D::set_bus); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_bus"), &AudioStreamPlayer3D::get_bus); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioStreamPlayer3D::set_autoplay); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer3D::is_autoplay_enabled); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer3D::_set_playing); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer3D::_is_active); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_max_distance", "metres"), &AudioStreamPlayer3D::set_max_distance); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_max_distance"), &AudioStreamPlayer3D::get_max_distance); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer3D::set_area_mask); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_area_mask"), &AudioStreamPlayer3D::get_area_mask); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_emission_angle", "degrees"), &AudioStreamPlayer3D::set_emission_angle); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_emission_angle"), &AudioStreamPlayer3D::get_emission_angle); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_emission_angle_enabled", "enabled"), &AudioStreamPlayer3D::set_emission_angle_enabled); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_emission_angle_enabled"), &AudioStreamPlayer3D::is_emission_angle_enabled); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_emission_angle_filter_attenuation_db", "db"), &AudioStreamPlayer3D::set_emission_angle_filter_attenuation_db); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_emission_angle_filter_attenuation_db"), &AudioStreamPlayer3D::get_emission_angle_filter_attenuation_db); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_attenuation_filter_cutoff_hz", "degrees"), &AudioStreamPlayer3D::set_attenuation_filter_cutoff_hz); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_attenuation_filter_cutoff_hz"), &AudioStreamPlayer3D::get_attenuation_filter_cutoff_hz); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_attenuation_filter_db", "db"), &AudioStreamPlayer3D::set_attenuation_filter_db); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_attenuation_filter_db"), &AudioStreamPlayer3D::get_attenuation_filter_db); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_attenuation_model", "model"), &AudioStreamPlayer3D::set_attenuation_model); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_attenuation_model"), &AudioStreamPlayer3D::get_attenuation_model); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_out_of_range_mode", "mode"), &AudioStreamPlayer3D::set_out_of_range_mode); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_out_of_range_mode"), &AudioStreamPlayer3D::get_out_of_range_mode); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &AudioStreamPlayer3D::set_doppler_tracking); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &AudioStreamPlayer3D::get_doppler_tracking); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer3D::set_stream_paused); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer3D::get_stream_paused); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-10 12:57:03 -03:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer3D::_bus_layout_changed); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); | 
					
						
							| 
									
										
										
										
											2019-03-10 13:25:54 +00:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,InverseSquare,Log,Disabled"), "set_attenuation_model", "get_attenuation_model"); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.1"), "set_unit_size", "get_unit_size"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db"); | 
					
						
							| 
									
										
										
										
											2020-02-15 15:12:13 +11:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale"); | 
					
						
							| 
									
										
										
										
											2017-09-13 08:40:41 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); | 
					
						
							| 
									
										
										
										
											2018-05-16 09:13:41 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance"); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode"); | 
					
						
							| 
									
										
										
										
											2020-02-20 18:58:05 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); | 
					
						
							|  |  |  | 	ADD_GROUP("Emission Angle", "emission_angle"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emission_angle_enabled"), "set_emission_angle_enabled", "is_emission_angle_enabled"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_angle_degrees", PROPERTY_HINT_RANGE, "0.1,90,0.1"), "set_emission_angle", "get_emission_angle"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_angle_filter_attenuation_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_emission_angle_filter_attenuation_db", "get_emission_angle_filter_attenuation_db"); | 
					
						
							|  |  |  | 	ADD_GROUP("Attenuation Filter", "attenuation_filter_"); | 
					
						
							| 
									
										
										
										
											2019-07-12 22:41:47 +02:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation_filter_cutoff_hz", PROPERTY_HINT_RANGE, "1,20500,1"), "set_attenuation_filter_cutoff_hz", "get_attenuation_filter_cutoff_hz"); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation_filter_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_attenuation_filter_db", "get_attenuation_filter_db"); | 
					
						
							|  |  |  | 	ADD_GROUP("Doppler", "doppler_"); | 
					
						
							| 
									
										
										
										
											2017-10-21 21:28:08 +07:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking"); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-20 17:45:01 +02:00
										 |  |  | 	BIND_ENUM_CONSTANT(ATTENUATION_INVERSE_DISTANCE); | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(ATTENUATION_INVERSE_SQUARE_DISTANCE); | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(ATTENUATION_LOGARITHMIC); | 
					
						
							| 
									
										
										
										
											2019-03-10 13:25:54 +00:00
										 |  |  | 	BIND_ENUM_CONSTANT(ATTENUATION_DISABLED); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-20 17:45:01 +02:00
										 |  |  | 	BIND_ENUM_CONSTANT(OUT_OF_RANGE_MIX); | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(OUT_OF_RANGE_PAUSE); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-20 17:45:01 +02:00
										 |  |  | 	BIND_ENUM_CONSTANT(DOPPLER_TRACKING_DISABLED); | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(DOPPLER_TRACKING_IDLE_STEP); | 
					
						
							| 
									
										
										
										
											2017-09-30 16:19:07 +02:00
										 |  |  | 	BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP); | 
					
						
							| 
									
										
										
										
											2017-08-25 11:58:21 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ADD_SIGNAL(MethodInfo("finished")); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioStreamPlayer3D::AudioStreamPlayer3D() { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	unit_db = 0; | 
					
						
							|  |  |  | 	unit_size = 1; | 
					
						
							|  |  |  | 	attenuation_model = ATTENUATION_INVERSE_DISTANCE; | 
					
						
							|  |  |  | 	max_db = 3; | 
					
						
							| 
									
										
										
										
											2018-01-01 22:23:16 +01:00
										 |  |  | 	pitch_scale = 1.0; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	autoplay = false; | 
					
						
							|  |  |  | 	setseek = -1; | 
					
						
							|  |  |  | 	active = false; | 
					
						
							|  |  |  | 	output_count = 0; | 
					
						
							|  |  |  | 	prev_output_count = 0; | 
					
						
							|  |  |  | 	max_distance = 0; | 
					
						
							|  |  |  | 	setplay = -1; | 
					
						
							|  |  |  | 	output_ready = false; | 
					
						
							|  |  |  | 	area_mask = 1; | 
					
						
							|  |  |  | 	emission_angle = 45; | 
					
						
							|  |  |  | 	emission_angle_enabled = false; | 
					
						
							|  |  |  | 	emission_angle_filter_attenuation_db = -12; | 
					
						
							|  |  |  | 	attenuation_filter_cutoff_hz = 5000; | 
					
						
							|  |  |  | 	attenuation_filter_db = -24; | 
					
						
							|  |  |  | 	out_of_range_mode = OUT_OF_RANGE_MIX; | 
					
						
							|  |  |  | 	doppler_tracking = DOPPLER_TRACKING_DISABLED; | 
					
						
							| 
									
										
										
										
											2018-05-27 15:29:10 -03:00
										 |  |  | 	stream_paused = false; | 
					
						
							| 
									
										
										
										
											2019-04-27 12:17:54 -03:00
										 |  |  | 	stream_paused_fade_in = false; | 
					
						
							|  |  |  | 	stream_paused_fade_out = false; | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	velocity_tracker.instance(); | 
					
						
							| 
									
										
										
										
											2020-02-19 16:27:19 -03:00
										 |  |  | 	AudioServer::get_singleton()->connect_compat("bus_layout_changed", this, "_bus_layout_changed"); | 
					
						
							| 
									
										
										
										
											2018-07-18 13:47:42 -03:00
										 |  |  | 	set_disable_scale(true); | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | } | 
					
						
							|  |  |  | AudioStreamPlayer3D::~AudioStreamPlayer3D() { | 
					
						
							|  |  |  | } |