Skip to content

Commit

Permalink
Properly deal with clicking on audio stream change or stop (AudioStre…
Browse files Browse the repository at this point in the history
…amPlayer only)
  • Loading branch information
reduz committed Apr 27, 2019
1 parent af9bb0e commit 040b59c
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 36 deletions.
115 changes: 79 additions & 36 deletions scene/audio/audio_stream_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,10 @@

#include "core/engine.h"

void AudioStreamPlayer::_mix_internal(bool p_fadeout) {

int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);

//get data
AudioFrame *buffer = mix_buffer.ptrw();
int buffer_size = mix_buffer.size();
void AudioStreamPlayer::_mix_to_bus(const AudioFrame *p_frames,int p_amount) {

if (p_fadeout) {
// Short fadeout ramp
buffer_size = MIN(buffer_size, 128);
}

stream_playback->mix(buffer, pitch_scale, buffer_size);

//multiply volume interpolating to avoid clicks if this changes
float target_volume = p_fadeout ? -80.0 : volume_db;
float vol = Math::db2linear(mix_volume_db);
float vol_inc = (Math::db2linear(target_volume) - 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 = target_volume;
int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);

AudioFrame *targets[4] = { NULL, NULL, NULL, NULL };

Expand All @@ -83,16 +60,53 @@ void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
for (int c = 0; c < 4; c++) {
if (!targets[c])
break;
for (int i = 0; i < buffer_size; i++) {
targets[c][i] += buffer[i];
for (int i = 0; i < p_amount; i++) {
targets[c][i] += p_frames[i];
}
}
}


void AudioStreamPlayer::_mix_internal(bool p_fadeout) {


//get data
AudioFrame *buffer = mix_buffer.ptrw();
int buffer_size = mix_buffer.size();

if (p_fadeout) {
// Short fadeout ramp
buffer_size = MIN(buffer_size, 128);
}

stream_playback->mix(buffer, pitch_scale, buffer_size);

//multiply volume interpolating to avoid clicks if this changes
float target_volume = p_fadeout ? -80.0 : volume_db;
float vol = Math::db2linear(mix_volume_db);
float vol_inc = (Math::db2linear(target_volume) - 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 = target_volume;

_mix_to_bus(buffer,buffer_size);

}

void AudioStreamPlayer::_mix_audio() {

if (use_fadeout) {
_mix_to_bus(fadeout_buffer.ptr(),fadeout_buffer.size());
use_fadeout=false;
}

if (!stream_playback.is_valid() || !active ||
(stream_paused && !stream_fade)) {
(stream_paused && !stream_paused_fade)) {
return;
}

Expand All @@ -104,7 +118,11 @@ void AudioStreamPlayer::_mix_audio() {
return;
}

if (setseek >= 0.0) {
if (setstop) {
_mix_internal(true);
stream_playback->stop();
setstop=false;
} else if (setseek >= 0.0) {
if (stream_playback->is_playing()) {

//fade out to avoid pops
Expand All @@ -131,7 +149,7 @@ void AudioStreamPlayer::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {

if (!active || (setseek < 0 && !stream_playback->is_playing())) {
active = false;
active = false;
set_process_internal(false);
emit_signal("finished");
}
Expand All @@ -158,13 +176,36 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {

AudioServer::get_singleton()->lock();

if (active && stream_playback.is_valid() && !stream_paused) {
//changing streams out of the blue is not a great idea, but at least
//lets try to somehow avoid a click

AudioFrame *buffer = fadeout_buffer.ptrw();
int buffer_size = fadeout_buffer.size();

stream_playback->mix(buffer, pitch_scale, buffer_size);

//multiply volume interpolating to avoid clicks if this changes
float target_volume = -80.0;
float vol = Math::db2linear(mix_volume_db);
float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size);

for (int i = 0; i < buffer_size; i++) {
buffer[i] *= vol;
vol += vol_inc;
}

use_fadeout=true;
}

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;
setstop = false;
}

if (p_stream.is_valid()) {
Expand Down Expand Up @@ -206,6 +247,7 @@ void AudioStreamPlayer::play(float p_from_pos) {
if (stream_playback.is_valid()) {
//mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks
setseek = p_from_pos;
setstop = false;
active = true;
set_process_internal(true);
}
Expand All @@ -220,17 +262,15 @@ void AudioStreamPlayer::seek(float p_seconds) {

void AudioStreamPlayer::stop() {

if (stream_playback.is_valid()) {
stream_playback->stop();
active = false;
set_process_internal(false);
if (stream_playback.is_valid() && active) {
setstop=true;
}
}

bool AudioStreamPlayer::is_playing() const {

if (stream_playback.is_valid()) {
return active; //&& stream_playback->is_playing();
return active && !setstop; //&& stream_playback->is_playing();
}

return false;
Expand Down Expand Up @@ -311,7 +351,7 @@ void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
if (property.name == "bus") {

String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
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);
Expand Down Expand Up @@ -395,6 +435,9 @@ AudioStreamPlayer::AudioStreamPlayer() {
stream_paused = false;
stream_paused_fade = false;
mix_target = MIX_TARGET_STEREO;
fadeout_buffer.resize(512);
setstop=false;
use_fadeout=false;

AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
}
Expand Down
6 changes: 6 additions & 0 deletions scene/audio/audio_stream_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,14 @@ class AudioStreamPlayer : public Node {
Ref<AudioStreamPlayback> stream_playback;
Ref<AudioStream> stream;
Vector<AudioFrame> mix_buffer;
Vector<AudioFrame> fadeout_buffer;
bool use_fadeout;



volatile float setseek;
volatile bool active;
volatile bool setstop;

float mix_volume_db;
float pitch_scale;
Expand All @@ -71,6 +76,7 @@ class AudioStreamPlayer : public Node {
bool _is_active() const;

void _bus_layout_changed();
void _mix_to_bus(const AudioFrame *p_frames, int p_amount);

protected:
void _validate_property(PropertyInfo &property) const;
Expand Down

0 comments on commit 040b59c

Please sign in to comment.