/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef AUDIO_MIDI_H
#define AUDIO_MIDI_H

#include "audio/mt32gm.h"

#include "common/config-manager.h"
#include "common/debug.h"

// The initialization of the static const integral data members is done in the class definition,
// but we still need to provide a definition if they are odr-used.
const uint8 MidiDriver_MT32GM::MT32_DEFAULT_CHANNEL_VOLUME;
const uint8 MidiDriver_MT32GM::GM_DEFAULT_CHANNEL_VOLUME;
const uint8 MidiDriver_MT32GM::MAXIMUM_MT32_ACTIVE_NOTES;
const uint8 MidiDriver_MT32GM::MAXIMUM_GM_ACTIVE_NOTES;

// These are the power-on default instruments of the Roland MT-32 family.
const byte MidiDriver_MT32GM::MT32_DEFAULT_INSTRUMENTS[8] = {
	0x44, 0x30, 0x5F, 0x4E, 0x29, 0x03, 0x6E, 0x7A
};

// These are the power-on default panning settings for channels 2-9 of the Roland MT-32 family.
// Internally, the MT-32 has 15 panning positions (0-E with 7 being center).
// This has been translated to the equivalent MIDI panning values (0-127).
// These are used for setting default panning on GM devices when using them with MT-32 data.
// Note that MT-32 panning is reversed compared to the MIDI specification. This is not reflected
// here; the driver is expected to flip these values based on the _midiDeviceReversePanning
// variable.
const byte MidiDriver_MT32GM::MT32_DEFAULT_PANNING[8] = {
	// 7,    8,    7,    8,    4,    A,    0,    E
	0x40, 0x49,	0x40, 0x49, 0x25, 0x5B, 0x00, 0x7F
};

// This is the drum map for the Roland Sound Canvas SC-55 v1.xx. It had a fallback mechanism
// to correct invalid drumkit selections. Some games rely on this mechanism to select the
// correct Roland GS drumkit. Use this map to emulate this mechanism.
// E.g. correct invalid drumkit 50: GS_DRUMKIT_FALLBACK_MAP[50] == 48
const uint8 MidiDriver_MT32GM::GS_DRUMKIT_FALLBACK_MAP[128] = {
	 0,  0,  0,  0,  0,  0,  0,  0, // STANDARD
	 8,  8,  8,  8,  8,  8,  8,  8, // ROOM
	16, 16, 16, 16, 16, 16, 16, 16, // POWER
	24, 25, 24, 24, 24, 24, 24, 24, // ELECTRONIC; TR-808 (25)
	32, 32, 32, 32, 32, 32, 32, 32, // JAZZ
	40, 40, 40, 40, 40, 40, 40, 40, // BRUSH
	48, 48, 48, 48, 48, 48, 48, 48, // ORCHESTRA
	56, 56, 56, 56, 56, 56, 56, 56, // SFX
	 0,  0,  0,  0,  0,  0,  0,  0, // No drumkit defined (fall back to STANDARD)
	 0,  0,  0,  0,  0,  0,  0,  0, // No drumkit defined
	 0,  0,  0,  0,  0,  0,  0,  0, // No drumkit defined
	 0,  0,  0,  0,  0,  0,  0,  0, // No drumkit defined
	 0,  0,  0,  0,  0,  0,  0,  0, // No drumkit defined
	 0,  0,  0,  0,  0,  0,  0,  0, // No drumkit defined
	 0,  0,  0,  0,  0,  0,  0,  0, // No drumkit defined
	 0,  0,  0,  0,  0,  0,  0, 127 // No drumkit defined; CM-64/32L (127)
};

const uint8 MidiDriver_MT32GM::MT32_DISPLAY_NUM_CHARS;
const uint32 MidiDriver_MT32GM::MT32_DISPLAY_MEMORY_ADDRESS;

// Callback hooked up to the driver wrapped by the MIDI driver
// object. Executes onTimer and the external callback set by
// the setTimerCallback function.
void MidiDriver_MT32GM::timerCallback(void *data) {
	MidiDriver_MT32GM *driver = (MidiDriver_MT32GM *)data;
	driver->onTimer();
}

MidiDriver_MT32GM::MidiDriver_MT32GM(MusicType midiType) :
		_driver(nullptr),
		_nativeMT32(false),
		_enableGS(false),
		_midiDataReversePanning(false),
		_midiDeviceReversePanning(false),
		_scaleGSPercussionVolumeToMT32(false),
		_isOpen(false),
		_outputChannelMask(65535), // Channels 1-16
		_baseFreq(250),
		_sysExDelay(0) {
	memset(_controlData, 0, sizeof(_controlData));

	switch (midiType) {
	case MT_MT32:
		_midiType = MT_MT32;
		break;
	case MT_GM:
	case MT_GS: // Treat GS same as GM
		_midiType = MT_GM;
		break;
	default:
		error("MidiDriver_MT32GM: Unsupported music type %i", midiType);
		break;
	}

	for (int i = 0; i < MAXIMUM_SOURCES; ++i) {
		_availableChannels[i] = 0;
		// Default MIDI channel mapping: data channel == output channel
		for (int j = 0; j < MIDI_CHANNEL_COUNT; ++j) {
			_channelMap[i][j] = j;
		}
	}

	// Default MT-32 <> GM instrument mappings.
	_mt32ToGMInstrumentMap = _mt32ToGm;
	_gmToMT32InstrumentMap = _gmToMt32;

	_maximumActiveNotes = _midiType == MT_MT32 ? MAXIMUM_MT32_ACTIVE_NOTES : MAXIMUM_GM_ACTIVE_NOTES;
	_activeNotes = new ActiveNote[_maximumActiveNotes];
	assert(_activeNotes);
}

MidiDriver_MT32GM::~MidiDriver_MT32GM() {
	if (_driver) {
		_driver->setTimerCallback(nullptr, nullptr);
		_driver->close();
		delete _driver;
	}
	_driver = nullptr;

	for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
		delete _controlData[i];
	}
	if (_activeNotes)
		delete[] _activeNotes;
}

