Path: blob/master/scene/2d/audio_stream_player_2d.cpp
9903 views
/**************************************************************************/1/* audio_stream_player_2d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "audio_stream_player_2d.h"31#include "audio_stream_player_2d.compat.inc"3233#include "core/config/project_settings.h"34#include "scene/2d/audio_listener_2d.h"35#include "scene/audio/audio_stream_player_internal.h"36#include "scene/main/viewport.h"37#include "scene/resources/world_2d.h"38#include "servers/audio/audio_stream.h"39#include "servers/audio_server.h"4041#ifndef PHYSICS_2D_DISABLED42#include "scene/2d/physics/area_2d.h"43#endif // PHYSICS_2D_DISABLED4445void AudioStreamPlayer2D::_notification(int p_what) {46internal->notification(p_what);4748switch (p_what) {49case NOTIFICATION_ENTER_TREE: {50AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this);51} break;5253case NOTIFICATION_EXIT_TREE: {54AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);55} break;5657case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {58// Update anything related to position first, if possible of course.59if (setplay.get() > 0 || (internal->active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count()) || force_update_panning) {60force_update_panning = false;61_update_panning();62}6364if (setplayback.is_valid() && setplay.get() >= 0) {65internal->active.set();66AudioServer::get_singleton()->start_playback_stream(setplayback, _get_actual_bus(), volume_vector, setplay.get(), internal->pitch_scale);67setplayback.unref();68setplay.set(-1);69}7071if (!internal->stream_playbacks.is_empty() && internal->active.is_set()) {72internal->process();73}74internal->ensure_playback_limit();75} break;76}77}7879// Interacts with PhysicsServer2D, so can only be called during _physics_process.80StringName AudioStreamPlayer2D::_get_actual_bus() {81#ifndef PHYSICS_2D_DISABLED82Vector2 global_pos = get_global_position();8384//check if any area is diverting sound into a bus85Ref<World2D> world_2d = get_world_2d();86ERR_FAIL_COND_V(world_2d.is_null(), SceneStringName(Master));8788PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());89ERR_FAIL_NULL_V(space_state, SceneStringName(Master));90PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];9192PhysicsDirectSpaceState2D::PointParameters point_params;93point_params.position = global_pos;94point_params.collision_mask = area_mask;95point_params.collide_with_bodies = false;96point_params.collide_with_areas = true;9798int areas = space_state->intersect_point(point_params, sr, MAX_INTERSECT_AREAS);99for (int i = 0; i < areas; i++) {100Area2D *area2d = Object::cast_to<Area2D>(sr[i].collider);101if (!area2d) {102continue;103}104105if (!area2d->is_overriding_audio_bus()) {106continue;107}108109return area2d->get_audio_bus_name();110}111#endif // PHYSICS_2D_DISABLED112113return internal->bus;114}115116// Interacts with PhysicsServer2D, so can only be called during _physics_process117void AudioStreamPlayer2D::_update_panning() {118if (!internal->active.is_set() || internal->stream.is_null()) {119return;120}121122Ref<World2D> world_2d = get_world_2d();123ERR_FAIL_COND(world_2d.is_null());124125Vector2 global_pos = get_global_position();126127HashSet<Viewport *> viewports = world_2d->get_viewports();128129volume_vector.resize(4);130volume_vector.write[0] = AudioFrame(0, 0);131volume_vector.write[1] = AudioFrame(0, 0);132volume_vector.write[2] = AudioFrame(0, 0);133volume_vector.write[3] = AudioFrame(0, 0);134135StringName actual_bus = _get_actual_bus();136137for (Viewport *vp : viewports) {138if (!vp->is_audio_listener_2d()) {139continue;140}141//compute matrix to convert to screen142Vector2 screen_size = vp->get_visible_rect().size;143Vector2 listener_in_global;144Vector2 relative_to_listener;145146//screen in global is used for attenuation147AudioListener2D *listener = vp->get_audio_listener_2d();148Transform2D full_canvas_transform = vp->get_global_canvas_transform() * vp->get_canvas_transform();149if (listener) {150listener_in_global = listener->get_global_position();151relative_to_listener = (global_pos - listener_in_global).rotated(-listener->get_global_rotation());152relative_to_listener *= full_canvas_transform.get_scale(); // Default listener scales with canvas size, do the same here.153} else {154listener_in_global = full_canvas_transform.affine_inverse().xform(screen_size * 0.5);155relative_to_listener = full_canvas_transform.xform(global_pos) - screen_size * 0.5;156}157158float dist = global_pos.distance_to(listener_in_global); // Distance to listener, or screen if none.159160if (dist > max_distance) {161continue; // Can't hear this sound in this viewport.162}163164float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);165multiplier *= Math::db_to_linear(internal->volume_db); // Also apply player volume!166167float pan = relative_to_listener.x / screen_size.x;168// Don't let the panning effect extend (too far) beyond the screen.169pan = CLAMP(pan, -1, 1);170171// Bake in a constant factor here to allow the project setting defaults for 2d and 3d to be normalized to 1.0.172pan *= panning_strength * cached_global_panning_strength * 0.5f;173174pan = CLAMP(pan + 0.5, 0.0, 1.0);175176float l = 1.0 - pan;177float r = pan;178179const AudioFrame &prev_sample = volume_vector[0];180AudioFrame new_sample = AudioFrame(l, r) * multiplier;181182volume_vector.write[0] = AudioFrame(MAX(prev_sample[0], new_sample[0]), MAX(prev_sample[1], new_sample[1]));183}184185for (const Ref<AudioStreamPlayback> &playback : internal->stream_playbacks) {186AudioServer::get_singleton()->set_playback_bus_exclusive(playback, actual_bus, volume_vector);187}188189for (const Ref<AudioStreamPlayback> &playback : internal->stream_playbacks) {190AudioServer::get_singleton()->set_playback_pitch_scale(playback, internal->pitch_scale);191if (playback->get_is_sample() && playback->get_sample_playback().is_valid()) {192Ref<AudioSamplePlayback> sample_playback = playback->get_sample_playback();193AudioServer::get_singleton()->update_sample_playback_pitch_scale(sample_playback, internal->pitch_scale);194}195}196197last_mix_count = AudioServer::get_singleton()->get_mix_count();198}199200void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {201internal->set_stream(p_stream);202}203204Ref<AudioStream> AudioStreamPlayer2D::get_stream() const {205return internal->stream;206}207208void AudioStreamPlayer2D::set_volume_db(float p_volume) {209ERR_FAIL_COND_MSG(Math::is_nan(p_volume), "Volume can't be set to NaN.");210internal->volume_db = p_volume;211}212213float AudioStreamPlayer2D::get_volume_db() const {214return internal->volume_db;215}216217void AudioStreamPlayer2D::set_volume_linear(float p_volume) {218set_volume_db(Math::linear_to_db(p_volume));219}220221float AudioStreamPlayer2D::get_volume_linear() const {222return Math::db_to_linear(get_volume_db());223}224225void AudioStreamPlayer2D::set_pitch_scale(float p_pitch_scale) {226internal->set_pitch_scale(p_pitch_scale);227}228229float AudioStreamPlayer2D::get_pitch_scale() const {230return internal->pitch_scale;231}232233void AudioStreamPlayer2D::play(float p_from_pos) {234Ref<AudioStreamPlayback> stream_playback = internal->play_basic();235if (stream_playback.is_null()) {236return;237}238setplayback = stream_playback;239setplay.set(p_from_pos);240241// Sample handling.242if (stream_playback->get_is_sample() && stream_playback->get_sample_playback().is_valid()) {243Ref<AudioSamplePlayback> sample_playback = stream_playback->get_sample_playback();244sample_playback->offset = p_from_pos;245sample_playback->bus = _get_actual_bus();246247AudioServer::get_singleton()->start_sample_playback(sample_playback);248}249}250251void AudioStreamPlayer2D::seek(float p_seconds) {252internal->seek(p_seconds);253}254255void AudioStreamPlayer2D::stop() {256setplay.set(-1);257internal->stop_basic();258}259260bool AudioStreamPlayer2D::is_playing() const {261if (setplay.get() >= 0) {262return true; // play() has been called this frame, but no playback exists just yet.263}264return internal->is_playing();265}266267float AudioStreamPlayer2D::get_playback_position() {268if (setplay.get() >= 0) {269return setplay.get(); // play() has been called this frame, but no playback exists just yet.270}271return internal->get_playback_position();272}273274void AudioStreamPlayer2D::set_bus(const StringName &p_bus) {275internal->bus = p_bus; // This will be pushed to the audio server during the next physics timestep, which is fast enough.276}277278StringName AudioStreamPlayer2D::get_bus() const {279return internal->get_bus();280}281282void AudioStreamPlayer2D::set_autoplay(bool p_enable) {283internal->autoplay = p_enable;284}285286bool AudioStreamPlayer2D::is_autoplay_enabled() const {287return internal->autoplay;288}289290void AudioStreamPlayer2D::_set_playing(bool p_enable) {291internal->set_playing(p_enable);292}293294void AudioStreamPlayer2D::_validate_property(PropertyInfo &p_property) const {295internal->validate_property(p_property);296}297298void AudioStreamPlayer2D::set_max_distance(float p_pixels) {299ERR_FAIL_COND(p_pixels <= 0.0);300max_distance = p_pixels;301}302303float AudioStreamPlayer2D::get_max_distance() const {304return max_distance;305}306307void AudioStreamPlayer2D::set_attenuation(float p_curve) {308attenuation = p_curve;309}310311float AudioStreamPlayer2D::get_attenuation() const {312return attenuation;313}314315void AudioStreamPlayer2D::set_area_mask(uint32_t p_mask) {316area_mask = p_mask;317}318319uint32_t AudioStreamPlayer2D::get_area_mask() const {320return area_mask;321}322323void AudioStreamPlayer2D::set_stream_paused(bool p_pause) {324internal->set_stream_paused(p_pause);325}326327bool AudioStreamPlayer2D::get_stream_paused() const {328return internal->get_stream_paused();329}330331bool AudioStreamPlayer2D::has_stream_playback() {332return internal->has_stream_playback();333}334335Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {336return internal->get_stream_playback();337}338339void AudioStreamPlayer2D::set_max_polyphony(int p_max_polyphony) {340internal->set_max_polyphony(p_max_polyphony);341}342343int AudioStreamPlayer2D::get_max_polyphony() const {344return internal->max_polyphony;345}346347void AudioStreamPlayer2D::set_panning_strength(float p_panning_strength) {348ERR_FAIL_COND_MSG(p_panning_strength < 0, "Panning strength must be a positive number.");349panning_strength = p_panning_strength;350}351352float AudioStreamPlayer2D::get_panning_strength() const {353return panning_strength;354}355356AudioServer::PlaybackType AudioStreamPlayer2D::get_playback_type() const {357return internal->get_playback_type();358}359360void AudioStreamPlayer2D::set_playback_type(AudioServer::PlaybackType p_playback_type) {361internal->set_playback_type(p_playback_type);362}363364bool AudioStreamPlayer2D::_set(const StringName &p_name, const Variant &p_value) {365return internal->set(p_name, p_value);366}367368bool AudioStreamPlayer2D::_get(const StringName &p_name, Variant &r_ret) const {369return internal->get(p_name, r_ret);370}371372void AudioStreamPlayer2D::_get_property_list(List<PropertyInfo> *p_list) const {373internal->get_property_list(p_list);374}375376void AudioStreamPlayer2D::_bind_methods() {377ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream);378ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer2D::get_stream);379380ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer2D::set_volume_db);381ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer2D::get_volume_db);382383ClassDB::bind_method(D_METHOD("set_volume_linear", "volume_linear"), &AudioStreamPlayer2D::set_volume_linear);384ClassDB::bind_method(D_METHOD("get_volume_linear"), &AudioStreamPlayer2D::get_volume_linear);385386ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer2D::set_pitch_scale);387ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer2D::get_pitch_scale);388389ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer2D::play, DEFVAL(0.0));390ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer2D::seek);391ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer2D::stop);392393ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer2D::is_playing);394ClassDB::bind_method(D_METHOD("get_playback_position"), &AudioStreamPlayer2D::get_playback_position);395396ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioStreamPlayer2D::set_bus);397ClassDB::bind_method(D_METHOD("get_bus"), &AudioStreamPlayer2D::get_bus);398399ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioStreamPlayer2D::set_autoplay);400ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer2D::is_autoplay_enabled);401402ClassDB::bind_method(D_METHOD("set_playing", "enable"), &AudioStreamPlayer2D::_set_playing);403404ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &AudioStreamPlayer2D::set_max_distance);405ClassDB::bind_method(D_METHOD("get_max_distance"), &AudioStreamPlayer2D::get_max_distance);406407ClassDB::bind_method(D_METHOD("set_attenuation", "curve"), &AudioStreamPlayer2D::set_attenuation);408ClassDB::bind_method(D_METHOD("get_attenuation"), &AudioStreamPlayer2D::get_attenuation);409410ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer2D::set_area_mask);411ClassDB::bind_method(D_METHOD("get_area_mask"), &AudioStreamPlayer2D::get_area_mask);412413ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer2D::set_stream_paused);414ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer2D::get_stream_paused);415416ClassDB::bind_method(D_METHOD("set_max_polyphony", "max_polyphony"), &AudioStreamPlayer2D::set_max_polyphony);417ClassDB::bind_method(D_METHOD("get_max_polyphony"), &AudioStreamPlayer2D::get_max_polyphony);418419ClassDB::bind_method(D_METHOD("set_panning_strength", "panning_strength"), &AudioStreamPlayer2D::set_panning_strength);420ClassDB::bind_method(D_METHOD("get_panning_strength"), &AudioStreamPlayer2D::get_panning_strength);421422ClassDB::bind_method(D_METHOD("has_stream_playback"), &AudioStreamPlayer2D::has_stream_playback);423ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer2D::get_stream_playback);424425ClassDB::bind_method(D_METHOD("set_playback_type", "playback_type"), &AudioStreamPlayer2D::set_playback_type);426ClassDB::bind_method(D_METHOD("get_playback_type"), &AudioStreamPlayer2D::get_playback_type);427428ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");429ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,suffix:dB"), "set_volume_db", "get_volume_db");430ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_linear", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_volume_linear", "get_volume_linear");431ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");432ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_ONESHOT, "", PROPERTY_USAGE_EDITOR), "set_playing", "is_playing");433ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");434ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");435ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "1,4096,1,or_greater,exp,suffix:px"), "set_max_distance", "get_max_distance");436ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation");437ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");438ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "panning_strength", PROPERTY_HINT_RANGE, "0,3,0.01,or_greater"), "set_panning_strength", "get_panning_strength");439ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");440ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");441ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_type", PROPERTY_HINT_ENUM, "Default,Stream,Sample"), "set_playback_type", "get_playback_type");442443ADD_SIGNAL(MethodInfo("finished"));444}445446AudioStreamPlayer2D::AudioStreamPlayer2D() {447internal = memnew(AudioStreamPlayerInternal(this, callable_mp(this, &AudioStreamPlayer2D::play), callable_mp(this, &AudioStreamPlayer2D::stop), true));448cached_global_panning_strength = GLOBAL_GET_CACHED(float, "audio/general/2d_panning_strength");449set_hide_clip_children(true);450}451452AudioStreamPlayer2D::~AudioStreamPlayer2D() {453memdelete(internal);454}455456457