Skip to content

Commit

Permalink
fix(DmSynth): implement stop-gap solution to fix audio flicker when s…
Browse files Browse the repository at this point in the history
…witching bands

This only really works for Gothic 1 and doesn't actually fix the root cause which is, that newly allocated TSFs will produce PCM that is drastically different from what was produced by the previous one, causing audio flicker.

In the future, a solution might be to fade out the audio to zero before the transition happens.
  • Loading branch information
lmichaelis committed Apr 30, 2024
1 parent 8554696 commit 51acfa4
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 6 deletions.
22 changes: 22 additions & 0 deletions src/Band.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,28 @@ DmResult DmBand_download(DmBand* slf, DmLoader* loader) {
return rv;
}

bool DmBand_isSortOfSameAs(DmBand* slf, DmBand* oth) {
if (slf == oth) {
return true;
}

if (slf == NULL || oth == NULL) {
return false;
}

if (slf->instrument_count != oth->instrument_count) {
return false;
}

for (size_t i = 0; i < oth->instrument_count; ++i) {
if (slf->instruments[i].dls != oth->instruments[i].dls) {
return false;
}
}

return true;
}

void DmInstrument_free(DmInstrument* slf) {
if (slf == NULL || slf->dls == NULL) {
return;
Expand Down
30 changes: 24 additions & 6 deletions src/Synth.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,22 +63,40 @@ void DmSynth_reset(DmSynth* slf) {
// instead of reloading the entire instrument list and re-creating all TSFs.
// See also: https://documentation.help/DirectMusic/usingbands.htm
void DmSynth_sendBandUpdate(DmSynth* slf, DmBand* band) {
if (slf == NULL) {
if (slf == NULL || band == NULL) {
return;
}

// Optimization: Don't re-alloc the entire thing if we're getting the same band
if (band == slf->band) {
// TODO(lmichaelis): This is a stop-gap solution to prevent audio flicker when replacing TSFs. It
// only works if all band instruments are in the same order and use the same DLS.
// When switching between actual bands, this will break!
if (DmBand_isSortOfSameAs(slf->band, band)) {
for (size_t i = 0; i < band->instrument_count; ++i) {
DmInstrument* ins = &band->instruments[i];
if (slf->channels[ins->channel].synth == NULL) {
continue;
}

float pan = (ins->flags & DmInstrument_PAN) ? (float) ins->pan / DmInt_MIDI_MAX : DmInt_PAN_CENTER;
float vol = (ins->flags & DmInstrument_VOLUME) ? (float) ins->volume / DmInt_MIDI_MAX : DmInt_VOLUME_MAX;

bool res = tsf_channel_set_pan(slf->channels[ins->channel].synth, 0, pan);
if (!res) {
Dm_report(DmLogLevel_ERROR, "DmSynth: tsf_channel_set_pan encountered an error.");
}

slf->channels[ins->channel].pitch_bend_reset = DmInt_PITCH_BEND_NEUTRAL;
slf->channels[ins->channel].volume = vol;
slf->channels[ins->channel].volume_reset = vol;
slf->channels[ins->channel].pan_reset = pan;
}
return;
}

slf->band = band;
DmSynth_freeChannels(slf);

if (band == NULL) {
return;
}

// Calculate the number of required performance channels
for (size_t i = 0; i < band->instrument_count; ++i) {
slf->channel_count = max_usize(band->instruments[i].channel, slf->channel_count);
Expand Down
1 change: 1 addition & 0 deletions src/_Internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ DMINT DmBand* DmBand_retain(DmBand* slf);
DMINT void DmBand_release(DmBand* slf);
DMINT DmResult DmBand_parse(DmBand* slf, DmRiff* rif);
DMINT DmResult DmBand_download(DmBand* slf, DmLoader* loader);
DMINT bool DmBand_isSortOfSameAs(DmBand* slf, DmBand* oth);
DMINT void DmInstrument_free(DmInstrument* slf);

DMINT DmResult DmStyle_create(DmStyle** slf);
Expand Down

0 comments on commit 51acfa4

Please sign in to comment.