int MidiDriver_MT32GM::open() {
	assert(!_driver);

	// Setup midi driver
	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | (_midiType == MT_MT32 ? MDT_PREFER_MT32 : MDT_PREFER_GM));
	MusicType deviceMusicType = MidiDriver::getMusicType(dev);
	if (!(deviceMusicType == MT_MT32 || deviceMusicType == MT_GM || deviceMusicType == MT_GS))
		error("MidiDriver_MT32GM: detected music device uses unsupported music type %i", deviceMusicType);

	MidiDriver *driver = MidiDriver::createMidi(dev);
	bool nativeMT32 = deviceMusicType == MT_MT32 || ConfMan.getBool("native_mt32");

	return open(driver, nativeMT32);
}

int MidiDriver_MT32GM::open(MidiDriver *driver, bool nativeMT32) {
	assert(!_driver);

	_driver = driver;
	_nativeMT32 = nativeMT32;

	_enableGS = ConfMan.getBool("enable_gs");

	if (!_driver)
		return 255;

	if (_nativeMT32)
		_outputChannelMask = _midiType == MT_MT32 ? 1022 : 767; // Channels 2-10 / 1-8 and 10
	_driver->property(MidiDriver::PROP_CHANNEL_MASK, _outputChannelMask);

	int ret = _driver->open();
	if (ret != MidiDriver::MERR_ALREADY_OPEN && ret != 0)
		return ret;

	_timerRate = _driver->getBaseTempo();
	_driver->setTimerCallback(this, timerCallback);

	initControlData();
	initMidiDevice();
	syncSoundSettings();

	_isOpen = true;

	return 0;
}

void MidiDriver_MT32GM::initControlData() {
	for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
		_controlData[i] = new MidiChannelControlData();
		_controlData[i]->volume = _controlData[i]->scaledVolume =
			(_nativeMT32 ? MT32_DEFAULT_CHANNEL_VOLUME : GM_DEFAULT_CHANNEL_VOLUME);
		_controlData[i]->pitchBendSensitivity =
			(_nativeMT32 ? MT32_PITCH_BEND_SENSITIVITY_DEFAULT : GM_PITCH_BEND_SENSITIVITY_DEFAULT);
		if (_nativeMT32 && i >= 1 && i <= 8) {
			_controlData[i]->program = MT32_DEFAULT_INSTRUMENTS[i - 1];
			_controlData[i]->panPosition = MT32_DEFAULT_PANNING[i - 1];
		}
	}
}

void MidiDriver_MT32GM::initMidiDevice() {
	if (_nativeMT32) {
		initMT32(_midiType != MT_MT32);
	} else {
		initGM(_midiType == MT_MT32, _enableGS);
	}
}

void MidiDriver_MT32GM::initMT32(bool initForGM) {
	sendMT32Reset();

	if (initForGM) {
		// Set up MT-32 for GM data.
		// This is based on Roland's GM settings for MT-32.
		debug("Initializing MT-32 for General MIDI data");

		byte buffer[17];

		// Roland MT-32 SysEx for system area
		memcpy(&buffer[0], "\x41\x10\x16\x12\x10\x00", 6);

		// Set reverb parameters:
		// - Mode 2 (Plate)
		// - Time 3
		// - Level 4
		memcpy(&buffer[6], "\x01\x02\x03\x04\x66", 5);
		sysEx(buffer, 11);

		// Set partial reserve to match SC-55
		memcpy(&buffer[6], "\x04\x08\x04\x04\x03\x03\x03\x03\x02\x02\x4C", 11);
		sysEx(buffer, 17);

		// Use MIDI instrument channels 1-8 instead of 2-9
		memcpy(&buffer[6], "\x0D\x00\x01\x02\x03\x04\x05\x06\x07\x09\x3E", 11);
		sysEx(buffer, 17);

		// The MT-32 has reversed stereo panning compared to the MIDI spec.
		// GM does use panning as specified by the MIDI spec.
		_midiDeviceReversePanning = true;

		int i;

		// Set default GM panning (center on all channels)
		for (i = 0; i < 8; ++i) {
			send((0x40 << 16) | (MIDI_CONTROLLER_PANNING << 8) | (MIDI_COMMAND_CONTROL_CHANGE | i));
		}

		// Set default GM instruments (0 on all channels).
		// This is expected to be mapped to the MT-32 equivalent by the driver.
		for (i = 0; i < 8; ++i) {
			send((0 << 8) | (MIDI_COMMAND_PROGRAM_CHANGE | i));
		}

		// Set Pitch Bend Sensitivity to 2 semitones.
		for (i = 0; i < 8; ++i) {
			setPitchBendRange(i, 2);
		}
		setPitchBendRange(MIDI_RHYTHM_CHANNEL, 2);
	}
}

