diff options
author | Juan Linietsky <reduzio@gmail.com> | 2017-01-21 19:00:25 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2017-01-21 19:01:00 -0300 |
commit | 0aa7242624fcd74eaf13db006274829c284fab3b (patch) | |
tree | 85ae8bc9d725f191da68f1b9ffe1e426025e8fb2 /scene/audio | |
parent | c4d6e54e93431e94888c5594386bcd0aa22528ee (diff) |
WIP new AudioServer, with buses, effects, etc.
Diffstat (limited to 'scene/audio')
-rw-r--r-- | scene/audio/audio_player.cpp | 301 | ||||
-rw-r--r-- | scene/audio/audio_player.h | 75 |
2 files changed, 376 insertions, 0 deletions
diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp new file mode 100644 index 0000000000..9fd005e6fb --- /dev/null +++ b/scene/audio/audio_player.cpp @@ -0,0 +1,301 @@ +#include "audio_player.h" + + +void AudioPlayer::_mix_audio() { + + if (!stream_playback.is_valid()) { + return; + } + + if (!active) { + return; + } + + if (setseek>=0.0) { + stream_playback->start(setseek); + setseek=-1.0; //reset seek + + } + + int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus); + + //get data + AudioFrame *buffer = mix_buffer.ptr(); + int buffer_size = mix_buffer.size(); + + //mix + stream_playback->mix(buffer,1.0,buffer_size); + + //multiply volume interpolating to avoid clicks if this changes + float vol = Math::db2linear(mix_volume_db); + float vol_inc = (Math::db2linear(volume_db) - vol)/float(buffer_size); + + for(int i=0;i<buffer_size;i++) { + buffer[i]*=vol; + vol+=vol_inc; + } + //set volume for next mix + mix_volume_db = volume_db; + + AudioFrame * targets[3]={NULL,NULL,NULL}; + + if (AudioServer::get_singleton()->get_speaker_mode()==AudioServer::SPEAKER_MODE_STEREO) { + targets[0] = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,0); + } else { + switch(mix_target) { + case MIX_TARGET_STEREO: { + targets[0]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,1); + } break; + case MIX_TARGET_SURROUND: { + targets[0]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,1); + targets[1]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,2); + if (AudioServer::get_singleton()->get_speaker_mode()==AudioServer::SPEAKER_SURROUND_71) { + targets[2]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,3); + } + } break; + case MIX_TARGET_CENTER: { + targets[0]=AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index,0); + } break; + + } + } + + for(int c=0;c<3;c++) { + if (!targets[c]) + break; + for(int i=0;i<buffer_size;i++) { + targets[c][i]+=buffer[i]; + } + } + + +} + +void AudioPlayer::_notification(int p_what) { + + if (p_what==NOTIFICATION_ENTER_TREE) { + + 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); + + } +} + +void AudioPlayer::set_stream(Ref<AudioStream> p_stream) { + + 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> AudioPlayer::get_stream() const { + + return stream; +} + +void AudioPlayer::set_volume_db(float p_volume) { + + volume_db=p_volume; +} +float AudioPlayer::get_volume_db() const { + + return volume_db; +} + +void AudioPlayer::play(float p_from_pos) { + + if (stream_playback.is_valid()) { + mix_volume_db=volume_db; //reset volume ramp + setseek=p_from_pos; + active=true; + } +} + +void AudioPlayer::seek(float p_seconds) { + + if (stream_playback.is_valid()) { + setseek=p_seconds; + } +} + +void AudioPlayer::stop() { + + if (stream_playback.is_valid()) { + active=false; + } + + +} + +bool AudioPlayer::is_playing() const { + + if (stream_playback.is_valid()) { + return active && stream_playback->is_playing(); + } + + return false; +} + +float AudioPlayer::get_pos() { + + if (stream_playback.is_valid()) { + return stream_playback->get_pos(); + } + + return 0; +} + +void AudioPlayer::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 AudioPlayer::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 AudioPlayer::set_autoplay(bool p_enable) { + + autoplay=p_enable; +} +bool AudioPlayer::is_autoplay_enabled() { + + return autoplay; +} + +void AudioPlayer::set_mix_target(MixTarget p_target) { + + mix_target=p_target; +} + +AudioPlayer::MixTarget AudioPlayer::get_mix_target() const{ + + return mix_target; +} + +void AudioPlayer::_set_playing(bool p_enable) { + + if (p_enable) + play(); + else + stop(); +} +bool AudioPlayer::_is_active() const { + + return active; +} + + +void AudioPlayer::_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 AudioPlayer::_bus_layout_changed() { + + _change_notify(); +} + +void AudioPlayer::_bind_methods() { + + ClassDB::bind_method(_MD("set_stream","stream:AudioStream"),&AudioPlayer::set_stream); + ClassDB::bind_method(_MD("get_stream"),&AudioPlayer::get_stream); + + ClassDB::bind_method(_MD("set_volume_db","volume_db"),&AudioPlayer::set_volume_db); + ClassDB::bind_method(_MD("get_volume_db"),&AudioPlayer::get_volume_db); + + ClassDB::bind_method(_MD("play","from_pos"),&AudioPlayer::play,DEFVAL(0.0)); + ClassDB::bind_method(_MD("seek","to_pos"),&AudioPlayer::seek); + ClassDB::bind_method(_MD("stop"),&AudioPlayer::stop); + + ClassDB::bind_method(_MD("is_playing"),&AudioPlayer::is_playing); + ClassDB::bind_method(_MD("get_pos"),&AudioPlayer::get_pos); + + ClassDB::bind_method(_MD("set_bus","bus"),&AudioPlayer::set_bus); + ClassDB::bind_method(_MD("get_bus"),&AudioPlayer::get_bus); + + ClassDB::bind_method(_MD("set_autoplay","enable"),&AudioPlayer::set_autoplay); + ClassDB::bind_method(_MD("is_autoplay_enabled"),&AudioPlayer::is_autoplay_enabled); + + ClassDB::bind_method(_MD("set_mix_target","mix_target"),&AudioPlayer::set_mix_target); + ClassDB::bind_method(_MD("get_mix_target"),&AudioPlayer::get_mix_target); + + ClassDB::bind_method(_MD("_set_playing","enable"),&AudioPlayer::_set_playing); + ClassDB::bind_method(_MD("_is_active"),&AudioPlayer::_is_active); + + ClassDB::bind_method(_MD("_bus_layout_changed"),&AudioPlayer::_bus_layout_changed); + + + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"stream",PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"),_SCS("set_stream"),_SCS("get_stream") ); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"volume_db",PROPERTY_HINT_RANGE,"-80,24"),_SCS("set_volume_db"),_SCS("get_volume_db") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"playing",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR),_SCS("_set_playing"),_SCS("_is_active" )); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"autoplay"),_SCS("set_autoplay"),_SCS("is_autoplay_enabled") ); + ADD_PROPERTY( PropertyInfo(Variant::INT,"mix_target",PROPERTY_HINT_ENUM,"Stereo,Surround,Center"),_SCS("set_mix_target"),_SCS("get_mix_target")); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"bus",PROPERTY_HINT_ENUM,""),_SCS("set_bus"),_SCS("get_bus")); + +} + +AudioPlayer::AudioPlayer() { + + mix_volume_db=0; + volume_db=0; + autoplay=false; + setseek=-1; + active=false; + mix_target=MIX_TARGET_STEREO; + + AudioServer::get_singleton()->connect("bus_layout_changed",this,"_bus_layout_changed"); +} + + + +AudioPlayer::~AudioPlayer() { + + +} + diff --git a/scene/audio/audio_player.h b/scene/audio/audio_player.h new file mode 100644 index 0000000000..249e5d0381 --- /dev/null +++ b/scene/audio/audio_player.h @@ -0,0 +1,75 @@ +#ifndef AUDIOPLAYER_H +#define AUDIOPLAYER_H + +#include "scene/main/node.h" +#include "servers/audio/audio_stream.h" + + +class AudioPlayer : public Node { + + GDCLASS( AudioPlayer, Node ) + +public: + + enum MixTarget { + MIX_TARGET_STEREO, + MIX_TARGET_SURROUND, + MIX_TARGET_CENTER + }; +private: + Ref<AudioStreamPlayback> stream_playback; + Ref<AudioStream> stream; + Vector<AudioFrame> mix_buffer; + + volatile float setseek; + volatile bool active; + + float mix_volume_db; + float volume_db; + bool autoplay; + StringName bus; + + MixTarget mix_target; + + void _mix_audio(); + static void _mix_audios(void *self) { reinterpret_cast<AudioPlayer*>(self)->_mix_audio(); } + + void _set_playing(bool p_enable); + bool _is_active() const; + + void _bus_layout_changed(); + +protected: + + void _validate_property(PropertyInfo& property) const; + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_stream(Ref<AudioStream> p_stream); + Ref<AudioStream> get_stream() const; + + void set_volume_db(float p_volume); + float get_volume_db() const; + + void play(float p_from_pos=0.0); + void seek(float p_seconds); + void stop(); + bool is_playing() const; + float get_pos(); + + void set_bus(const StringName& p_bus); + StringName get_bus() const; + + void set_autoplay(bool p_enable); + bool is_autoplay_enabled(); + + void set_mix_target(MixTarget p_target); + MixTarget get_mix_target() const; + + AudioPlayer(); + ~AudioPlayer(); +}; + +VARIANT_ENUM_CAST(AudioPlayer::MixTarget) +#endif // AUDIOPLAYER_H |