Пример #1
0
void SoundGen2GS::playMidiSound() {
	if (_disabledMidi)
		return;

	const uint8 *p;
	uint8 parm1, parm2;
	static uint8 cmd, ch;

	if (_playingSound == -1 || _vm->_game.sounds[_playingSound] == NULL) {
		warning("Error playing Apple IIGS MIDI sound resource");
		_playing = false;

		return;
	}

	IIgsMidi *midiObj = (IIgsMidi *) _vm->_game.sounds[_playingSound];

	_playing = true;
	p = midiObj->getPtr();

	midiObj->_soundBufTicks++;

	while (true) {
		uint8 readByte = *p;

		// Check for end of MIDI sequence marker (Can also be here before delta-time)
		if (readByte == MIDI_BYTE_STOP_SEQUENCE) {
			debugC(3, kDebugLevelSound, "End of MIDI sequence (Before reading delta-time)");
			_playing = false;

			midiObj->rewind();

			return;
		} else if (readByte == MIDI_BYTE_TIMER_SYNC) {
			debugC(3, kDebugLevelSound, "Timer sync");
			p++; // Jump over the timer sync byte as it's not needed

			continue;
		}

		uint8 deltaTime = readByte;
		if (midiObj->_midiTicks + deltaTime > midiObj->_soundBufTicks) {
			break;
		}
		midiObj->_midiTicks += deltaTime;
		p++; // Jump over the delta-time byte as it was already taken care of

		// Check for end of MIDI sequence marker (This time it after reading delta-time)
		if (*p == MIDI_BYTE_STOP_SEQUENCE) {
			debugC(3, kDebugLevelSound, "End of MIDI sequence (After reading delta-time)");
			_playing = false;

			midiObj->rewind();

			return;
		}

		// Separate byte into command and channel if it's a command byte.
		// Otherwise use running status (i.e. previously set command and channel).
		if (*p & 0x80) {
			cmd = *p++;
			ch = cmd & 0x0f;
			cmd >>= 4;
		}

		switch (cmd) {
		case MIDI_CMD_NOTE_OFF:
			parm1 = *p++;
			parm2 = *p++;
			midiNoteOff(ch, parm1, parm2);
			break;
		case MIDI_CMD_NOTE_ON:
			parm1 = *p++;
			parm2 = *p++;
			midiNoteOn(ch, parm1, parm2);
			break;
		case MIDI_CMD_CONTROLLER:
			parm1 = *p++;
			parm2 = *p++;
			midiController(ch, parm1, parm2);
			break;
		case MIDI_CMD_PROGRAM_CHANGE:
			parm1 = *p++;
			midiProgramChange(ch, parm1);
			break;
		case MIDI_CMD_PITCH_WHEEL:
			parm1 = *p++;
			parm2 = *p++;

			uint16 wheelPos = ((parm2 & 0x7F) << 7) | (parm1 & 0x7F); // 14-bit value
			midiPitchWheel(wheelPos);
			break;
		}
	}
Пример #2
0
void SoundGen2GS::advanceMidiPlayer() {
	if (_disableMidi)
		return;

	const uint8 *p;
	uint8 parm1, parm2;
	static uint8 cmd, chn;

	if (_playingSound == -1 || _vm->_game.sounds[_playingSound] == NULL) {
		warning("Error playing Apple IIGS MIDI sound resource");
		_playing = false;
		return;
	}

	IIgsMidi *midiObj = (IIgsMidi *) _vm->_game.sounds[_playingSound];

	_ticks++;
	_playing = true;
	p = midiObj->getPtr();

	while (true) {
		// Check for end of MIDI sequence marker (Can also be here before delta-time)
		if (*p == MIDI_STOP_SEQUENCE) {
			debugC(3, kDebugLevelSound, "End of MIDI sequence (Before reading delta-time)");
			_playing = false;
			midiObj->rewind();
			return;
		}
		if (*p == MIDI_TIMER_SYNC) {
			debugC(3, kDebugLevelSound, "Timer sync");
			p++; // Jump over the timer sync byte as it's not needed
			continue;
		}

		// Check for delta time
		uint8 delta = *p;
		if (midiObj->_ticks + delta > _ticks)
			break;
		midiObj->_ticks += delta;
		p++;

		// Check for end of MIDI sequence marker (This time it after reading delta-time)
		if (*p == MIDI_STOP_SEQUENCE) {
			debugC(3, kDebugLevelSound, "End of MIDI sequence (After reading delta-time)");
			_playing = false;
			midiObj->rewind();
			return;
		}

		// Separate byte into command and channel if it's a command byte.
		// Otherwise use running status (i.e. previously set command and channel).
		if (*p & 0x80) {
			cmd = *p++;
			chn = cmd & 0x0f;
			cmd >>= 4;
		}

		switch (cmd) {
		case MIDI_NOTE_OFF:
			parm1 = *p++;
			parm2 = *p++;
			debugC(3, kDebugLevelSound, "channel %X: note off (key = %d, velocity = %d)", chn, parm1, parm2);
			midiNoteOff(chn, parm1, parm2);
			break;
		case MIDI_NOTE_ON:
			parm1 = *p++;
			parm2 = *p++;
			debugC(3, kDebugLevelSound, "channel %X: note on (key = %d, velocity = %d)", chn, parm1, parm2);
			midiNoteOn(chn, parm1, parm2);
			break;
		case MIDI_CONTROLLER:
			parm1 = *p++;
			parm2 = *p++;
			debugC(3, kDebugLevelSound, "channel %X: controller %02X = %02X", chn, parm1, parm2);
			// The tested Apple IIGS AGI MIDI resources only used
			// controllers 0 (Bank select?), 7 (Volume) and 64 (Sustain On/Off).
			// Controller 0's parameter was in range 94-127,
			// controller 7's parameter was in range 0-127 and
			// controller 64's parameter was always 0 (i.e. sustain off).
			switch (parm1) {
			case 7:
				_channels[chn].setVolume(parm2);
				break;
			}
			break;
		case MIDI_PROGRAM_CHANGE:
			parm1 = *p++;
			debugC(3, kDebugLevelSound, "channel %X: program change %02X", chn, parm1);
			_channels[chn].setInstrument(getInstrument(parm1));
			break;
		case MIDI_PITCH_WHEEL:
			parm1 = *p++;
			parm2 = *p++;
			debugC(3, kDebugLevelSound, "channel %X: pitch wheel (unimplemented)", chn);
			break;

		default:
			debugC(3, kDebugLevelSound, "channel %X: unimplemented command %02X", chn, cmd);
			break;
		}
	}