summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2021-08-27 15:38:20 -0300
committerGitHub <noreply@github.com>2021-08-27 15:38:20 -0300
commit54caaa21ce427ac3b240d5b514dc339fd8e13204 (patch)
treefc2bfcdf0c1cc8fc8fd66e9bf68c1b74b006b4f9 /scene
parent87f575efddf503297e056f169cfd8a68dbe859c5 (diff)
parent3598d300cb43797a4f18b34d921875d060ce7de7 (diff)
Merge pull request #51296 from ellenhp/mix_in_audio_server
Move mixing out of the AudioStreamPlayback* nodes
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/audio_stream_player_2d.cpp326
-rw-r--r--scene/2d/audio_stream_player_2d.h26
-rw-r--r--scene/3d/audio_stream_player_3d.cpp661
-rw-r--r--scene/3d/audio_stream_player_3d.h42
-rw-r--r--scene/audio/audio_stream_player.cpp237
-rw-r--r--scene/audio/audio_stream_player.h13
-rw-r--r--scene/gui/video_player.cpp5
-rw-r--r--scene/main/viewport.cpp9
-rw-r--r--scene/resources/audio_stream_sample.cpp7
-rw-r--r--scene/resources/audio_stream_sample.h2
10 files changed, 481 insertions, 847 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 8a4d42fd1f..ea491e8b0e 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -33,125 +33,17 @@
#include "scene/2d/area_2d.h"
#include "scene/main/window.h"
-void AudioStreamPlayer2D::_mix_audio() {
- if (!stream_playback.is_valid() || !active.is_set() ||
- (stream_paused && !stream_paused_fade_out)) {
- return;
- }
-
- if (setseek.get() >= 0.0) {
- stream_playback->start(setseek.get());
- setseek.set(-1.0); //reset seek
- }
-
- //get data
- AudioFrame *buffer = mix_buffer.ptrw();
- int buffer_size = mix_buffer.size();
-
- if (stream_paused_fade_out) {
- // Short fadeout ramp
- buffer_size = MIN(buffer_size, 128);
- }
-
- stream_playback->mix(buffer, pitch_scale, buffer_size);
-
- //write all outputs
- int oc = output_count.get();
- for (int i = 0; i < oc; 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;
- }
- }
-
- 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;
- }
-
- //mix!
- AudioFrame target_volume = stream_paused_fade_out ? AudioFrame(0.f, 0.f) : current.vol;
- AudioFrame vol_prev = stream_paused_fade_in ? AudioFrame(0.f, 0.f) : prev_outputs[i].vol;
- AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
- AudioFrame vol = vol_prev;
-
- int cc = AudioServer::get_singleton()->get_channel_count();
-
- if (cc == 1) {
- if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, 0)) {
- continue; //may have been removed
- }
-
- AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 0);
-
- for (int j = 0; j < buffer_size; j++) {
- target[j] += buffer[j] * vol;
- vol += vol_inc;
- }
-
- } else {
- AudioFrame *targets[4];
- bool valid = true;
-
- for (int k = 0; k < cc; k++) {
- if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, k)) {
- valid = false; //may have been removed
- break;
- }
-
- targets[k] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k);
- }
-
- if (!valid) {
- continue;
- }
-
- for (int j = 0; j < buffer_size; j++) {
- AudioFrame frame = buffer[j] * vol;
- for (int k = 0; k < cc; k++) {
- targets[k][j] += frame;
- }
- vol += vol_inc;
- }
- }
-
- prev_outputs[i] = current;
- }
-
- prev_output_count = oc;
-
- //stream is no longer active, disable this.
- if (!stream_playback->is_playing()) {
- active.clear();
- }
-
- output_ready.clear();
- stream_paused_fade_in = false;
- stream_paused_fade_out = false;
-}
-
void AudioStreamPlayer2D::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- AudioServer::get_singleton()->add_callback(_mix_audios, this);
+ AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this);
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
}
if (p_what == NOTIFICATION_EXIT_TREE) {
- AudioServer::get_singleton()->remove_callback(_mix_audios, this);
+ stop();
+ AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
}
if (p_what == NOTIFICATION_PAUSED) {
@@ -168,109 +60,120 @@ void AudioStreamPlayer2D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
//update anything related to position first, if possible of course
- if (!output_ready.is_set()) {
- Ref<World2D> world_2d = get_world_2d();
- ERR_FAIL_COND(world_2d.is_null());
+ if (!stream_playback.is_valid()) {
+ return;
+ }
+ if (setplay.get() >= 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) {
+ _update_panning();
+ if (setplay.get() >= 0) {
+ active.set();
+ AudioServer::get_singleton()->start_playback_stream(stream_playback, _get_actual_bus(), volume_vector, setplay.get());
+ setplay.set(-1);
+ }
+ }
+
+ // Stop playing if no longer active.
+ if (active.is_set() && !AudioServer::get_singleton()->is_playback_active(stream_playback)) {
+ active.clear();
+ set_physics_process_internal(false);
+ emit_signal(SNAME("finished"));
+ }
+ }
+}
- int new_output_count = 0;
+StringName AudioStreamPlayer2D::_get_actual_bus() {
+ if (!stream_playback.is_valid()) {
+ return SNAME("Master");
+ }
- Vector2 global_pos = get_global_position();
+ Vector2 global_pos = get_global_position();
- int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
+ //check if any area is diverting sound into a bus
+ Ref<World2D> world_2d = get_world_2d();
+ ERR_FAIL_COND_V(world_2d.is_null(), SNAME("Master"));
- //check if any area is diverting sound into a bus
+ PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
+ PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];
- PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
+ int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];
+ for (int i = 0; i < areas; i++) {
+ Area2D *area2d = Object::cast_to<Area2D>(sr[i].collider);
+ if (!area2d) {
+ continue;
+ }
- int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
+ if (!area2d->is_overriding_audio_bus()) {
+ continue;
+ }
- for (int i = 0; i < areas; i++) {
- Area2D *area2d = Object::cast_to<Area2D>(sr[i].collider);
- if (!area2d) {
- continue;
- }
+ return area2d->get_audio_bus_name();
+ }
+ return default_bus;
+}
- if (!area2d->is_overriding_audio_bus()) {
- continue;
- }
+void AudioStreamPlayer2D::_update_panning() {
+ if (!stream_playback.is_valid()) {
+ return;
+ }
- StringName bus_name = area2d->get_audio_bus_name();
- bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
- break;
- }
+ last_mix_count = AudioServer::get_singleton()->get_mix_count();
- const Set<Viewport *> viewports = world_2d->get_viewports();
+ Ref<World2D> world_2d = get_world_2d();
+ ERR_FAIL_COND(world_2d.is_null());
- for (Set<Viewport *>::Element *E = viewports.front(); E; E = E->next()) {
- Viewport *vp = E->get();
- if (vp->is_audio_listener_2d()) {
- //compute matrix to convert to screen
- Transform2D to_screen = vp->get_global_canvas_transform() * vp->get_canvas_transform();
- Vector2 screen_size = vp->get_visible_rect().size;
+ Vector2 global_pos = get_global_position();
- //screen in global is used for attenuation
- Vector2 screen_in_global = to_screen.affine_inverse().xform(screen_size * 0.5);
+ Set<Viewport *> viewports = world_2d->get_viewports();
+ viewports.insert(get_viewport()); // TODO: This is a mediocre workaround for #50958. Remove when that bug is fixed!
- float dist = global_pos.distance_to(screen_in_global); //distance to screen center
+ volume_vector.resize(4);
+ volume_vector.write[0] = AudioFrame(0, 0);
+ volume_vector.write[1] = AudioFrame(0, 0);
+ volume_vector.write[2] = AudioFrame(0, 0);
+ volume_vector.write[3] = AudioFrame(0, 0);
- if (dist > max_distance) {
- continue; //can't hear this sound in this viewport
- }
+ for (Viewport *vp : viewports) {
+ if (!vp->is_audio_listener_2d()) {
+ continue;
+ }
+ //compute matrix to convert to screen
+ Transform2D to_screen = vp->get_global_canvas_transform() * vp->get_canvas_transform();
+ Vector2 screen_size = vp->get_visible_rect().size;
- float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);
- multiplier *= Math::db2linear(volume_db); //also apply player volume!
+ //screen in global is used for attenuation
+ Vector2 screen_in_global = to_screen.affine_inverse().xform(screen_size * 0.5);
- //point in screen is used for panning
- Vector2 point_in_screen = to_screen.xform(global_pos);
+ float dist = global_pos.distance_to(screen_in_global); //distance to screen center
- float pan = CLAMP(point_in_screen.x / screen_size.width, 0.0, 1.0);
+ if (dist > max_distance) {
+ continue; //can't hear this sound in this viewport
+ }
- float l = 1.0 - pan;
- float r = pan;
+ float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);
+ multiplier *= Math::db2linear(volume_db); //also apply player volume!
- outputs[new_output_count].vol = AudioFrame(l, r) * multiplier;
- outputs[new_output_count].bus_index = bus_index;
- outputs[new_output_count].viewport = vp; //keep pointer only for reference
- new_output_count++;
- if (new_output_count == MAX_OUTPUTS) {
- break;
- }
- }
- }
+ //point in screen is used for panning
+ Vector2 point_in_screen = to_screen.xform(global_pos);
- output_count.set(new_output_count);
- output_ready.set();
- }
+ float pan = CLAMP(point_in_screen.x / screen_size.width, 0.0, 1.0);
- //start playing if requested
- if (setplay.get() >= 0.0) {
- setseek.set(setplay.get());
- active.set();
- setplay.set(-1);
- }
+ float l = 1.0 - pan;
+ float r = pan;
- //stop playing if no longer active
- if (!active.is_set()) {
- set_physics_process_internal(false);
- emit_signal(SNAME("finished"));
- }
+ volume_vector.write[0] = AudioFrame(l, r) * multiplier;
}
+
+ AudioServer::get_singleton()->set_playback_bus_exclusive(stream_playback, _get_actual_bus(), volume_vector);
}
void AudioStreamPlayer2D::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.clear();
- setseek.set(-1);
+ stop();
}
+ stream_playback.unref();
+ stream.unref();
if (p_stream.is_valid()) {
stream_playback = p_stream->instance_playback();
if (stream_playback.is_valid()) {
@@ -280,8 +183,6 @@ void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
}
}
- AudioServer::get_singleton()->unlock();
-
if (p_stream.is_valid() && stream_playback.is_null()) {
stream.unref();
}
@@ -302,6 +203,9 @@ float AudioStreamPlayer2D::get_volume_db() const {
void AudioStreamPlayer2D::set_pitch_scale(float p_pitch_scale) {
ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
+ if (stream_playback.is_valid()) {
+ AudioServer::get_singleton()->set_playback_pitch_scale(stream_playback, p_pitch_scale);
+ }
}
float AudioStreamPlayer2D::get_pitch_scale() const {
@@ -309,27 +213,26 @@ float AudioStreamPlayer2D::get_pitch_scale() const {
}
void AudioStreamPlayer2D::play(float p_from_pos) {
- if (!is_playing()) {
- // Reset the prev_output_count if the stream is stopped
- prev_output_count = 0;
+ stop();
+ if (stream.is_valid()) {
+ stream_playback = stream->instance_playback();
}
-
if (stream_playback.is_valid()) {
setplay.set(p_from_pos);
- output_ready.clear();
set_physics_process_internal(true);
}
}
void AudioStreamPlayer2D::seek(float p_seconds) {
- if (stream_playback.is_valid()) {
- setseek.set(p_seconds);
+ if (stream_playback.is_valid() && active.is_set()) {
+ play(p_seconds);
}
}
void AudioStreamPlayer2D::stop() {
if (stream_playback.is_valid()) {
active.clear();
+ AudioServer::get_singleton()->stop_playback_stream(stream_playback);
set_physics_process_internal(false);
setplay.set(-1);
}
@@ -337,7 +240,7 @@ void AudioStreamPlayer2D::stop() {
bool AudioStreamPlayer2D::is_playing() const {
if (stream_playback.is_valid()) {
- return active.is_set() || setplay.get() >= 0;
+ return AudioServer::get_singleton()->is_playback_active(stream_playback);
}
return false;
@@ -345,30 +248,23 @@ bool AudioStreamPlayer2D::is_playing() const {
float AudioStreamPlayer2D::get_playback_position() {
if (stream_playback.is_valid()) {
- float ss = setseek.get();
- if (ss >= 0.0) {
- return ss;
- }
- return stream_playback->get_playback_position();
+ return AudioServer::get_singleton()->get_playback_position(stream_playback);
}
return 0;
}
void AudioStreamPlayer2D::set_bus(const StringName &p_bus) {
- //if audio is active, must lock this
- AudioServer::get_singleton()->lock();
- bus = p_bus;
- AudioServer::get_singleton()->unlock();
+ default_bus = p_bus; // This will be pushed to the audio server during the next physics timestep, which is fast enough.
}
StringName AudioStreamPlayer2D::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;
+ if (AudioServer::get_singleton()->get_bus_name(i) == default_bus) {
+ return default_bus;
}
}
- return "Master";
+ return SNAME("Master");
}
void AudioStreamPlayer2D::set_autoplay(bool p_enable) {
@@ -388,7 +284,11 @@ void AudioStreamPlayer2D::_set_playing(bool p_enable) {
}
bool AudioStreamPlayer2D::_is_active() const {
- return active.is_set();
+ if (stream_playback.is_valid()) {
+ // TODO make sure this doesn't change any behavior w.r.t. pauses. Is a paused stream active?
+ return AudioServer::get_singleton()->is_playback_active(stream_playback);
+ }
+ return false;
}
void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
@@ -436,15 +336,17 @@ uint32_t AudioStreamPlayer2D::get_area_mask() const {
}
void AudioStreamPlayer2D::set_stream_paused(bool p_pause) {
- if (p_pause != stream_paused) {
- stream_paused = p_pause;
- stream_paused_fade_in = !p_pause;
- stream_paused_fade_out = p_pause;
+ // TODO this does not have perfect recall, fix that maybe? If the stream isn't set, we can't persist this bool.
+ if (stream_playback.is_valid()) {
+ AudioServer::get_singleton()->set_playback_paused(stream_playback, p_pause);
}
}
bool AudioStreamPlayer2D::get_stream_paused() const {
- return stream_paused;
+ if (stream_playback.is_valid()) {
+ return AudioServer::get_singleton()->is_playback_paused(stream_playback);
+ }
+ return false;
}
Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index cf05a49b00..6428fbe017 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -51,38 +51,30 @@ private:
Viewport *viewport = nullptr; //pointer only used for reference to previous mix
};
- Output outputs[MAX_OUTPUTS];
- SafeNumeric<int> output_count;
- SafeFlag output_ready;
-
- //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
- Output prev_outputs[MAX_OUTPUTS];
- int prev_output_count = 0;
-
Ref<AudioStreamPlayback> stream_playback;
Ref<AudioStream> stream;
- Vector<AudioFrame> mix_buffer;
- SafeNumeric<float> setseek{ -1.0 };
SafeFlag active;
SafeNumeric<float> setplay{ -1.0 };
+ Vector<AudioFrame> volume_vector;
+
+ uint64_t last_mix_count = -1;
+
float volume_db = 0.0;
float pitch_scale = 1.0;
bool autoplay = false;
- bool stream_paused = false;
- bool stream_paused_fade_in = false;
- bool stream_paused_fade_out = false;
- StringName bus;
-
- void _mix_audio();
- static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->_mix_audio(); }
+ StringName default_bus = "Master";
void _set_playing(bool p_enable);
bool _is_active() const;
+ StringName _get_actual_bus();
+ void _update_panning();
void _bus_layout_changed();
+ static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->_update_panning(); }
+
uint32_t area_mask = 1;
float max_distance = 2000.0;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 3b44580264..16d5b9da3e 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -95,7 +95,7 @@ static const Vector3 speaker_directions[7] = {
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) {
+void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tightness, Vector<AudioFrame> &output) {
unsigned int speaker_count = 0; // only main speakers (no LFE)
switch (AudioServer::get_singleton()->get_speaker_mode()) {
case AudioServer::SPEAKER_MODE_STEREO:
@@ -118,182 +118,94 @@ void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tig
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
+ output.write[3].l = volumes[5]; // side-left
+ output.write[3].r = volumes[6]; // side-right
[[fallthrough]];
case AudioServer::SPEAKER_SURROUND_51:
- output.vol[2].l = volumes[3]; // rear-left
- output.vol[2].r = volumes[4]; // rear-right
+ output.write[2].l = volumes[3]; // rear-left
+ output.write[2].r = volumes[4]; // rear-right
[[fallthrough]];
case AudioServer::SPEAKER_SURROUND_31:
- output.vol[1].r = 1.0; // LFE - always full power
- output.vol[1].l = volumes[2]; // center
+ output.write[1].r = 1.0; // LFE - always full power
+ output.write[1].l = volumes[2]; // center
[[fallthrough]];
case AudioServer::SPEAKER_MODE_STEREO:
- output.vol[0].r = volumes[1]; // front-right
- output.vol[0].l = volumes[0]; // front-left
+ output.write[0].r = volumes[1]; // front-right
+ output.write[0].l = volumes[0]; // front-left
break;
}
}
-void AudioStreamPlayer3D::_mix_audio() {
- if (!stream_playback.is_valid() || !active.is_set() ||
- (stream_paused && !stream_paused_fade_out)) {
- return;
- }
+void AudioStreamPlayer3D::_calc_reverb_vol(Area3D *area, Vector3 listener_area_pos, Vector<AudioFrame> direct_path_vol, Vector<AudioFrame> &reverb_vol) {
+ reverb_vol.resize(4);
+ reverb_vol.write[0] = AudioFrame(0, 0);
+ reverb_vol.write[1] = AudioFrame(0, 0);
+ reverb_vol.write[2] = AudioFrame(0, 0);
+ reverb_vol.write[3] = AudioFrame(0, 0);
- bool started = false;
- if (setseek.get() >= 0.0) {
- stream_playback->start(setseek.get());
- setseek.set(-1.0); //reset seek
- started = true;
- }
+ float uniformity = area->get_reverb_uniformity();
+ float area_send = area->get_reverb_amount();
- //get data
- AudioFrame *buffer = mix_buffer.ptrw();
- int buffer_size = mix_buffer.size();
+ if (uniformity > 0.0) {
+ float distance = listener_area_pos.length();
+ float attenuation = Math::db2linear(_get_attenuation_db(distance));
- if (stream_paused_fade_out) {
- // Short fadeout ramp
- buffer_size = MIN(buffer_size, 128);
- }
+ // Determine the fraction of sound that would come from each speaker if they were all driven uniformly.
+ float center_val[3] = { 0.5f, 0.25f, 0.16666f };
+ int channel_count = AudioServer::get_singleton()->get_channel_count();
+ AudioFrame center_frame(center_val[channel_count - 1], center_val[channel_count - 1]);
- // Mix if we're not paused or we're fading out
- if ((output_count.get() > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) {
- float output_pitch_scale = 0.0;
- if (output_count.get()) {
- //used for doppler, not realistic but good enough
- for (int i = 0; i < output_count.get(); i++) {
- output_pitch_scale += outputs[i].pitch_scale;
- }
- output_pitch_scale /= float(output_count.get());
- } else {
- output_pitch_scale = 1.0;
- }
+ if (attenuation < 1.0) {
+ //pan the uniform sound
+ Vector3 rev_pos = listener_area_pos;
+ rev_pos.y = 0;
+ rev_pos.normalize();
- stream_playback->mix(buffer, pitch_scale * output_pitch_scale, buffer_size);
- }
-
- //write all outputs
- for (int i = 0; i < output_count.get(); 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;
+ if (channel_count >= 1) {
+ // Stereo pair
+ float c = rev_pos.x * 0.5 + 0.5;
+ reverb_vol.write[0].l = 1.0 - c;
+ reverb_vol.write[0].r = c;
}
- }
- bool interpolate_filter = !started;
+ if (channel_count >= 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;
- 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++;
+ reverb_vol.write[1].l = xl;
+ reverb_vol.write[1].r = xr;
+ reverb_vol.write[2].l = 1.0 - xr;
+ reverb_vol.write[2].r = 1.0 - xl;
}
- prev_outputs[i] = current;
- interpolate_filter = false;
- }
-
- //mix!
-
- int buffers = AudioServer::get_singleton()->get_channel_count();
-
- for (int k = 0; k < buffers; k++) {
- 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];
- AudioFrame vol_inc = (target_volume - vol_prev) / float(buffer_size);
- AudioFrame vol = vol_prev;
- if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.bus_index, k)) {
- continue; //may have been deleted, will be updated on process
+ if (channel_count >= 4) {
+ // Rear pair
+ // FIXME: Not sure what math should be done here
+ float c = rev_pos.x * 0.5 + 0.5;
+ reverb_vol.write[3].l = 1.0 - c;
+ reverb_vol.write[3].r = c;
}
- AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, k);
- 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(&current.filter, false);
- current.filter_process[k * 2 + 1].set_filter(&current.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(&current.filter);
- current.filter_process[k * 2 + 1].set_filter(&current.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;
- }
+ for (int i = 0; i < channel_count; i++) {
+ reverb_vol.write[i] = reverb_vol[i].lerp(center_frame, attenuation);
}
-
- if (current.reverb_bus_index >= 0) {
- if (!AudioServer::get_singleton()->thread_has_channel_mix_buffer(current.reverb_bus_index, k)) {
- continue; //may have been deleted, will be updated on process
- }
-
- AudioFrame *rtarget = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.reverb_bus_index, k);
-
- 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;
- }
- }
+ } else {
+ for (int i = 0; i < channel_count; i++) {
+ reverb_vol.write[i] = center_frame;
}
}
- prev_outputs[i] = current;
- }
-
- prev_output_count = output_count.get();
+ for (int i = 0; i < channel_count; i++) {
+ reverb_vol.write[i] = direct_path_vol[i].lerp(reverb_vol[i] * attenuation, uniformity);
+ reverb_vol.write[i] *= area_send;
+ }
- //stream is no longer active, disable this.
- if (!stream_playback->is_playing()) {
- active.clear();
+ } else {
+ for (int i = 0; i < 4; i++) {
+ reverb_vol.write[i] = direct_path_vol[i] * area_send;
+ }
}
-
- output_ready.clear();
- stream_paused_fade_in = false;
- stream_paused_fade_out = false;
}
float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
@@ -329,14 +241,15 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
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);
+ AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this);
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
}
if (p_what == NOTIFICATION_EXIT_TREE) {
- AudioServer::get_singleton()->remove_callback(_mix_audios, this);
+ stop();
+ AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
}
if (p_what == NOTIFICATION_PAUSED) {
@@ -359,268 +272,216 @@ void AudioStreamPlayer3D::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
//update anything related to position first, if possible of course
- if (!output_ready.is_set()) {
- Vector3 linear_velocity;
+ if (!stream_playback.is_valid()) {
+ return;
+ }
+ //start playing if requested
- //compute linear velocity for doppler
- if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
- linear_velocity = velocity_tracker->get_tracked_linear_velocity();
- }
+ if (setplay.get() >= 0) {
+ Vector<AudioFrame> volume_vector = _update_panning();
+ AudioServer::get_singleton()->start_playback_stream(stream_playback, _get_actual_bus(), volume_vector, setplay.get());
+ active.set();
+ setplay.set(-1);
+ }
+
+ if (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count()) {
+ _update_panning();
+ last_mix_count = AudioServer::get_singleton()->get_mix_count();
+ }
+
+ // Stop playing if no longer active.
+ if (!active.is_set()) {
+ set_physics_process_internal(false);
+ emit_signal(SNAME("finished"));
+ }
+ }
+}
+
+Area3D *AudioStreamPlayer3D::_get_overriding_area() {
+ //check if any area is diverting sound into a bus
+ Ref<World3D> world_3d = get_world_3d();
+ ERR_FAIL_COND_V(world_3d.is_null(), nullptr);
+
+ Vector3 global_pos = get_global_transform().origin;
- Ref<World3D> world_3d = get_world_3d();
- ERR_FAIL_COND(world_3d.is_null());
+ PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
- int new_output_count = 0;
+ PhysicsDirectSpaceState3D::ShapeResult sr[MAX_INTERSECT_AREAS];
- Vector3 global_pos = get_global_transform().origin;
+ int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
+ for (int i = 0; i < areas; i++) {
+ if (!sr[i].collider) {
+ continue;
+ }
+
+ Area3D *tarea = Object::cast_to<Area3D>(sr[i].collider);
+ if (!tarea) {
+ continue;
+ }
+
+ if (!tarea->is_overriding_audio_bus() && !tarea->is_using_reverb_bus()) {
+ continue;
+ }
+
+ return tarea;
+ }
+ return nullptr;
+}
- //check if any area is diverting sound into a bus
+StringName AudioStreamPlayer3D::_get_actual_bus() {
+ if (!stream_playback.is_valid()) {
+ return SNAME("Master");
+ }
+ Area3D *overriding_area = _get_overriding_area();
+ if (overriding_area && overriding_area->is_overriding_audio_bus() && !overriding_area->is_using_reverb_bus()) {
+ return overriding_area->get_audio_bus_name();
+ }
+ return bus;
+}
- PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
+Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
+ Vector<AudioFrame> output_volume_vector;
+ output_volume_vector.resize(4);
+ for (AudioFrame &frame : output_volume_vector) {
+ frame = AudioFrame(0, 0);
+ }
- PhysicsDirectSpaceState3D::ShapeResult sr[MAX_INTERSECT_AREAS];
+ ERR_FAIL_COND_V(stream_playback.is_null(), output_volume_vector);
- int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
- Area3D *area = nullptr;
+ Vector3 linear_velocity;
- for (int i = 0; i < areas; i++) {
- if (!sr[i].collider) {
- continue;
- }
+ //compute linear velocity for doppler
+ if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
+ linear_velocity = velocity_tracker->get_tracked_linear_velocity();
+ }
- Area3D *tarea = Object::cast_to<Area3D>(sr[i].collider);
- if (!tarea) {
- continue;
- }
+ Vector3 global_pos = get_global_transform().origin;
- if (!tarea->is_overriding_audio_bus() && !tarea->is_using_reverb_bus()) {
- continue;
- }
+ Ref<World3D> world_3d = get_world_3d();
+ ERR_FAIL_COND_V(world_3d.is_null(), output_volume_vector);
- area = tarea;
- break;
+ Set<Camera3D *> cameras = world_3d->get_cameras();
+ cameras.insert(get_viewport()->get_camera_3d());
+
+ PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
+
+ for (Camera3D *camera : cameras) {
+ Viewport *vp = camera->get_viewport();
+ if (!vp->is_audio_listener_3d()) {
+ continue;
+ }
+
+ bool listener_is_camera = true;
+ Node3D *listener_node = camera;
+
+ Listener3D *listener = vp->get_listener_3d();
+ if (listener) {
+ listener_node = listener;
+ listener_is_camera = false;
+ }
+
+ Vector3 local_pos = listener_node->get_global_transform().orthonormalized().affine_inverse().xform(global_pos);
+
+ float dist = local_pos.length();
+
+ Vector3 area_sound_pos;
+ Vector3 listener_area_pos;
+
+ Area3D *area = _get_overriding_area();
+
+ if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
+ 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);
+ }
+
+ if (max_distance > 0) {
+ float total_max = max_distance;
+
+ if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
+ total_max = MAX(total_max, listener_area_pos.length());
}
+ if (total_max > max_distance) {
+ continue; //can't hear this sound in this listener
+ }
+ }
+
+ float multiplier = Math::db2linear(_get_attenuation_db(dist));
+ if (max_distance > 0) {
+ multiplier *= MAX(0, 1.0 - (dist / max_distance));
+ }
- for (const Set<Camera3D *>::Element *E = world_3d->get_cameras().front(); E; E = E->next()) {
- Camera3D *camera = E->get();
- Viewport *vp = camera->get_viewport();
- if (!vp->is_audio_listener_3d()) {
- continue;
- }
-
- bool listener_is_camera = true;
- Node3D *listener_node = camera;
-
- Listener3D *listener = vp->get_listener_3d();
- if (listener) {
- listener_node = listener;
- listener_is_camera = false;
- }
-
- Vector3 local_pos = listener_node->get_global_transform().orthonormalized().affine_inverse().xform(global_pos);
-
- float dist = local_pos.length();
-
- Vector3 area_sound_pos;
- Vector3 listener_area_pos;
-
- if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
- 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->to_local(area_sound_pos);
- }
-
- if (max_distance > 0) {
- float total_max = max_distance;
-
- if (area && area->is_using_reverb_bus() && area->get_reverb_uniformity() > 0) {
- total_max = MAX(total_max, listener_area_pos.length());
- }
- if (total_max > max_distance) {
- continue; //can't hear this sound in this listener
- }
- }
-
- 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) {
- 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
- 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);
-
- //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);
-
- unsigned int cc = AudioServer::get_singleton()->get_channel_count();
- for (unsigned int k = 0; k < cc; k++) {
- output.vol[k] *= multiplier;
- }
-
- bool filled_reverb = false;
- int vol_index_max = AudioServer::get_singleton()->get_speaker_mode() + 1;
-
- if (area) {
- if (area->is_overriding_audio_bus()) {
- //override audio bus
- StringName bus_name = area->get_audio_bus_name();
- output.bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
- }
-
- if (area->is_using_reverb_bus()) {
- filled_reverb = true;
- 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) {
- float distance = listener_area_pos.length();
- float attenuation = Math::db2linear(_get_attenuation_db(distance));
-
- //float dist_att_db = -20 * Math::log(dist + 0.00001); //logarithmic attenuation, like in real life
-
- float center_val[3] = { 0.5f, 0.25f, 0.16666f };
- AudioFrame center_frame(center_val[vol_index_max - 1], center_val[vol_index_max - 1]);
-
- if (attenuation < 1.0) {
- //pan the uniform sound
- Vector3 rev_pos = listener_area_pos;
- rev_pos.y = 0;
- rev_pos.normalize();
-
- 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;
- }
-
- 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;
-
- 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;
- }
-
- 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;
- }
-
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = output.reverb_vol[i].lerp(center_frame, attenuation);
- }
- } else {
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = center_frame;
- }
- }
-
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = output.vol[i].lerp(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) {
- Vector3 listener_velocity;
-
- if (listener_is_camera) {
- listener_velocity = camera->get_doppler_tracked_velocity();
- }
-
- Vector3 local_velocity = listener_node->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - listener_velocity);
-
- 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;
- }
-
- if (!filled_reverb) {
- for (int i = 0; i < vol_index_max; i++) {
- output.reverb_vol[i] = AudioFrame(0, 0);
- }
- }
-
- outputs[new_output_count] = output;
- new_output_count++;
- if (new_output_count == MAX_OUTPUTS) {
- break;
- }
+ float db_att = (1.0 - MIN(1.0, multiplier)) * attenuation_filter_db;
+
+ if (emission_angle_enabled) {
+ 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
+ float angle = Math::rad2deg(Math::acos(c));
+ if (angle > emission_angle) {
+ db_att -= -emission_angle_filter_attenuation_db;
}
+ }
+
+ AudioServer::get_singleton()->set_playback_highshelf_params(stream_playback, Math::db2linear(db_att), attenuation_filter_cutoff_hz);
+ //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_volume_vector);
- output_count.set(new_output_count);
- output_ready.set();
+ for (unsigned int k = 0; k < 4; k++) {
+ output_volume_vector.write[k] = multiplier * output_volume_vector[k];
}
- //start playing if requested
- if (setplay.get() >= 0.0) {
- setseek.set(setplay.get());
- active.set();
- setplay.set(-1);
+ Map<StringName, Vector<AudioFrame>> bus_volumes;
+ if (area) {
+ if (area->is_overriding_audio_bus()) {
+ //override audio bus
+ bus_volumes[area->get_audio_bus_name()] = output_volume_vector;
+ }
+
+ if (area->is_using_reverb_bus()) {
+ StringName reverb_bus_name = area->get_reverb_bus();
+ Vector<AudioFrame> reverb_vol;
+ _calc_reverb_vol(area, listener_area_pos, output_volume_vector, reverb_vol);
+ bus_volumes[reverb_bus_name] = reverb_vol;
+ }
+ } else {
+ bus_volumes[bus] = output_volume_vector;
}
+ AudioServer::get_singleton()->set_playback_bus_volumes_linear(stream_playback, bus_volumes);
- //stop playing if no longer active
- if (!active.is_set()) {
- set_physics_process_internal(false);
- emit_signal(SNAME("finished"));
+ if (doppler_tracking != DOPPLER_TRACKING_DISABLED) {
+ Vector3 listener_velocity;
+
+ if (listener_is_camera) {
+ listener_velocity = camera->get_doppler_tracked_velocity();
+ }
+
+ Vector3 local_velocity = listener_node->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - listener_velocity);
+
+ if (local_velocity == Vector3()) {
+ AudioServer::get_singleton()->set_playback_pitch_scale(stream_playback, pitch_scale);
+ } else {
+ float approaching = local_pos.normalized().dot(local_velocity.normalized());
+ float velocity = local_velocity.length();
+ float speed_of_sound = 343.0;
+
+ float doppler_pitch_scale = pitch_scale * speed_of_sound / (speed_of_sound + velocity * approaching);
+ doppler_pitch_scale = CLAMP(doppler_pitch_scale, (1 / 8.0), 8.0); //avoid crazy stuff
+
+ AudioServer::get_singleton()->set_playback_pitch_scale(stream_playback, doppler_pitch_scale);
+ }
+ } else {
+ AudioServer::get_singleton()->set_playback_pitch_scale(stream_playback, pitch_scale);
}
}
+ return output_volume_vector;
}
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()) {
+ stop();
stream_playback.unref();
stream.unref();
- active.clear();
- setseek.set(-1);
}
if (p_stream.is_valid()) {
@@ -632,8 +493,6 @@ void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) {
}
}
- AudioServer::get_singleton()->unlock();
-
if (p_stream.is_valid() && stream_playback.is_null()) {
stream.unref();
}
@@ -677,27 +536,22 @@ float AudioStreamPlayer3D::get_pitch_scale() const {
}
void AudioStreamPlayer3D::play(float p_from_pos) {
- if (!is_playing()) {
- // Reset the prev_output_count if the stream is stopped
- prev_output_count = 0;
- }
-
if (stream_playback.is_valid()) {
setplay.set(p_from_pos);
- output_ready.clear();
set_physics_process_internal(true);
}
}
void AudioStreamPlayer3D::seek(float p_seconds) {
- if (stream_playback.is_valid()) {
- setseek.set(p_seconds);
+ if (stream_playback.is_valid() && active.is_set()) {
+ play(p_seconds);
}
}
void AudioStreamPlayer3D::stop() {
if (stream_playback.is_valid()) {
active.clear();
+ AudioServer::get_singleton()->stop_playback_stream(stream_playback);
set_physics_process_internal(false);
setplay.set(-1);
}
@@ -713,11 +567,7 @@ bool AudioStreamPlayer3D::is_playing() const {
float AudioStreamPlayer3D::get_playback_position() {
if (stream_playback.is_valid()) {
- float ss = setseek.get();
- if (ss >= 0.0) {
- return ss;
- }
- return stream_playback->get_playback_position();
+ return AudioServer::get_singleton()->get_playback_position(stream_playback);
}
return 0;
@@ -736,7 +586,7 @@ StringName AudioStreamPlayer3D::get_bus() const {
return bus;
}
}
- return "Master";
+ return SNAME("Master");
}
void AudioStreamPlayer3D::set_autoplay(bool p_enable) {
@@ -879,15 +729,16 @@ AudioStreamPlayer3D::DopplerTracking AudioStreamPlayer3D::get_doppler_tracking()
}
void AudioStreamPlayer3D::set_stream_paused(bool p_pause) {
- if (p_pause != stream_paused) {
- stream_paused = p_pause;
- stream_paused_fade_in = !stream_paused;
- stream_paused_fade_out = stream_paused;
+ if (stream_playback.is_valid()) {
+ AudioServer::get_singleton()->set_playback_paused(stream_playback, p_pause);
}
}
bool AudioStreamPlayer3D::get_stream_paused() const {
- return stream_paused;
+ if (stream_playback.is_valid()) {
+ return AudioServer::get_singleton()->is_playback_paused(stream_playback);
+ }
+ return false;
}
Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() {
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index f86e19403c..f915abad2b 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -31,10 +31,12 @@
#ifndef AUDIO_STREAM_PLAYER_3D_H
#define AUDIO_STREAM_PLAYER_3D_H
+#include "scene/3d/area_3d.h"
#include "scene/3d/node_3d.h"
#include "scene/3d/velocity_tracker_3d.h"
#include "servers/audio/audio_filter_sw.h"
#include "servers/audio/audio_stream.h"
+#include "servers/audio_server.h"
class Camera3D;
class AudioStreamPlayer3D : public Node3D {
@@ -66,31 +68,9 @@ private:
};
- struct Output {
- AudioFilterSW filter;
- AudioFilterSW::Processor filter_process[8];
- AudioFrame vol[4];
- float filter_gain = 0.0;
- float pitch_scale = 0.0;
- int bus_index = -1;
- int reverb_bus_index = -1;
- AudioFrame reverb_vol[4];
- Viewport *viewport = nullptr; //pointer only used for reference to previous mix
- };
-
- Output outputs[MAX_OUTPUTS];
- SafeNumeric<int> output_count;
- SafeFlag output_ready;
-
- //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
- Output prev_outputs[MAX_OUTPUTS];
- int prev_output_count = 0;
-
Ref<AudioStreamPlayback> stream_playback;
Ref<AudioStream> stream;
- Vector<AudioFrame> mix_buffer;
- SafeNumeric<float> setseek{ -1.0 };
SafeFlag active;
SafeNumeric<float> setplay{ -1.0 };
@@ -100,17 +80,21 @@ private:
float max_db = 3.0;
float pitch_scale = 1.0;
bool autoplay = false;
- bool stream_paused = false;
- bool stream_paused_fade_in = false;
- bool stream_paused_fade_out = false;
- StringName bus;
+ StringName bus = "Master";
+
+ uint64_t last_mix_count = -1;
+
+ static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Vector<AudioFrame> &output);
+
+ void _calc_reverb_vol(Area3D *area, Vector3 listener_area_pos, Vector<AudioFrame> direct_path_vol, Vector<AudioFrame> &reverb_vol);
- static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Output &output);
- void _mix_audio();
- static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_mix_audio(); }
+ static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->_update_panning(); }
void _set_playing(bool p_enable);
bool _is_active() const;
+ StringName _get_actual_bus();
+ Area3D *_get_overriding_area();
+ Vector<AudioFrame> _update_panning();
void _bus_layout_changed();
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 9383355292..f7b7604fd5 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -31,119 +31,18 @@
#include "audio_stream_player.h"
#include "core/config/engine.h"
-
-void AudioStreamPlayer::_mix_to_bus(const AudioFrame *p_frames, int p_amount) {
- int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
-
- AudioFrame *targets[4] = { nullptr, nullptr, nullptr, nullptr };
-
- if (AudioServer::get_singleton()->get_speaker_mode() == AudioServer::SPEAKER_MODE_STEREO) {
- targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0);
- } else {
- switch (mix_target) {
- case MIX_TARGET_STEREO: {
- targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0);
- } break;
- case MIX_TARGET_SURROUND: {
- for (int i = 0; i < AudioServer::get_singleton()->get_channel_count(); i++) {
- targets[i] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, i);
- }
- } break;
- case MIX_TARGET_CENTER: {
- targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1);
- } break;
- }
- }
-
- for (int c = 0; c < 4; c++) {
- if (!targets[c]) {
- break;
- }
- for (int i = 0; i < p_amount; i++) {
- targets[c][i] += p_frames[i];
- }
- }
-}
-
-void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
- //get data
- AudioFrame *buffer = mix_buffer.ptrw();
- int buffer_size = mix_buffer.size();
-
- if (p_fadeout) {
- // Short fadeout ramp
- buffer_size = MIN(buffer_size, 128);
- }
-
- stream_playback->mix(buffer, pitch_scale, buffer_size);
-
- //multiply volume interpolating to avoid clicks if this changes
- float target_volume = p_fadeout ? -80.0 : volume_db;
- float vol = Math::db2linear(mix_volume_db);
- float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size);
-
- for (int i = 0; i < buffer_size; i++) {
- buffer[i] *= vol;
- vol += vol_inc;
- }
-
- //set volume for next mix
- mix_volume_db = target_volume;
-
- _mix_to_bus(buffer, buffer_size);
-}
-
-void AudioStreamPlayer::_mix_audio() {
- if (use_fadeout) {
- _mix_to_bus(fadeout_buffer.ptr(), fadeout_buffer.size());
- use_fadeout = false;
- }
-
- if (!stream_playback.is_valid() || !active.is_set() ||
- (stream_paused && !stream_paused_fade)) {
- return;
- }
-
- if (stream_paused) {
- if (stream_paused_fade && stream_playback->is_playing()) {
- _mix_internal(true);
- stream_paused_fade = false;
- }
- return;
- }
-
- if (setstop.is_set()) {
- _mix_internal(true);
- stream_playback->stop();
- setstop.clear();
- }
-
- if (setseek.get() >= 0.0 && !stop_has_priority.is_set()) {
- if (stream_playback->is_playing()) {
- //fade out to avoid pops
- _mix_internal(true);
- }
-
- stream_playback->start(setseek.get());
- setseek.set(-1.0); //reset seek
- mix_volume_db = volume_db; //reset ramp
- }
-
- stop_has_priority.clear();
-
- _mix_internal(false);
-}
+#include "core/math/audio_frame.h"
+#include "servers/audio_server.h"
void AudioStreamPlayer::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
- AudioServer::get_singleton()->add_callback(_mix_audios, this);
if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
}
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
- if (!active.is_set() || (setseek.get() < 0 && !stream_playback->is_playing())) {
+ if (stream_playback.is_valid() && active.is_set() && !AudioServer::get_singleton()->is_playback_active(stream_playback)) {
active.clear();
set_process_internal(false);
emit_signal(SNAME("finished"));
@@ -151,7 +50,9 @@ void AudioStreamPlayer::_notification(int p_what) {
}
if (p_what == NOTIFICATION_EXIT_TREE) {
- AudioServer::get_singleton()->remove_callback(_mix_audios, this);
+ if (stream_playback.is_valid()) {
+ AudioServer::get_singleton()->stop_playback_stream(stream_playback);
+ }
}
if (p_what == NOTIFICATION_PAUSED) {
@@ -167,38 +68,10 @@ void AudioStreamPlayer::_notification(int p_what) {
}
void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
- AudioServer::get_singleton()->lock();
-
- if (active.is_set() && stream_playback.is_valid() && !stream_paused) {
- //changing streams out of the blue is not a great idea, but at least
- //let's try to somehow avoid a click
-
- AudioFrame *buffer = fadeout_buffer.ptrw();
- int buffer_size = fadeout_buffer.size();
-
- stream_playback->mix(buffer, pitch_scale, buffer_size);
-
- //multiply volume interpolating to avoid clicks if this changes
- float target_volume = -80.0;
- float vol = Math::db2linear(mix_volume_db);
- float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size);
-
- for (int i = 0; i < buffer_size; i++) {
- buffer[i] *= vol;
- vol += vol_inc;
- }
-
- use_fadeout = true;
- }
-
- mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
-
if (stream_playback.is_valid()) {
+ stop();
stream_playback.unref();
stream.unref();
- active.clear();
- setseek.set(-1);
- setstop.clear();
}
if (p_stream.is_valid()) {
@@ -210,8 +83,6 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
}
}
- AudioServer::get_singleton()->unlock();
-
if (p_stream.is_valid() && stream_playback.is_null()) {
stream.unref();
}
@@ -223,6 +94,8 @@ Ref<AudioStream> AudioStreamPlayer::get_stream() const {
void AudioStreamPlayer::set_volume_db(float p_volume) {
volume_db = p_volume;
+
+ AudioServer::get_singleton()->set_playback_all_bus_volumes_linear(stream_playback, _get_volume_vector());
}
float AudioStreamPlayer::get_volume_db() const {
@@ -232,6 +105,8 @@ float AudioStreamPlayer::get_volume_db() const {
void AudioStreamPlayer::set_pitch_scale(float p_pitch_scale) {
ERR_FAIL_COND(p_pitch_scale <= 0.0);
pitch_scale = p_pitch_scale;
+
+ AudioServer::get_singleton()->set_playback_pitch_scale(stream_playback, pitch_scale);
}
float AudioStreamPlayer::get_pitch_scale() const {
@@ -239,31 +114,32 @@ float AudioStreamPlayer::get_pitch_scale() const {
}
void AudioStreamPlayer::play(float p_from_pos) {
+ stop();
+ if (stream.is_valid()) {
+ stream_playback = stream->instance_playback();
+ }
if (stream_playback.is_valid()) {
- //mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks
- setseek.set(p_from_pos);
- stop_has_priority.clear();
+ AudioServer::get_singleton()->start_playback_stream(stream_playback, bus, _get_volume_vector(), p_from_pos);
active.set();
- set_process_internal(true);
}
}
void AudioStreamPlayer::seek(float p_seconds) {
- if (stream_playback.is_valid()) {
- setseek.set(p_seconds);
+ if (stream_playback.is_valid() && active.is_set()) {
+ play(p_seconds);
}
}
void AudioStreamPlayer::stop() {
- if (stream_playback.is_valid() && active.is_set()) {
- setstop.set();
- stop_has_priority.set();
+ if (stream_playback.is_valid()) {
+ active.clear();
+ AudioServer::get_singleton()->stop_playback_stream(stream_playback);
}
}
bool AudioStreamPlayer::is_playing() const {
if (stream_playback.is_valid()) {
- return active.is_set() && !setstop.is_set(); //&& stream_playback->is_playing();
+ return AudioServer::get_singleton()->is_playback_active(stream_playback);
}
return false;
@@ -271,26 +147,22 @@ bool AudioStreamPlayer::is_playing() const {
float AudioStreamPlayer::get_playback_position() {
if (stream_playback.is_valid()) {
- float ss = setseek.get();
- if (ss >= 0.0) {
- return ss;
- }
- return stream_playback->get_playback_position();
+ return AudioServer::get_singleton()->get_playback_position(stream_playback);
}
return 0;
}
void AudioStreamPlayer::set_bus(const StringName &p_bus) {
- //if audio is active, must lock this
- AudioServer::get_singleton()->lock();
bus = p_bus;
- AudioServer::get_singleton()->unlock();
+ if (stream_playback.is_valid()) {
+ AudioServer::get_singleton()->set_playback_bus_exclusive(stream_playback, p_bus, _get_volume_vector());
+ }
}
StringName AudioStreamPlayer::get_bus() const {
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
- if (AudioServer::get_singleton()->get_bus_name(i) == bus) {
+ if (AudioServer::get_singleton()->get_bus_name(i) == String(bus)) {
return bus;
}
}
@@ -322,18 +194,61 @@ void AudioStreamPlayer::_set_playing(bool p_enable) {
}
bool AudioStreamPlayer::_is_active() const {
- return active.is_set();
+ if (stream_playback.is_valid()) {
+ return AudioServer::get_singleton()->is_playback_active(stream_playback);
+ }
+ return false;
}
void AudioStreamPlayer::set_stream_paused(bool p_pause) {
- if (p_pause != stream_paused) {
- stream_paused = p_pause;
- stream_paused_fade = p_pause;
+ // TODO this does not have perfect recall, fix that maybe? If the stream isn't set, we can't persist this bool.
+ if (stream_playback.is_valid()) {
+ AudioServer::get_singleton()->set_playback_paused(stream_playback, p_pause);
}
}
bool AudioStreamPlayer::get_stream_paused() const {
- return stream_paused;
+ if (stream_playback.is_valid()) {
+ return AudioServer::get_singleton()->is_playback_paused(stream_playback);
+ }
+ return false;
+}
+
+Vector<AudioFrame> AudioStreamPlayer::_get_volume_vector() {
+ Vector<AudioFrame> volume_vector;
+ // We need at most four stereo pairs (for 7.1 systems).
+ volume_vector.resize(4);
+
+ // Initialize the volume vector to zero.
+ for (AudioFrame &channel_volume_db : volume_vector) {
+ channel_volume_db = AudioFrame(0, 0);
+ }
+
+ float volume_linear = Math::db2linear(volume_db);
+
+ // Set the volume vector up according to the speaker mode and mix target.
+ // TODO do we need to scale the volume down when we output to more channels?
+ if (AudioServer::get_singleton()->get_speaker_mode() == AudioServer::SPEAKER_MODE_STEREO) {
+ volume_vector.write[0] = AudioFrame(volume_linear, volume_linear);
+ } else {
+ switch (mix_target) {
+ case MIX_TARGET_STEREO: {
+ volume_vector.write[0] = AudioFrame(volume_linear, volume_linear);
+ } break;
+ case MIX_TARGET_SURROUND: {
+ // TODO Make sure this is right.
+ volume_vector.write[0] = AudioFrame(volume_linear, volume_linear);
+ volume_vector.write[1] = AudioFrame(volume_linear, /* LFE= */ 1.0f);
+ volume_vector.write[2] = AudioFrame(volume_linear, volume_linear);
+ volume_vector.write[3] = AudioFrame(volume_linear, volume_linear);
+ } break;
+ case MIX_TARGET_CENTER: {
+ // TODO Make sure this is right.
+ volume_vector.write[1] = AudioFrame(volume_linear, /* LFE= */ 1.0f);
+ } break;
+ }
+ }
+ return volume_vector;
}
void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
@@ -410,8 +325,6 @@ void AudioStreamPlayer::_bind_methods() {
}
AudioStreamPlayer::AudioStreamPlayer() {
- fadeout_buffer.resize(512);
-
AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer::_bus_layout_changed));
}
diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h
index aa8d088be5..76b6698c9d 100644
--- a/scene/audio/audio_stream_player.h
+++ b/scene/audio/audio_stream_player.h
@@ -48,22 +48,13 @@ public:
private:
Ref<AudioStreamPlayback> stream_playback;
Ref<AudioStream> stream;
- Vector<AudioFrame> mix_buffer;
- Vector<AudioFrame> fadeout_buffer;
- bool use_fadeout = false;
- SafeNumeric<float> setseek{ -1.0 };
SafeFlag active;
- SafeFlag setstop;
- SafeFlag stop_has_priority;
- float mix_volume_db = 0.0;
float pitch_scale = 1.0;
float volume_db = 0.0;
bool autoplay = false;
- bool stream_paused = false;
- bool stream_paused_fade = false;
- StringName bus;
+ StringName bus = "Master";
MixTarget mix_target = MIX_TARGET_STEREO;
@@ -77,6 +68,8 @@ private:
void _bus_layout_changed();
void _mix_to_bus(const AudioFrame *p_frames, int p_amount);
+ Vector<AudioFrame> _get_volume_vector();
+
protected:
void _validate_property(PropertyInfo &property) const override;
void _notification(int p_what);
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 229b5384ea..8734037a57 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -129,7 +129,7 @@ void VideoPlayer::_mix_audio() {
void VideoPlayer::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_ENTER_TREE: {
- AudioServer::get_singleton()->add_callback(_mix_audios, this);
+ AudioServer::get_singleton()->add_mix_callback(_mix_audios, this);
if (stream.is_valid() && autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
@@ -138,8 +138,7 @@ void VideoPlayer::_notification(int p_notification) {
} break;
case NOTIFICATION_EXIT_TREE: {
- AudioServer::get_singleton()->remove_callback(_mix_audios, this);
-
+ AudioServer::get_singleton()->remove_mix_callback(_mix_audios, this);
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 801c7cf86e..6e0b161e54 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -52,6 +52,7 @@
#include "scene/resources/text_line.h"
#include "scene/resources/world_2d.h"
#include "scene/scene_string_names.h"
+#include "servers/audio_server.h"
void ViewportTexture::setup_local_to_scene() {
if (vp) {
@@ -820,12 +821,7 @@ Rect2 Viewport::get_visible_rect() const {
}
void Viewport::_update_listener_2d() {
- /*
- if (is_inside_tree() && audio_listener_3d && (!get_parent() || (Object::cast_to<Control>(get_parent()) && Object::cast_to<Control>(get_parent())->is_visible_in_tree())))
- SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, find_world_2d()->get_sound_space());
- else
- SpatialSound2DServer::get_singleton()->listener_set_space(internal_listener_2d, RID());
-*/
+ AudioServer::get_singleton()->notify_listener_changed();
}
void Viewport::set_as_audio_listener_2d(bool p_enable) {
@@ -3072,6 +3068,7 @@ bool Viewport::is_audio_listener_3d() const {
}
void Viewport::_update_listener_3d() {
+ AudioServer::get_singleton()->notify_listener_changed();
}
void Viewport::_listener_transform_3d_changed_notify() {
diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp
index ef070589e4..2ab9b7b5a4 100644
--- a/scene/resources/audio_stream_sample.cpp
+++ b/scene/resources/audio_stream_sample.cpp
@@ -221,12 +221,12 @@ void AudioStreamPlaybackSample::do_resample(const Depth *p_src, AudioFrame *p_ds
}
}
-void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
+int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
if (!base->data || !active) {
for (int i = 0; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0, 0);
}
- return;
+ return 0;
}
int len = base->data_bytes;
@@ -395,12 +395,15 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in
}
if (todo) {
+ int mixed_frames = p_frames - todo;
//bit was missing from mix
int todo_ofs = p_frames - todo;
for (int i = todo_ofs; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0, 0);
}
+ return mixed_frames;
}
+ return p_frames;
}
AudioStreamPlaybackSample::AudioStreamPlaybackSample() {}
diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h
index 70b8ba79ad..8bf3d29123 100644
--- a/scene/resources/audio_stream_sample.h
+++ b/scene/resources/audio_stream_sample.h
@@ -73,7 +73,7 @@ public:
virtual float get_playback_position() const override;
virtual void seek(float p_time) override;
- virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
+ virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
AudioStreamPlaybackSample();
};