void MidiDriver_MT32GM::initGM(bool initForMT32, bool enableGS) {
	sendGMReset();

	if (initForMT32) {
		// Set up the GM device for MT-32 MIDI data.
		// Based on iMuse implementation (which is based on Roland's MT-32 settings for GS)
		debug("Initializing GM device for MT-32 MIDI data");

		// The MT-32 has reversed stereo panning compared to the MIDI spec.
		// GM does use panning as specified by the MIDI spec.
		_midiDeviceReversePanning = true;

		int i;

		// Set the default panning for the MT-32 instrument channels.
		for (i = 1; i < 9; ++i) {
			send((MT32_DEFAULT_PANNING[i - 1] << 16) | (MIDI_CONTROLLER_PANNING << 8) | (MIDI_COMMAND_CONTROL_CHANGE | i));
		}

		// Set Channels 1-16 Reverb to 64, which is the
		// equivalent of MT-32 default Reverb Level 5
		for (i = 0; i < 16; ++i)
			send((64 << 16) | (MIDI_CONTROLLER_REVERB << 8) | (MIDI_COMMAND_CONTROL_CHANGE | i));

		// Set Channels 1-16 Chorus to 0. The MT-32 has no chorus capability.
		// (This is probably the default for many GM devices with chorus anyway.)
		for (i = 0; i < 16; ++i)
			send((0 << 16) | (MIDI_CONTROLLER_CHORUS << 8) | (MIDI_COMMAND_CONTROL_CHANGE | i));

		// Set Channels 1-16 Pitch Bend Sensitivity to 12 semitones.
		for (i = 0; i < 16; ++i) {
			setPitchBendRange(i, 12);
		}

		if (enableGS) {
			// GS specific settings for MT-32 instrument mapping.
			debug("Additional initialization of GS device for MT-32 MIDI data");

			// Note: All Roland GS devices support CM-64/32L maps

			if (getPercussionChannel() != nullptr) {
				// Set Percussion Channel to SC-55 Map (CC#32, 01H), then
				// Switch Drum Map to CM-64/32L (MT-32 Compatible Drums)
				// Bank select MSB: bank 0
				getPercussionChannel()->controlChange(MIDI_CONTROLLER_BANK_SELECT_MSB, 0);
				// Bank select LSB: map 1 (SC-55)
				getPercussionChannel()->controlChange(MIDI_CONTROLLER_BANK_SELECT_LSB, 1);
			}
			// Patch change: 127 (CM-64/32L)
			send((127 << 8) | MIDI_COMMAND_PROGRAM_CHANGE | 9);

			// Set Channels 1-16 to SC-55 Map, then CM-64/32L Variation
			for (i = 0; i < 16; ++i) {
				if (getPercussionChannel() != nullptr && i == getPercussionChannel()->getNumber())
					continue;
				// Bank select MSB: bank 127 (CM-64/32L)
				send((127 << 16) | (MIDI_CONTROLLER_BANK_SELECT_MSB << 8) | (MIDI_COMMAND_CONTROL_CHANGE | i));
				// Bank select LSB: map 1 (SC-55)
				send((1 << 16) | (MIDI_CONTROLLER_BANK_SELECT_LSB << 8) | (MIDI_COMMAND_CONTROL_CHANGE | i));
				// Patch change: 0 (causes bank select to take effect)
				send((0 << 16) | (0 << 8) | (MIDI_COMMAND_PROGRAM_CHANGE | i));
			}

			byte buffer[12];

			// Roland GS SysEx ID
			memcpy(&buffer[0], "\x41\x10\x42\x12", 4);

			// Set channels 1-16 Mod. LFO1 Pitch Depth to 4
			memcpy(&buffer[4], "\x40\x20\x04\x04\x18", 5);
			for (i = 0; i < 16; ++i) {
				buffer[5] = 0x20 + i;
				buffer[8] = 0x18 - i;
				sysEx(buffer, 9);
			}

			// In Roland's GS MT-32 emulation settings, percussion channel expression
			// is locked at 80. This corrects a difference in volume of the SC-55 MT-32
			// drum kit vs the drums of the MT-32. However, this approach has a problem:
			// the MT-32 supports expression on the percussion channel, so MIDI data
			// which uses this will play incorrectly. So instead, percussion channel
			// volume will be scaled by the driver by a factor 80/127.
			// Strangely, the regular GM drum kit does have a volume that matches the
			// MT-32 drums, so scaling is only necessary when using GS MT-32 emulation.
			_scaleGSPercussionVolumeToMT32 = true;

			// Change Reverb settings (as used by Roland):
			// - Character: 0
			// - Pre-LPF: 4
			// - Level: 35h
			// - Time: 6Ah
			memcpy(&buffer[4], "\x40\x01\x31\x00\x04\x35\x6A\x6B", 8);
			sysEx(buffer, 12);
		}

		// Set the default MT-32 patches. For non-GS devices these are expected to be
		// mapped to the GM equivalents by the driver.
		for (i = 1; i < 9; ++i) {
			send((MT32_DEFAULT_INSTRUMENTS[i - 1] << 8) | (MIDI_COMMAND_PROGRAM_CHANGE | i));
		}

		// Regarding Master Tune: 442 kHz was intended for the MT-32 family, but
		// apparently due to a firmware bug the master tune was actually 440 kHz for
		// all models (see MUNT source code for more details). So master tune is left
		// at 440 kHz for GM devices playing MT-32 MIDI data.
	}
}

void MidiDriver_MT32GM::close() {
	if (_driver) {
		_driver->close();
	}
}

bool MidiDriver_MT32GM::isReady(int8 source) {
	Common::StackLock lock(_sysExQueueMutex);

	// For an unspecified source, just return if the queue is empty or not.
	if (source < 0)
		return _sysExQueue.empty();

	// For a specific source, check if there is a SysEx for that source in the
	// queue.
	for (Common::ListInternal::Iterator<SysExData> it = _sysExQueue.begin();
			it != _sysExQueue.end(); it++) {
		if (it->source == source)
			return false;
	}

	return true;
}

uint32 MidiDriver_MT32GM::property(int prop, uint32 param) {
	switch (prop) {
	case PROP_MIDI_DATA_REVERSE_PANNING:
		if (param == 0xFFFF)
			return _midiDataReversePanning ? 1 : 0;
		_midiDataReversePanning = param > 0;
		break;
	default:
		return MidiDriver_Multisource::property(prop, param);
	}
	return 0;
}

void MidiDriver_MT32GM::send(uint32 b) {
	send(-1, b);
}

void MidiDriver_MT32GM::send(int8 source, uint32 b) {
	byte dataChannel = b & 0xf;
	int8 outputChannel = source < 0 ? dataChannel : mapSourceChannel(source, dataChannel);

	MidiChannelControlData &controlData = *_controlData[outputChannel];

	processEvent(source, b, outputChannel, controlData);
}

