[Scummvm-git-logs] scummvm master -> fa802b5d5e73875e53e42b964df5a15b8e154628

athrxx noreply at scummvm.org
Fri Nov 29 16:38:54 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:
fa802b5d5e SCUMM: (IMS/Mac) - add Samnmax specific code to sound driver


Commit: fa802b5d5e73875e53e42b964df5a15b8e154628
    https://github.com/scummvm/scummvm/commit/fa802b5d5e73875e53e42b964df5a15b8e154628
Author: athrxx (athrxx at scummvm.org)
Date: 2024-11-29T16:55:20+01:00

Commit Message:
SCUMM: (IMS/Mac) - add Samnmax specific code to sound driver

(also some minor fixes and cleanup)

Changed paths:
    engines/scumm/imuse/drivers/macintosh.cpp


diff --git a/engines/scumm/imuse/drivers/macintosh.cpp b/engines/scumm/imuse/drivers/macintosh.cpp
index ae67282ceb3..801392a9b00 100644
--- a/engines/scumm/imuse/drivers/macintosh.cpp
+++ b/engines/scumm/imuse/drivers/macintosh.cpp
@@ -34,9 +34,13 @@
 namespace IMSMacintosh {
 using namespace Scumm;
 
+enum : byte {
+	kRhythmPart = 9
+};
+
 struct ChanControlNode;
 struct DeviceChannel {
-	DeviceChannel(const uint32 *_pitchTable) : pitchTable(_pitchTable), frequency(0), phase(0), end(nullptr), pos(nullptr), smpBuffStart(nullptr),
+	DeviceChannel(const uint32 *pitchtable) : pitchTable(pitchtable), frequency(0), phase(0), end(nullptr), pos(nullptr), smpBuffStart(nullptr),
 		smpBuffEnd(nullptr), loopStart(nullptr), loopEnd(nullptr), pitch(0), mute(true), release(false), instr(nullptr),
 		prog(0), baseFreq(0), note(0), volumeL(0), volumeR(0), rate(0), totalLevelL(0), totalLevelR(0), node(nullptr), prev(nullptr), next(nullptr) {}
 	~DeviceChannel() {}
@@ -82,7 +86,7 @@ public:
 	virtual void setQuality(int qual) = 0;
 	void noteOn(const ChanControlNode *node);
 	void noteOff(const ChanControlNode *node);
-	void soundOff(const ChanControlNode *node);
+	void voiceOff(const ChanControlNode *node);
 	void setVolume(const ChanControlNode *node);
 	void setPitchBend(const ChanControlNode *node);
 
@@ -149,9 +153,9 @@ public:
 
 private:
 	bool loadInstruments(const char *const *fileNames, int numFileNames) override;
-	void setInstrument(DeviceChannel *c) override;
-	void recalcFrequency(DeviceChannel *c) override;
-	void recalcVolume(DeviceChannel *c) override;
+	void setInstrument(DeviceChannel *chan) override;
+	void recalcFrequency(DeviceChannel *chan) override;
+	void recalcVolume(DeviceChannel *chan) override;
 	void noteOffIntern(DeviceChannel *chan) override;
 
 	DeviceChannel *allocateChannel(const ChanControlNode *node) override;
@@ -238,6 +242,9 @@ private:
 	byte _panPos;
 	int16 _detune;
 	int8 _transpose;
+	byte _polyphony;
+	byte _usage;
+	bool _overuse;
 	int16 _pitchBendSet;
 	byte _pitchBendSensitivity;
 	int16 _pitchBendEff;
@@ -262,10 +269,11 @@ private:
 };
 
 struct ChanControlNode {
-	ChanControlNode(int num) : in(nullptr), number(num), note(0), sustain(false), prio(0x7F), volume(0x7F), panPos(0x40), velocity(0), pitchBend(0), prog(0), prev(nullptr), next(nullptr) {}
+	ChanControlNode(byte num) : in(nullptr), number(num), note(0), sustain(false), rhythmPart(false), prio(0x7F), volume(0x7F), panPos(0x40), velocity(0), pitchBend(0), prog(0), prev(nullptr), next(nullptr) {}
 	IMuseChannel_Macintosh *in;
 	const byte number;
 	bool sustain;
+	bool rhythmPart;
 	byte prio;
 	byte note;
 	byte volume;
@@ -352,7 +360,7 @@ bool IMSMacSoundSystem::init(const char *const *instrFileNames, int numInstrFile
 		return false;
 
 	_internal16Bit = internal16Bit;
-	_stereo = _version > 0 && stereo;
+	_stereo = (_version) > 0 && stereo;
 
 	uint16 feedBufferSize = _stereo ? 2048 : 1024;
 	if (_feedBufferSize != feedBufferSize) {
@@ -401,10 +409,11 @@ bool IMSMacSoundSystem::init(const char *const *instrFileNames, int numInstrFile
 
 	_macstr->initBuffers(1024);
 	_macstr->addVolumeGroup(Audio::Mixer::kMusicSoundType);
-	// Only MI2 and FOA have MIDI sound effects
-	if (_version == 0)
+	// Only MI2 and FOA have MIDI sound effects. Also, the later versions use a different update method.
+	if (_version == 0) {
 		_macstr->addVolumeGroup(Audio::Mixer::kSFXSoundType);
-	_macstr->setVblCallback(&_vblTskProc);
+		_macstr->setVblCallback(&_vblTskProc);
+	}
 
 	_mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, _macstr, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
 
@@ -415,6 +424,7 @@ void IMSMacSoundSystem::deinit() {
 	Common::StackLock lock(_mixer->mutex());
 	stop();
 	_mixer->stopHandle(_soundHandle);
+	_timerProc = nullptr;
 	delete _macstr;
 	_macstr = nullptr;
 	delete _sdrv;
@@ -445,12 +455,12 @@ void IMSMacSoundSystem::noteOn(const ChanControlNode *node) {
 	if (c->instr == nullptr)
 		return;
 
-	debug(6, "%s(): chan %d, note %d, instr id %d (%s)", __FUNCTION__, node->number, node->note, node->prog, c->instr.get()->name());
+	debug(6, "NOTE ON: ims part %d, chan node %d, note %d, instr id %d (%s)", node->in ? node->in->getNumber() : node->number, node->number, node->note, node->prog, c->instr.get()->name());
 
 	recalcVolume(c);
 
 	const MacLowLevelPCMDriver::PCMSound *s = c->instr.get()->data();
-	c->baseFreq = (node->number != 9) ? s->baseFreq : 60;
+	c->baseFreq = !node->rhythmPart ? s->baseFreq : 60;
 	c->rate = s->rate;
 	c->smpBuffStart = s->data.get();
 	c->smpBuffEnd = c->smpBuffStart + s->len;
@@ -475,18 +485,21 @@ void IMSMacSoundSystem::noteOff(const ChanControlNode *node) {
 	Common::StackLock lock(_mixer->mutex());
 	for (int i = 0; i < _numChannels; ++i) {
 		DeviceChannel *c = _channels[i];
-		if (c->node == node)
+		if (c->node == node) {
 			noteOffIntern(c);
+			c->node = nullptr;
+		}
 	}
 }
 
-void IMSMacSoundSystem::soundOff(const ChanControlNode *node) {
+void IMSMacSoundSystem::voiceOff(const ChanControlNode *node) {
 	Common::StackLock lock(_mixer->mutex());
 	for (int i = 0; i < _numChannels; ++i) {
 		DeviceChannel *c = _channels[i];
 		if (c->node == node) {
 			c->mute = true;
 			c->release = false;
+			c->node = nullptr;
 		}
 	}
 }
@@ -532,6 +545,9 @@ const MacSoundDriver::Status &IMSMacSoundSystem::getDriverStatus(Audio::Mixer::S
 }
 
 void IMSMacSoundSystem::dblBuffCallback(MacLowLevelPCMDriver::DoubleBuffer *dblBuffer) {
+	if (_version > 0 && _timerProc)
+		_timerProc(_timerParam);
+
 	uint16 sil = 0;
 	memset(_mixBuffer16Bit, 0, _feedBufferSize * sizeof(uint16));
 	uint16 frameSize = _stereo ? 2 : 1;
@@ -752,19 +768,19 @@ bool DJMSoundSystem::loadInstruments(const char *const *fileNames, int numFileNa
 	return !_smpResources.empty();
 }
 
-void DJMSoundSystem::setInstrument(DeviceChannel *c) {
-	assert(c && c->node);
-	if (c->instr == nullptr || c->prog != c->node->prog) {
-		c->instr = getSndResource(c->node->prog);
-		c->prog = c->node->prog;
+void DJMSoundSystem::setInstrument(DeviceChannel *chan) {
+	assert(chan && chan->node);
+	if (chan->instr == nullptr || chan->prog != chan->node->prog) {
+		chan->instr = getSndResource(chan->node->prog);
+		chan->prog = chan->node->prog;
 	}
 }
 
-void DJMSoundSystem::recalcFrequency(DeviceChannel *c) {
-	assert(c);
-	c->recalcFrequency();
-	if (c->instr != nullptr)
-		c->mute = false;
+void DJMSoundSystem::recalcFrequency(DeviceChannel *chan) {
+	assert(chan);
+	chan->recalcFrequency();
+	if (chan->instr != nullptr)
+		chan->mute = false;
 }
 
 void DJMSoundSystem::recalcVolume(DeviceChannel *c) {
@@ -787,12 +803,12 @@ DeviceChannel *DJMSoundSystem::allocateChannel(const ChanControlNode *node) {
 	return c;
 }
 
-NewMacSoundSystem::NewMacSoundSystem(ScummEngine *vm, Audio::Mixer *mixer) : IMSMacSoundSystem(mixer, 1),
+NewMacSoundSystem::NewMacSoundSystem(ScummEngine *vm, Audio::Mixer *mixer) : IMSMacSoundSystem(mixer, 1), // It is sufficient to distinguish version 0 and 1 here.
 	_fileMan(nullptr), _container(vm ? vm->_containerFile : _dummy), _dbCbProc(this, &MacLowLevelPCMDriver::CallbackClient::dblBuffCallback) {
 	assert(vm);
 	_defaultInstrID = 0xFFFF;
 	_fileMan = new ScummFile(vm);
-}
+	}
 
 NewMacSoundSystem::~NewMacSoundSystem() {
 	delete _fileMan;
@@ -875,16 +891,16 @@ Common::SharedPtr<MacSndResource> NewMacSoundSystem::getNoteRangeSndResource(uin
 
 void NewMacSoundSystem::setInstrument(DeviceChannel *chan) {
 	assert(chan && chan->node);
-	if (chan->instr == nullptr || (chan->node->number != 9 && chan->prog != chan->node->prog) || chan->note != chan->node->note) {
+	if (chan->instr == nullptr || (!chan->node->rhythmPart && chan->prog != chan->node->prog) || chan->note != chan->node->note) {
 		chan->note = chan->node->note;
 		chan->prog = chan->node->prog;
-		chan->instr = (chan->node->number == 9) ? getSndResource(6000 + chan->note) : getNoteRangeSndResource(chan->prog, chan->note);
+		chan->instr = chan->node->rhythmPart ? getSndResource(6000 + chan->note) : getNoteRangeSndResource(chan->prog, chan->note);
 	}
 }
 
 void NewMacSoundSystem::recalcFrequency(DeviceChannel *chan) {
 	assert(chan && chan->node);
-	if (chan->node->number == 9)
+	if (chan->node->rhythmPart)
 		chan->frequency = 0x8000;
 	else
 		chan->recalcFrequency();
@@ -950,7 +966,7 @@ void NewMacSoundSystem::recalcVolume(DeviceChannel *chan) {
 
 void NewMacSoundSystem::noteOffIntern(DeviceChannel *chan) {
 	assert(chan && chan->node);
-	if (chan->node->number != 9)
+	if (!chan->node->rhythmPart)
 		chan->release = true;
 	chan->loopStart = nullptr;
 	chan->loopEnd = chan->smpBuffEnd;
@@ -1001,10 +1017,10 @@ DeviceChannel *NewMacSoundSystem::allocateChannel(const ChanControlNode *node) {
 
 byte IMuseChannel_Macintosh::_allocCur = 0;
 
-IMuseChannel_Macintosh::IMuseChannel_Macintosh(IMuseDriver_Macintosh *drv, int number) : MidiChannel(), _drv(drv), _number(number), _allocated(false),
-	_sustain(false), _bank(0), _panPos(0x40), _pitchBendEff(0), _prio(0x80), _detune(0), _transpose(0), _pitchBendSet(0), _pitchBendSensitivity(2), _volume(0x7F),
-	_rpn(0), _pitchBendRange(0), _channels(drv ? drv->_channels : nullptr), _prog(0), _out(nullptr), _device(drv ? drv->_device : nullptr), _version(drv->_version),
-	_rtmChannel((drv && drv->_version > 0) ? drv->_channels[drv->_numChannels - 1] : nullptr), _numChannels(drv ? (drv->_version < 1 ? drv->_numChannels : drv->_numChannels - 1) : 0) {
+IMuseChannel_Macintosh::IMuseChannel_Macintosh(IMuseDriver_Macintosh *drv, int number) : MidiChannel(), _drv(drv), _number(number), _allocated(false), _polyphony(1), _usage(0),
+	_sustain(false), _bank(0), _panPos(0x40), _pitchBendEff(0), _prio(0x80), _detune(0), _transpose(0), _pitchBendSet(0), _pitchBendSensitivity(2), _volume(0x7F), _overuse(false),
+	_rpn(0), _pitchBendRange(0), _channels(drv ? drv->_channels : nullptr), _prog(0), _out(nullptr), _device(drv ? drv->_device : nullptr), _version(drv ? drv->_version : -1),
+	_rtmChannel((drv && drv->_version == 1) ? drv->_channels[drv->_numChannels - 1] : nullptr), _numChannels(drv ? (drv->_version != 1 ? drv->_numChannels : drv->_numChannels - 1) : 0) {
 	assert(_drv);
 	assert(_channels);
 	assert(_device);
@@ -1015,11 +1031,14 @@ bool IMuseChannel_Macintosh::allocate() {
 	if (_allocated)
 		return false;
 
+	_usage = 0;
+	_overuse = false;
+
 	return (_allocated = true);
 }
 
 void IMuseChannel_Macintosh::noteOff(byte note)  {
-	for (ChanControlNode *node = (_version > 0 && _number == 9) ? _rtmChannel : _out; node; ) {
+	for (ChanControlNode *node = (_version == 1 && _number == kRhythmPart) ? _rtmChannel : _out; node; ) {
 		ChanControlNode *n = node->next;
 		if (node->note == note) {
 			if (_sustain && node != _rtmChannel) {
@@ -1027,6 +1046,8 @@ void IMuseChannel_Macintosh::noteOff(byte note)  {
 			} else {
 				_device->noteOff(node);
 				disconnect(_out, node);
+				if (_version == 2)
+					_overuse = (--_usage > _polyphony);
 			}
 		}
 		node = n;
@@ -1034,21 +1055,24 @@ void IMuseChannel_Macintosh::noteOff(byte note)  {
 }
 
 void IMuseChannel_Macintosh::noteOn(byte note, byte velocity)  {
-	ChanControlNode *node = (_version > 0 && _number == 9) ? _rtmChannel : allocateNode(_prio);
+	ChanControlNode *node = allocateNode(_prio);
 	if (node == nullptr)
 		return;
 
-	if (node != _rtmChannel) {
-		if (_prog == 0)
-			return;
-		connect(_out, node);
+	if (_version == 0 || _number != kRhythmPart) {
 		node->in = this;
 		node->prio = _prio;
 		node->prog = _prog;
 		node->pitchBend = _pitchBendEff;
 		node->volume = _volume;
+		node->rhythmPart = false;
 	} else {
+		if (_version == 2) {
+			node->in = this;
+			node->prio = _prio;
+		}
 		node->volume = _volume * 6 / 7;
+		node->rhythmPart = true;
 	}
 
 	node->note = note;
@@ -1056,6 +1080,9 @@ void IMuseChannel_Macintosh::noteOn(byte note, byte velocity)  {
 	node->panPos = _panPos;
 	node->velocity = velocity;
 
+	if (_version == 2)
+		_overuse = (++_usage > _polyphony);
+
 	_device->noteOn(node);
 }
 
@@ -1063,8 +1090,8 @@ void IMuseChannel_Macintosh::controlChange(byte control, byte value)  {
 	switch (control) {
 	case 0:
 		// The original MI2/INDY4 code doesn't have that. It will just call a different
-		// programChange() method from the sysex handler. Only DOTT and SAMNMAX have the
-		// bank select like this in the original code.
+		// programChange() method from the sysex handler. Only DOTT and SAMNMAX call a
+		// bank select, but the actual selection is not implemented, since it is not needed.
 		_bank = value;
 		break;
 	case 6:
@@ -1078,6 +1105,15 @@ void IMuseChannel_Macintosh::controlChange(byte control, byte value)  {
 			_panPos = value;
 		updateVolume();
 		break;
+	case 17:
+		if (_version == 2)
+			_polyphony = value;
+		else
+			detune(value);
+		break;
+	case 18:
+		priority(value);
+		break;
 	case 64:
 		sustain(value);
 		break;
@@ -1087,6 +1123,9 @@ void IMuseChannel_Macintosh::controlChange(byte control, byte value)  {
 	case 101:
 		_rpn = value | 0x80;
 		break;
+	case 123:
+		allNotesOff();
+		break;
 	default:
 		break;
 	}
@@ -1107,10 +1146,9 @@ void IMuseChannel_Macintosh::pitchBend(int16 bend)  {
 	else
 		bend = ((bend * _pitchBendSensitivity) >> 6) + _detune + (_transpose << 7); // DOTT, INDY4 and MI2 formula
 
-	if (_version == 1)
-		bend = CLIP<int16>(bend, -2048, 2047) << 2;
-
 	if (_version > 0) {
+		if (_version == 1)
+			bend = CLIP<int16>(bend, -2048, 2047) << 2;
 		if (bend > 7936)
 			bend = 8192;
 		else if (bend < -7936)
@@ -1120,6 +1158,9 @@ void IMuseChannel_Macintosh::pitchBend(int16 bend)  {
 
 	_pitchBendEff = bend;
 
+	if (_pitchBendSet)
+		debug(6, "PITCH BEND: ims part %d, pb para %d, pb snstvty %d, pb range %d, _detune %d, transpose %d, pb eff %d", _number, _pitchBendSet, _pitchBendSensitivity, _pitchBendRange, _detune, _transpose, _pitchBendEff);
+
 	for (ChanControlNode *node = _out; node; node = node->next) {
 		node->pitchBend = _pitchBendEff;
 		_device->setPitchBend(node);
@@ -1136,16 +1177,20 @@ void IMuseChannel_Macintosh::sustain(bool value) {
 		if (node->sustain) {
 			_device->noteOff(node);
 			disconnect(_out, node);
+			if (_version == 2)
+				_overuse = (--_usage > _polyphony);
 		}
 		node = n;
 	}
 }
 
 void IMuseChannel_Macintosh::allNotesOff() {
-	for (ChanControlNode *node = (_version > 0 && _number == 9) ? _rtmChannel : _out; node; ) {
-		_device->soundOff(node);
+	for (ChanControlNode *node = (_version == 1 && _number == kRhythmPart) ? _rtmChannel : _out; node; ) {
+		_device->voiceOff(node);
 		ChanControlNode *n = node->next;
 		disconnect(_out, node);
+		if (_version == 2)
+			_overuse = (--_usage > _polyphony);
 		node = n;
 	}
 }
@@ -1167,31 +1212,51 @@ void IMuseChannel_Macintosh::dataEntry(byte value) {
 void IMuseChannel_Macintosh::updateVolume() {
 	for (ChanControlNode *node = _out; node; node = node->next) {
 		node->panPos = _panPos;
-		node->volume = (node == _rtmChannel) ? _volume * 6 / 7 : _volume;
+		node->volume = (_version > 0 && _number == kRhythmPart) ? _volume * 6 / 7 : _volume;
 		_device->setVolume(node);
 	}
 }
 
 ChanControlNode *IMuseChannel_Macintosh::allocateNode(int prio) {
-	ChanControlNode *res = nullptr;
-	if (_version > 0)
+	if (_version > 0) {
 		_allocCur = 0;
+		if (_version == 1 && _number == kRhythmPart)
+			return _rtmChannel;
+	}
+
+	if (_version < 1 && _prog == 0)
+		return nullptr;
+
+	IMuseChannel_Macintosh *best = this;
+	ChanControlNode *res = nullptr;
 
 	for (byte i = 0; i < _numChannels; ++i) {
 		_allocCur = (_allocCur + 1) % _numChannels;
 		ChanControlNode *node = _channels[_allocCur];
-		if (node->in == nullptr)
-			return node;
-		if (!node->next && node->in && node->in->_prio <= prio) {
+		if (node->in == nullptr) {
 			res = node;
-			prio = node->in->_prio;
+			best = nullptr;
+			break;
+		}
+
+		if ((_version == 2 && ((best->_overuse == node->in->_overuse && best->_prio >= node->prio) || (!best->_overuse && node->in->_overuse))) ||
+			(_version < 2 && (!node->next && node->in && node->in->_prio <= prio))) {
+			res = node;
+			best = node->in;
+			prio = best->_prio;
 		}
 	}
 
-	if (res) {
-		_device->soundOff(res);
-		disconnect(res->in->_out, res);
+	if (res && best) {
+		if (_version == 2)
+			best->_overuse = (--best->_usage > best->_polyphony);
+		_device->voiceOff(res);
+		disconnect(best->_out, res);
 	}
+
+	assert(!(_out && _out == res));
+	connect(_out, res);
+
 	return res;
 }
 
@@ -1201,21 +1266,19 @@ namespace Scumm {
 using namespace IMSMacintosh;
 
 IMuseDriver_Macintosh::IMuseDriver_Macintosh(ScummEngine *vm, Audio::Mixer *mixer, byte gameID) : MidiDriver(), _isOpen(false), _device(nullptr), _imsParts(nullptr), _channels(nullptr),
-	_numParts(24), _numChannels(8), _baseTempo(16666), _quality(1), _musicVolume(0), _sfxVolume(0), _version(-1) {
+	_numParts(32), _numChannels(8), _baseTempo(16666), _quality(1), _musicVolume(0), _sfxVolume(0), _version(-1) {
 
 	switch (gameID) {
-	case GID_SAMNMAX:
-		_version = 2;
-		_numChannels = 16;
-		_numParts = 32;
-		//_baseTempo = 46439;
-		_device = new NewMacSoundSystem(vm, mixer);
-		break;
 	case GID_TENTACLE:
-		_version = 1;
-		_numChannels = 16;
-		_numParts = 32;
-		//_baseTempo = 46439;
+	case GID_SAMNMAX:
+		if (gameID == GID_SAMNMAX) {
+			_version = 2;
+			_numChannels = 12;
+		} else {
+			_version = 1;
+			_numChannels = 16;
+		}
+		_baseTempo = 46439;
 		_device = new NewMacSoundSystem(vm, mixer);
 		break;
 	case GID_INDY4:
@@ -1279,7 +1342,7 @@ int IMuseDriver_Macintosh::open() {
 		_imsParts[i]->controlChange(0x00, 0x00);
 		_imsParts[i]->controlChange(0x7B, 0x00);
 		_imsParts[i]->programChange(0);
-		_imsParts[i]->pitchBend(0x2000);
+		_imsParts[i]->pitchBend(0);
 	}
 
 	return 0;
@@ -1340,7 +1403,7 @@ MidiChannel *IMuseDriver_Macintosh::allocateChannel() {
 
 	for (int i = 0; i < _numParts; ++i) {
 		IMuseChannel_Macintosh *ch = _imsParts[i];
-		if (ch && !(_version > 0 && i == 9) && ch->allocate())
+		if (ch && !(_version > 0 && i == kRhythmPart) && ch->allocate())
 			return ch;
 	}
 
@@ -1348,7 +1411,7 @@ MidiChannel *IMuseDriver_Macintosh::allocateChannel() {
 }
 
 MidiChannel *IMuseDriver_Macintosh::getPercussionChannel() {
-	return (_isOpen && _version > 0) ? _imsParts[9] : nullptr;
+	return (_isOpen && _version > 0) ? _imsParts[kRhythmPart] : nullptr;
 }
 
 void IMuseDriver_Macintosh::createChannels() {
@@ -1357,7 +1420,7 @@ void IMuseDriver_Macintosh::createChannels() {
 	_channels = new ChanControlNode*[_numChannels];
 	assert(_channels);
 	for (int i = 0; i < _numChannels; ++i) {
-		_channels[i] = new ChanControlNode(i < 9 ? i : (i == 15 ? 9 : i + 1));
+		_channels[i] = new ChanControlNode(i < kRhythmPart ? i : (i == _numChannels - 1 ? kRhythmPart : i + 1));
 		assert(_channels[i]);
 	}
 




More information about the Scummvm-git-logs mailing list