[Scummvm-git-logs] scummvm master -> 0df5112bb018879355e32d4f57150574dfb192e2

athrxx noreply at scummvm.org
Fri Feb 9 15:03:03 UTC 2024


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
0df5112bb0 SCUMM: (INDY3/MAC) - add support for low quality music


Commit: 0df5112bb018879355e32d4f57150574dfb192e2
    https://github.com/scummvm/scummvm/commit/0df5112bb018879355e32d4f57150574dfb192e2
Author: athrxx (athrxx at scummvm.org)
Date: 2024-02-09T15:58:27+01:00

Commit Message:
SCUMM: (INDY3/MAC) - add support for low quality music

Changed paths:
    engines/scumm/players/player_mac_indy3.cpp


diff --git a/engines/scumm/players/player_mac_indy3.cpp b/engines/scumm/players/player_mac_indy3.cpp
index 3458c394d1d..3b8e8b98845 100644
--- a/engines/scumm/players/player_mac_indy3.cpp
+++ b/engines/scumm/players/player_mac_indy3.cpp
@@ -97,43 +97,52 @@ private:
 
 class I3MSoundDriver {
 public:
-	I3MSoundDriver(Common::Mutex &mutex, uint32 deviceRate, bool isStereo, bool canInterpolate, bool internal16Bit) : _mutex(mutex), _sig(false), _caps(deviceRate, isStereo, canInterpolate),
-		_smpSize(internal16Bit ? 2 : 1), _smpMin(internal16Bit ? -32768 : -128), _smpMax(internal16Bit ? 32767 : 127) {}
+	I3MSoundDriver(Common::Mutex &mutex, uint32 deviceRate, bool canInterpolate, bool internal16Bit) : _mutex(mutex), _caps(deviceRate, canInterpolate),
+		_smpSize(internal16Bit ? 2 : 1), _smpMin(internal16Bit ? -32768 : -128), _smpMax(internal16Bit ? 32767 : 127), _status(0) {}
 	virtual ~I3MSoundDriver() {}
 	virtual void feed(int8 *dst, uint32 byteSize, Audio::Mixer::SoundType type, bool expectStereo) = 0;
 
-	bool checkSignal() const { return _sig; }
-	void resetSignal(bool state) { _sig = state; }
-
 	struct Caps {
-		Caps(uint32 rate, bool stereo, bool interp) :deviceRate(rate), isStereo(stereo), allowInterPolation(interp) {}
+		Caps(uint32 rate, bool interp) :deviceRate(rate), allowInterPolation(interp) {}
 		const uint32 deviceRate;
-		const bool isStereo;
 		const bool allowInterPolation;
 	};
 	const Caps &getCaps() const { return _caps; }
+
+	enum StatusFlag : uint8 {
+		kStatusPlaying =		1	<<		0,
+		kStatusOverflow =		1	<<		1,
+		kStatusStartup =		1	<<		2,
+		kStatusDone =			1	<<		3
+	};
+	uint8 getStatus() const { return _status; }
+	void clearFlags(uint8 flags) { _status &= ~flags; }
+
 protected:
+	void setFlags(uint8 flags) { _status |= flags; }
+
 	Common::Mutex &_mutex;
 	const int _smpSize;
 	const int16 _smpMin;
 	const int16 _smpMax;
 	const Caps _caps;
-	bool _sig;
+	uint8 _status;
 };
 
 class I3MLowLevelPCMDriver final : public I3MSoundDriver {
 public:
 	struct PCMSound {
-		PCMSound() : len(0), rate(0), loopst(0), loopend(0), baseFreq(0) {}
+		PCMSound() : len(0), rate(0), loopst(0), loopend(0), baseFreq(0), stereo(false) {}
 		Common::SharedPtr<const byte> data;
 		uint32 len;
 		uint32 rate;
 		uint32 loopst;
 		uint32 loopend;
 		byte baseFreq;
+		bool stereo;
 	};
 public:
-	I3MLowLevelPCMDriver(Common::Mutex &mutex, uint32 deviceRate, bool enableInterpolation, bool isStereo, bool internal16Bit);
+	I3MLowLevelPCMDriver(Common::Mutex &mutex, uint32 deviceRate, bool enableInterpolation, bool internal16Bit);
 	void feed(int8 *dst, uint32 byteSize, Audio::Mixer::SoundType type, bool expectStereo) override;
 	void play(PCMSound *snd);
 	void stop();
@@ -142,7 +151,6 @@ private:
 
 	Common::SharedPtr<const int8> _res;
 	const int8 *_data;
-	const uint16 _frameSize;
 	const bool _interp;
 	int8 _lastSmp[2];
 	uint32 _len;
@@ -153,35 +161,54 @@ private:
 	byte _baseFreq;
 	uint32 _rcPos;
 	uint32 _smpWtAcc;
+	uint16 _frameSize;
 };
 
 class I3MMusicDriver : public I3MSoundDriver {
 public:
-	enum ParaType {
+	I3MMusicDriver(uint16 numChannels, Common::Mutex &mutex, bool canInterpolate, bool internal16Bit) : I3MSoundDriver(mutex, ASC_DEVICE_RATE, canInterpolate, internal16Bit), _numChan(numChannels) {}
+	virtual void start() = 0;
+	virtual void stop() = 0;
+
+	enum SendDataType {
 		kDuration = 0,
 		kChanRate = 1,
 		kChanWaveform = 2,
-		kSwTriplet = 3
+		kSquareWaveTriplet = 3
 	};
 
-	I3MMusicDriver(uint16 numChannels, Common::Mutex &mutex, bool isStereo, bool internal16Bit) : I3MSoundDriver(mutex, ASC_DEVICE_RATE, isStereo, false, internal16Bit), _numChan(numChannels) {}
-	virtual void start() = 0;
-	virtual void stop() = 0;
-	virtual void setParameter(int type, ...) = 0;
+	virtual void send(int dataType, ...) = 0;
 	uint16 numChannels() const { return _numChan; }
+
 protected:
+	void putSample(int8 *&dst, int16 smp, bool expectStereo) {
+		if (_smpSize == 2) {
+			smp = CLIP<int16>(smp, _smpMin, _smpMax);
+			*reinterpret_cast<int16*>(dst) = smp;
+			dst += _smpSize;
+			if (expectStereo) {
+				*reinterpret_cast<int16*>(dst) = smp;
+				dst += _smpSize;
+			}
+		} else {
+			smp = CLIP<int8>(smp >> 2, _smpMin, _smpMax);
+			*dst++ = smp;
+			if (expectStereo)
+				*dst++ = smp;
+		}
+	}
 	const uint16 _numChan;
 };
 
 class I3MFourToneSynthDriver final : public I3MMusicDriver {
 public:
-	I3MFourToneSynthDriver(Common::Mutex &mutex, bool isStereo, bool internal16bit);
+	I3MFourToneSynthDriver(Common::Mutex &mutex, bool internal16bit);
 	~I3MFourToneSynthDriver() override;
 
 	void feed(int8 *dst, uint32 byteSize, Audio::Mixer::SoundType type, bool expectStereo) override;
 	void start() override;
 	void stop() override;
-	void setParameter(int type, ...) override;
+	void send(int dataType, ...) override;
 
 private:
 	void setWaveForm(uint8 chan, const uint8 *data, uint32 dataSize);
@@ -203,22 +230,33 @@ private:
 
 class I3MSquareWaveSynthDriver final : public I3MMusicDriver {
 public:
-	I3MSquareWaveSynthDriver(Common::Mutex &mutex, bool isStereo, bool internal16Bit) : I3MMusicDriver(1, mutex, isStereo, internal16Bit) {}
-	~I3MSquareWaveSynthDriver() override {}
+	I3MSquareWaveSynthDriver(Common::Mutex &mutex, bool internal16Bit);
+	~I3MSquareWaveSynthDriver() override {};
 
 	void feed(int8 *dst, uint32 byteSize, Audio::Mixer::SoundType type, bool expectStereo) override;
 	void start() override;
 	void stop() override;
-	void setParameter(int argType, ...) override;
+	void send(int dataType, ...) override;
 private:
-	void pushTriplet(uint16 count, uint16 amplitude, uint16 duration);
+	void addTriplet(uint16 frequency, uint16 amplitude);
 
 	struct Triplet {
-		Triplet(uint16 cnt, uint16 ampl, uint16 dur) : count(cnt), amplitude(ampl), duration(dur) {}
+		Triplet(uint16 cnt, uint16 ampl, uint16 dur) : count(cnt), amplitude(ampl & 0xff), duration(dur) {}
+		Triplet() : Triplet(0xffff, 0xffff, 1) {}
+		Triplet &&fromScumm() { count = (count / 3) * 2; duration = MAX<uint8>(duration, 1); return Common::move(*this); }
+		void toHardware(uint32 &dstCount, uint8 &dstAmpl, uint16 &dstDur) { dstCount = count ? 0x58000000 / (5 * count) : 0; dstAmpl = amplitude >> 1; dstDur = duration; }
 		uint16 count;
 		uint16 amplitude;
 		uint16 duration;
 	};
+
+	Common::Array<I3MSquareWaveSynthDriver::Triplet> _tripletsQueue;
+	Triplet _lastPara;
+	uint16 _pos;
+	uint32 _count;
+	uint16 _duration;
+	uint8 _amplitude;
+	uint32 _phase;
 };
 
 class I3MPlayer {
@@ -251,6 +289,7 @@ private:
 	void stopSong();
 	void stopSoundEffect();
 	void stopActiveSound();
+	void finishSong();
 	void updateSong();
 	void updateSoundEffect();
 
@@ -260,20 +299,19 @@ private:
 	bool isSong(int id) const;
 	bool isHiQuality() const;
 
-	int _lastSound;
-	int _lastSong;
+	int _curSound;
+	int _curSong;
 	int _lastSoundEffectPrio;
 	int _soundEffectNumLoops;
 	int _songTimer;
+	bool _songUnfinished;
 	uint _activeChanCount;
 	byte _songTimerInternal;
 	byte *_soundUsage;
 
-	bool _songPlaying;
 	bool _soundEffectPlaying;
 	int _qmode;
 	bool _16bit;
-	bool _stereo;
 	bool _qualHi;
 	bool _mixerThread;
 
@@ -367,6 +405,7 @@ private:
 
 	MusicChannel **_musicChannels;
 	const int _numMusicChannels;
+	const int _numMusicTracks;
 
 	static const uint8 _fourToneSynthWaveForm[256];
 
@@ -522,8 +561,8 @@ void AudioStream_I3M::runVblTask() {
 		(*_vblCbProc)();
 }
 
-I3MLowLevelPCMDriver::I3MLowLevelPCMDriver(Common::Mutex &mutex, uint32 deviceRate, bool enableInterpolation, bool isStereo, bool internal16Bit) :
-	I3MSoundDriver(mutex, deviceRate, isStereo, true, internal16Bit), _interp(enableInterpolation), _frameSize(isStereo ? 2 : 1), _len(0), _rmH(0), _rmL(0), _smpWtAcc(0), _loopSt(0),
+I3MLowLevelPCMDriver::I3MLowLevelPCMDriver(Common::Mutex &mutex, uint32 deviceRate, bool enableInterpolation, bool internal16Bit) :
+	I3MSoundDriver(mutex, deviceRate, true, internal16Bit), _interp(enableInterpolation), _frameSize(1), _len(0), _rmH(0), _rmL(0), _smpWtAcc(0), _loopSt(0),
 		_loopEnd(0), _baseFreq(0), _rcPos(0), _data(nullptr) {
 			_lastSmp[0] = _lastSmp[1] = 0;
 }
@@ -537,33 +576,27 @@ void I3MLowLevelPCMDriver::feed(int8 *dst, uint32 byteSize, Audio::Mixer::SoundT
 	if (_data == nullptr)
 		return;
 
-	if (expectStereo != _caps.isStereo)
-		error("I3MLowLevelPCMDriver::feed(): stereo/mono mismatch between sound data and mixer stream");
-
 	int32 diff = 0;
+	uint16 destFrameSize = expectStereo ? 2 : 1;
 	bool interp = (_interp && _rmL);
 
-	for (const int8 *end = &dst[byteSize]; dst < end; dst += _smpSize) {
-		if (interp) {
-			for (int i = 0; i < _frameSize; ++ i) {
-				int8 in = _data[_rcPos + i];
-				if (in != _lastSmp[i]) {
+	for (const int8 *end = &dst[byteSize]; dst < end; ) {
+		int8 in = 0;
+		for (int i = 0; i < destFrameSize; ++i) {
+			if (i < _frameSize) {
+				in = _data[_rcPos + i];
+				if (interp && in != _lastSmp[i]) {
 					diff = in - _lastSmp[i];
 					diff = (diff * (_smpWtAcc >> 1)) >> 15;
 					in = (_lastSmp[i] + diff) & 0xff;
 				}
-				if (_smpSize == 2)
-					*reinterpret_cast<int16*>(dst) = in << 2;
-				else
-					*dst = in;
 			}
-		} else {
 			if (_smpSize == 2)
-				*reinterpret_cast<int16*>(dst) = _data[_rcPos] << 2;
+				*reinterpret_cast<int16*>(dst) = in << 2;
 			else
-				*dst = _data[_rcPos];
+				*dst = in;
+			dst += _smpSize;
 		}
-
 		uint32 lpos = _rcPos;
 		_rcPos += (_rmH * _frameSize);
 		_smpWtAcc += _rmL;
@@ -590,7 +623,7 @@ void I3MLowLevelPCMDriver::feed(int8 *dst, uint32 byteSize, Audio::Mixer::SoundT
 				_res.reset();
 				end = dst;
 			}
-			_sig = true;
+			setFlags(kStatusDone);
 		}
 	}
 }
@@ -619,6 +652,8 @@ void I3MLowLevelPCMDriver::play(PCMSound *snd) {
 	_rmL = rmul & 0xffff;
 	_rmH = rmul >> 16;
 
+	_frameSize = snd->stereo ? 2 : 1;
+
 	if (snd->loopend - snd->loopst < 2 || snd->loopend < snd->loopst) {
 		_loopSt = 0;
 		_loopEnd = 0;
@@ -633,14 +668,14 @@ void I3MLowLevelPCMDriver::play(PCMSound *snd) {
 	_lastSmp[0] = _data[0];
 	if (_len >= _frameSize)
 		_lastSmp[1] = _data[1];
-	_sig = false;
+	clearFlags(kStatusDone);
 }
 
 void I3MLowLevelPCMDriver::stop() {
 	Common::StackLock lock(_mutex);
 	_data = nullptr;
 	_res.reset();
-	_sig = true;
+	setFlags(kStatusDone);
 }
 
 uint32 I3MLowLevelPCMDriver::calcRate(uint32 outRate, uint32 factor, uint32 dataRate) {
@@ -796,8 +831,7 @@ uint32 I3MLowLevelPCMDriver::calcRate(uint32 outRate, uint32 factor, uint32 data
 	return result;
 }
 
-I3MFourToneSynthDriver::I3MFourToneSynthDriver(Common::Mutex &mutex, bool isStereo, bool internal16Bit) :
-	I3MMusicDriver(4, mutex, isStereo, internal16Bit), _duration(0), _pos(0), _chan(nullptr) {
+I3MFourToneSynthDriver::I3MFourToneSynthDriver(Common::Mutex &mutex, bool internal16Bit) : I3MMusicDriver(4, mutex, false, internal16Bit), _duration(0), _pos(0), _chan(nullptr) {
 	_chan = new Channel[_numChan];
 }
 
@@ -812,9 +846,6 @@ void I3MFourToneSynthDriver::feed(int8 *dst, uint32 byteSize, Audio::Mixer::Soun
 	if (dst == nullptr || type != Audio::Mixer::kMusicSoundType)
 		return;
 
-	if (expectStereo != _caps.isStereo)
-		error("I3MFourToneSynthDriver::feed(): stereo/mono mismatch between sound data and mixer stream");
-
 	const int8 *end = &dst[byteSize];
 
 	while (_duration && dst < end) {
@@ -828,25 +859,12 @@ void I3MFourToneSynthDriver::feed(int8 *dst, uint32 byteSize, Audio::Mixer::Soun
 				smp += _chan[i].waveform[(_chan[i].phase >> 16) & 0xff];
 		}
 
-		if (_smpSize == 2) {
-			smp = CLIP<int16>(smp, _smpMin, _smpMax);
-			*reinterpret_cast<int16*>(dst) = smp;
-			dst += _smpSize;
-			if (_caps.isStereo) {
-				*reinterpret_cast<int16*>(dst) = smp;
-				dst += _smpSize;
-			}
-		} else {
-			smp = CLIP<int16>(smp >> 2, _smpMin, _smpMax);
-			*dst++ = smp;
-			if (_caps.isStereo)
-				*dst++ = smp;
-		}
+		putSample(dst, smp, expectStereo);
 
 		if (++_pos == 370) {
 			_pos = 0;
 			if (!_duration)
-				_sig = true;
+				setFlags(kStatusDone);
 		}
 	}
 
@@ -869,14 +887,14 @@ void I3MFourToneSynthDriver::stop() {
 	setDuration(0);
 }
 
-void I3MFourToneSynthDriver::setParameter(int type, ...)  {
+void I3MFourToneSynthDriver::send(int dataType, ...)  {
 	Common::StackLock lock(_mutex);
 	va_list arg;
-	va_start(arg, type);
-	int chan = (type == kChanRate || type == kChanWaveform) ? va_arg(arg, int) : 0;
-	const uint8 *ptr = (type == kChanWaveform) ? va_arg(arg, const uint8*) : nullptr;
+	va_start(arg, dataType);
+	int chan = (dataType == kChanRate || dataType == kChanWaveform) ? va_arg(arg, int) : 0;
+	const uint8 *ptr = (dataType == kChanWaveform) ? va_arg(arg, const uint8*) : nullptr;
 
-	switch (type) {
+	switch (dataType) {
 	case kDuration:
 		setDuration((uint16)va_arg(arg, uint));
 		break;
@@ -890,6 +908,8 @@ void I3MFourToneSynthDriver::setParameter(int type, ...)  {
 		break;
 	}
 
+	_status |= kStatusOverflow;
+
 	va_end(arg);
 }
 
@@ -910,7 +930,7 @@ void I3MFourToneSynthDriver::setWaveForm(uint8 chan, const uint8 *data, uint32 d
 void I3MFourToneSynthDriver::setDuration(uint16 duration) {
 	_duration = duration;
 	_pos = 0;
-	_sig = false;
+	clearFlags(kStatusDone);
 }
 
 void I3MFourToneSynthDriver::setRate(uint8 chan, uint16 rate) {
@@ -918,30 +938,68 @@ void I3MFourToneSynthDriver::setRate(uint8 chan, uint16 rate) {
 	_chan[chan].rate = rate ? (0x5060000 / (rate >> ((rate < 1600) ? 4 : 6))) : 0;
 }
 
-void I3MSquareWaveSynthDriver::feed(int8 *dst, uint32 len, Audio::Mixer::SoundType type, bool expectStereo) {
+I3MSquareWaveSynthDriver::I3MSquareWaveSynthDriver(Common::Mutex &mutex, bool internal16Bit) :
+	I3MMusicDriver(1, mutex, false, internal16Bit), _count(0xffff), _duration(0), _amplitude(0), _phase(0), _pos(0) {
 
 }
 
-void I3MSquareWaveSynthDriver::start() {
+void I3MSquareWaveSynthDriver::feed(int8 *dst, uint32 byteSize, Audio::Mixer::SoundType type, bool expectStereo) {
+	if (dst == nullptr || type != Audio::Mixer::kMusicSoundType)
+		return;
+
+	Common::Array<Triplet>::iterator t = _tripletsQueue.begin();
+	const int8 *end = &dst[byteSize];
+
+	while (dst < end && (_count != 0xffff || t != _tripletsQueue.end())) {
+		if (_pos == 0 && (_count == 0xffff || (_duration && !--_duration) || !_duration)) {
+			if (t == _tripletsQueue.end()) {
+				_count = 0xffff;
+				_duration = 1;
+				setFlags(kStatusDone);
+				break;
+			} else {
+				t->toHardware(_count, _amplitude, _duration);
+				t = _tripletsQueue.erase(t);
+				_phase = _count;
+			}
+		}
+
+		_phase += _count;
+		putSample(dst, _phase ? -(int8)((_phase >> 23) & 1) ^ _amplitude : 0, expectStereo);
+
+		if (++_pos == 370)
+			_pos = 0;
+	}
 
+	if (dst < end)
+		memset(dst, 0, end - dst);
 }
 
-void I3MSquareWaveSynthDriver::stop() {
+void I3MSquareWaveSynthDriver::start() {
+	Common::StackLock lock(_mutex);
+	stop();
+	setFlags(kStatusPlaying | kStatusStartup);
+}
 
+void I3MSquareWaveSynthDriver::stop() {
+	Common::StackLock lock(_mutex);
+	_lastPara = Triplet();
+	_count = 0xffff;
+	_duration = 1;
+	_tripletsQueue.clear();
+	clearFlags(kStatusPlaying);
+	setFlags(kStatusDone);
 }
 
-void I3MSquareWaveSynthDriver::setParameter(int type, ...)  {
+void I3MSquareWaveSynthDriver::send(int dataType, ...)  {
 	Common::StackLock lock(_mutex);
 	va_list arg;
-	va_start(arg, type);
-	uint16 a = 0;
-	uint16 b = 0;
-
-	switch (type) {
-	case kSwTriplet:
-		a = (uint16)va_arg(arg, uint);
-		b = (uint16)va_arg(arg, uint);
-		pushTriplet(a, b, (uint16)va_arg(arg, uint));
+	va_start(arg, dataType);
+	uint16 a = (uint16)va_arg(arg, uint);
+
+	switch (dataType) {
+	case kSquareWaveTriplet:
+		addTriplet(a, (uint16)va_arg(arg, uint));
 		break;
 	default:
 		break;
@@ -950,15 +1008,37 @@ void I3MSquareWaveSynthDriver::setParameter(int type, ...)  {
 	va_end(arg);
 }
 
-void I3MSquareWaveSynthDriver::I3MSquareWaveSynthDriver::pushTriplet(uint16 count, uint16 amplitude, uint16 duration) {
+void I3MSquareWaveSynthDriver::addTriplet(uint16 frequency, uint16 amplitude) {
+	if ((_status & kStatusStartup) && frequency < 3)
+		return;
+
+	clearFlags(kStatusStartup);
+
+	if (_lastPara.count == 0xffff)
+		_lastPara.count = frequency;
+	if (_lastPara.amplitude == 0xffff)
+		_lastPara.amplitude = amplitude;
 
+	if ((_status & kStatusPlaying) && _tripletsQueue.size() < 177) {
+		if (frequency >> 3 != _lastPara.count >> 3 || amplitude != _lastPara.amplitude) {
+			_tripletsQueue.push_back(_lastPara.fromScumm());
+			_lastPara = Triplet(frequency, amplitude, 0);
+			clearFlags(kStatusDone);
+		}
+		_lastPara.duration++;
+
+	} else {
+		setFlags(kStatusOverflow);
+	}
 }
 
 Common::WeakPtr<I3MPlayer> *I3MPlayer::_inst = nullptr;
 
-I3MPlayer::I3MPlayer(ScummEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer), _musicChannels(nullptr), _lastSound(0), _lastSong(-1), _lastSoundEffectPrio(0), _soundEffectNumLoops(-1),
-	_musicIDTable(nullptr), _macstr(nullptr), _musicIDTableLen(0), _soundUsage(0), _idRangeMax(86), _mdrv(nullptr), _sdrv(nullptr), _nextTickProc(this, &I3MPlayer::nextTick),
-	_songPlaying(false), _soundEffectPlaying(false), _songTimer(0), _songTimerInternal(0), _qmode(0), _stereo(false), _16bit(false), _qualHi(false), _mixerThread(false), _activeChanCount(0), _numMusicChannels(4) {
+I3MPlayer::I3MPlayer(ScummEngine *vm, Audio::Mixer *mixer) :
+	_vm(vm), _mixer(mixer), _musicChannels(nullptr), _curSound(0), _curSong(0), _lastSoundEffectPrio(0), _idRangeMax(86), _soundEffectNumLoops(-1),
+	_musicIDTable(nullptr), _macstr(nullptr), _musicIDTableLen(0), _soundUsage(0), _mdrv(nullptr), _sdrv(nullptr), _nextTickProc(this, &I3MPlayer::nextTick),
+	_soundEffectPlaying(false), _songTimer(0), _songTimerInternal(0), _qmode(2), _16bit(false), _qualHi(false),	_mixerThread(false), _activeChanCount(0),
+	_songUnfinished(false), _numMusicChannels(8), _numMusicTracks(4) {
 	assert(_vm);
 	assert(_mixer);
 
@@ -1015,16 +1095,15 @@ bool I3MPlayer::startDevices(uint32 outputRate, uint32 pcmDeviceRate, uint32 fee
 	if (!_macstr || !_mixer)
 		return false;
 
-	_sdrv = new I3MLowLevelPCMDriver(_mixer->mutex(), pcmDeviceRate, enableInterpolation, stereo, internal16Bit);
-	I3MFourToneSynthDriver *mdrv = new I3MFourToneSynthDriver(_mixer->mutex(), stereo, internal16Bit);
+	_sdrv = new I3MLowLevelPCMDriver(_mixer->mutex(), pcmDeviceRate, enableInterpolation, internal16Bit);
+	I3MFourToneSynthDriver *mdrv = new I3MFourToneSynthDriver(_mixer->mutex(), internal16Bit);
 	if (!mdrv || !_sdrv)
 		return false;
 
 	for (int i = 0; i < mdrv->numChannels(); ++i)
-		mdrv->setParameter(I3MMusicDriver::kChanWaveform, i, _fourToneSynthWaveForm, sizeof(_fourToneSynthWaveForm));
+		mdrv->send(I3MMusicDriver::kChanWaveform, i, _fourToneSynthWaveForm, sizeof(_fourToneSynthWaveForm));
 	_qualHi = true;
 	_16bit = internal16Bit;
-	_stereo = stereo;
 	_mdrv = mdrv;
 
 	_drivers.push_back(_mdrv);
@@ -1070,7 +1149,7 @@ void I3MPlayer::stopSound(int id) {
 	Common::StackLock lock(_mixer->mutex());
 	_soundUsage[id] = 0;
 
-	if (id == _lastSound)
+	if (id == _curSound)
 		stopActiveSound();
 }
 
@@ -1105,17 +1184,18 @@ void I3MPlayer::setQuality(int qual) {
 	Common::StackLock lock(_mixer->mutex());
 	Common::Array<I3MSoundDriver*>::iterator dr = Common::find(_drivers.begin(), _drivers.end(), _mdrv);
 	delete _mdrv;
+	_mdrv = nullptr;
 	_qmode = qual;
 
 	if (isHiQuality()) {
-		I3MFourToneSynthDriver *mdrv = new I3MFourToneSynthDriver(_mixer->mutex(), _stereo, _16bit);
+		I3MFourToneSynthDriver *mdrv = new I3MFourToneSynthDriver(_mixer->mutex(), _16bit);
 		assert(mdrv);
 		for (int i = 0; i < mdrv->numChannels(); ++i)
-			mdrv->setParameter(I3MMusicDriver::kChanWaveform, i, _fourToneSynthWaveForm, sizeof(_fourToneSynthWaveForm));
+			mdrv->send(I3MMusicDriver::kChanWaveform, i, _fourToneSynthWaveForm, sizeof(_fourToneSynthWaveForm));
 		_mdrv = mdrv;
 		_qualHi = true;
 	} else {
-		_mdrv = new I3MSquareWaveSynthDriver(_mixer->mutex(), _stereo, _16bit);
+		_mdrv = new I3MSquareWaveSynthDriver(_mixer->mutex(), _16bit);
 		_qualHi = false;
 		assert(_mdrv);
 	}
@@ -1158,10 +1238,12 @@ void I3MPlayer::nextTick() {
 
 	_mixerThread = true;
 
-	if (!_songPlaying && _sdrv->checkSignal())
+	if (!_curSong && (_sdrv->getStatus() & I3MSoundDriver::kStatusDone))
 		updateSoundEffect();
-	else if (_songPlaying)
+	else if (_curSong)
 		updateSong();
+	else if (_songUnfinished && (_mdrv->getStatus() & I3MSoundDriver::kStatusDone))
+		stopSong();
 
 	_mixerThread = false;
 }
@@ -1191,9 +1273,9 @@ void I3MPlayer::startSong(int id) {
 
 	_songTimer = 0;
 	++_soundUsage[id];
-	if (_lastSong != -1)
-		--_soundUsage[_lastSong];
-	_lastSong = _lastSound = id;
+	if (_curSong > 0)
+		--_soundUsage[_curSong];
+	_curSong = _curSound = id;
 
 	// This applies if the quality mode is set to kQualAuto
 	// and the VAR_SOUNDCARD setting changes.
@@ -1211,14 +1293,13 @@ void I3MPlayer::startSong(int id) {
 	_mdrv->start();
 
 	_activeChanCount = 0;
-	for (int i = 0; i < 3; ++i) {
+	for (int i = 0; i < _numMusicTracks; ++i) {
 		uint16 offs = READ_LE_UINT16(ptr);
 		ptr += 2;
 		if (offs)
 			++_activeChanCount;
 		_musicChannels[i]->start(sres, offs, _qualHi);
 	}
-	_songPlaying = true;
 }
 
 void I3MPlayer::startSoundEffect(int id) {
@@ -1237,18 +1318,18 @@ void I3MPlayer::startSoundEffect(int id) {
 		return;
 	}
 
-	if (_songPlaying)
+	if (_curSong)
 		return;
 
 	uint16 prio = READ_BE_UINT16(ptr + 4);
 
-	if (_lastSound) {
+	if (_curSound) {
 		if (prio < _lastSoundEffectPrio)
 			return;
-		const uint8 *ptr2 = _vm->getResourceAddress(rtSound, _lastSound);
+		const uint8 *ptr2 = _vm->getResourceAddress(rtSound, _curSound);
 		assert(ptr2);
 		if (READ_BE_UINT16(ptr2 + 6) == 0)
-			_soundUsage[_lastSound] = 0;
+			_soundUsage[_curSound] = 0;
 	}
 
 	stopActiveSound();
@@ -1276,17 +1357,15 @@ void I3MPlayer::startSoundEffect(int id) {
 
 	_sdrv->play(&_pcmSnd);
 
-	_lastSound = id;
+	_curSound = id;
 	_soundUsage[id]++;
 }
 
 void I3MPlayer::stopSong() {
 	Common::StackLock lock(_mixer->mutex());
 	_mdrv->stop();
-	_songPlaying = false;
-	if (_soundUsage[_lastSong])
-		--_soundUsage[_lastSong];
-	_lastSound = _lastSong = 0;
+	finishSong();
+	_curSound = 0;
 }
 
 void I3MPlayer::stopSoundEffect() {
@@ -1294,35 +1373,129 @@ void I3MPlayer::stopSoundEffect() {
 	_sdrv->stop();
 	_soundEffectPlaying = false;
 	_lastSoundEffectPrio = 0;
-	_lastSound = 0;
+	_curSound = 0;
 }
 
 void I3MPlayer::stopActiveSound() {
 	if (_soundEffectPlaying)
 		stopSoundEffect();
-	else if (_songPlaying)
+	else if (_curSong || _songUnfinished)
 		stopSong();
+	_songUnfinished = false;
+}
+
+void I3MPlayer::finishSong() {
+	if (_soundUsage[_curSong])
+		--_soundUsage[_curSong];
+	_curSong = 0;
+	_songUnfinished = !(_mdrv->getStatus() & I3MSoundDriver::kStatusDone);
 }
 
 void I3MPlayer::updateSong() {
-	if (_lastSong) {
-		for (int i = (_qualHi ? 4 : 1); i; --i) {
-			for (int ii = 0; ii < _numMusicChannels && _songPlaying; ++ii)
-				_musicChannels[ii]->nextTick();
+	if (_curSong && (_qualHi || (_mdrv->getStatus() & I3MSoundDriver::kStatusDone))) {
+		_mdrv->clearFlags(I3MSoundDriver::kStatusOverflow);
+		while (_curSong && !(_mdrv->getStatus() & I3MSoundDriver::kStatusOverflow)) {
+			for (int i = _qualHi ? 4 : 4; i; --i) {
+				for (int ii = 0; ii < _numMusicTracks && _curSong; ++ii)
+					_musicChannels[ii]->nextTick();
+			}
+
+			if (_qualHi) {
+				for (int i = 0; i < _mdrv->numChannels(); ++i)
+					_mdrv->send(I3MMusicDriver::kChanRate, i, _curSong ? _musicChannels[i]->checkPeriod() : 0);
+				if (_curSong)
+					_mdrv->send(I3MMusicDriver::kDuration, 10);
+			} else {
+				MusicChannel *ch = nullptr;
+				for (int i = 0; i < _numMusicTracks && ch == nullptr && _curSong; ++i) {
+					if (_musicChannels[i]->checkPeriod())
+						ch = _musicChannels[i];
+				}
+				_mdrv->send(I3MMusicDriver::kSquareWaveTriplet, ch ? ch->checkPeriod() : 0, 0xff);
+			}
 		}
 	}
+}
 
-	for (int i = 0; i < _mdrv->numChannels(); ++i)
-		_mdrv->setParameter(I3MMusicDriver::kChanRate, i, _lastSong ? _musicChannels[i]->checkPeriod() : 0);
-	if (_songPlaying)
-		_mdrv->setParameter(I3MMusicDriver::kDuration, 10);
+void I3MPlayer::updateSoundEffect() {
+	_sdrv->clearFlags(I3MSoundDriver::kStatusDone);
+	bool chkRestart = false;
+
+	if (!_soundEffectPlaying || !_curSound) {
+		chkRestart = true;
+	} else {
+		if (_soundEffectNumLoops > 0)
+			--_soundEffectNumLoops;
+		if (_soundEffectNumLoops)
+			_sdrv->play(&_pcmSnd);
+		else
+			--_soundUsage[_curSound];
+		chkRestart = (_soundEffectNumLoops == 0);
+	}
+
+	if (chkRestart) {
+		_curSound = 0;
+		_lastSoundEffectPrio = 0;
+		checkRestartSoundEffects();
+	}
+}
+
+void I3MPlayer::checkRestartSoundEffects() {
+	for (int i = 1; i < _idRangeMax; ++i) {
+		if (!_soundUsage[i] || isSong(i))
+			continue;
+
+		const uint8 *ptr = _vm->getResourceAddress(rtSound, i);
+		assert(ptr);
+		if (READ_BE_UINT16(ptr + 6) == 0)
+			continue;
+
+		_soundUsage[i] = 1;
+		startSoundEffect(i);
+	}
+}
+
+const uint8 I3MPlayer::_fourToneSynthWaveForm[256] = {
+	0x80, 0x7a, 0x74, 0x6e, 0x69, 0x63, 0x5d, 0x57, 0x52, 0x4c, 0x47, 0x42, 0x3e, 0x3b, 0x38, 0x35,
+	0x34, 0x33, 0x34, 0x35, 0x37, 0x3a, 0x3e, 0x43, 0x49, 0x4e, 0x54, 0x5b, 0x61, 0x67, 0x6c, 0x71,
+	0x75, 0x78, 0x7a, 0x7c, 0x7c, 0x7b, 0x79, 0x76, 0x73, 0x6f, 0x6b, 0x66, 0x62, 0x5e, 0x5b, 0x58,
+	0x56, 0x56, 0x57, 0x59, 0x5c, 0x61, 0x67, 0x6e, 0x77, 0x80, 0x8a, 0x95, 0xa0, 0xac, 0xb7, 0xc2,
+	0xcc, 0xd6, 0xdf, 0xe7, 0xee, 0xf4, 0xf8, 0xfb, 0xfe, 0xff, 0xff, 0xfe, 0xfd, 0xfb, 0xf9, 0xf6,
+	0xf3, 0xf0, 0xec, 0xe9, 0xe6, 0xe3, 0xe0, 0xdd, 0xda, 0xd7, 0xd4, 0xd1, 0xce, 0xca, 0xc6, 0xc2,
+	0xbd, 0xb8, 0xb3, 0xad, 0xa7, 0xa1, 0x9a, 0x93, 0x8d, 0x86, 0x7f, 0x79, 0x73, 0x6d, 0x68, 0x63,
+	0x5f, 0x5c, 0x5a, 0x58, 0x57, 0x57, 0x58, 0x5a, 0x5c, 0x5f, 0x63, 0x67, 0x6b, 0x70, 0x75, 0x7b,
+	0x80, 0x85, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa1, 0xa4, 0xa6, 0xa8, 0xa9, 0xa9, 0xa8, 0xa6, 0xa4,
+	0xa1, 0x9d, 0x98, 0x93, 0x8d, 0x87, 0x81, 0x7a, 0x73, 0x6d, 0x66, 0x5f, 0x59, 0x53, 0x4d, 0x48,
+	0x43, 0x3e, 0x3a, 0x36, 0x32, 0x2f, 0x2c, 0x29, 0x26, 0x23, 0x20, 0x1d, 0x1a, 0x17, 0x14, 0x10,
+	0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x02, 0x05, 0x08, 0x0c, 0x12, 0x19, 0x21, 0x2a,
+	0x34, 0x3e, 0x49, 0x54, 0x60, 0x6b, 0x76, 0x80, 0x89, 0x92, 0x99, 0x9f, 0xa4, 0xa7, 0xa9, 0xaa,
+	0xaa, 0xa8, 0xa5, 0xa2, 0x9e, 0x9a, 0x95, 0x91, 0x8d, 0x8a, 0x87, 0x85, 0x84, 0x84, 0x86, 0x88,
+	0x8b, 0x8f, 0x94, 0x99, 0x9f, 0xa5, 0xac, 0xb2, 0xb7, 0xbd, 0xc2, 0xc6, 0xc9, 0xcb, 0xcc, 0xcd,
+	0xcc, 0xcb, 0xc8, 0xc5, 0xc2, 0xbe, 0xb9, 0xb4, 0xae, 0xa9, 0xa3, 0x9d, 0x97, 0x92, 0x8c, 0x86
+};
+
+void I3MPlayer::endOfTrack() {
+	if (!_activeChanCount || !--_activeChanCount)
+		finishSong();
+}
+
+bool I3MPlayer::isSong(int id) const {
+	return (Common::find(_musicIDTable, &_musicIDTable[_musicIDTableLen], id) != &_musicIDTable[_musicIDTableLen]);
+}
+
+bool I3MPlayer::isHiQuality() const {
+	return _mixerThread ? _qualHi : (_qmode == Player_Mac_Indy3::kQualAuto && (_vm->VAR_SOUNDCARD == 0xff || _vm->VAR(_vm->VAR_SOUNDCARD) == 11)) || (_qmode == Player_Mac_Indy3::kQualHi);
+}
+
+I3MPlayer::MusicChannel *I3MPlayer::getMusicChannel(uint8 id) const {
+	return (id < _numMusicChannels) ? _musicChannels[id] : 0;
 }
 
 uint16 savedOffset = 0;
 I3MPlayer::MusicChannel *I3MPlayer::MusicChannel::_ctrlChan = nullptr;
 
 I3MPlayer::MusicChannel::MusicChannel(I3MPlayer *pl) : _player(pl), _vars(nullptr), _numVars(0), _ctrlProc(nullptr),
-	_resSize(0), _savedOffset(savedOffset), _modShapes(g_pv2ModTbl), _modShapesTableSize(g_pv2ModTblSize) {
+_resSize(0), _savedOffset(savedOffset), _modShapes(g_pv2ModTbl), _modShapesTableSize(g_pv2ModTblSize) {
 	static const CtrlProc ctrl[8] {
 		&I3MPlayer::MusicChannel::ctrl_setShape,
 		&I3MPlayer::MusicChannel::ctrl_modPara,
@@ -1335,11 +1508,11 @@ I3MPlayer::MusicChannel::MusicChannel(I3MPlayer *pl) : _player(pl), _vars(nullpt
 	};
 
 	const uint16 *mVars[] = {
-	/*  0 */	&_frameLen,			&_curPos,			&_freqCur,			&_freqIncr,			&_freqEff,
-	/*  5 */	&_envPhase,			&_envRate,			&_tempo,			&_envSust,			(uint16*)&_transpose,
-	/* 10 */	&_envAtt,			&_envShape,			&_envStep,			&_envStepLen,		&_modType,
-	/* 15 */	&_modState,			&_modStep,			&_modSensitivity,	&_modRange,			&_localVars[0],
-	/* 20 */	&_localVars[1],		&_localVars[2],		&_localVars[3],		&_localVars[4]
+		/*  0 */	&_frameLen,			&_curPos,			&_freqCur,			&_freqIncr,			&_freqEff,
+		/*  5 */	&_envPhase,			&_envRate,			&_tempo,			&_envSust,			(uint16*)&_transpose,
+		/* 10 */	&_envAtt,			&_envShape,			&_envStep,			&_envStepLen,		&_modType,
+		/* 15 */	&_modState,			&_modStep,			&_modSensitivity,	&_modRange,			&_localVars[0],
+		/* 20 */	&_localVars[1],		&_localVars[2],		&_localVars[3],		&_localVars[4]
 	};
 
 	_ctrlProc = ctrl;
@@ -1624,80 +1797,6 @@ const uint32 I3MPlayer::MusicChannel::_envShapes[98] = {
 	0x88b8ffff, 0x01f40014, 0x00000000, 0x00000000, 0xafc8ffff, 0xfe0c003c, 0x0000ffff, 0x00000000
 };
 
-void I3MPlayer::updateSoundEffect() {
-	_sdrv->resetSignal(false);
-	bool chkRestart = false;
-
-	if (!_soundEffectPlaying || !_lastSound) {
-		chkRestart = true;
-	} else {
-		if (_soundEffectNumLoops > 0)
-			--_soundEffectNumLoops;
-		if (_soundEffectNumLoops)
-			_sdrv->play(&_pcmSnd);
-		else
-			--_soundUsage[_lastSound];
-		chkRestart = (_soundEffectNumLoops == 0);
-	}
-
-	if (chkRestart) {
-		_lastSound = 0;
-		_lastSoundEffectPrio = 0;
-		checkRestartSoundEffects();
-	}
-}
-
-void I3MPlayer::checkRestartSoundEffects() {
-	for (int i = 1; i < _idRangeMax; ++i) {
-		if (!_soundUsage[i] || isSong(i))
-			continue;
-
-		const uint8 *ptr = _vm->getResourceAddress(rtSound, i);
-		assert(ptr);
-		if (READ_BE_UINT16(ptr + 6) == 0)
-			continue;
-
-		_soundUsage[i] = 1;
-		startSoundEffect(i);
-	}
-}
-
-const uint8 I3MPlayer::_fourToneSynthWaveForm[256] = {
-	0x80, 0x7a, 0x74, 0x6e, 0x69, 0x63, 0x5d, 0x57, 0x52, 0x4c, 0x47, 0x42, 0x3e, 0x3b, 0x38, 0x35,
-	0x34, 0x33, 0x34, 0x35, 0x37, 0x3a, 0x3e, 0x43, 0x49, 0x4e, 0x54, 0x5b, 0x61, 0x67, 0x6c, 0x71,
-	0x75, 0x78, 0x7a, 0x7c, 0x7c, 0x7b, 0x79, 0x76, 0x73, 0x6f, 0x6b, 0x66, 0x62, 0x5e, 0x5b, 0x58,
-	0x56, 0x56, 0x57, 0x59, 0x5c, 0x61, 0x67, 0x6e, 0x77, 0x80, 0x8a, 0x95, 0xa0, 0xac, 0xb7, 0xc2,
-	0xcc, 0xd6, 0xdf, 0xe7, 0xee, 0xf4, 0xf8, 0xfb, 0xfe, 0xff, 0xff, 0xfe, 0xfd, 0xfb, 0xf9, 0xf6,
-	0xf3, 0xf0, 0xec, 0xe9, 0xe6, 0xe3, 0xe0, 0xdd, 0xda, 0xd7, 0xd4, 0xd1, 0xce, 0xca, 0xc6, 0xc2,
-	0xbd, 0xb8, 0xb3, 0xad, 0xa7, 0xa1, 0x9a, 0x93, 0x8d, 0x86, 0x7f, 0x79, 0x73, 0x6d, 0x68, 0x63,
-	0x5f, 0x5c, 0x5a, 0x58, 0x57, 0x57, 0x58, 0x5a, 0x5c, 0x5f, 0x63, 0x67, 0x6b, 0x70, 0x75, 0x7b,
-	0x80, 0x85, 0x8b, 0x90, 0x95, 0x99, 0x9d, 0xa1, 0xa4, 0xa6, 0xa8, 0xa9, 0xa9, 0xa8, 0xa6, 0xa4,
-	0xa1, 0x9d, 0x98, 0x93, 0x8d, 0x87, 0x81, 0x7a, 0x73, 0x6d, 0x66, 0x5f, 0x59, 0x53, 0x4d, 0x48,
-	0x43, 0x3e, 0x3a, 0x36, 0x32, 0x2f, 0x2c, 0x29, 0x26, 0x23, 0x20, 0x1d, 0x1a, 0x17, 0x14, 0x10,
-	0x0d, 0x0a, 0x07, 0x05, 0x03, 0x02, 0x01, 0x01, 0x02, 0x05, 0x08, 0x0c, 0x12, 0x19, 0x21, 0x2a,
-	0x34, 0x3e, 0x49, 0x54, 0x60, 0x6b, 0x76, 0x80, 0x89, 0x92, 0x99, 0x9f, 0xa4, 0xa7, 0xa9, 0xaa,
-	0xaa, 0xa8, 0xa5, 0xa2, 0x9e, 0x9a, 0x95, 0x91, 0x8d, 0x8a, 0x87, 0x85, 0x84, 0x84, 0x86, 0x88,
-	0x8b, 0x8f, 0x94, 0x99, 0x9f, 0xa5, 0xac, 0xb2, 0xb7, 0xbd, 0xc2, 0xc6, 0xc9, 0xcb, 0xcc, 0xcd,
-	0xcc, 0xcb, 0xc8, 0xc5, 0xc2, 0xbe, 0xb9, 0xb4, 0xae, 0xa9, 0xa3, 0x9d, 0x97, 0x92, 0x8c, 0x86
-};
-
-void I3MPlayer::endOfTrack() {
-	if (!_activeChanCount || !--_activeChanCount)
-		stopSong();
-}
-
-bool I3MPlayer::isSong(int id) const {
-	return (Common::find(_musicIDTable, &_musicIDTable[_musicIDTableLen], id) != &_musicIDTable[_musicIDTableLen]);
-}
-
-bool I3MPlayer::isHiQuality() const {
-	return _mixerThread ? _qualHi : (_qmode == Player_Mac_Indy3::kQualAuto && (_vm->VAR_SOUNDCARD == 0xff || _vm->VAR(_vm->VAR_SOUNDCARD) == 11)) || (_qmode == Player_Mac_Indy3::kQualHi);
-}
-
-I3MPlayer::MusicChannel *I3MPlayer::getMusicChannel(uint8 id) const {
-	return (id < _numMusicChannels) ? _musicChannels[id] : 0;
-}
-
 Player_Mac_Indy3::Player_Mac_Indy3(ScummEngine *vm, Audio::Mixer *mixer) : _player(nullptr) {
 	_player = I3MPlayer::open(vm, mixer);
 }




More information about the Scummvm-git-logs mailing list