// MIDI messages can be found at https://web.archive.org/web/20120128110425/http://www.midi.org/techspecs/midimessages.php
void MidiDriver_MT32GM::processEvent(int8 source, uint32 b, uint8 outputChannel, MidiChannelControlData &controlData, bool channelLockedByOtherSource) {
	assert(source < MAXIMUM_SOURCES);

	byte command = b & 0xf0;
	byte op1 = (b >> 8) & 0xff;
	byte op2 = (b >> 16) & 0xff;

	if (command != MIDI_COMMAND_SYSTEM && controlData.source != source) {
		// A new source has sent an event on this channel.
		controlData.sourceVolumeApplied = false;
		controlData.source = source;

		if (source >= 0)
			// If the new source is a real MIDI source, apply controller
			// default values.
			applyControllerDefaults(source, controlData, outputChannel, channelLockedByOtherSource);
	}

	switch (command) {
	case MIDI_COMMAND_NOTE_OFF:
	case MIDI_COMMAND_NOTE_ON:
		if (!channelLockedByOtherSource)
			noteOnOff(outputChannel, command, op1, op2, source, controlData);
		break;
	case MIDI_COMMAND_PITCH_BEND:
		pitchBend(outputChannel, op1, op2, source, controlData, channelLockedByOtherSource);
		break;
	case MIDI_COMMAND_POLYPHONIC_AFTERTOUCH: // Not supported by MT-32 or GM
		polyAftertouch(outputChannel, op1, op2, source, controlData, channelLockedByOtherSource);
		break;
	case MIDI_COMMAND_CHANNEL_AFTERTOUCH: // Not supported by MT-32
		channelAftertouch(outputChannel, op1, source, controlData, channelLockedByOtherSource);
		break;
	case MIDI_COMMAND_CONTROL_CHANGE:
		controlChange(outputChannel, op1, op2, source, controlData, channelLockedByOtherSource);
		break;
	case MIDI_COMMAND_PROGRAM_CHANGE:
		programChange(outputChannel, op1, source, controlData, channelLockedByOtherSource);
		break;
	case MIDI_COMMAND_SYSTEM:
		// The only supported system event is SysEx and that should be sent using the sysEx functions.
		warning("MidiDriver_MT32GM: send received system event (not processed): %x", b);
		break;
	default:
		warning("MidiDriver_MT32GM: Received unknown event %02x", command);
		break;
	}
}

void MidiDriver_MT32GM::applyControllerDefaults(uint8 source, MidiChannelControlData &controlData, uint8 outputChannel, bool channelLockedByOtherSource) {
	if (outputChannel != MIDI_RHYTHM_CHANNEL) {
		// Apply default bank and program only to melodic channels.
		if (_controllerDefaults.instrumentBank >= 0 && controlData.instrumentBank != _controllerDefaults.instrumentBank) {
			controlChange(outputChannel, MIDI_CONTROLLER_BANK_SELECT_MSB, _controllerDefaults.instrumentBank, source, controlData);
			controlChange(outputChannel, MIDI_CONTROLLER_BANK_SELECT_LSB, 0, source, controlData);
		}
		if (_controllerDefaults.program[outputChannel] >= 0 && controlData.program != _controllerDefaults.program[outputChannel]) {
			programChange(outputChannel, _controllerDefaults.program[outputChannel], source, controlData);
		}
	} else {
		// Apply default drumkit only to the rhythm channel.
		if (_controllerDefaults.drumkit >= 0 && controlData.program != _controllerDefaults.drumkit) {
			programChange(outputChannel, _controllerDefaults.drumkit, source, controlData);
		}
	}
	if (_controllerDefaults.channelPressure >= 0 && controlData.channelPressure != _controllerDefaults.channelPressure) {
		channelAftertouch(outputChannel, _controllerDefaults.channelPressure, source, controlData);
	}
	if (_controllerDefaults.pitchBend >= 0 && controlData.pitchWheel != _controllerDefaults.pitchBend) {
		pitchBend(outputChannel, _controllerDefaults.pitchBend & 0x7F, _controllerDefaults.pitchBend >> 7, source, controlData);
	}

	if (_controllerDefaults.modulation >= 0 && controlData.modulation != _controllerDefaults.modulation) {
		controlChange(outputChannel, MIDI_CONTROLLER_MODULATION, _controllerDefaults.modulation, source, controlData);
	}
	if (_controllerDefaults.volume >= 0 && controlData.volume != _controllerDefaults.volume) {
		controlChange(outputChannel, MIDI_CONTROLLER_VOLUME, _controllerDefaults.volume, source, controlData);
	}
	if (_controllerDefaults.panning >= 0 && controlData.panPosition != _controllerDefaults.panning) {
		controlChange(outputChannel, MIDI_CONTROLLER_PANNING, _controllerDefaults.panning, source, controlData);
	}
	if (_controllerDefaults.expression >= 0 && controlData.expression != _controllerDefaults.expression) {
		controlChange(outputChannel, MIDI_CONTROLLER_EXPRESSION, _controllerDefaults.expression, source, controlData);
	}

	// RPN will be changed by setting pitch bend sensitivity, so store the
	// current value.
	uint16 rpn = controlData.rpn;
	bool setRpn = false;
	if (_controllerDefaults.pitchBendSensitivity >= 0 && controlData.pitchBendSensitivity != _controllerDefaults.pitchBendSensitivity) {
		controlChange(outputChannel, MIDI_CONTROLLER_RPN_MSB, MIDI_RPN_PITCH_BEND_SENSITIVITY >> 8, source, controlData);
		controlChange(outputChannel, MIDI_CONTROLLER_RPN_LSB, MIDI_RPN_PITCH_BEND_SENSITIVITY & 0xFF, source, controlData);
		controlChange(outputChannel, MIDI_CONTROLLER_DATA_ENTRY_MSB, _controllerDefaults.pitchBendSensitivity, source, controlData);
		controlChange(outputChannel, MIDI_CONTROLLER_DATA_ENTRY_LSB, 0, source, controlData);
		if (rpn != controlData.rpn)
			// Active RPN was changed; reset it to previous value (or default).
			setRpn = true;
	}
	if (_controllerDefaults.rpn >= 0 && rpn != _controllerDefaults.rpn) {
		// Set RPN to the specified default value.
		rpn = _controllerDefaults.rpn;
		setRpn = true;
	}

	if (setRpn) {
		controlChange(outputChannel, MIDI_CONTROLLER_RPN_MSB, rpn >> 8, source, controlData);
		controlChange(outputChannel, MIDI_CONTROLLER_RPN_LSB, rpn & 0xFF, source, controlData);
	}
}

