diff options
author | Paul Gilbert | 2011-06-13 16:31:35 +1000 |
---|---|---|
committer | Paul Gilbert | 2011-06-13 16:31:35 +1000 |
commit | 34fd272841c0dc80e3de2dd66b671eb84fe78aba (patch) | |
tree | ea4237c138b04a9374fd07492ea62378523a808d | |
parent | dc1c9224abb9b2ac1e79e8512d98ceba2436a889 (diff) | |
download | scummvm-rg350-34fd272841c0dc80e3de2dd66b671eb84fe78aba.tar.gz scummvm-rg350-34fd272841c0dc80e3de2dd66b671eb84fe78aba.tar.bz2 scummvm-rg350-34fd272841c0dc80e3de2dd66b671eb84fe78aba.zip |
TSAGE: Completed initial implementation of _sfRethinkVoiceTypes
-rw-r--r-- | engines/tsage/sound.cpp | 326 | ||||
-rw-r--r-- | engines/tsage/sound.h | 81 |
2 files changed, 361 insertions, 46 deletions
diff --git a/engines/tsage/sound.cpp b/engines/tsage/sound.cpp index ac7217a753..1976013946 100644 --- a/engines/tsage/sound.cpp +++ b/engines/tsage/sound.cpp @@ -358,7 +358,6 @@ void SoundManager::_sfSoundServer() { do { _sfProcessFading(); } while (sfManager()._serverSuspendedCount > 0); - sfManager()._serverSuspendedCount = 0; // Poll all sound drivers in case they need it for (Common::List<SoundDriver *>::iterator i = sfManager()._installedDrivers.begin(); @@ -416,12 +415,14 @@ void SoundManager::_sfProcessFading() { // Loop through the voiceType list for (int voiceIndex = 0; voiceIndex < SOUND_ARR_SIZE; ++voiceIndex) { - VoiceTypeStruct &voiceType = *sfManager()._voiceTypeStructPtrs[voiceIndex]; + VoiceTypeStruct *vtStruct = sfManager()._voiceTypeStructPtrs[voiceIndex]; + if (!vtStruct) + continue; - if (voiceType._voiceType == VOICETYPE_1) { - for (uint idx = 0; idx < voiceType._entries.size(); ++idx) { - if (voiceType._entries[idx]._type1._field6 >= -1) - ++voiceType._entries[idx]._type1._field6; + if (vtStruct->_voiceType == VOICETYPE_1) { + for (uint idx = 0; idx < vtStruct->_entries.size(); ++idx) { + if (vtStruct->_entries[idx]._type1._field6 >= -1) + ++vtStruct->_entries[idx]._type1._field6; } } } @@ -430,6 +431,8 @@ void SoundManager::_sfProcessFading() { void SoundManager::_sfUpdateVoiceStructs() { for (int voiceIndex = 0; voiceIndex < SOUND_ARR_SIZE; ++voiceIndex) { VoiceTypeStruct *vs = sfManager()._voiceTypeStructPtrs[voiceIndex]; + if (!vs) + continue; for (uint idx = 0; idx < vs->_entries.size(); ++idx) { VoiceStructEntry &vse = vs->_entries[idx]; @@ -496,6 +499,7 @@ void SoundManager::listenerSynchronize(Serializer &s) { /*--------------------------------------------------------------------------*/ SoundManager &SoundManager::sfManager() { + assert(_soundManager); return *_soundManager; } @@ -584,18 +588,15 @@ void SoundManager::_sfRethinkSoundDrivers() { } if (total) { - int dataSize = !flag ? total * 28 + 30 : total * 26 + 30; - debugC(9, ktSageSound, "data Size = %d\n", dataSize); - VoiceTypeStruct *vs = new VoiceTypeStruct(); sfManager()._voiceTypeStructPtrs[idx] = vs; if (!flag) { vs->_voiceType = VOICETYPE_0; - vs->_field1 = total; + vs->_total = total; } else { vs->_voiceType = VOICETYPE_1; - vs->_field1 = vs->_numVoices = total; + vs->_total = vs->_numVoices = total; } for (Common::List<SoundDriver *>::iterator i = sfManager()._installedDrivers.begin(); @@ -608,6 +609,8 @@ void SoundManager::_sfRethinkSoundDrivers() { byte byteVal = *groupData++; if (byteVal == idx) { + ++groupData; + if (!flag) { while ((byteVal = *groupData++) != 0xff) { VoiceStructEntry ve; @@ -628,7 +631,7 @@ void SoundManager::_sfRethinkSoundDrivers() { VoiceStructEntry ve; ve._voiceNum = idx; ve._driver = driver; - ve._type1._field4 = 0xff; + ve._type1._field4 = -1; ve._type1._field5 = 0; ve._type1._field6 = 0; ve._type1._sound = NULL; @@ -642,6 +645,8 @@ void SoundManager::_sfRethinkSoundDrivers() { if (*groupData++ != 0) { while (*groupData != 0xff) ++groupData; + } else { + groupData += 2; } } } @@ -1171,6 +1176,8 @@ void SoundManager::_sfRethinkVoiceTypes() { } } } + + --sfManager()._serverSuspendedCount; } void SoundManager::_sfUpdateVolume(Sound *sound) { @@ -1287,7 +1294,7 @@ void SoundManager::_sfUnInstallDriver(SoundDriver *driver) { } void SoundManager::_sfInstallPatchBank(SoundDriver *driver, const byte *bankData) { - driver->installPatchBank(bankData); + driver->installPatch(bankData); } /** @@ -1392,7 +1399,6 @@ void Sound::play(int soundNum) { } void Sound::stop() { - _soundManager->removeFromPlayList(this); _unPrime(); } @@ -1458,7 +1464,8 @@ void Sound::_unPrime() { } _trackInfo._numTracks = 0; - _soundManager->removeFromSoundList(this); + if (_soundManager) + _soundManager->removeFromSoundList(this); _primed = false; _stoppedAsynchronously = false; @@ -1738,7 +1745,8 @@ void Sound::_soPrimeChannelData() { int mode = *d; int channelNum = (int8)*(d + 1); assert((channelNum >= 0) && (channelNum < 16)); - + + _trkChannel[idx] = channelNum; _chProgram[idx] = *(d + 10); _chModulation[idx] = 0; _chVolume[idx] = *(d + 11); @@ -1784,6 +1792,7 @@ void Sound::_soServiceTrackType0(int trackIndex, const byte *channelData) { return; int channelNum = _trkChannel[trackIndex]; + assert((channelNum >= 0) && (channelNum < SOUND_ARR_SIZE)); int chFlags = (channelNum == -1) ? 0 : _chFlags[channelNum]; int voiceNum = -1; SoundDriver *driver = NULL; @@ -1847,7 +1856,7 @@ void Sound::_soServiceTrackType0(int trackIndex, const byte *channelData) { if (chFlags & 0x10) _soProc42(vtStruct, channelNum, chVoiceType, v); else - _soProc32(vtStruct, channelNum, chVoiceType, v); + _soProc32(vtStruct, channelNum, chVoiceType, v, b); } else if (voiceNum != -1) { assert(driver); driver->proc20(voiceNum, chVoiceType); @@ -2011,7 +2020,7 @@ void Sound::_soUpdateDamper(VoiceTypeStruct *voiceType, int channelNum, VoiceTyp } } -void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0) { +void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0, int v1) { int entryIndex = _soFindSound(vtStruct, channelNum); if (entryIndex != -1) { SoundDriver *driver = vtStruct->_entries[entryIndex]._driver; @@ -2021,7 +2030,7 @@ void Sound::_soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice vtStruct->_entries[entryIndex]._type1._field4 = v0; vtStruct->_entries[entryIndex]._type1._field5 = 0; - driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum]); + driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, _chProgram[channelNum], v0, v1); } } @@ -2039,8 +2048,7 @@ void Sound::_soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voice vtStruct->_entries[entryIndex]._type1._field4 = v0; vtStruct->_entries[entryIndex]._type1._field5 = 0; - driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, voiceType, - _channelData[trackCtr], this, 0x7f, 0xff, 0xE); + driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, -1, v0, 0x7F); driver->proc42(vtStruct->_entries[entryIndex]._voiceNum, voiceType, 0); } break; @@ -2168,8 +2176,7 @@ void Sound::_soServiceTrackType1(int trackIndex, const byte *channelData) { vtStruct->_entries[entryIndex]._type1._field4 = *(channelData + 1); vtStruct->_entries[entryIndex]._type1._field5 = 0; - driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, voiceType, - _channelData[trackIndex], this, 0x7f, 0xff, 0xE); + driver->proc32(vtStruct->_entries[entryIndex]._voiceNum, -1, *(channelData + 1), 0x7f); } } else { @@ -2295,9 +2302,34 @@ SoundDriver::SoundDriver() { const byte adlib_group_data[] = { 1, 1, 9, 1, 0xff }; -AdlibSoundDriver::AdlibSoundDriver() { +const byte v440B0[9] = { 0, 1, 2, 6, 7, 8, 12, 13, 14 }; + +const byte v440B9[9] = { 3, 4, 5, 9, 10, 11, 15, 16, 17 }; + +const byte v440C2[18] = { + 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21 +}; + +const byte v44134[64] = { + 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 47, 48, 49, 50, 50, 51, 52, 52, 53, 54, 54, 55, + 56, 56, 57, 57, 58, 58, 59, 59, 59, 60, 60, 60, 61, 61, + 61, 62, 62, 62, 62, 63, 63, 63 +}; + +const int v440D4[48] = { + 343, 348, 353, 358, 363, 369, 374, 379, 385, 391, 396, + 402, 408, 414, 420, 426, 432, 438, 445, 451, 458, 465, + 471, 478, 485, 492, 499, 507, 514, 521, 529, 537, 544, + 552, 560, 569, 577, 585, 594, 602, 611, 620, 629, 638, + 647, 657, 666, 676 +}; + +AdlibSoundDriver::AdlibSoundDriver(): SoundDriver() { _minVersion = 0x102; _maxVersion = 0x10A; + _masterVolume = 0; _groupData.groupMask = 9; _groupData.v1 = 0x46; @@ -2305,6 +2337,252 @@ AdlibSoundDriver::AdlibSoundDriver() { _groupData.pData = &adlib_group_data[0]; _mixer = _vm->_mixer; + _sampleRate = _mixer->getOutputRate(); + _opl = makeAdLibOPL(_sampleRate); + + memset(_channelVoiced, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); + memset(_channelVolume, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); + memset(_v4405E, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); + memset(_v44067, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); + memset(_v44070, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); + memset(_v44079, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); + memset(_v44082, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); + _v44082[ADLIB_CHANNEL_COUNT] = 0x90; + Common::set_to(_v4408C, _v4408C + ADLIB_CHANNEL_COUNT, 0x2000); + memset(_v4409E, 0, ADLIB_CHANNEL_COUNT * sizeof(int)); +} + +AdlibSoundDriver::~AdlibSoundDriver() { + DEALLOCATE(_patchData); +} + +bool AdlibSoundDriver::open() { + write(1, 0x20); + if (!reset()) + return false; + + write(8, 0); + for (int idx = 0x20; idx < 0xF6; ++idx) + write(idx, 0); + + write(0xBD, 0); + return true; +} + +void AdlibSoundDriver::close() { + for (int idx = 0xB0; idx < 0xB8; ++idx) + write(idx, _portContents[idx] & 0xDF); + for (int idx = 0x40; idx < 0x55; ++idx) + write(idx, 0x3F); + reset(); +} + +bool AdlibSoundDriver::reset() { + write(1, 0x20); + write(4, 0x80); +/* + * code fragment originally part of testing Adlib timer speed + write(2, 1); + write(4, 1); +*/ + return true; +} + +const GroupData *AdlibSoundDriver::getGroupData() { + return &_groupData; +} + +void AdlibSoundDriver::installPatch(const byte *data) { + _patchData = data; +} + +int AdlibSoundDriver::setMasterVolume(int volume) { + int oldVolume = _masterVolume; + _masterVolume = volume; + + for (int channelNum = 0; channelNum < ADLIB_CHANNEL_COUNT; ++channelNum) + updateChannelVolume(channelNum); + + return oldVolume; +} + +void AdlibSoundDriver::proc32(int channel, int program, int v0, int v1) { + if (program == -1) + return; + + int offset = READ_LE_UINT16(_patchData + program * 2); + if (offset) { + const byte *dataP = _patchData + offset; + + for (int offset = 2, id = 0; id != READ_LE_UINT16(dataP); offset += 30, ++id) { + if ((dataP[offset] <= v0) && (dataP[offset + 1] >= v0)) { + if (dataP[offset + 2] != 0xff) + v0 = dataP[offset + 2]; + + // Set sustain/release + int portNum = v440C2[v440B0[channel]] + 0x80; + write(portNum, (_portContents[portNum] & 0xF0) | 0xF); + + portNum = v440C2[v440B9[channel]] + 0x80; + write(portNum, (_portContents[portNum] & 0xF0) | 0xF); + + if (_channelVoiced[channel]) + clearVoice(channel); + + _v44067[channel] = v0; + _v4405E[channel] = v1; + + updateChannel(channel); + setFrequency(channel); + updateChannelVolume(channel); + setVoice(channel); + break; + } + } + } +} + +void AdlibSoundDriver::updateVoice(int channel) { + if (_channelVoiced[channel]) + clearVoice(channel); +} + +void AdlibSoundDriver::proc38(int channel, int cmd, int value) { + if (cmd == 7) { + // Set channel volume + _channelVolume[channel] = value; + updateChannelVolume(channel); + } +} + +void AdlibSoundDriver::proc40(int channel, int pitchBlend) { + _v4408C[channel] = pitchBlend; + setFrequency(channel); +} + +void AdlibSoundDriver::write(byte reg, byte value) { +static int num = 0; +debug("%d [%x]=%x", ++num, reg, value);//***DEBUG**** + _portContents[reg] = value; + OPLWriteReg(_opl, reg, value); +} + +void AdlibSoundDriver::updateChannelVolume(int channelNum) { + int volume = (_masterVolume * _channelVolume[channelNum] / 127 * _v4405E[channelNum] / 127) / 2; + int level2 = 63 - v44134[volume * _v44079[channelNum] / 63]; + int level1 = !_v44082[channelNum] ? 63 - _v44070[channelNum] : + 63 - v44134[volume * _v44070[channelNum] / 63]; + + int portNum = v440C2[v440B0[channelNum]] + 0x40; + write(portNum, (_portContents[portNum] & 0x80) | level1); + + portNum = v440C2[v440B9[channelNum]] + 0x40; + write(portNum, (_portContents[portNum] & 0x80) | level2); +} + +void AdlibSoundDriver::setVoice(int channel) { + int portNum = 0xB0 + channel; + write(portNum, _portContents[portNum] | 0x20); + _channelVoiced[channel] = true; +} + +void AdlibSoundDriver::clearVoice(int channel) { + write(0xB0 + channel, _portContents[0xB0 + channel] & ~0x20); + _channelVoiced[channel] = false; +} + +void AdlibSoundDriver::updateChannel(int channel) { + const byte *dataP = _patchData + _v4409E[channel]; + int portOffset = v440C2[v440B0[channel]]; + + int portNum = portOffset + 0x20; + int portValue = 0; + if (*(dataP + 4)) + portValue |= 0x80; + if (*(dataP + 5)) + portValue |= 0x40; + if (*(dataP + 8)) + portValue |= 0x20; + if (*(dataP + 6)) + portValue |= 0x10; + portValue |= *(dataP + 7); + write(portNum, portValue); + + portValue = (_portContents[0x40 + portOffset] & 0x3F) | (*(dataP + 9) << 6); + write(0x40 + portOffset, portValue); + + _v44070[channel] = 63 - *(dataP + 10); + write(0x60 + portOffset, *(dataP + 12) | (*(dataP + 11) << 4)); + write(0x80 + portOffset, *(dataP + 14) | (*(dataP + 13) << 4)); + write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 15)); + + portNum = portOffset + 0x20; + portValue = 0; + if (*(dataP + 17)) + portValue |= 0x80; + if (*(dataP + 18)) + portValue |= 0x40; + if (*(dataP + 21)) + portValue |= 0x20; + if (*(dataP + 19)) + portValue |= 0x10; + portValue |= *(dataP + 20); + write(portNum, portValue); + + write(0x40 + portOffset, (_portContents[0x40 + portOffset] & 0x3f) | (*(dataP + 22) << 6)); + _v44079[channel] = *(dataP + 23); + write(0x60 + portOffset, *(dataP + 25) | (*(dataP + 24) << 4)); + write(0x80 + portOffset, *(dataP + 27) | (*(dataP + 26) << 4)); + write(0xE0 + portOffset, (_portContents[0xE0 + portOffset] & 0xFC) | *(dataP + 28)); + write(0xC0 + portOffset, (_portContents[0xE0 + portOffset] & 0xF0) + | (*(dataP + 16) << 1) | *(dataP + 3)); + + _v44082[channel] = *(dataP + 3); +} + +void AdlibSoundDriver::setFrequency(int channel) { + int offset, ch; + + int v = _v4408C[channel]; + if (v == 0x2000) { + offset = 0; + ch = _v44067[channel]; + } else if (v > 0x2000) { + ch = _v44067[channel]; + v -= 0x2000; + if (v == 0x1fff) + v = 0x2000; + + offset = (v / 170) & 3; + ch += (v / 170) >> 2; + + if (ch >= 128) + ch = 127; + } else { + ch = _v44067[channel]; + int tempVal = (0x2000 - v) / 170; + int tempVal2 = 4 - (tempVal & 3); + + if (tempVal2 == 4) + offset = 0; + else { + offset = tempVal2; + --ch; + } + + ch -= tempVal >> 2; + if (ch >= 128) + ch = 0; + } + + int var2 = ch / 12; + if (var2) + --var2; + + int dataWord = v440D4[((ch % 12) << 2) + offset]; + write(0xA0 + channel, dataWord & 0xff); + write(0xB0 + channel, (_portContents[0xB0 + channel] & 0xE0) | + ((dataWord >> 8) & 3) | (var2 << 2)); } } // End of namespace tSage diff --git a/engines/tsage/sound.h b/engines/tsage/sound.h index 1dc40b2e4c..fec065e0d2 100644 --- a/engines/tsage/sound.h +++ b/engines/tsage/sound.h @@ -78,24 +78,28 @@ public: const Common::String &getShortDriverDescription() { return _shortDescription; } const Common::String &getLongDriverDescription() { return _longDescription; } - virtual bool open() { return true; } - virtual void close() {} - virtual const GroupData *getGroupData() = 0; - virtual void installPatchBank(const byte *data) {} - virtual void poll() {} - virtual void setMasterVolume(int volume) {} - virtual void proc18(int al, VoiceType voiceType) {} - virtual void proc20(int al, VoiceType voiceType) {} - virtual void proc22(int al, VoiceType voiceType, int v3) {} + virtual bool open() { return true; } // Method #0 + virtual void close() {} // Method #1 + virtual bool reset() { return true; } // Method #2 + virtual const GroupData *getGroupData() { return NULL; } // Method #3 + virtual void installPatch(const byte *data) {} // Method #4 + virtual void poll() {} // Method #5 + virtual void proc12() {} // Method #6 + virtual int setMasterVolume(int volume) { return 0; } // Method #7 + virtual void proc16() {} // Method #8 + virtual void proc18(int al, VoiceType voiceType) {} // Method #9 + virtual void proc20(int al, VoiceType voiceType) {} // Method #10 + virtual void proc22(int al, VoiceType voiceType, int v3) {} // Method #11 virtual void proc24(int channel, int voiceIndex, Sound *sound, int v1, int v2) {} - virtual void setProgram(int channel, int program) {} + virtual void setProgram(int channel, int program) {} // Method #13 virtual void setVolume1(int channel, int v2, int v3, int volume) {} - virtual void setPitchBlend(int channel, int pitchBlend) {} - virtual void proc32(int voiceNum, int program, ...) {} // TODO: Determine params - virtual void proc38(int voiceNum, int cmd, int value) {} - virtual void proc40(int voiceNum, int pitchBlend) {} - virtual void proc42(int voiceNum, ...) {} // TODO: Determine params - virtual void updateVoice(int voiceNum) {} + virtual void setPitchBlend(int channel, int pitchBlend) {} // Method #15 + virtual void proc32(int channel, int program, int v0, int v1) {}// Method #16 + virtual void updateVoice(int channel) {} // Method #17 + virtual void proc36() {} // Method #18 + virtual void proc38(int channel, int cmd, int value) {} // Method #19 + virtual void proc40(int channel, int pitchBlend) {} // Method #20 + virtual void proc42(int channel, int v0, int v1) {} // Method #21 }; struct VoiceStructEntryType0 { @@ -141,7 +145,7 @@ struct VoiceStructEntry { class VoiceTypeStruct { public: VoiceType _voiceType; - int _field1; + int _total; int _numVoices; int _field3; @@ -332,7 +336,7 @@ public: void _soRemoteReceive(); void _soServiceTrackType0(int trackIndex, const byte *channelData); void _soUpdateDamper(VoiceTypeStruct *voiceType, int channelNum, VoiceType mode, int v0); - void _soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0); + void _soProc32(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0, int v1); void _soProc42(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int v0); void _soProc38(VoiceTypeStruct *vtStruct, int channelNum, VoiceType voiceType, int cmd, int value); void _soProc40(VoiceTypeStruct *vtStruct, int channelNum, int pitchBlend); @@ -381,16 +385,49 @@ public: void release() { _sound.release(); } }; +#define ADLIB_CHANNEL_COUNT 9 + class AdlibSoundDriver: public SoundDriver { private: GroupData _groupData; Audio::Mixer *_mixer; + FM_OPL *_opl; + int _sampleRate; + byte _portContents[256]; + const byte *_patchData; + int _masterVolume; + + bool _channelVoiced[ADLIB_CHANNEL_COUNT]; + int _channelVolume[ADLIB_CHANNEL_COUNT]; + int _v4405E[ADLIB_CHANNEL_COUNT]; + int _v44067[ADLIB_CHANNEL_COUNT]; + int _v44070[ADLIB_CHANNEL_COUNT]; + int _v44079[ADLIB_CHANNEL_COUNT]; + int _v44082[ADLIB_CHANNEL_COUNT + 1]; + int _v4408C[ADLIB_CHANNEL_COUNT]; + int _v4409E[ADLIB_CHANNEL_COUNT]; + + + void write(byte reg, byte value); + void updateChannelVolume(int channel); + void setVoice(int channel); + void clearVoice(int channel); + void updateChannel(int channel); + void setFrequency(int channel); public: AdlibSoundDriver(); - - virtual void setVolume(int volume) {} - virtual void installPatchBank(const byte *data) {} - virtual const GroupData *getGroupData() { return &_groupData; } + ~AdlibSoundDriver(); + + virtual bool open(); + virtual void close(); + virtual bool reset(); + virtual const GroupData *getGroupData(); + virtual void installPatch(const byte *data); + virtual int setMasterVolume(int volume); + virtual void proc32(int channel, int program, int v0, int v1); + virtual void updateVoice(int channel); + virtual void proc38(int channel, int cmd, int value); + void proc40(int channel, int pitchBlend); }; } // End of namespace tSage |