Merge pull request #71855 from reduz/audio-stream-polyphonic
Add AudioStreamPolyphonic to simplify sound playback from code
This commit is contained in:
commit
78d45fc51c
5 changed files with 489 additions and 0 deletions
61
doc/classes/AudioStreamPlaybackPolyphonic.xml
Normal file
61
doc/classes/AudioStreamPlaybackPolyphonic.xml
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="AudioStreamPlaybackPolyphonic" inherits="AudioStreamPlayback" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Playback instance for [AudioStreamPolyphonic].
|
||||
</brief_description>
|
||||
<description>
|
||||
Playback instance for [AudioStreamPolyphonic]. After setting the [code]stream[/code] property of [AudioStreamPlayer], [AudioStreamPlayer2D], or [AudioStreamPlayer3D], the playback instance can be obtained by calling [method AudioStreamPlayer.get_stream_playback], [method AudioStreamPlayer2D.get_stream_playback] or [method AudioStreamPlayer3D.get_stream_playback] methods.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="is_stream_playing" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<param index="0" name="stream" type="int" />
|
||||
<description>
|
||||
Return true whether the stream associated with an integer ID is still playing. Check [method play_stream] for information on when this ID becomes invalid.
|
||||
</description>
|
||||
</method>
|
||||
<method name="play_stream">
|
||||
<return type="int" />
|
||||
<param index="0" name="stream" type="AudioStream" />
|
||||
<param index="1" name="from_offset" type="float" default="0" />
|
||||
<param index="2" name="volume_db" type="float" default="0" />
|
||||
<param index="3" name="pitch_scale" type="float" default="1.0" />
|
||||
<description>
|
||||
Play an [AudioStream] at a given offset, volume and pitch scale. Playback starts immediately.
|
||||
The return value is an unique integer ID that is associated to this playback stream and which can be used to controll it.
|
||||
This ID becomes invalid when the stream ends (if it does not loop), when the [AudioStreamPlaybackPolyphonic] is stopped, or when [method stop_stream] is called.
|
||||
This function returns [constant INVALID_ID] if the amount of streams currently playing equals [member AudioStreamPolyphonic.polyphony]. If you need a higher amount of maximum polyphony, raise this value.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_stream_pitch_scale">
|
||||
<return type="void" />
|
||||
<param index="0" name="stream" type="int" />
|
||||
<param index="1" name="pitch_scale" type="float" />
|
||||
<description>
|
||||
Change the stream pitch scale. The [param stream] argument is an integer ID returned by [method play_stream].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_stream_volume">
|
||||
<return type="void" />
|
||||
<param index="0" name="stream" type="int" />
|
||||
<param index="1" name="volume_db" type="float" />
|
||||
<description>
|
||||
Change the stream volume (in db). The [param stream] argument is an integer ID returned by [method play_stream].
|
||||
</description>
|
||||
</method>
|
||||
<method name="stop_stream">
|
||||
<return type="void" />
|
||||
<param index="0" name="stream" type="int" />
|
||||
<description>
|
||||
Stop a stream. The [param stream] argument is an integer ID returned by [method play_stream], which becomes invalid after calling this function.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<constants>
|
||||
<constant name="INVALID_ID" value="-1">
|
||||
Returned by [method play_stream] in case it could not allocate a stream for playback.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
17
doc/classes/AudioStreamPolyphonic.xml
Normal file
17
doc/classes/AudioStreamPolyphonic.xml
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="AudioStreamPolyphonic" inherits="AudioStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
AudioStream that lets the user play custom streams at any time from code, simultaneously using a single player.
|
||||
</brief_description>
|
||||
<description>
|
||||
AudioStream that lets the user play custom streams at any time from code, simultaneously using a single player.
|
||||
Playback control is done via the [AudioStreamPlaybackPolyphonic] instance set inside the player, which can be obtained via [method AudioStreamPlayer.get_stream_playback], [method AudioStreamPlayer2D.get_stream_playback] or [method AudioStreamPlayer3D.get_stream_playback] methods. Obtaining the playback instance is only valid after the [code]stream[/code] property is set as an [AudioStreamPolyphonic] in those players.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="polyphony" type="int" setter="set_polyphony" getter="get_polyphony" default="32">
|
||||
Maximum amount of simultaneous streams that can be played.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
|
@ -140,6 +140,7 @@
|
|||
#include "scene/main/viewport.h"
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/resources/animation_library.h"
|
||||
#include "scene/resources/audio_stream_polyphonic.h"
|
||||
#include "scene/resources/audio_stream_wav.h"
|
||||
#include "scene/resources/bit_map.h"
|
||||
#include "scene/resources/bone_map.h"
|
||||
|
@ -907,6 +908,8 @@ void register_scene_types() {
|
|||
#endif
|
||||
GDREGISTER_ABSTRACT_CLASS(VideoStream);
|
||||
GDREGISTER_CLASS(AudioStreamWAV);
|
||||
GDREGISTER_CLASS(AudioStreamPolyphonic);
|
||||
GDREGISTER_ABSTRACT_CLASS(AudioStreamPlaybackPolyphonic);
|
||||
|
||||
OS::get_singleton()->yield(); // may take time to init
|
||||
|
||||
|
|
286
scene/resources/audio_stream_polyphonic.cpp
Normal file
286
scene/resources/audio_stream_polyphonic.cpp
Normal file
|
@ -0,0 +1,286 @@
|
|||
/**************************************************************************/
|
||||
/* audio_stream_polyphonic.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "audio_stream_polyphonic.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
|
||||
Ref<AudioStreamPlayback> AudioStreamPolyphonic::instantiate_playback() {
|
||||
Ref<AudioStreamPlaybackPolyphonic> playback;
|
||||
playback.instantiate();
|
||||
playback->streams.resize(polyphony);
|
||||
return playback;
|
||||
}
|
||||
|
||||
String AudioStreamPolyphonic::get_stream_name() const {
|
||||
return "AudioStreamPolyphonic";
|
||||
}
|
||||
|
||||
bool AudioStreamPolyphonic::is_monophonic() const {
|
||||
return true; // This avoids stream players to instantiate more than one of these.
|
||||
}
|
||||
|
||||
void AudioStreamPolyphonic::set_polyphony(int p_voices) {
|
||||
ERR_FAIL_COND(p_voices < 0 || p_voices > 128);
|
||||
polyphony = p_voices;
|
||||
}
|
||||
int AudioStreamPolyphonic::get_polyphony() const {
|
||||
return polyphony;
|
||||
}
|
||||
|
||||
void AudioStreamPolyphonic::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_polyphony", "voices"), &AudioStreamPolyphonic::set_polyphony);
|
||||
ClassDB::bind_method(D_METHOD("get_polyphony"), &AudioStreamPolyphonic::get_polyphony);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "polyphony", PROPERTY_HINT_RANGE, "1,128,1"), "set_polyphony", "get_polyphony");
|
||||
}
|
||||
|
||||
AudioStreamPolyphonic::AudioStreamPolyphonic() {
|
||||
}
|
||||
|
||||
////////////////////////
|
||||
|
||||
void AudioStreamPlaybackPolyphonic::start(double p_from_pos) {
|
||||
if (active) {
|
||||
stop();
|
||||
}
|
||||
|
||||
active = true;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackPolyphonic::stop() {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool locked = false;
|
||||
for (Stream &s : streams) {
|
||||
if (s.active.is_set()) {
|
||||
// Need locking because something may still be mixing.
|
||||
locked = true;
|
||||
AudioServer::get_singleton()->lock();
|
||||
}
|
||||
s.active.clear();
|
||||
s.finalizing.clear();
|
||||
s.finish_request.clear();
|
||||
s.stream_playback.unref();
|
||||
s.stream.unref();
|
||||
}
|
||||
if (locked) {
|
||||
AudioServer::get_singleton()->unlock();
|
||||
}
|
||||
|
||||
active = false;
|
||||
}
|
||||
|
||||
bool AudioStreamPlaybackPolyphonic::is_playing() const {
|
||||
return active;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackPolyphonic::get_loop_count() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
double AudioStreamPlaybackPolyphonic::get_playback_position() const {
|
||||
return 0;
|
||||
}
|
||||
void AudioStreamPlaybackPolyphonic::seek(double p_time) {
|
||||
// Ignored.
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackPolyphonic::tag_used_streams() {
|
||||
for (Stream &s : streams) {
|
||||
if (s.active.is_set()) {
|
||||
s.stream_playback->tag_used_streams();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackPolyphonic::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) {
|
||||
if (!active) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pre-clear buffer.
|
||||
for (int i = 0; i < p_frames; i++) {
|
||||
p_buffer[i] = AudioFrame(0, 0);
|
||||
}
|
||||
|
||||
for (Stream &s : streams) {
|
||||
if (!s.active.is_set()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float volume_db = s.volume_db; // Copy because it can be overriden at any time.
|
||||
float next_volume = Math::db_to_linear(volume_db);
|
||||
s.prev_volume_db = volume_db;
|
||||
|
||||
if (s.finish_request.is_set()) {
|
||||
if (s.pending_play.is_set()) {
|
||||
// Did not get the chance to play, was finalized too soon.
|
||||
s.active.clear();
|
||||
s.finalizing.set();
|
||||
continue;
|
||||
}
|
||||
next_volume = 0;
|
||||
}
|
||||
|
||||
if (s.pending_play.is_set()) {
|
||||
s.stream_playback->start(s.play_offset);
|
||||
s.pending_play.clear();
|
||||
}
|
||||
float prev_volume = Math::db_to_linear(s.prev_volume_db);
|
||||
|
||||
float volume_inc = (next_volume - prev_volume) / float(p_frames);
|
||||
|
||||
int todo = p_frames;
|
||||
int offset = 0;
|
||||
float volume = prev_volume;
|
||||
|
||||
while (todo) {
|
||||
int to_mix = MIN(todo, int(INTERNAL_BUFFER_LEN));
|
||||
int mixed = s.stream_playback->mix(internal_buffer, s.pitch_scale, to_mix);
|
||||
|
||||
for (int i = 0; i < to_mix; i++) {
|
||||
p_buffer[offset + i] += internal_buffer[i] * volume;
|
||||
volume += volume_inc;
|
||||
}
|
||||
|
||||
if (mixed < to_mix) {
|
||||
// Stream is done.
|
||||
s.active.clear();
|
||||
s.finalizing.set();
|
||||
break;
|
||||
}
|
||||
|
||||
todo -= to_mix;
|
||||
offset += to_mix;
|
||||
}
|
||||
|
||||
if (s.finish_request.is_set()) {
|
||||
s.active.clear();
|
||||
s.finalizing.set();
|
||||
}
|
||||
}
|
||||
|
||||
return p_frames;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackPolyphonic::_check_finalized_streams() {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Stream &s : streams) {
|
||||
if (!s.active.is_set() && s.finalizing.is_set()) {
|
||||
s.stream_playback.unref();
|
||||
s.stream.unref();
|
||||
s.finalizing.clear();
|
||||
s.finish_request.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AudioStreamPlaybackPolyphonic::ID AudioStreamPlaybackPolyphonic::play_stream(const Ref<AudioStream> &p_stream, float p_from_offset, float p_volume_db, float p_pitch_scale) {
|
||||
ERR_FAIL_COND_V(p_stream.is_null(), INVALID_ID);
|
||||
for (uint32_t i = 0; i < streams.size(); i++) {
|
||||
if (!streams[i].active.is_set() && !streams[i].finish_request.is_set() && !streams[i].finalizing.is_set()) {
|
||||
// Can use this stream, as it's not active.
|
||||
streams[i].stream = p_stream;
|
||||
streams[i].stream_playback = streams[i].stream->instantiate_playback();
|
||||
streams[i].play_offset = p_from_offset;
|
||||
streams[i].volume_db = p_volume_db;
|
||||
streams[i].prev_volume_db = p_volume_db;
|
||||
streams[i].pitch_scale = p_pitch_scale;
|
||||
streams[i].id = id_counter++;
|
||||
streams[i].pending_play.set();
|
||||
streams[i].active.set();
|
||||
return (ID(i) << INDEX_SHIFT) | ID(streams[i].id);
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID_ID;
|
||||
}
|
||||
|
||||
AudioStreamPlaybackPolyphonic::Stream *AudioStreamPlaybackPolyphonic::_find_stream(int64_t p_id) {
|
||||
uint32_t index = p_id >> INDEX_SHIFT;
|
||||
if (index >= streams.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!streams[index].active.is_set()) {
|
||||
return nullptr; // Not active, no longer exists.
|
||||
}
|
||||
int64_t id = p_id & ID_MASK;
|
||||
if (streams[index].id != id) {
|
||||
return nullptr;
|
||||
}
|
||||
return &streams[index];
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackPolyphonic::set_stream_volume(ID p_stream_id, float p_volume_db) {
|
||||
Stream *s = _find_stream(p_stream_id);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
s->volume_db = p_volume_db;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackPolyphonic::set_stream_pitch_scale(ID p_stream_id, float p_pitch_scale) {
|
||||
Stream *s = _find_stream(p_stream_id);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
s->pitch_scale = p_pitch_scale;
|
||||
}
|
||||
|
||||
bool AudioStreamPlaybackPolyphonic::is_stream_playing(ID p_stream_id) const {
|
||||
return const_cast<AudioStreamPlaybackPolyphonic *>(this)->_find_stream(p_stream_id) != nullptr;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackPolyphonic::stop_stream(ID p_stream_id) {
|
||||
Stream *s = _find_stream(p_stream_id);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
s->finish_request.set();
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackPolyphonic::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("play_stream", "stream", "from_offset", "volume_db", "pitch_scale"), &AudioStreamPlaybackPolyphonic::play_stream, DEFVAL(0), DEFVAL(0), DEFVAL(1.0));
|
||||
ClassDB::bind_method(D_METHOD("set_stream_volume", "stream", "volume_db"), &AudioStreamPlaybackPolyphonic::set_stream_volume);
|
||||
ClassDB::bind_method(D_METHOD("set_stream_pitch_scale", "stream", "pitch_scale"), &AudioStreamPlaybackPolyphonic::set_stream_pitch_scale);
|
||||
ClassDB::bind_method(D_METHOD("is_stream_playing", "stream"), &AudioStreamPlaybackPolyphonic::is_stream_playing);
|
||||
ClassDB::bind_method(D_METHOD("stop_stream", "stream"), &AudioStreamPlaybackPolyphonic::stop_stream);
|
||||
|
||||
BIND_CONSTANT(INVALID_ID);
|
||||
}
|
||||
|
||||
AudioStreamPlaybackPolyphonic::AudioStreamPlaybackPolyphonic() {
|
||||
SceneTree::get_singleton()->connect(SNAME("process_frame"), callable_mp(this, &AudioStreamPlaybackPolyphonic::_check_finalized_streams));
|
||||
}
|
122
scene/resources/audio_stream_polyphonic.h
Normal file
122
scene/resources/audio_stream_polyphonic.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/**************************************************************************/
|
||||
/* audio_stream_polyphonic.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef AUDIO_STREAM_POLYPHONIC_H
|
||||
#define AUDIO_STREAM_POLYPHONIC_H
|
||||
|
||||
#include "core/templates/local_vector.h"
|
||||
#include "servers/audio/audio_stream.h"
|
||||
|
||||
class AudioStreamPolyphonic : public AudioStream {
|
||||
GDCLASS(AudioStreamPolyphonic, AudioStream)
|
||||
int polyphony = 32;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual Ref<AudioStreamPlayback> instantiate_playback() override;
|
||||
virtual String get_stream_name() const override;
|
||||
virtual bool is_monophonic() const override;
|
||||
|
||||
void set_polyphony(int p_voices);
|
||||
int get_polyphony() const;
|
||||
|
||||
AudioStreamPolyphonic();
|
||||
};
|
||||
|
||||
class AudioStreamPlaybackPolyphonic : public AudioStreamPlayback {
|
||||
GDCLASS(AudioStreamPlaybackPolyphonic, AudioStreamPlayback)
|
||||
|
||||
enum {
|
||||
INTERNAL_BUFFER_LEN = 128,
|
||||
ID_MASK = 0xFFFFFFFF,
|
||||
INDEX_SHIFT = 32
|
||||
};
|
||||
struct Stream {
|
||||
SafeFlag active;
|
||||
SafeFlag pending_play;
|
||||
SafeFlag finish_request;
|
||||
SafeFlag finalizing;
|
||||
float play_offset = 0;
|
||||
float pitch_scale = 1.0;
|
||||
Ref<AudioStream> stream;
|
||||
Ref<AudioStreamPlayback> stream_playback;
|
||||
float prev_volume_db = 0;
|
||||
float volume_db = 0;
|
||||
uint32_t id = 0;
|
||||
|
||||
Stream() :
|
||||
active(false), pending_play(false), finish_request(false), finalizing(false) {}
|
||||
};
|
||||
|
||||
LocalVector<Stream> streams;
|
||||
AudioFrame internal_buffer[INTERNAL_BUFFER_LEN];
|
||||
|
||||
bool active = false;
|
||||
uint32_t id_counter = 1;
|
||||
|
||||
_FORCE_INLINE_ Stream *_find_stream(int64_t p_id);
|
||||
|
||||
void _check_finalized_streams();
|
||||
|
||||
friend class AudioStreamPolyphonic;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
typedef int64_t ID;
|
||||
enum {
|
||||
INVALID_ID = -1
|
||||
};
|
||||
|
||||
virtual void start(double p_from_pos = 0.0) override;
|
||||
virtual void stop() override;
|
||||
virtual bool is_playing() const override;
|
||||
|
||||
virtual int get_loop_count() const override; //times it looped
|
||||
|
||||
virtual double get_playback_position() const override;
|
||||
virtual void seek(double p_time) override;
|
||||
|
||||
virtual void tag_used_streams() override;
|
||||
|
||||
virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override;
|
||||
|
||||
ID play_stream(const Ref<AudioStream> &p_stream, float p_from_offset = 0, float p_volume_db = 0, float p_pitch_scale = 1.0);
|
||||
void set_stream_volume(ID p_stream_id, float p_volume_db);
|
||||
void set_stream_pitch_scale(ID p_stream_id, float p_pitch_scale);
|
||||
bool is_stream_playing(ID p_stream_id) const;
|
||||
void stop_stream(ID p_stream_id);
|
||||
|
||||
AudioStreamPlaybackPolyphonic();
|
||||
};
|
||||
|
||||
#endif // AUDIO_STREAM_POLYPHONIC_H
|
Loading…
Reference in a new issue