void MidiDriver_MT32GM::noteOnOff(byte outputChannel, byte command, byte note, byte velocity, int8 source, MidiChannelControlData &controlData) {
	if (!isOutputChannelUsed(outputChannel))
		return;

	// Note On with velocity 0 is treated as Note Off
	bool addNote = command == MIDI_COMMAND_NOTE_ON && velocity != 0;
	if (addNote) {
		if (source >= 0 && !controlData.sourceVolumeApplied)
			// Source volume hasn't been applied yet. Do so now.
			controlChange(outputChannel, MIDI_CONTROLLER_VOLUME, controlData.volume, source, controlData);

		// Add the new note to the active note registration
		addActiveNote(outputChannel, note, source);
	} else {
		// Remove the note from the active note registration
		removeActiveNote(outputChannel, note, source);
	}

	_driver->send(command | outputChannel, note, velocity);
}

void MidiDriver_MT32GM::polyAftertouch(byte outputChannel, byte note, byte pressure,
		int8 source, MidiChannelControlData &controlData, bool channelLockedByOtherSource) {
	if (!channelLockedByOtherSource)
		_driver->send(MIDI_COMMAND_CHANNEL_AFTERTOUCH | outputChannel, note, pressure);
}

void MidiDriver_MT32GM::controlChange(byte outputChannel, byte controllerNumber, byte controllerValue, int8 source, MidiChannelControlData &controlData, bool channelLockedByOtherSource) {
	assert(source < MAXIMUM_SOURCES);

	// Standard MIDI controllers
	switch (controllerNumber) {
	case MIDI_CONTROLLER_BANK_SELECT_MSB:
		// Keep track of the current bank for each channel
		controlData.instrumentBank = controllerValue;
		break;
	case MIDI_CONTROLLER_MODULATION:
		controlData.modulation = controllerValue;
		break;
	case MIDI_CONTROLLER_DATA_ENTRY_MSB:
		if (controlData.rpn == MIDI_RPN_PITCH_BEND_SENSITIVITY)
			controlData.pitchBendSensitivity = controllerValue;
		break;
	case MIDI_CONTROLLER_VOLUME:
		controlData.volume = controllerValue;
		controlData.sourceVolumeApplied = true;
		if (source >= 0) {
			// Scale to source volume
			controllerValue = (controllerValue * _sources[source].volume) / _sources[source].neutralVolume;
		}
		if (_userVolumeScaling) {
			if (_userMute) {
				controllerValue = 0;
			} else {
				// Scale to user volume
				uint16 userVolume = _sources[source].type == SOURCE_TYPE_SFX ? _userSfxVolume : _userMusicVolume; // Treat SOURCE_TYPE_UNDEFINED as music
				controllerValue = (controllerValue * userVolume) >> 8;
			}
		}
		if (_scaleGSPercussionVolumeToMT32 && outputChannel == MIDI_RHYTHM_CHANNEL) {
			// Scale GS percussion channel volume to MT-32 level (80/127)
			controllerValue = (80 * controllerValue) >> 7;
		}
		// Source volume scaling might clip volume, so reduce to maximum
		controllerValue = MIN(controllerValue, (byte)0x7F);
		if (controlData.scaledVolume == controllerValue) {
			// Volume is already at this value, so no need to send it out
			// to the MIDI device.
			return;
		}
		controlData.scaledVolume = controllerValue;
		break;
	case MIDI_CONTROLLER_PANNING:
		if (_midiDeviceReversePanning != _midiDataReversePanning) {
			// Center panning is 0x40
			controllerValue = 0x80 - controllerValue;
			if (controllerValue > 0x7F)
				controllerValue = 0x7F;
		}
		break;
	case MIDI_CONTROLLER_EXPRESSION:
		controlData.expression = controllerValue;
		break;
	case MIDI_CONTROLLER_SUSTAIN:
		controlData.sustain = controllerValue >= 0x40;
		if (!channelLockedByOtherSource && !controlData.sustain) {
			removeActiveNotes(outputChannel, true);
		}
		break;
	case MIDI_CONTROLLER_RPN_LSB:
		controlData.rpn &= 0xFF00;
		controlData.rpn |= controllerValue;
		break;
	case MIDI_CONTROLLER_RPN_MSB:
		controlData.rpn &= 0x00FF;
		controlData.rpn |= controllerValue << 8;
		break;
	case MIDI_CONTROLLER_RESET_ALL_CONTROLLERS:
		controlData.channelPressure = 0;
		controlData.pitchWheel = MIDI_PITCH_BEND_DEFAULT;
		controlData.modulation = 0;
		controlData.expression = MIDI_EXPRESSION_DEFAULT;
		controlData.sustain = false;
		if (!channelLockedByOtherSource) {
			removeActiveNotes(outputChannel, true);
		}
		controlData.rpn = MIDI_RPN_NULL;
		break;
	case MIDI_CONTROLLER_OMNI_ON:
	case MIDI_CONTROLLER_OMNI_OFF:
	case MIDI_CONTROLLER_MONO_ON:
	case MIDI_CONTROLLER_POLY_ON:
		// These act as an All Notes Off on MT-32, but also turn sustain off.
		// They are not part of GM, so should not be used in GM data.
		if (_midiType != MT_MT32) {
			warning("MidiDriver_MT32GM: unsupported GM controller %x", controllerNumber);
			return;
		}

		controlData.sustain = false;
		if (!channelLockedByOtherSource)
			removeActiveNotes(outputChannel, true);
		if (!_nativeMT32) {
			// MT-32 data on GM device.
			// These controllers might not be supported or have side effects
			// (changing omni or mono/poly mode). Send All Notes Off and
			// Sustain Off instead.
			if (!channelLockedByOtherSource) {
				controllerNumber = MIDI_CONTROLLER_ALL_NOTES_OFF;
				_driver->send(MIDI_COMMAND_CONTROL_CHANGE | outputChannel | (MIDI_CONTROLLER_SUSTAIN << 8) | (0 << 16));
			}
		}
		// fall through
	case MIDI_CONTROLLER_ALL_NOTES_OFF:
		if (!channelLockedByOtherSource)
			removeActiveNotes(outputChannel, false);
		break;
	default:
		break;
	}

	if (!channelLockedByOtherSource)
		_driver->send(MIDI_COMMAND_CONTROL_CHANGE | outputChannel | (controllerNumber << 8) | (controllerValue << 16));
}

