aboutsummaryrefslogtreecommitdiff
path: root/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
diff options
context:
space:
mode:
authorathrxx2019-09-09 22:11:29 +0200
committerathrxx2019-12-18 20:50:39 +0100
commit711034b74dd291286943a5b4aa17077ef05a39b2 (patch)
treea621b47a363244ab84f0c71ae220d5fe98c15b98 /audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
parentd67885f4f3d1be173f6b8e8688da5f18f34b9350 (diff)
downloadscummvm-rg350-711034b74dd291286943a5b4aa17077ef05a39b2.tar.gz
scummvm-rg350-711034b74dd291286943a5b4aa17077ef05a39b2.tar.bz2
scummvm-rg350-711034b74dd291286943a5b4aa17077ef05a39b2.zip
AUDIO: (FM-TOWNS/PC-98) - improve sound quality
- Increase internal sample rate to dividers of the actual chip clocks and fix other related things. This seems to improve certain sfx/noise generator like sounds. The performance still seems to be okay. - Fix feedback glitch that caused some noise with certain instrument patches when playing short notes. - Fix squarewave sound glitch (mute channels when volume is zero; this could also cause unnecessary noise). - Some cleanup.
Diffstat (limited to 'audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h')
-rw-r--r--audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h63
1 files changed, 55 insertions, 8 deletions
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
index 730dbecb16..05f83867bf 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
@@ -26,6 +26,8 @@
#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/mutex.h"
+#include "common/func.h"
+#include "common/array.h"
#ifdef __DS__
/* This disables the rhythm channel when emulating the PC-98 type 86 sound card.
@@ -34,11 +36,23 @@
* (very rare) PC-98 versions of Legend of Kyrandia 2 and Lands of Lore. Music will
* still be okay, just missing a couple of rhythm instruments.
*/
-#define DISABLE_PC98_RHYTHM_CHANNEL
+#define DISABLE_PC98_RHYTHM_CHANNEL
#endif
+/* Experimental code for emulation of the chip's busy flag wait cycle.
+ * Explanation:
+ * Before attempting a port write a client application would usually read the chip's
+ * busy flag and remain in a loop until the flag is cleared. This does not work with
+ * an emulator that is on the same thread as the client code (the busy flag will never
+ * clear). Instead, I emulate a wait cycle by withholding (enqueueing) incoming register
+ * writes for the duration of the wait cycle.
+ * For now I have disabled this with an #ifdef since I haven't seen any impact on the
+ * sound.
+ */
+//#define ENABLE_SNDTOWNS98_WAITCYCLES
+
class TownsPC98_FmSynthOperator;
-class TownsPC98_FmSynthSquareSineSource;
+class TownsPC98_FmSynthSquareWaveSource;
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
class TownsPC98_FmSynthPercussionSource;
#endif
@@ -92,6 +106,7 @@ protected:
void setVolumeIntern(int volA, int volB);
void setVolumeChannelMasks(int channelMaskA, int channelMaskB);
+ // This allows to balance out the fm/ssg levels.
void setLevelSSG(int vol);
const int _numChan;
@@ -102,8 +117,13 @@ protected:
private:
void generateTables();
+ void writeRegInternal(uint8 part, uint8 regAddress, uint8 value);
void nextTick(int32 *buffer, uint32 bufferSize);
+#ifdef ENABLE_SNDTOWNS98_WAITCYCLES
+ void startWaitCycle();
+#endif
+
struct ChanInternal {
ChanInternal();
~ChanInternal();
@@ -114,6 +134,9 @@ private:
void frqModSensitivity(uint32 value) {
frqModSvty = value << 5;
}
+ void fbClear() {
+ feedbuf[0] = feedbuf[1] = feedbuf[2] = 0;
+ }
bool enableLeft;
bool enableRight;
@@ -127,7 +150,7 @@ private:
TownsPC98_FmSynthOperator *opr[4];
};
- TownsPC98_FmSynthSquareSineSource *_ssg;
+ TownsPC98_FmSynthSquareWaveSource *_ssg;
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
TownsPC98_FmSynthPercussionSource *_prc;
#endif
@@ -141,7 +164,10 @@ private:
int32 *_oprLevelOut;
int32 *_oprDetune;
- typedef void (TownsPC98_FmSynth::*ChipTimerProc)();
+ typedef Common::Functor0Mem<void, TownsPC98_FmSynth> ChipTimerProc;
+ ChipTimerProc *_timerProcIdle;
+ ChipTimerProc *_timerProcA;
+ ChipTimerProc *_timerProcB;
void idleTimerCallback() {}
struct ChipTimer {
@@ -153,7 +179,7 @@ private:
int32 smpPerCb;
uint32 smpPerCbRem;
- ChipTimerProc cb;
+ ChipTimerProc *cb;
};
ChipTimer _timers[2];
@@ -161,9 +187,30 @@ private:
int _volMaskA, _volMaskB;
uint16 _volumeA, _volumeB;
- const float _baserate;
- uint32 _timerbase;
- uint32 _rtt;
+ int32 *_renderBuffer;
+ int _renderBufferSize;
+ int _numPending;
+ int _offsPending;
+ int _rateScale;
+ int _outRateMult;
+ int _rateConvCnt;
+ float _predSmpCount;
+ const int _internalRate;
+ const int _outputRate;
+
+#ifdef ENABLE_SNDTOWNS98_WAITCYCLES
+ int _waitCycleRemainder;
+ const int _samplesPerWaitCycle;
+
+ struct RegEntry {
+ RegEntry(uint8 p, uint8 r, uint8 v) : part(p), reg(r), val(v) {}
+ uint8 part;
+ uint8 reg;
+ uint8 val;
+ };
+
+ Common::Array<RegEntry> _waitCycleElapsedWrites;
+#endif
uint8 _registers[255][2];