Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/classes/AudioStreamPlayer3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@
<member name="stream_paused" type="bool" setter="set_stream_paused" getter="get_stream_paused" default="false">
If [code]true[/code], the playback is paused. You can resume it by setting [member stream_paused] to [code]false[/code].
</member>
<member name="tightness" type="float" setter="set_tightness" getter="get_tightness" default="1.0">
How steeply the signal dies off relative to angle from the source.
</member>
<member name="rear_attenuation" type="float" setter="set_rear_attenuation" getter="get_rear_attenuation" default="-3.0">
Attenuation applied to the rear channels when downmixing to stereo or 3.1.
</member>
<member name="equalpower_model" type="bool" setter="set_equalpower_model" getter="get_equalpower_model" default="false">
Use equalpower model.
</member>
<member name="unit_size" type="float" setter="set_unit_size" getter="get_unit_size" default="10.0">
The factor for the attenuation effect. Higher values make the sound audible over a larger distance.
</member>
Expand Down
141 changes: 110 additions & 31 deletions scene/3d/audio_stream_player_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class Spcap {
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 speaker_num = 0; speaker_num < speaker_count; speaker_num++) {
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));
}
Expand All @@ -74,7 +76,8 @@ class Spcap {
return speakers.ptr()[index].direction;
}

void calculate(const Vector3 &source_direction, real_t tightness, unsigned int volume_count, real_t *volumes) const {
void calculate(const Vector3 &source_direction, real_t tightness, real_t *volumes) const {
const unsigned int volume_count = get_speaker_count();
const Speaker *r = speakers.ptr();
real_t sum_squared_gains = 0.0;
for (unsigned int speaker_num = 0; speaker_num < (unsigned int)speakers.size(); speaker_num++) {
Expand All @@ -100,44 +103,80 @@ 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, 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:
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;
void AudioStreamPlayer3D::update_volumes(const Vector3 &source_dir, real_t *volumes) {
std::unique_ptr<Spcap> spcap;
AudioServer::SpeakerMode speaker_mode = AudioServer::get_singleton()->get_speaker_mode();

if (spcap == nullptr || cached_speaker_mode != speaker_mode) {
cached_speaker_mode = speaker_mode;
switch (speaker_mode) {
case AudioServer::SPEAKER_MODE_STEREO:
case AudioServer::SPEAKER_SURROUND_31:
case AudioServer::SPEAKER_SURROUND_51:
speaker_count = 5;
break;
case AudioServer::SPEAKER_SURROUND_71:
speaker_count = 7;
break;
}
spcap = std::unique_ptr<Spcap>(new Spcap(speaker_count, speaker_directions));
}

Spcap spcap(speaker_count, speaker_directions); //TODO: should only be created/recreated once the speaker mode / speaker positions changes
spcap->calculate(source_dir, tightness, volumes);
}

void AudioStreamPlayer3D::update_volumes2(Vector3 source_dir, real_t *volumes) {
source_dir.y = 0;
if (source_dir.z > 0) {
source_dir.z = -source_dir.z;
}
Vector3 left_dir = Vector3(-1, 0, 0);
float cosine = left_dir.dot(source_dir);
volumes[0] = sqrt((1. + cosine) / 2.);
volumes[1] = sqrt((1. - cosine) / 2.);
}

void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, Vector<AudioFrame> &output) {
real_t volumes[7];
spcap.calculate(source_dir, tightness, speaker_count, volumes);
update_volumes(source_dir, volumes);

switch (AudioServer::get_singleton()->get_speaker_mode()) {
switch (cached_speaker_mode) {
case AudioServer::SPEAKER_SURROUND_71:
output.write[3].left = volumes[5]; // side-left
output.write[3].right = volumes[6]; // side-right
[[fallthrough]];
case AudioServer::SPEAKER_SURROUND_51:
output.write[2].left = volumes[3]; // rear-left
output.write[2].right = volumes[4]; // rear-right
[[fallthrough]];
case AudioServer::SPEAKER_SURROUND_31:
output.write[1].right = 1.0; // LFE - always full power
output.write[1].left = volumes[2]; // center
[[fallthrough]];
case AudioServer::SPEAKER_MODE_STEREO:
output.write[0].right = volumes[1]; // front-right
output.write[0].left = volumes[0]; // front-left
break;
case AudioServer::SPEAKER_SURROUND_31: {
float rear_mult = Math::db_to_linear(rear_attenuation);
output.write[1].right = 1.0; // LFE - always full power
output.write[1].left = volumes[2]; // center
output.write[0].left = volumes[0] + volumes[3] * rear_mult; // front-left
output.write[0].right = volumes[1] + volumes[4] * rear_mult; // front-right
break;
}
case AudioServer::SPEAKER_MODE_STEREO: {
float rear_mult = Math::db_to_linear(rear_attenuation);
output.write[0].left = (volumes[0] + volumes[2] / Math_SQRT2 + volumes[3] * rear_mult) / Math_SQRT2; // front-left
output.write[0].right = (volumes[1] + volumes[2] / Math_SQRT2 + volumes[4] * rear_mult) / Math_SQRT2; // front-right
printf("left: %f + %f + %f = %f\n", volumes[0], volumes[2], volumes[3], output[0].left);
printf("right: %f + %f + %f = %f\n", volumes[1], volumes[2], volumes[4], output[0].right);
update_volumes2(source_dir, volumes);
if (equalpower_model) {
output.write[0].left = volumes[0];
output.write[0].right = volumes[1];
}
printf("left: %f\n", volumes[0]);
printf("right: %f\n", volumes[1]);
printf("-------------------------------------------------------------------\n");
break;
}
}
}

Expand Down Expand Up @@ -335,9 +374,6 @@ StringName AudioStreamPlayer3D::_get_actual_bus() {
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);
}

if (!internal->active.is_set() || internal->stream.is_null()) {
return output_volume_vector;
Expand Down Expand Up @@ -435,13 +471,20 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
for (Ref<AudioStreamPlayback> &playback : internal->stream_playbacks) {
AudioServer::get_singleton()->set_playback_highshelf_params(playback, linear_attenuation, attenuation_filter_cutoff_hz);
}
// Bake in a constant factor here to allow the project setting defaults for 2d and 3d to be normalized to 1.0.
float tightness = cached_global_panning_strength * 2.0f;
tightness *= panning_strength;
_calc_output_vol(local_pos.normalized(), tightness, output_volume_vector);

_calc_output_vol(local_pos.normalized(), output_volume_vector);

// Apply panning effect.
float panning = CLAMP(panning_strength * cached_global_panning_strength, 0., 1.) / 2.;
for (unsigned int k = 0; k < 4; k++) {
output_volume_vector.write[k] = multiplier * output_volume_vector[k];
AudioFrame volume(multiplier, multiplier);
if (k != 1) {
volume.left *= (0.5 + panning) * output_volume_vector[k].left + (0.5 - panning) * output_volume_vector[k].right;
volume.right *= (0.5 - panning) * output_volume_vector[k].left + (0.5 + panning) * output_volume_vector[k].right;
} else {
volume *= output_volume_vector[k];
}
output_volume_vector.write[k] = volume;
}

HashMap<StringName, Vector<AudioFrame>> bus_volumes;
Expand Down Expand Up @@ -743,6 +786,30 @@ float AudioStreamPlayer3D::get_panning_strength() const {
return panning_strength;
}

void AudioStreamPlayer3D::set_tightness(float p_tightness) {
tightness = p_tightness;
}

float AudioStreamPlayer3D::get_tightness() const {
return tightness;
}

void AudioStreamPlayer3D::set_rear_attenuation(float p_rear_attenuation) {
rear_attenuation = p_rear_attenuation;
}

float AudioStreamPlayer3D::get_rear_attenuation() const {
return rear_attenuation;
}

void AudioStreamPlayer3D::set_equalpower_model(bool p_equalpower_model) {
equalpower_model = p_equalpower_model;
}

bool AudioStreamPlayer3D::get_equalpower_model() const {
return equalpower_model;
}

AudioServer::PlaybackType AudioStreamPlayer3D::get_playback_type() const {
return internal->get_playback_type();
}
Expand Down Expand Up @@ -833,6 +900,15 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_panning_strength", "panning_strength"), &AudioStreamPlayer3D::set_panning_strength);
ClassDB::bind_method(D_METHOD("get_panning_strength"), &AudioStreamPlayer3D::get_panning_strength);

ClassDB::bind_method(D_METHOD("set_tightness", "tightness"), &AudioStreamPlayer3D::set_tightness);
ClassDB::bind_method(D_METHOD("get_tightness"), &AudioStreamPlayer3D::get_tightness);

ClassDB::bind_method(D_METHOD("set_rear_attenuation", "rear_attenuation"), &AudioStreamPlayer3D::set_rear_attenuation);
ClassDB::bind_method(D_METHOD("get_rear_attenuation"), &AudioStreamPlayer3D::get_rear_attenuation);

ClassDB::bind_method(D_METHOD("set_equalpower_model", "equalpower_model"), &AudioStreamPlayer3D::set_equalpower_model);
ClassDB::bind_method(D_METHOD("get_equalpower_model"), &AudioStreamPlayer3D::get_equalpower_model);

ClassDB::bind_method(D_METHOD("has_stream_playback"), &AudioStreamPlayer3D::has_stream_playback);
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback);

Expand All @@ -852,6 +928,9 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,or_greater,suffix:m"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "panning_strength", PROPERTY_HINT_RANGE, "0,3,0.01,or_greater"), "set_panning_strength", "get_panning_strength");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tightness", PROPERTY_HINT_EXP_EASING, "tightness"), "set_tightness", "get_tightness");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rear_attenuation", PROPERTY_HINT_RANGE, "-80,0,suffix:dB"), "set_rear_attenuation", "get_rear_attenuation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "equalpower_model", PROPERTY_HINT_NONE, ""), "set_equalpower_model", "get_equalpower_model");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_type", PROPERTY_HINT_ENUM, "Default,Stream,Sample"), "set_playback_type", "get_playback_type");
Expand Down
21 changes: 20 additions & 1 deletion scene/3d/audio_stream_player_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,15 @@ class AudioStreamPlayer3D : public Node3D {
uint64_t last_mix_count = -1;
bool force_update_panning = false;

static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Vector<AudioFrame> &output);
void _calc_output_vol(const Vector3 &source_dir, Vector<AudioFrame> &output);