bool MidiDriver_MT32GM::addActiveNote(uint8 outputChannel, uint8 note, int8 source) {
	Common::StackLock lock(_activeNotesMutex);

	for (int i = 0; i < _maximumActiveNotes; ++i) {
		ActiveNote &activeNote = _activeNotes[i];
		if (activeNote.channel == 0xFF) {
			// Add the new note.
			activeNote.source = source;
			activeNote.channel = outputChannel;
			activeNote.note = note;
			activeNote.sustain = false;
			return true;
		}
	}
	warning("MidiDriver_MT32GM: Could not add active note %x on channel %i", note, outputChannel);
	return false;
}

bool MidiDriver_MT32GM::removeActiveNote(uint8 outputChannel, uint8 note, int8 source) {
	Common::StackLock lock(_activeNotesMutex);

	for (int i = 0; i < _maximumActiveNotes; ++i) {
		ActiveNote &activeNote = _activeNotes[i];
		if (activeNote.channel == outputChannel && activeNote.source == source && activeNote.note == note) {
			if (_controlData[outputChannel]->sustain) {
				// Sustain is on, so the note should be turned off
				// when sustain is turned off.
				activeNote.sustain = true;
				return false;
			} else {
				// Turn off the existing note.
				activeNote.clear();
				return true;
			}
		}
	}
	//warning("MidiDriver_MT32GM: Could not find active note %x on channel %i when removing", note, outputChannel);
	return false;
}

void MidiDriver_MT32GM::removeActiveNotes(uint8 outputChannel, bool sustainedNotes) {
	Common::StackLock lock(_activeNotesMutex);

	// Remove sustained or non-sustained notes from the active notes registration
	for (int i = 0; i < _maximumActiveNotes; ++i) {
		if (_activeNotes[i].channel == outputChannel && _activeNotes[i].sustain == sustainedNotes) {
			_activeNotes[i].clear();
		}
	}
}

void MidiDriver_MT32GM::programChange(byte outputChannel, byte patchId, int8 source, MidiChannelControlData &controlData, bool channelLockedByOtherSource) {
	// remember patch id for the current MIDI-channel
	controlData.program = patchId;

	if (channelLockedByOtherSource)
		return;

	if (_instrumentRemapping && outputChannel != MIDI_RHYTHM_CHANNEL)
		// Apply instrument remapping (if specified) to instrument channels.
		patchId = _instrumentRemapping[patchId];

	if (_midiType == MT_MT32) {
		if (outputChannel == MIDI_RHYTHM_CHANNEL &&
				!(!_nativeMT32 && _enableGS && patchId == 0x7F)) {
			// Patch changes on the rhythm channel do nothing on an MT-32.
			// On GM/GS devices they might unintentionally change the drumkit.
			// Exception: changing the drumkit to the MT-32 drumkit on a GS
			// device.
			return;
		}

		if (!_nativeMT32 && !_enableGS) {
			// GM device: map the patch to GM equivalent
			patchId = mapMT32InstrumentToGM(patchId);
		}
	} else {
		// GM/GS MIDI
		if (outputChannel == MIDI_RHYTHM_CHANNEL) {
			// Correct possible wrong GS drumkit number
			patchId = GS_DRUMKIT_FALLBACK_MAP[patchId];
		} else if (!_nativeMT32) {
			// Correct possible wrong bank / instrument variation
			byte correctedBank = correctInstrumentBank(controlData.instrumentBank, patchId);
			if (correctedBank != 0xFF) {
				// Send out a bank select for the corrected bank number
				controlChange(outputChannel, MIDI_CONTROLLER_BANK_SELECT_MSB, correctedBank, source, controlData);
				controlChange(outputChannel, MIDI_CONTROLLER_BANK_SELECT_LSB, 0, source, controlData);
			}
		} else {
			// GM on an MT-32: map the patch to the MT-32 equivalent
			patchId = mapGMInstrumentToMT32(patchId);
		}
	}

	// Finally send program change to MIDI device
	_driver->send(MIDI_COMMAND_PROGRAM_CHANGE | outputChannel | (patchId << 8));
}

byte MidiDriver_MT32GM::mapMT32InstrumentToGM(byte mt32Instrument) {
	return _mt32ToGMInstrumentMap[mt32Instrument];
}

byte MidiDriver_MT32GM::mapGMInstrumentToMT32(byte gmInstrument) {
	return _gmToMT32InstrumentMap[gmInstrument];
}

byte MidiDriver_MT32GM::correctInstrumentBank(byte instrumentBank, byte patchId) {
	if (instrumentBank == 0 || patchId >= 120 || instrumentBank >= 64)
		// Usually, no bank select has been sent and no correction is
		// necessary.
		// No correction is performed on banks 64-127 or on the SFX
		// instruments (120-127).
		return 0xFF;

	// Determine the intended bank. This emulates the behavior of the
	// Roland SC-55 v1.2x. Instruments have 2, 1 or 0 sub-capital tones.
	// Depending on the selected bank and the selected instrument, the
	// bank will "fall back" to a sub-capital tone or to the capital
	// tone (bank 0).
	byte correctedBank = 0xFF;

	switch (patchId) {
	case 25:  // Steel-String Guitar / 12-string Guitar / Mandolin
		// This instrument has 2 sub-capital tones. Bank selects 17-63
		// are corrected to the second sub-capital tone at 16.
		if (instrumentBank >= 16) {
			correctedBank = 16;
			break;
		}
		// Corrections for values below 16 are handled below.

		// fall through
	case 4:   // Electric Piano 1 / Detuned Electric Piano 1
	case 5:   // Electric Piano 2 / Detuned Electric Piano 2
	case 6:   // Harpsichord / Coupled Harpsichord
	case 14:  // Tubular-bell / Church Bell
	case 16:  // Organ 1 / Detuned Organ 1
	case 17:  // Organ 2 / Detuned Organ 2
	case 19:  // Church Organ 1 / Church Organ 2
	case 21:  // Accordion Fr / Accordion It
	case 24:  // Nylon-string Guitar / Ukelele
	case 26:  // Jazz Guitar / Hawaiian Guitar
	case 27:  // Clean Guitar / Chorus Guitar
	case 28:  // Muted Guitar / Funk Guitar
	case 30:  // Distortion Guitar / Feedback Guitar
	case 31:  // Guitar Harmonics / Guitar Feedback
	case 38:  // Synth Bass 1 / Synth Bass 3
	case 39:  // Synth Bass 2 / Synth Bass 4
	case 48:  // Strings / Orchestra
	case 50:  // Synth Strings 1 / Synth Strings 3
	case 61:  // Brass 1 / Brass 2
	case 62:  // Synth Brass 1 / Synth Brass 3
	case 63:  // Synth Brass 2 / Synth Brass 4
	case 80:  // Square Wave / Sine Wave
	case 107: // Koto / Taisho Koto
	case 115: // Woodblock / Castanets
	case 116: // Taiko / Concert BD
	case 117: // Melodic Tom 1 / Melodic Tom 2
	case 118: // Synth Drum / 808 Tom
		// These instruments have one sub-capital tone. Bank selects 9-63
		// are corrected to the sub-capital tone at 8.
		if (instrumentBank >= 8) {
			correctedBank = 8;
			break;
		}
		// Corrections for values below 8 are handled below.

		// fall through
	default:
		// The other instruments only have a capital tone. Bank selects
		// 1-63 are corrected to the capital tone.
		correctedBank = 0;
		break;
	}

	// Return the corrected bank, or 0xFF if no correction is needed.
	return instrumentBank != correctedBank ? correctedBank : 0xFF;
}

