diff options
Diffstat (limited to 'scene/3d/audio_stream_player_3d.cpp')
-rw-r--r-- | scene/3d/audio_stream_player_3d.cpp | 910 |
1 files changed, 910 insertions, 0 deletions
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp new file mode 100644 index 0000000000..cc9470e88d --- /dev/null +++ b/scene/3d/audio_stream_player_3d.cpp @@ -0,0 +1,910 @@ +#include "audio_stream_player_3d.h" +#include "engine.h" +#include "scene/3d/area.h" +#include "scene/3d/camera.h" +#include "scene/main/viewport.h" +void AudioStreamPlayer3D::_mix_audio() { + + if (!stream_playback.is_valid()) { + return; + } + + if (!active) { + return; + } + + bool started = false; + if (setseek >= 0.0) { + stream_playback->start(setseek); + setseek = -1.0; //reset seek + started = true; + } + + //get data + AudioFrame *buffer = mix_buffer.ptr(); + int buffer_size = mix_buffer.size(); + + //mix + if (output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX) { + + float pitch_scale = 0.0; + if (output_count) { + //used for doppler, not realistic but good enough + for (int i = 0; i < output_count; i++) { + pitch_scale += outputs[i].pitch_scale; + } + pitch_scale /= float(output_count); + } else { + pitch_scale = 1.0; + } + + stream_playback->mix(buffer, pitch_scale, buffer_size); + } + + //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; + ; + 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! + + int buffers = 0; + int first = 0; + + switch (AudioServer::get_singleton()->get_speaker_mode()) { + + case AudioServer::SPEAKER_MODE_STEREO: { + buffers = 1; + first = 0; + + } break; + case AudioServer::SPEAKER_SURROUND_51: { + buffers = 2; + first = 1; + + } break; + case AudioServer::SPEAKER_SURROUND_71: { + + buffers = 3; + first = 1; + + } break; + } + + for (int k = 0; k < buffers; k++) { + AudioFrame vol_inc = (current.vol[k] - prev_outputs[i].vol[k]) / float(buffer_size); + AudioFrame vol = current.vol[k]; + + AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, first + 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(¤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) { + + AudioFrame *rtarget = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.reverb_bus_index, first + 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; + } + } + } + } + + 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; +} + +float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const { + + float att; + switch (attenuation_model) { + case ATTENUATION_INVERSE_DISTANCE: { + att = Math::linear2db(1.0 / ((p_distance / unit_size) + 000001)); + } break; + case ATTENUATION_INVERSE_SQUARE_DISTANCE: { + float d = (p_distance / unit_size); + d *= d; + att = Math::linear2db(1.0 / (d + 0.00001)); + } break; + case ATTENUATION_LOGARITHMIC: { + att = -20 * Math::log(p_distance / unit_size + 000001); + } break; + } + + 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); + if (autoplay && !get_tree()->is_editor_hint()) { + play(); + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + + AudioServer::get_singleton()->remove_callback(_mix_audios, this); + } + if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { + + if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { + velocity_tracker->update_position(get_global_transform().origin); + } + } + + if (p_what == NOTIFICATION_INTERNAL_FIXED_PROCESS) { + + //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]; + + int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, PhysicsDirectSpaceState::TYPE_MASK_AREA); + Area *area = NULL; + + for (int i = 0; i < areas; i++) { + if (!sr[i].collider) + continue; + + Area *tarea = sr[i].collider->cast_to<Area>(); + 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; + + Vector3 local_pos = camera->get_global_transform().orthonormalized().affine_inverse().xform(global_pos); + + float dist = local_pos.length(); + + Vector3 area_sound_pos; + Vector3 cam_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(), camera->get_global_transform().origin); + cam_area_pos = camera->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, cam_area_pos.length()); + } + if (total_max > max_distance) { + continue; //cant hear this sound in this camera + } + } + + 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 camtopos = global_pos - camera->get_global_transform().origin; + float c = camtopos.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); + + Vector3 flat_pos = local_pos; + flat_pos.y = 0; + flat_pos.normalize(); + + switch (AudioServer::get_singleton()->get_speaker_mode()) { + + case AudioServer::SPEAKER_MODE_STEREO: { + + float c = flat_pos.x * 0.5 + 0.5; + output.vol[0].l = 1.0 - c; + output.vol[0].r = c; + + output.vol[0] *= multiplier; + + } break; + case AudioServer::SPEAKER_SURROUND_51: { + + float xl = Vector3(-1, 0, -1).normalized().dot(flat_pos) * 0.5 + 0.5; + float xr = Vector3(1, 0, -1).normalized().dot(flat_pos) * 0.5 + 0.5; + + output.vol[0].l = xl; + output.vol[1].r = 1.0 - xl; + output.vol[0].r = xr; + output.vol[1].l = 1.0 - xr; + + output.vol[0] *= multiplier; + output.vol[1] *= multiplier; + } break; + case AudioServer::SPEAKER_SURROUND_71: { + + float xl = Vector3(-1, 0, -1).normalized().dot(flat_pos) * 0.5 + 0.5; + float xr = Vector3(1, 0, -1).normalized().dot(flat_pos) * 0.5 + 0.5; + + output.vol[0].l = xl; + output.vol[1].r = 1.0 - xl; + output.vol[0].r = xr; + output.vol[1].l = 1.0 - xr; + + float c = flat_pos.x * 0.5 + 0.5; + output.vol[2].l = 1.0 - c; + output.vol[2].r = c; + + output.vol[0] *= multiplier; + output.vol[1] *= multiplier; + output.vol[2] *= multiplier; + + } break; + } + + 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()) { + 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(); + + int vol_index_max = AudioServer::get_singleton()->get_speaker_mode() + 1; + + if (uniformity > 0.0) { + + float distance = cam_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 + + if (attenuation < 1.0) { + //pan the uniform sound + Vector3 rev_pos = cam_area_pos; + rev_pos.y = 0; + rev_pos.normalize(); + + switch (AudioServer::get_singleton()->get_speaker_mode()) { + + case AudioServer::SPEAKER_MODE_STEREO: { + + float c = rev_pos.x * 0.5 + 0.5; + output.reverb_vol[0].l = 1.0 - c; + output.reverb_vol[0].r = c; + + } break; + case AudioServer::SPEAKER_SURROUND_51: { + + 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[0].l = xl; + output.reverb_vol[1].r = 1.0 - xl; + output.reverb_vol[0].r = xr; + output.reverb_vol[1].l = 1.0 - xr; + + } break; + case AudioServer::SPEAKER_SURROUND_71: { + + 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[0].l = xl; + output.reverb_vol[1].r = 1.0 - xl; + output.reverb_vol[0].r = xr; + output.reverb_vol[1].l = 1.0 - xr; + + float c = rev_pos.x * 0.5 + 0.5; + output.reverb_vol[2].l = 1.0 - c; + output.reverb_vol[2].r = c; + + } break; + } + } + + float center_val[3] = { 0.5, 0.25, 0.16666 }; + AudioFrame center_frame(center_val[vol_index_max - 1], center_val[vol_index_max - 1]); + + for (int i = 0; i < vol_index_max; i++) { + + output.reverb_vol[i] = output.reverb_vol[i].linear_interpolate(center_frame, attenuation); + 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) { + + Vector3 camera_velocity = camera->get_doppler_tracked_velocity(); + + Vector3 local_velocity = camera->get_global_transform().orthonormalized().basis.xform_inv(linear_velocity - camera_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; + } + + 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; + _change_notify("playing"); //update property in editor + } + + //stop playing if no longer active + if (!active) { + set_fixed_process_internal(false); + _change_notify("playing"); //update property in editor + } + } +} + +void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) { + + ERR_FAIL_COND(!p_stream.is_valid()); + 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; + } + + stream = p_stream; + stream_playback = p_stream->instance_playback(); + + if (stream_playback.is_null()) { + stream.unref(); + ERR_FAIL_COND(stream_playback.is_null()); + } + + AudioServer::get_singleton()->unlock(); +} + +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; +} + +void AudioStreamPlayer3D::play(float p_from_pos) { + + if (stream_playback.is_valid()) { + setplay = p_from_pos; + output_ready = false; + set_fixed_process_internal(true); + } +} + +void AudioStreamPlayer3D::seek(float p_seconds) { + + if (stream_playback.is_valid()) { + setseek = p_seconds; + } +} + +void AudioStreamPlayer3D::stop() { + + if (stream_playback.is_valid()) { + active = false; + set_fixed_process_internal(false); + setplay = -1; + } +} + +bool AudioStreamPlayer3D::is_playing() const { + + if (stream_playback.is_valid()) { + return active; // && stream_playback->is_playing(); + } + + return false; +} + +float AudioStreamPlayer3D::get_pos() { + + if (stream_playback.is_valid()) { + return stream_playback->get_pos(); + } + + 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(); +} + +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) { + ERR_FAIL_INDEX(p_model, 3); + attenuation_model = p_model; +} + +AudioStreamPlayer3D::AttenuationModel AudioStreamPlayer3D::get_attenuation_model() const { + return attenuation_model; +} + +void AudioStreamPlayer3D::set_out_of_range_mode(OutOfRangeMode p_mode) { + + ERR_FAIL_INDEX(p_mode, 2); + 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); + velocity_tracker->set_track_fixed_step(doppler_tracking == DOPPLER_TRACKING_FIXED_STEP); + velocity_tracker->reset(get_global_transform().origin); + } else { + set_notify_transform(false); + } +} + +AudioStreamPlayer3D::DopplerTracking AudioStreamPlayer3D::get_doppler_tracking() const { + + return doppler_tracking; +} + +void AudioStreamPlayer3D::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_stream", "stream:AudioStream"), &AudioStreamPlayer3D::set_stream); + 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); + + ClassDB::bind_method(D_METHOD("play", "from_pos"), &AudioStreamPlayer3D::play, DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("seek", "to_pos"), &AudioStreamPlayer3D::seek); + ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer3D::stop); + + ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer3D::is_playing); + ClassDB::bind_method(D_METHOD("get_pos"), &AudioStreamPlayer3D::get_pos); + + 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); + + 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"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,InverseSquare,Log"), "set_attenuation_model", "get_attenuation_model"); + 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"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "_is_active"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,65536,1"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "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_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_"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation_filter_cutoff_hz", PROPERTY_HINT_RANGE, "50,50000,1"), "set_attenuation_filter_cutoff_hz", "get_attenuation_filter_cutoff_hz"); + 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_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Fixed"), "set_doppler_tracking", "get_doppler_tracking"); + + BIND_CONSTANT(ATTENUATION_INVERSE_DISTANCE); + BIND_CONSTANT(ATTENUATION_INVERSE_SQUARE_DISTANCE); + BIND_CONSTANT(ATTENUATION_LOGARITHMIC); + + BIND_CONSTANT(OUT_OF_RANGE_MIX); + BIND_CONSTANT(OUT_OF_RANGE_PAUSE); + + BIND_CONSTANT(DOPPLER_TRACKING_DISABLED); + BIND_CONSTANT(DOPPLER_TRACKING_IDLE_STEP); + BIND_CONSTANT(DOPPLER_TRACKING_FIXED_STEP); +} + +AudioStreamPlayer3D::AudioStreamPlayer3D() { + + unit_db = 0; + unit_size = 1; + attenuation_model = ATTENUATION_INVERSE_DISTANCE; + max_db = 3; + 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; + + velocity_tracker.instance(); + AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed"); +} +AudioStreamPlayer3D::~AudioStreamPlayer3D() { +} |