void _calc_reverb_vol(Area3D *area, Vector3 listener_area_pos, Vector<AudioFrame> direct_path_vol, Vector<AudioFrame> &reverb_vol);

static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer3D *>(self)->force_update_panning = true; }

void update_volumes(const Vector3 &source_dir, real_t *volumes);
void update_volumes2(Vector3 source_dir, real_t *volumes);

void _set_playing(bool p_enable);
bool _is_active() const;
StringName _get_actual_bus();
Expand Down Expand Up @@ -114,6 +117,13 @@ class AudioStreamPlayer3D : public Node3D {
float panning_strength = 1.0f;
float cached_global_panning_strength = 0.5f;

real_t tightness = 1.0f;
real_t rear_attenuation = -3.0;
bool equalpower_model = false;

AudioServer::SpeakerMode cached_speaker_mode;
unsigned int speaker_count = 0; // only main speakers (no LFE)

protected:
void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
Expand Down Expand Up @@ -195,6 +205,15 @@ class AudioStreamPlayer3D : public Node3D {
void set_panning_strength(float p_panning_strength);
float get_panning_strength() const;

void set_tightness(float p_tightness);
float get_tightness() const;

void set_rear_attenuation(float p_rear_attenuation);
float get_rear_attenuation() const;

void set_equalpower_model(bool p_equalpower_model);
bool get_equalpower_model() const;

bool has_stream_playback();
Ref<AudioStreamPlayback> get_stream_playback();

Expand Down
Loading