void MidiDriver_MT32GM::channelAftertouch(byte outputChannel, byte pressure, int8 source,
		MidiChannelControlData &controlData, bool channelLockedByOtherSource) {
	controlData.channelPressure = pressure;

	if (!channelLockedByOtherSource)
		_driver->send(MIDI_COMMAND_CHANNEL_AFTERTOUCH | outputChannel, pressure, 0);
}

void MidiDriver_MT32GM::pitchBend(byte outputChannel, uint8 pitchBendLsb, uint8 pitchBendMsb,
		int8 source, MidiChannelControlData &controlData, bool channelLockedByOtherSource) {
	controlData.pitchWheel = ((uint16)pitchBendMsb << 7) | (uint16)pitchBendLsb;

	if (!channelLockedByOtherSource)
		_driver->send(MIDI_COMMAND_PITCH_BEND | outputChannel, pitchBendLsb, pitchBendMsb);
}

void MidiDriver_MT32GM::sysEx(const byte *msg, uint16 length) {
	uint16 delay = sysExNoDelay(msg, length);

	if (delay > 0)
		g_system->delayMillis(delay);
}

uint16 MidiDriver_MT32GM::sysExNoDelay(const byte *msg, uint16 length) {
	if (!_nativeMT32 && length >= 3 && msg[0] == 0x41 && msg[2] == 0x16)
		// MT-32 SysExes have no effect on GM devices.
		return 0;

	// Send SysEx
	_driver->sysEx(msg, length);

	// Wait the time it takes to send the SysEx data
	uint16 delay = (length + 2) * 1000 / 3125;

	// Plus an additional delay for the MT-32 rev00
	if (_nativeMT32)
		delay += 40;

	return delay;
}

void MidiDriver_MT32GM::sysExQueue(const byte *msg, uint16 length, int8 source) {
	SysExData sysEx;
	memcpy(sysEx.data, msg, length);
	sysEx.length = length;
	sysEx.source = source;

	_sysExQueueMutex.lock();
	_sysExQueue.push_back(sysEx);
	_sysExQueueMutex.unlock();
}

uint16 MidiDriver_MT32GM::sysExMT32(const byte *msg, uint16 length, const uint32 targetAddress, bool queue, bool delay, int8 source) {
	if (!_nativeMT32)
		// MT-32 SysExes have no effect on GM devices.
		return 0;

	byte   sysExMessage[270];
	uint16 sysExPos = 0;
	byte   sysExByte;
	uint16 sysExChecksum = 0;

	memset(&sysExMessage, 0, sizeof(sysExMessage));

	sysExMessage[0] = 0x41; // Roland
	sysExMessage[1] = 0x10;
	sysExMessage[2] = 0x16; // Model MT32
	sysExMessage[3] = 0x12; // Command DT1

	sysExChecksum = 0;

	sysExMessage[4] = (targetAddress >> 14) & 0x7F;
	sysExMessage[5] = (targetAddress >> 7) & 0x7F;
	sysExMessage[6] = targetAddress & 0x7F;

	for (byte targetAddressByte = 4; targetAddressByte < 7; targetAddressByte++) {
		assert(sysExMessage[targetAddressByte] < 0x80); // security check
		sysExChecksum -= sysExMessage[targetAddressByte];
	}

	sysExPos = 7;
	for (int i = 0; i < length; ++i) {
		sysExByte = *msg++;

		assert(sysExPos < sizeof(sysExMessage));
		assert(sysExByte < 0x80); // security check
		sysExMessage[sysExPos++] = sysExByte;
		sysExChecksum -= sysExByte;
	}

	// Calculate checksum
	assert(sysExPos < sizeof(sysExMessage));
	sysExMessage[sysExPos++] = sysExChecksum & 0x7F;

	if (queue) {
		sysExQueue(sysExMessage, sysExPos, source);
	} else if (!delay) {
		return sysExNoDelay(sysExMessage, sysExPos);
	} else {
		sysEx(sysExMessage, sysExPos);
	}

	return 0;
}

void MidiDriver_MT32GM::metaEvent(int8 source, byte type, byte *data, uint16 length) {
	assert(source < MAXIMUM_SOURCES);

	if (type == 0x2F && source >= 0) // End of Track
		deinitSource(source);

	_driver->metaEvent(type, data, length);
}

