From de853142341da1b7f3b27e1d5f05e860a7e63231 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 29 Apr 2008 04:33:43 +0000 Subject: [PATCH] - Added dynamic recentering for the OPL synth. The chip has four basic waveforms, and three of them are non-negative. This can cause a tendency for the resulting output waveform to go into very high ranges depending on the timbres used, and Heretic's exemplify this problem. - Reduced the OPL volume level slightly. - Fixed: The waveform view from snd_drawoutput was upside-down. SVN r949 (trunk) --- docs/rh-log.txt | 6 +++ src/oplsynth/fmopl.cpp | 2 +- src/oplsynth/opl_mus_player.cpp | 71 +++++++++++++++++++++++++++++++++ src/oplsynth/opl_mus_player.h | 2 + src/sound/fmodsound.cpp | 4 +- 5 files changed, 82 insertions(+), 3 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index c2bc43831..19c0dcfc7 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,10 @@ April 28, 2008 +- Added dynamic recentering for the OPL synth. The chip has four basic + waveforms, and three of them are non-negative. This can cause a tendency + for the resulting output waveform to go into very high ranges depending on + the timbres used, and Heretic's exemplify this problem. +- Reduced the OPL volume level slightly. +- Fixed: The waveform view from snd_drawoutput was upside-down. - Various fixes for compiling working 64-bit binaries with Visual C++. The number of changes was pleasantly small, and a cursory check seems to show everything working alright. diff --git a/src/oplsynth/fmopl.cpp b/src/oplsynth/fmopl.cpp index 99e7794e5..cd3746f08 100644 --- a/src/oplsynth/fmopl.cpp +++ b/src/oplsynth/fmopl.cpp @@ -1638,7 +1638,7 @@ static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length) output[0] += tl_tab[p]; } // [RH] Convert to floating point. - buffer[i] += float(output[0]) / 7168.f; + buffer[i] += float(output[0]) / 10240; } // advance diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index b71d8230f..40324c882 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -3,6 +3,7 @@ #endif #include #include +#include #include "opl_mus_player.h" #include "doomtype.h" @@ -21,6 +22,7 @@ OPLmusicBlock::OPLmusicBlock() { scoredata = NULL; NextTickIn = 0; + LastOffset = 0; TwoChips = !opl_onechip; Looping = false; io = NULL; @@ -47,6 +49,7 @@ void OPLmusicBlock::Restart() OPLplayMusic (127); MLtime = 0; playingcount = 0; + LastOffset = 0; } OPLmusicFile::OPLmusicFile (FILE *file, char *musiccache, int len) @@ -209,6 +212,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { YM3812UpdateOne (1, samples1, samplesleft); } + OffsetSamples(samples1, samplesleft); assert(NextTickIn == ticky); NextTickIn -= samplesleft; assert (NextTickIn >= 0); @@ -231,6 +235,7 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) { YM3812UpdateOne (1, samples1, numsamples); } + OffsetSamples(samples1, numsamples); } res = false; break; @@ -256,6 +261,72 @@ bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) return res; } +void OPLmusicBlock::OffsetSamples(float *buff, int count) +{ + // Three out of four of the OPL waveforms are non-negative. Depending on + // timbre selection, this can cause the output waveform to tend toward + // very large positive values. Heretic's music is particularly bad for + // this. This function attempts to compensate by offseting the sample + // data back to around the [-1.0, 1.0] range. + + double max = -1e10, min = 1e10, offset, step; + int i, ramp; + + // Find max and min values for this segment of the waveform. + for (i = 0; i < count; ++i) + { + if (buff[i] > max) + { + max = buff[i]; + } + if (buff[i] < min) + { + min = buff[i]; + } + } + // Don't slide if we don't have to, because doing so introduces noise. + // However, if the amplitude is low, we do want to slide so that when + // the song ends, the wave will be around 0 and not click when the song + // starts over. + if (min - LastOffset > -0.5 && max - LastOffset < 0.5 && max - min > 0.5) + { + offset = LastOffset; + } + else + { + offset = (max + min) / 2; + // If the new offset is close to 0, make it 0 to avoid making another + // full loop through the sample data. + if (fabs(offset) < 1/256.0) + { + offset = 0; + } + } + // Ramp the offset change so there aren't any abrupt clicks in the output. + // If the ramp is too short, it can sound scratchy. cblood2.mid is + // particularly unforgiving of short ramps. + ramp = MIN(512, count); + step = (offset - LastOffset) / 512; + offset = LastOffset; + i = 0; + if (step != 0) + { + for (; i < ramp; ++i) + { + buff[i] = float(buff[i] - offset); + offset += step; + } + } + if (offset != 0) + { + for (; i < count; ++i) + { + buff[i] = float(buff[i] - offset); + } + } + LastOffset = float(offset); +} + int OPLmusicFile::PlayTick () { BYTE reg, data; diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h index 0540ecb13..ceb44fc0b 100644 --- a/src/oplsynth/opl_mus_player.h +++ b/src/oplsynth/opl_mus_player.h @@ -15,11 +15,13 @@ public: protected: virtual int PlayTick() = 0; + void OffsetSamples(float *buff, int count); double NextTickIn; double SamplesPerTick; bool TwoChips; bool Looping; + double LastOffset; FCriticalSection ChipAccess; }; diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 9709e0a56..c6f90b234 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1970,11 +1970,11 @@ void FMODSoundRenderer::DrawWave(float *wavearray, int x, int y, int width, int if (screen->Accel2D) { // Drawing this with lines is super-slow without hardware acceleration, at least with // the debug build. - float lasty = wavearray[0] * scale + mid; + float lasty = mid - wavearray[0] * scale; float newy; for (i = 1; i < width; ++i) { - newy = wavearray[i] * scale + mid; + newy = mid - wavearray[i] * scale; screen->DrawLine(x + i - 1, int(lasty), x + i, int(newy), -1, MAKEARGB(255,255,248,248)); lasty = newy; }