1/**************************************************************************/
2/* audio_stream_player_2d.cpp */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#include "audio_stream_player_2d.h"
32
33#include "core/config/project_settings.h"
34#include "scene/2d/area_2d.h"
35#include "scene/2d/audio_listener_2d.h"
36#include "scene/main/window.h"
37#include "scene/resources/world_2d.h"
38
39void AudioStreamPlayer2D::_notification(int p_what) {
40 switch (p_what) {
41 case NOTIFICATION_ENTER_TREE: {
42 AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this);
43 if (autoplay && !Engine::get_singleton()->is_editor_hint()) {
44 play();
45 }
46 set_stream_paused(false);
47 } break;
48
49 case NOTIFICATION_EXIT_TREE: {
50 set_stream_paused(true);
51 AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this);
52 } break;
53
54 case NOTIFICATION_PREDELETE: {
55 stop();
56 } break;
57
58 case NOTIFICATION_PAUSED: {
59 if (!can_process()) {
60 // Node can't process so we start fading out to silence.
61 set_stream_paused(true);
62 }
63 } break;
64
65 case NOTIFICATION_UNPAUSED: {
66 set_stream_paused(false);
67 } break;
68
69 case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
70 // Update anything related to position first, if possible of course.
71 if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count()) || force_update_panning) {
72 force_update_panning = false;
73 _update_panning();
74 }
75
76 if (setplayback.is_valid() && setplay.get() >= 0) {
77 active.set();
78 AudioServer::get_singleton()->start_playback_stream(setplayback, _get_actual_bus(), volume_vector, setplay.get(), pitch_scale);
79 setplayback.unref();
80 setplay.set(-1);
81 }
82
83 if (!stream_playbacks.is_empty() && active.is_set()) {
84 // Stop playing if no longer active.
85 Vector<Ref<AudioStreamPlayback>> playbacks_to_remove;
86 for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
87 if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) {
88 playbacks_to_remove.push_back(playback);
89 }
90 }
91 // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble.
92 for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) {
93 stream_playbacks.erase(playback);
94 }
95 if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) {
96 // This node is no longer actively playing audio.
97 active.clear();
98 set_physics_process_internal(false);
99 }
100 if (!playbacks_to_remove.is_empty()) {
101 emit_signal(SNAME("finished"));
102 }
103 }
104
105 while (stream_playbacks.size() > max_polyphony) {
106 AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]);
107 stream_playbacks.remove_at(0);
108 }
109 } break;
110 }
111}
112
113// Interacts with PhysicsServer2D, so can only be called during _physics_process
114StringName AudioStreamPlayer2D::_get_actual_bus() {
115 Vector2 global_pos = get_global_position();
116
117 //check if any area is diverting sound into a bus
118 Ref<World2D> world_2d = get_world_2d();
119 ERR_FAIL_COND_V(world_2d.is_null(), SceneStringNames::get_singleton()->Master);
120
121 PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
122 ERR_FAIL_NULL_V(space_state, SceneStringNames::get_singleton()->Master);
123 PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];
124
125 PhysicsDirectSpaceState2D::PointParameters point_params;
126 point_params.position = global_pos;
127 point_params.collision_mask = area_mask;
128 point_params.collide_with_bodies = false;
129 point_params.collide_with_areas = true;
130
131 int areas = space_state->intersect_point(point_params, sr, MAX_INTERSECT_AREAS);
132
133 for (int i = 0; i < areas; i++) {
134 Area2D *area2d = Object::cast_to<Area2D>(sr[i].collider);
135 if (!area2d) {
136 continue;
137 }
138
139 if (!area2d->is_overriding_audio_bus()) {
140 continue;
141 }
142
143 return area2d->get_audio_bus_name();
144 }
145 return default_bus;
146}
147
148// Interacts with PhysicsServer2D, so can only be called during _physics_process
149void AudioStreamPlayer2D::_update_panning() {
150 if (!active.is_set() || stream.is_null()) {
151 return;
152 }
153
154 Ref<World2D> world_2d = get_world_2d();
155 ERR_FAIL_COND(world_2d.is_null());
156
157 Vector2 global_pos = get_global_position();
158
159 HashSet<Viewport *> viewports = world_2d->get_viewports();
160
161 volume_vector.resize(4);
162 volume_vector.write[0] = AudioFrame(0, 0);
163 volume_vector.write[1] = AudioFrame(0, 0);
164 volume_vector.write[2] = AudioFrame(0, 0);
165 volume_vector.write[3] = AudioFrame(0, 0);
166
167 for (Viewport *vp : viewports) {
168 if (!vp->is_audio_listener_2d()) {
169 continue;
170 }
171 //compute matrix to convert to screen
172 Vector2 screen_size = vp->get_visible_rect().size;
173 Vector2 listener_in_global;
174 Vector2 relative_to_listener;
175
176 //screen in global is used for attenuation
177 AudioListener2D *listener = vp->get_audio_listener_2d();
178 Transform2D full_canvas_transform = vp->get_global_canvas_transform() * vp->get_canvas_transform();
179 if (listener) {
180 listener_in_global = listener->get_global_position();
181 relative_to_listener = (global_pos - listener_in_global).rotated(-listener->get_global_rotation());
182 relative_to_listener *= full_canvas_transform.get_scale(); // Default listener scales with canvas size, do the same here.
183 } else {
184 listener_in_global = full_canvas_transform.affine_inverse().xform(screen_size * 0.5);
185 relative_to_listener = full_canvas_transform.xform(global_pos) - screen_size * 0.5;
186 }
187
188 float dist = global_pos.distance_to(listener_in_global); // Distance to listener, or screen if none.
189
190 if (dist > max_distance) {
191 continue; // Can't hear this sound in this viewport.
192 }
193
194 float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);
195 multiplier *= Math::db_to_linear(volume_db); // Also apply player volume!
196
197 float pan = relative_to_listener.x / screen_size.x;
198 // Don't let the panning effect extend (too far) beyond the screen.
199 pan = CLAMP(pan, -1, 1);
200
201 // Bake in a constant factor here to allow the project setting defaults for 2d and 3d to be normalized to 1.0.
202 pan *= panning_strength * cached_global_panning_strength * 0.5f;
203
204 pan = CLAMP(pan + 0.5, 0.0, 1.0);
205
206 float l = 1.0 - pan;
207 float r = pan;
208
209 const AudioFrame &prev_sample = volume_vector[0];
210 AudioFrame new_sample = AudioFrame(l, r) * multiplier;
211 volume_vector.write[0] = AudioFrame(MAX(prev_sample[0], new_sample[0]), MAX(prev_sample[1], new_sample[1]));
212 }
213
214 for (const Ref<AudioStreamPlayback> &playback : stream_playbacks) {
215 AudioServer::get_singleton()->set_playback_bus_exclusive(playback, _get_actual_bus(), volume_vector);
216 }
217
218 for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
219 AudioServer::get_singleton()->set_playback_pitch_scale(playback, pitch_scale);
220 }
221
222 last_mix_count = AudioServer::get_singleton()->get_mix_count();
223}
224
225void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
226 stop();
227 stream = p_stream;
228}
229
230Ref<AudioStream> AudioStreamPlayer2D::get_stream() const {
231 return stream;
232}
233
234void AudioStreamPlayer2D::set_volume_db(float p_volume) {
235 volume_db = p_volume;
236}
237
238float AudioStreamPlayer2D::get_volume_db() const {
239 return volume_db;
240}
241
242void AudioStreamPlayer2D::set_pitch_scale(float p_pitch_scale) {
243 ERR_FAIL_COND(!(p_pitch_scale > 0.0));
244 pitch_scale = p_pitch_scale;
245 for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
246 AudioServer::get_singleton()->set_playback_pitch_scale(playback, p_pitch_scale);
247 }
248}
249
250float AudioStreamPlayer2D::get_pitch_scale() const {
251 return pitch_scale;
252}
253
254void AudioStreamPlayer2D::play(float p_from_pos) {
255 if (stream.is_null()) {
256 return;
257 }
258 ERR_FAIL_COND_MSG(!is_inside_tree(), "Playback can only happen when a node is inside the scene tree");
259 if (stream->is_monophonic() && is_playing()) {
260 stop();
261 }
262 Ref<AudioStreamPlayback> stream_playback = stream->instantiate_playback();
263 ERR_FAIL_COND_MSG(stream_playback.is_null(), "Failed to instantiate playback.");
264
265 stream_playbacks.push_back(stream_playback);
266 setplayback = stream_playback;
267 setplay.set(p_from_pos);
268 active.set();
269 set_physics_process_internal(true);
270}
271
272void AudioStreamPlayer2D::seek(float p_seconds) {
273 if (is_playing()) {
274 stop();
275 play(p_seconds);
276 }
277}
278
279void AudioStreamPlayer2D::stop() {
280 setplay.set(-1);
281 for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
282 AudioServer::get_singleton()->stop_playback_stream(playback);
283 }
284 stream_playbacks.clear();
285 active.clear();
286 set_physics_process_internal(false);
287}
288
289bool AudioStreamPlayer2D::is_playing() const {
290 for (const Ref<AudioStreamPlayback> &playback : stream_playbacks) {
291 if (AudioServer::get_singleton()->is_playback_active(playback)) {
292 return true;
293 }
294 }
295 if (setplay.get() >= 0) {
296 return true; // play() has been called this frame, but no playback exists just yet.
297 }
298 return false;
299}
300
301float AudioStreamPlayer2D::get_playback_position() {
302 // Return the playback position of the most recently started playback stream.
303 if (!stream_playbacks.is_empty()) {
304 return AudioServer::get_singleton()->get_playback_position(stream_playbacks[stream_playbacks.size() - 1]);
305 }
306 return 0;
307}
308
309void AudioStreamPlayer2D::set_bus(const StringName &p_bus) {
310 default_bus = p_bus; // This will be pushed to the audio server during the next physics timestep, which is fast enough.
311}
312
313StringName AudioStreamPlayer2D::get_bus() const {
314 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
315 if (AudioServer::get_singleton()->get_bus_name(i) == default_bus) {
316 return default_bus;
317 }
318 }
319 return SceneStringNames::get_singleton()->Master;
320}
321
322void AudioStreamPlayer2D::set_autoplay(bool p_enable) {
323 autoplay = p_enable;
324}
325
326bool AudioStreamPlayer2D::is_autoplay_enabled() {
327 return autoplay;
328}
329
330void AudioStreamPlayer2D::_set_playing(bool p_enable) {
331 if (p_enable) {
332 play();
333 } else {
334 stop();
335 }
336}
337
338bool AudioStreamPlayer2D::_is_active() const {
339 return active.is_set();
340}
341
342void AudioStreamPlayer2D::_validate_property(PropertyInfo &p_property) const {
343 if (p_property.name == "bus") {
344 String options;
345 for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
346 if (i > 0) {
347 options += ",";
348 }
349 String name = AudioServer::get_singleton()->get_bus_name(i);
350 options += name;
351 }
352
353 p_property.hint_string = options;
354 }
355}
356
357void AudioStreamPlayer2D::_bus_layout_changed() {
358 notify_property_list_changed();
359}
360
361void AudioStreamPlayer2D::set_max_distance(float p_pixels) {
362 ERR_FAIL_COND(p_pixels <= 0.0);
363 max_distance = p_pixels;
364}
365
366float AudioStreamPlayer2D::get_max_distance() const {
367 return max_distance;
368}
369
370void AudioStreamPlayer2D::set_attenuation(float p_curve) {
371 attenuation = p_curve;
372}
373
374float AudioStreamPlayer2D::get_attenuation() const {
375 return attenuation;
376}
377
378void AudioStreamPlayer2D::set_area_mask(uint32_t p_mask) {
379 area_mask = p_mask;
380}
381
382uint32_t AudioStreamPlayer2D::get_area_mask() const {
383 return area_mask;
384}
385
386void AudioStreamPlayer2D::set_stream_paused(bool p_pause) {
387 // TODO this does not have perfect recall, fix that maybe? If there are zero playbacks registered with the AudioServer, this bool isn't persisted.
388 for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
389 AudioServer::get_singleton()->set_playback_paused(playback, p_pause);
390 }
391}
392
393bool AudioStreamPlayer2D::get_stream_paused() const {
394 // There's currently no way to pause some playback streams but not others. Check the first and don't bother looking at the rest.
395 if (!stream_playbacks.is_empty()) {
396 return AudioServer::get_singleton()->is_playback_paused(stream_playbacks[0]);
397 }
398 return false;
399}
400
401bool AudioStreamPlayer2D::has_stream_playback() {
402 return !stream_playbacks.is_empty();
403}
404
405Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
406 ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
407 return stream_playbacks[stream_playbacks.size() - 1];
408}
409
410void AudioStreamPlayer2D::set_max_polyphony(int p_max_polyphony) {
411 if (p_max_polyphony > 0) {
412 max_polyphony = p_max_polyphony;
413 }
414}
415
416int AudioStreamPlayer2D::get_max_polyphony() const {
417 return max_polyphony;
418}
419
420void AudioStreamPlayer2D::set_panning_strength(float p_panning_strength) {
421 ERR_FAIL_COND_MSG(p_panning_strength < 0, "Panning strength must be a positive number.");
422 panning_strength = p_panning_strength;
423}
424
425float AudioStreamPlayer2D::get_panning_strength() const {
426 return panning_strength;
427}
428
429void AudioStreamPlayer2D::_bind_methods() {
430 ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream);
431 ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer2D::get_stream);
432
433 ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer2D::set_volume_db);
434 ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer2D::get_volume_db);
435
436 ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer2D::set_pitch_scale);
437 ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer2D::get_pitch_scale);
438
439 ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer2D::play, DEFVAL(0.0));
440 ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer2D::seek);
441 ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer2D::stop);
442
443 ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer2D::is_playing);
444 ClassDB::bind_method(D_METHOD("get_playback_position"), &AudioStreamPlayer2D::get_playback_position);
445
446 ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioStreamPlayer2D::set_bus);
447 ClassDB::bind_method(D_METHOD("get_bus"), &AudioStreamPlayer2D::get_bus);
448
449 ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioStreamPlayer2D::set_autoplay);
450 ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer2D::is_autoplay_enabled);
451
452 ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer2D::_set_playing);
453 ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer2D::_is_active);
454
455 ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &AudioStreamPlayer2D::set_max_distance);
456 ClassDB::bind_method(D_METHOD("get_max_distance"), &AudioStreamPlayer2D::get_max_distance);
457
458 ClassDB::bind_method(D_METHOD("set_attenuation", "curve"), &AudioStreamPlayer2D::set_attenuation);
459 ClassDB::bind_method(D_METHOD("get_attenuation"), &AudioStreamPlayer2D::get_attenuation);
460
461 ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer2D::set_area_mask);
462 ClassDB::bind_method(D_METHOD("get_area_mask"), &AudioStreamPlayer2D::get_area_mask);
463
464 ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer2D::set_stream_paused);
465 ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer2D::get_stream_paused);
466
467 ClassDB::bind_method(D_METHOD("set_max_polyphony", "max_polyphony"), &AudioStreamPlayer2D::set_max_polyphony);
468 ClassDB::bind_method(D_METHOD("get_max_polyphony"), &AudioStreamPlayer2D::get_max_polyphony);
469
470 ClassDB::bind_method(D_METHOD("set_panning_strength", "panning_strength"), &AudioStreamPlayer2D::set_panning_strength);
471 ClassDB::bind_method(D_METHOD("get_panning_strength"), &AudioStreamPlayer2D::get_panning_strength);
472
473 ClassDB::bind_method(D_METHOD("has_stream_playback"), &AudioStreamPlayer2D::has_stream_playback);
474 ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer2D::get_stream_playback);
475
476 ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
477 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,suffix:dB"), "set_volume_db", "get_volume_db");
478 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,4,0.01,or_greater"), "set_pitch_scale", "get_pitch_scale");
479 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
480 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
481 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused");
482 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "1,4096,1,or_greater,exp,suffix:px"), "set_max_distance", "get_max_distance");
483 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation");
484 ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony");
485 ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "panning_strength", PROPERTY_HINT_RANGE, "0,3,0.01,or_greater"), "set_panning_strength", "get_panning_strength");
486 ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
487 ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
488
489 ADD_SIGNAL(MethodInfo("finished"));
490}
491
492AudioStreamPlayer2D::AudioStreamPlayer2D() {
493 AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer2D::_bus_layout_changed));
494 cached_global_panning_strength = GLOBAL_GET("audio/general/2d_panning_strength");
495 set_hide_clip_children(true);
496}
497
498AudioStreamPlayer2D::~AudioStreamPlayer2D() {
499}
500