void MidiDriver_MT32GM::stopAllNotes(bool stopSustainedNotes) {
	if (!_driver)
		return;

	for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
		if (!isOutputChannelUsed(i))
			continue;

		if (stopSustainedNotes) {
			_driver->send(MIDI_COMMAND_CONTROL_CHANGE | i, MIDI_CONTROLLER_SUSTAIN, 0);
			_controlData[i]->sustain = false;
		}
		_driver->send(MIDI_COMMAND_CONTROL_CHANGE | i, MIDI_CONTROLLER_ALL_NOTES_OFF, 0);
	}

	_activeNotesMutex.lock();

	for (int i = 0; i < _maximumActiveNotes; ++i) {
		_activeNotes[i].clear();
	}

	_activeNotesMutex.unlock();
}


void MidiDriver_MT32GM::clearSysExQueue() {
	Common::StackLock lock(_sysExQueueMutex);

	_sysExQueue.clear();
}

MidiChannel *MidiDriver_MT32GM::allocateChannel() {
	if (_driver)
		return _driver->allocateChannel();
	return nullptr;
}

MidiChannel *MidiDriver_MT32GM::getPercussionChannel() {
	if (_driver)
		return _driver->getPercussionChannel();
	return nullptr;
}

bool MidiDriver_MT32GM::isOutputChannelUsed(int8 outputChannel) {
	return outputChannel >= 0 && outputChannel < MIDI_CHANNEL_COUNT &&
		_outputChannelMask & (1 << outputChannel);
}

uint32 MidiDriver_MT32GM::getBaseTempo() {
	if (_driver) {
		return _driver->getBaseTempo();
	}
	return 1000000 / _baseFreq;
}

bool MidiDriver_MT32GM::allocateSourceChannels(uint8 source, uint8 numChannels) {
	assert(source < MAXIMUM_SOURCES);

	deinitSource(source);

	_allocationMutex.lock();

	uint16 claimedChannels = 0;
	if (numChannels > 0) {
		for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
			if (!isOutputChannelUsed(i) || i == MIDI_RHYTHM_CHANNEL)
				continue;

			if (_controlData[i]->source == -1) {
				claimedChannels |= (1 << i);
				numChannels--;
			}
			if (numChannels == 0)
				break;
		}
	}

	if (numChannels > 0) {
		// Not enough channels available.
		_allocationMutex.unlock();
		return false;
	}

	// Allocate the channels.
	for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
		if ((claimedChannels >> i) & 1) {
			_controlData[i]->source = source;
		}
		// Clear the source channel mapping.
		if (i != MIDI_RHYTHM_CHANNEL)
			_channelMap[source][i] = -1;
	}

	_allocationMutex.unlock();

	_availableChannels[source] = claimedChannels;

	return true;
}

int8 MidiDriver_MT32GM::mapSourceChannel(uint8 source, uint8 dataChannel) {
	int8 outputChannel = _channelMap[source][dataChannel];
	if (outputChannel == -1) {
		for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
			if ((_availableChannels[source] >> i) & 1) {
				_availableChannels[source] &= ~(1 << i);
				_channelMap[source][dataChannel] = i;
				outputChannel = i;
				break;
			}
		}
		if (outputChannel == -1) {
			warning("MidiDriver_MT32GM: Insufficient available channels for source %i", source);
		}
	}
	return outputChannel;
}

void MidiDriver_MT32GM::deinitSource(uint8 source) {
	assert(source < MAXIMUM_SOURCES);

	_sysExQueueMutex.lock();

	// Remove any pending SysExes for this source from the queue.
	Common::ListInternal::Iterator<SysExData> it = _sysExQueue.begin();
	while (it != _sysExQueue.end()) {
		if (it->source == source) {
			it = _sysExQueue.erase(it);
		} else {
			it++;
		}
	}

	_sysExQueueMutex.unlock();

	MidiDriver_Multisource::deinitSource(source);

	// Free channels which were used by this source.
	for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
		if (!isOutputChannelUsed(i))
			continue;

		if (_controlData[i]->source == source) {
			// Set the sustain default value if it is specified (typically
			// sustain would be turned off).
			if (_controllerDefaults.sustain >= 0 && _controlData[i]->sustain != (_controllerDefaults.sustain >= 0x40)) {
				controlChange(i, MIDI_CONTROLLER_SUSTAIN, _controllerDefaults.sustain, _controlData[i]->source, *_controlData[i]);
			}

			_controlData[i]->source = -1;
		}
	}
	_availableChannels[source] = 0xFFFF;
	// Reset the data to output channel mapping
	for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
		_channelMap[source][i] = i;
	}
}

void MidiDriver_MT32GM::applySourceVolume(uint8 source) {
	for (int i = 0; i < MIDI_CHANNEL_COUNT; ++i) {
		if (!isOutputChannelUsed(i))
			continue;

		if (source == 0xFF || _controlData[i]->source == source)
			controlChange(i, MIDI_CONTROLLER_VOLUME, _controlData[i]->volume, _controlData[i]->source, *_controlData[i]);
	}
}

void MidiDriver_MT32GM::stopAllNotes(uint8 source, uint8 channel) {
	_activeNotesMutex.lock();

	for (int i = 0; i < _maximumActiveNotes; ++i) {
		if ((source == 0xFF || _activeNotes[i].source == source) &&
				(channel == 0xFF || _activeNotes[i].channel == channel)) {
			if (_activeNotes[i].sustain) {
				// Turn off sustain
				controlChange(_activeNotes[i].channel, MIDI_CONTROLLER_SUSTAIN, 0x00, _activeNotes[i].source, *_controlData[i]);
			} else {
				// Send note off
				noteOnOff(_activeNotes[i].channel, MIDI_COMMAND_NOTE_OFF, _activeNotes[i].note, 0x00, _activeNotes[i].source, *_controlData[i]);
			}
		}
	}

	_activeNotesMutex.unlock();
}

void MidiDriver_MT32GM::onTimer() {
	MidiDriver_Multisource::onTimer();

	_sysExQueueMutex.lock();

	_sysExDelay -= (_sysExDelay > _timerRate) ? _timerRate : _sysExDelay;

	if (!_sysExQueue.empty() && _sysExDelay == 0) {
		// Ready to send next SysEx message to the MIDI device
		SysExData sysEx = _sysExQueue.front();
		_sysExDelay = sysExNoDelay(sysEx.data, sysEx.length) * 1000;
		_sysExQueue.pop_front();
	}

	_sysExQueueMutex.unlock();
}

#endif
