1
0
mirror of https://github.com/godotengine/godot.git synced 2025-12-05 17:15:09 +00:00

Add polyphony to Audio Stream Player nodes

This commit is contained in:
Ellen Poe
2021-08-27 21:51:03 -07:00
parent ec70295c01
commit 0e3cab41eb
22 changed files with 428 additions and 242 deletions

View File

@@ -363,10 +363,10 @@ void AudioServer::_mix_step() {
if (mixed_frames != buffer_size) {
// We know we have at least the size of our lookahead buffer for fade-out purposes.
float fadeout_base = 0.87;
float fadeout_base = 0.94;
float fadeout_coefficient = 1;
static_assert(LOOKAHEAD_BUFFER_SIZE == 32, "Update fadeout_base and comment here if you change LOOKAHEAD_BUFFER_SIZE.");
// 0.87 ^ 32 = 0.0116. There might still be a pop but it'll be way better than if we didn't do this.
static_assert(LOOKAHEAD_BUFFER_SIZE == 64, "Update fadeout_base and comment here if you change LOOKAHEAD_BUFFER_SIZE.");
// 0.94 ^ 64 = 0.01906. There might still be a pop but it'll be way better than if we didn't do this.
for (unsigned int idx = mixed_frames; idx < buffer_size; idx++) {
fadeout_coefficient *= fadeout_base;
buf[idx] *= fadeout_coefficient;
@@ -381,29 +381,24 @@ void AudioServer::_mix_step() {
}
}
ERR_FAIL_COND(playback->bus_details.load() == nullptr);
AudioStreamPlaybackBusDetails *ptr = playback->bus_details.load();
ERR_FAIL_COND(ptr == nullptr);
// By putting null into the bus details pointers, we're taking ownership of their memory for the duration of this mix.
AudioStreamPlaybackBusDetails *bus_details = nullptr;
{
std::atomic<AudioStreamPlaybackBusDetails *> bus_details_atomic = nullptr;
bus_details = playback->bus_details.exchange(bus_details_atomic);
}
ERR_FAIL_COND(bus_details == nullptr);
AudioStreamPlaybackBusDetails *prev_bus_details = playback->prev_bus_details;
AudioStreamPlaybackBusDetails bus_details = *ptr;
// Mix to any active buses.
for (int idx = 0; idx < MAX_BUSES_PER_PLAYBACK; idx++) {
if (!bus_details->bus_active[idx]) {
if (!bus_details.bus_active[idx]) {
continue;
}
int bus_idx = thread_find_bus_index(bus_details->bus[idx]);
int bus_idx = thread_find_bus_index(bus_details.bus[idx]);
int prev_bus_idx = -1;
for (int search_idx = 0; search_idx < MAX_BUSES_PER_PLAYBACK; search_idx++) {
if (!prev_bus_details->bus_active[search_idx]) {
if (!playback->prev_bus_details->bus_active[search_idx]) {
continue;
}
if (prev_bus_details->bus[search_idx].hash() == bus_details->bus[idx].hash()) {
if (playback->prev_bus_details->bus[search_idx].hash() == bus_details.bus[idx].hash()) {
prev_bus_idx = search_idx;
}
}
@@ -411,13 +406,13 @@ void AudioServer::_mix_step() {
for (int channel_idx = 0; channel_idx < channel_count; channel_idx++) {
AudioFrame *channel_buf = thread_get_channel_mix_buffer(bus_idx, channel_idx);
if (fading_out) {
bus_details->volume[idx][channel_idx] = AudioFrame(0, 0);
bus_details.volume[idx][channel_idx] = AudioFrame(0, 0);
}
AudioFrame channel_vol = bus_details->volume[idx][channel_idx];
AudioFrame channel_vol = bus_details.volume[idx][channel_idx];
AudioFrame prev_channel_vol = AudioFrame(0, 0);
if (prev_bus_idx != -1) {
prev_channel_vol = prev_bus_details->volume[prev_bus_idx][channel_idx];
prev_channel_vol = playback->prev_bus_details->volume[prev_bus_idx][channel_idx];
}
_mix_step_for_channel(channel_buf, buf, prev_channel_vol, channel_vol, playback->attenuation_filter_cutoff_hz.get(), playback->highshelf_gain.get(), &playback->filter_process[channel_idx * 2], &playback->filter_process[channel_idx * 2 + 1]);
}
@@ -425,14 +420,14 @@ void AudioServer::_mix_step() {
// Now go through and fade-out any buses that were being played to previously that we missed by going through current data.
for (int idx = 0; idx < MAX_BUSES_PER_PLAYBACK; idx++) {
if (!prev_bus_details->bus_active[idx]) {
if (!playback->prev_bus_details->bus_active[idx]) {
continue;
}
int bus_idx = thread_find_bus_index(prev_bus_details->bus[idx]);
int bus_idx = thread_find_bus_index(playback->prev_bus_details->bus[idx]);
int current_bus_idx = -1;
for (int search_idx = 0; search_idx < MAX_BUSES_PER_PLAYBACK; search_idx++) {
if (bus_details->bus[search_idx] == prev_bus_details->bus[idx]) {
if (bus_details.bus[search_idx] == playback->prev_bus_details->bus[idx]) {
current_bus_idx = search_idx;
}
}
@@ -443,24 +438,17 @@ void AudioServer::_mix_step() {
for (int channel_idx = 0; channel_idx < channel_count; channel_idx++) {
AudioFrame *channel_buf = thread_get_channel_mix_buffer(bus_idx, channel_idx);
AudioFrame prev_channel_vol = prev_bus_details->volume[idx][channel_idx];
AudioFrame prev_channel_vol = playback->prev_bus_details->volume[idx][channel_idx];
// Fade out to silence
_mix_step_for_channel(channel_buf, buf, prev_channel_vol, AudioFrame(0, 0), playback->attenuation_filter_cutoff_hz.get(), playback->highshelf_gain.get(), &playback->filter_process[channel_idx * 2], &playback->filter_process[channel_idx * 2 + 1]);
}
}
// Copy the bus details we mixed with to the previous bus details to maintain volume ramps.
std::copy(std::begin(bus_details->bus_active), std::end(bus_details->bus_active), std::begin(prev_bus_details->bus_active));
std::copy(std::begin(bus_details->bus), std::end(bus_details->bus), std::begin(prev_bus_details->bus));
std::copy(std::begin(bus_details.bus_active), std::end(bus_details.bus_active), std::begin(playback->prev_bus_details->bus_active));
std::copy(std::begin(bus_details.bus), std::end(bus_details.bus), std::begin(playback->prev_bus_details->bus));
for (int bus_idx = 0; bus_idx < MAX_BUSES_PER_PLAYBACK; bus_idx++) {
std::copy(std::begin(bus_details->volume[bus_idx]), std::end(bus_details->volume[bus_idx]), std::begin(prev_bus_details->volume[bus_idx]));
}
AudioStreamPlaybackBusDetails *bus_details_expected = nullptr;
// Only put the bus details pointer back if it hasn't been updated already.
if (!playback->bus_details.compare_exchange_strong(/* expected= */ bus_details_expected, /* new= */ bus_details)) {
// If it *has* been updated already, queue the old one for deletion.
bus_details_graveyard.insert(bus_details);
std::copy(std::begin(bus_details.volume[bus_idx]), std::end(bus_details.volume[bus_idx]), std::begin(playback->prev_bus_details->volume[bus_idx]));
}
switch (playback->state.load()) {
@@ -1132,7 +1120,7 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Str
start_playback_stream(p_playback, map, p_start_time);
}
void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time) {
void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time, float p_highshelf_gain, float p_attenuation_cutoff_hz, float p_pitch_scale) {
ERR_FAIL_COND(p_playback.is_null());
AudioStreamPlaybackListNode *playback_node = new AudioStreamPlaybackListNode();
@@ -1154,10 +1142,9 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map
playback_node->bus_details = new_bus_details;
playback_node->prev_bus_details = new AudioStreamPlaybackBusDetails();
playback_node->setseek.set(-1);
playback_node->pitch_scale.set(1);
playback_node->highshelf_gain.set(0);
playback_node->attenuation_filter_cutoff_hz.set(0);
playback_node->pitch_scale.set(p_pitch_scale);
playback_node->highshelf_gain.set(p_highshelf_gain);
playback_node->attenuation_filter_cutoff_hz.set(p_attenuation_cutoff_hz);
memset(playback_node->prev_bus_details->volume, 0, sizeof(playback_node->prev_bus_details->volume));
@@ -1181,6 +1168,9 @@ void AudioServer::stop_playback_stream(Ref<AudioStreamPlayback> p_playback) {
AudioStreamPlaybackListNode::PlaybackState new_state, old_state;
do {
old_state = playback_node->state.load();
if (old_state == AudioStreamPlaybackListNode::AWAITING_DELETION) {
break; // Don't fade out again.
}
new_state = AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION;
} while (!playback_node->state.compare_exchange_strong(old_state, new_state));
@@ -1206,6 +1196,9 @@ void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_pla
int idx = 0;
for (KeyValue<StringName, Vector<AudioFrame>> pair : p_bus_volumes) {
if (idx >= MAX_BUSES_PER_PLAYBACK) {
break;
}
ERR_FAIL_COND(pair.value.size() < channel_count);
ERR_FAIL_COND(pair.value.size() != MAX_CHANNELS_PER_BUS);
@@ -1214,6 +1207,7 @@ void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_pla
for (int channel_idx = 0; channel_idx < MAX_CHANNELS_PER_BUS; channel_idx++) {
new_bus_details->volume[idx][channel_idx] = pair.value[channel_idx];
}
idx++;
}
do {
@@ -1260,17 +1254,18 @@ void AudioServer::set_playback_paused(Ref<AudioStreamPlayback> p_playback, bool
if (!playback_node) {
return;
}
if (!p_paused && playback_node->state == AudioStreamPlaybackListNode::PLAYING) {
return; // No-op.
}
if (p_paused && (playback_node->state == AudioStreamPlaybackListNode::PAUSED || playback_node->state == AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE)) {
return; // No-op.
}
AudioStreamPlaybackListNode::PlaybackState new_state, old_state;
do {
old_state = playback_node->state.load();
new_state = p_paused ? AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE : AudioStreamPlaybackListNode::PLAYING;
if (!p_paused && old_state == AudioStreamPlaybackListNode::PLAYING) {
return; // No-op.
}
if (p_paused && (old_state == AudioStreamPlaybackListNode::PAUSED || old_state == AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE)) {
return; // No-op.
}
} while (!playback_node->state.compare_exchange_strong(old_state, new_state));
}
@@ -1444,10 +1439,15 @@ void AudioServer::update() {
update_callback_list.maybe_cleanup();
listener_changed_callback_list.maybe_cleanup();
playback_list.maybe_cleanup();
for (AudioStreamPlaybackBusDetails *bus_details : bus_details_graveyard_frame_old) {
bus_details_graveyard_frame_old.erase(bus_details, [](AudioStreamPlaybackBusDetails *d) { delete d; });
}
for (AudioStreamPlaybackBusDetails *bus_details : bus_details_graveyard) {
bus_details_graveyard.erase(bus_details, [](AudioStreamPlaybackBusDetails *d) { delete d; });
bus_details_graveyard_frame_old.insert(bus_details);
bus_details_graveyard.erase(bus_details);
}
bus_details_graveyard.maybe_cleanup();
bus_details_graveyard_frame_old.maybe_cleanup();
}
void AudioServer::load_default_bus_layout() {