summaryrefslogtreecommitdiff
path: root/scene/3d
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2015-09-09 18:50:52 -0300
committerJuan Linietsky <reduzio@gmail.com>2015-09-09 18:50:52 -0300
commit97413746173b4f872e8c72eba0e58d7092a93269 (patch)
tree576708292cc3e39f8acc3047441aaeb23e952164 /scene/3d
parentb0aa49accbd7e45dae38f1bd43b0fbdd11714211 (diff)
Rewrite of the AudioStream API
-Fixes long-standing issues regarding to playing a single stream multiple times simultanteously -Fixes wrong-looping, starting, caching, etc. Issues resulting from bad original design -Allows more interesting kinds of streams (stream graphs with streams inside streams!) in the future
Diffstat (limited to 'scene/3d')
-rw-r--r--scene/3d/spatial_stream_player.cpp288
-rw-r--r--scene/3d/spatial_stream_player.h56
2 files changed, 302 insertions, 42 deletions
diff --git a/scene/3d/spatial_stream_player.cpp b/scene/3d/spatial_stream_player.cpp
index 84e68bf418..b81d98e8bf 100644
--- a/scene/3d/spatial_stream_player.cpp
+++ b/scene/3d/spatial_stream_player.cpp
@@ -30,21 +30,79 @@
-void SpatialStreamPlayer::_notification(int p_what) {
+int SpatialStreamPlayer::InternalStream::get_channel_count() const {
- switch(p_what) {
+ return player->sp_get_channel_count();
+}
+void SpatialStreamPlayer::InternalStream::set_mix_rate(int p_rate){
- case NOTIFICATION_ENTER_WORLD: {
+ return player->sp_set_mix_rate(p_rate);
+}
+bool SpatialStreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){
+
+ return player->sp_mix(p_buffer,p_frames);
+}
+void SpatialStreamPlayer::InternalStream::update(){
+
+ player->sp_update();
+}
+
+
+int SpatialStreamPlayer::sp_get_channel_count() const {
+
+ return playback->get_channels();
+}
+
+void SpatialStreamPlayer::sp_set_mix_rate(int p_rate){
+
+ server_mix_rate=p_rate;
+}
+
+bool SpatialStreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) {
+
+ if (resampler.is_ready()) {
+ return resampler.mix(p_buffer,p_frames);
+ }
+
+ return false;
+}
+
+void SpatialStreamPlayer::sp_update() {
+
+ _THREAD_SAFE_METHOD_
+ if (!paused && resampler.is_ready() && playback.is_valid()) {
+
+ if (!playback->is_playing()) {
+ //stream depleted data, but there's still audio in the ringbuffer
+ //check that all this audio has been flushed before stopping the stream
+ int to_mix = resampler.get_total() - resampler.get_todo();
+ if (to_mix==0) {
+ stop();
+ return;
+ }
+
+ return;
+ }
+
+ int todo =resampler.get_todo();
+ int wrote = playback->mix(resampler.get_write_buffer(),todo);
+ resampler.write(wrote);
+ }
+}
-// set_idle_process(false); //don't annoy
- } break;
- case NOTIFICATION_PROCESS: {
-// if (!stream.is_null())
-// stream->update();
+void SpatialStreamPlayer::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ //set_idle_process(false); //don't annoy
+ if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint())
+ play();
} break;
- case NOTIFICATION_EXIT_WORLD: {
+ case NOTIFICATION_EXIT_TREE: {
stop(); //wathever it may be doing, stop
} break;
@@ -58,12 +116,20 @@ void SpatialStreamPlayer::set_stream(const Ref<AudioStream> &p_stream) {
stop();
stream=p_stream;
- if (!stream.is_null()) {
- stream->set_loop(loops);
+ if (!stream.is_null()) {
+ playback=stream->instance_playback();
+ playback->set_loop(loops);
+ playback->set_loop_restart_time(loop_point);
+ AudioServer::get_singleton()->lock();
+ resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size());
+ AudioServer::get_singleton()->unlock();
+ } else {
+ AudioServer::get_singleton()->lock();
+ resampler.clear();
+ playback.unref();
+ AudioServer::get_singleton()->unlock();
}
-
-
}
Ref<AudioStream> SpatialStreamPlayer::get_stream() const {
@@ -72,18 +138,25 @@ Ref<AudioStream> SpatialStreamPlayer::get_stream() const {
}
-void SpatialStreamPlayer::play() {
+void SpatialStreamPlayer::play(float p_from_offset) {
- if (!is_inside_tree())
+ ERR_FAIL_COND(!is_inside_tree());
+ if (playback.is_null())
return;
- if (stream.is_null())
- return;
- if (stream->is_playing())
+ if (playback->is_playing())
stop();
- stream->play();
- SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),stream->get_audio_stream());
- //if (stream->get_update_mode()!=AudioStream::UPDATE_NONE)
- // set_idle_process(true);
+
+ _THREAD_SAFE_METHOD_
+ playback->play(p_from_offset);
+ //feed the ringbuffer as long as no update callback is going on
+ sp_update();
+
+ SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),&internal_stream);
+
+// AudioServer::get_singleton()->stream_set_active(stream_rid,true);
+// AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
+// if (stream->get_update_mode()!=AudioStream::UPDATE_NONE)
+// set_idle_process(true);
}
@@ -91,28 +164,30 @@ void SpatialStreamPlayer::stop() {
if (!is_inside_tree())
return;
- if (stream.is_null())
+ if (playback.is_null())
return;
+ _THREAD_SAFE_METHOD_
+ //AudioServer::get_singleton()->stream_set_active(stream_rid,false);
SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),NULL);
- stream->stop();
+ playback->stop();
//set_idle_process(false);
}
bool SpatialStreamPlayer::is_playing() const {
- if (stream.is_null())
+ if (playback.is_null())
return false;
- return stream->is_playing();
+ return playback->is_playing();
}
void SpatialStreamPlayer::set_loop(bool p_enable) {
loops=p_enable;
- if (stream.is_null())
+ if (playback.is_null())
return;
- stream->set_loop(loops);
+ playback->set_loop(loops);
}
bool SpatialStreamPlayer::has_loop() const {
@@ -120,6 +195,46 @@ bool SpatialStreamPlayer::has_loop() const {
return loops;
}
+void SpatialStreamPlayer::set_volume(float p_vol) {
+
+ volume=p_vol;
+ if (stream_rid.is_valid())
+ AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
+}
+
+float SpatialStreamPlayer::get_volume() const {
+
+ return volume;
+}
+
+void SpatialStreamPlayer::set_loop_restart_time(float p_secs) {
+
+ loop_point=p_secs;
+ if (playback.is_valid())
+ playback->set_loop_restart_time(p_secs);
+}
+
+float SpatialStreamPlayer::get_loop_restart_time() const {
+
+ return loop_point;
+}
+
+
+void SpatialStreamPlayer::set_volume_db(float p_db) {
+
+ if (p_db<-79)
+ set_volume(0);
+ else
+ set_volume(Math::db2linear(p_db));
+}
+
+float SpatialStreamPlayer::get_volume_db() const {
+
+ if (volume==0)
+ return -80;
+ else
+ return Math::linear2db(volume);
+}
String SpatialStreamPlayer::get_stream_name() const {
@@ -132,27 +247,85 @@ String SpatialStreamPlayer::get_stream_name() const {
int SpatialStreamPlayer::get_loop_count() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_loop_count();
+ return playback->get_loop_count();
}
float SpatialStreamPlayer::get_pos() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_pos();
+ return playback->get_pos();
+
+}
+
+float SpatialStreamPlayer::get_length() const {
+ if (playback.is_null())
+ return 0;
+ return playback->get_length();
}
void SpatialStreamPlayer::seek_pos(float p_time) {
- if (stream.is_null())
+ if (playback.is_null())
return;
- return stream->seek_pos(p_time);
+ return playback->seek_pos(p_time);
+
+}
+
+void SpatialStreamPlayer::set_autoplay(bool p_enable) {
+
+ autoplay=p_enable;
+}
+
+bool SpatialStreamPlayer::has_autoplay() const {
+
+ return autoplay;
+}
+
+void SpatialStreamPlayer::set_paused(bool p_paused) {
+
+ paused=p_paused;
+ //if (stream.is_valid())
+ // stream->set_paused(p_paused);
+}
+
+bool SpatialStreamPlayer::is_paused() const {
+ return paused;
}
+void SpatialStreamPlayer::_set_play(bool p_play) {
+
+ _play=p_play;
+ if (is_inside_tree()) {
+ if(_play)
+ play();
+ else
+ stop();
+ }
+
+}
+
+bool SpatialStreamPlayer::_get_play() const{
+
+ return _play;
+}
+
+void SpatialStreamPlayer::set_buffering_msec(int p_msec) {
+
+ buffering_ms=p_msec;
+}
+
+int SpatialStreamPlayer::get_buffering_msec() const{
+
+ return buffering_ms;
+}
+
+
+
void SpatialStreamPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&SpatialStreamPlayer::set_stream);
@@ -163,28 +336,67 @@ void SpatialStreamPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_playing"),&SpatialStreamPlayer::is_playing);
+ ObjectTypeDB::bind_method(_MD("set_paused","paused"),&SpatialStreamPlayer::set_paused);
+ ObjectTypeDB::bind_method(_MD("is_paused"),&SpatialStreamPlayer::is_paused);
+
ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&SpatialStreamPlayer::set_loop);
ObjectTypeDB::bind_method(_MD("has_loop"),&SpatialStreamPlayer::has_loop);
+ ObjectTypeDB::bind_method(_MD("set_volume","volume"),&SpatialStreamPlayer::set_volume);
+ ObjectTypeDB::bind_method(_MD("get_volume"),&SpatialStreamPlayer::get_volume);
+
+ ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&SpatialStreamPlayer::set_volume_db);
+ ObjectTypeDB::bind_method(_MD("get_volume_db"),&SpatialStreamPlayer::get_volume_db);
+
+ ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&SpatialStreamPlayer::set_buffering_msec);
+ ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&SpatialStreamPlayer::get_buffering_msec);
+
+ ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&SpatialStreamPlayer::set_loop_restart_time);
+ ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&SpatialStreamPlayer::get_loop_restart_time);
+
ObjectTypeDB::bind_method(_MD("get_stream_name"),&SpatialStreamPlayer::get_stream_name);
ObjectTypeDB::bind_method(_MD("get_loop_count"),&SpatialStreamPlayer::get_loop_count);
ObjectTypeDB::bind_method(_MD("get_pos"),&SpatialStreamPlayer::get_pos);
ObjectTypeDB::bind_method(_MD("seek_pos","time"),&SpatialStreamPlayer::seek_pos);
- ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"),_SCS("get_stream") );
- ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"),_SCS("has_loop") );
+ ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&SpatialStreamPlayer::set_autoplay);
+ ObjectTypeDB::bind_method(_MD("has_autoplay"),&SpatialStreamPlayer::has_autoplay);
+ ObjectTypeDB::bind_method(_MD("get_length"),&SpatialStreamPlayer::get_length);
+
+ ObjectTypeDB::bind_method(_MD("_set_play","play"),&SpatialStreamPlayer::_set_play);
+ ObjectTypeDB::bind_method(_MD("_get_play"),&SpatialStreamPlayer::_get_play);
+
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"), _SCS("get_stream") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/play"), _SCS("_set_play"), _SCS("_get_play") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"), _SCS("has_loop") );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") );
}
SpatialStreamPlayer::SpatialStreamPlayer() {
+ volume=1;
loops=false;
+ paused=false;
+ autoplay=false;
+ _play=false;
+ server_mix_rate=1;
+ internal_stream.player=this;
+ stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
+ buffering_ms=500;
+ loop_point=0;
+
}
SpatialStreamPlayer::~SpatialStreamPlayer() {
-
-}
+ AudioServer::get_singleton()->free(stream_rid);
+ resampler.clear();
+}
diff --git a/scene/3d/spatial_stream_player.h b/scene/3d/spatial_stream_player.h
index 7e639a7232..f2775a4982 100644
--- a/scene/3d/spatial_stream_player.h
+++ b/scene/3d/spatial_stream_player.h
@@ -31,16 +31,48 @@
#include "scene/resources/audio_stream.h"
#include "scene/3d/spatial_player.h"
-
+#include "servers/audio/audio_rb_resampler.h"
class SpatialStreamPlayer : public SpatialPlayer {
OBJ_TYPE(SpatialStreamPlayer,SpatialPlayer);
+ _THREAD_SAFE_CLASS_
+
+ struct InternalStream : public AudioServer::AudioStream {
+ SpatialStreamPlayer *player;
+ virtual int get_channel_count() const;
+ virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
+ virtual bool mix(int32_t *p_buffer,int p_frames);
+ virtual void update();
+ };
+
+
+ InternalStream internal_stream;
+ Ref<AudioStreamPlayback> playback;
Ref<AudioStream> stream;
+
+ int sp_get_channel_count() const;
+ void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
+ bool sp_mix(int32_t *p_buffer,int p_frames);
+ void sp_update();
+
+ int server_mix_rate;
+
+ RID stream_rid;
+ bool paused;
+ bool autoplay;
bool loops;
-protected:
+ float volume;
+ float loop_point;
+ int buffering_ms;
+ AudioRBResampler resampler;
+
+ bool _play;
+ void _set_play(bool p_play);
+ bool _get_play() const;
+protected:
void _notification(int p_what);
static void _bind_methods();
@@ -49,21 +81,37 @@ public:
void set_stream(const Ref<AudioStream> &p_stream);
Ref<AudioStream> get_stream() const;
- void play();
+ void play(float p_from_offset=0);
void stop();
bool is_playing() const;
+ void set_paused(bool p_paused);
+ bool is_paused() const;
+
void set_loop(bool p_enable);
bool has_loop() const;
+ void set_volume(float p_vol);
+ float get_volume() const;
+
+ void set_loop_restart_time(float p_secs);
+ float get_loop_restart_time() const;
+
+ void set_volume_db(float p_db);
+ float get_volume_db() const;
String get_stream_name() const;
- int get_loop_count() const;
+ int get_loop_count() const;
float get_pos() const;
void seek_pos(float p_time);
+ float get_length() const;
+ void set_autoplay(bool p_vol);
+ bool has_autoplay() const;
+ void set_buffering_msec(int p_msec);
+ int get_buffering_msec() const;
SpatialStreamPlayer();
~SpatialStreamPlayer();