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

NMIError noreply at scummvm.org
Sun Oct 27 20:34:15 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:
bcdd54ee8d DARKSEED: Add CD version music player


Commit: bcdd54ee8d34bdecd4e8189d0eca6795f23dc78c
    https://github.com/scummvm/scummvm/commit/bcdd54ee8d34bdecd4e8189d0eca6795f23dc78c
Author: Coen Rampen (crampen at gmail.com)
Date: 2024-10-27T21:34:06+01:00

Commit Message:
DARKSEED: Add CD version music player

Changed paths:
  A engines/darkseed/adlib_worx.cpp
  A engines/darkseed/adlib_worx.h
  A engines/darkseed/music.cpp
  A engines/darkseed/music.h
    audio/adlib_ms.cpp
    audio/adlib_ms.h
    engines/darkseed/cutscene.cpp
    engines/darkseed/darkseed.cpp
    engines/darkseed/darkseed.h
    engines/darkseed/module.mk
    engines/darkseed/sound.cpp
    engines/darkseed/sound.h


diff --git a/audio/adlib_ms.cpp b/audio/adlib_ms.cpp
index e2284c15047..8ecec4052cc 100644
--- a/audio/adlib_ms.cpp
+++ b/audio/adlib_ms.cpp
@@ -93,6 +93,50 @@ void AdLibBnkInstrumentDefinition::toOplInstrumentDefinition(OplInstrumentDefini
 	instrumentDef.rhythmType = RHYTHM_TYPE_UNDEFINED;
 }
 
+void AdLibIbkInstrumentDefinition::toOplInstrumentDefinition(OplInstrumentDefinition &instrumentDef) {
+	instrumentDef.fourOperator = false;
+
+	instrumentDef.operator0.freqMultMisc = o0FreqMultMisc;
+	instrumentDef.operator0.level = o0Level;
+	instrumentDef.operator0.decayAttack = o0DecayAttack;
+	instrumentDef.operator0.releaseSustain = o0ReleaseSustain;
+	instrumentDef.operator0.waveformSelect = o0WaveformSelect;
+
+	instrumentDef.operator1.freqMultMisc = o1FreqMultMisc;
+	instrumentDef.operator1.level = o1Level;
+	instrumentDef.operator1.decayAttack = o1DecayAttack;
+	instrumentDef.operator1.releaseSustain = o1ReleaseSustain;
+	instrumentDef.operator1.waveformSelect = o1WaveformSelect;
+
+	instrumentDef.connectionFeedback0 = connectionFeedback;
+
+	instrumentDef.rhythmNote = rhythmNote;
+	OplInstrumentRhythmType convRhythmType;
+	switch (rhythmType) {
+		case 6:
+			convRhythmType = RHYTHM_TYPE_BASS_DRUM;
+			break;
+		case 7:
+			convRhythmType = RHYTHM_TYPE_SNARE_DRUM;
+			break;
+		case 8:
+			convRhythmType = RHYTHM_TYPE_TOM_TOM;
+			break;
+		case 9:
+			convRhythmType = RHYTHM_TYPE_CYMBAL;
+			break;
+		case 10:
+			convRhythmType = RHYTHM_TYPE_HI_HAT;
+			break;
+		case 0:
+		default:
+			convRhythmType = RHYTHM_TYPE_UNDEFINED;
+			break;
+	}
+	instrumentDef.rhythmType = convRhythmType;
+	// TODO Add support for transpose
+}
+
 // These are the melodic instrument definitions used by the Win95 SB16 driver.
 OplInstrumentDefinition MidiDriver_ADLIB_Multisource::OPL_INSTRUMENT_BANK[128] = {
 	// 0x00
@@ -402,6 +446,7 @@ MidiDriver_ADLIB_Multisource::MidiDriver_ADLIB_Multisource(OPL::Config::OplType
 		_allocationMode(ALLOCATION_MODE_DYNAMIC),
 		_instrumentWriteMode(INSTRUMENT_WRITE_MODE_NOTE_ON),
 		_rhythmModeIgnoreNoteOffs(false),
+		_channel10Melodic(false),
 		_defaultChannelVolume(0),
 		_noteSelect(NOTE_SELECT_MODE_0),
 		_modulationDepth(MODULATION_DEPTH_HIGH),
@@ -1317,7 +1362,7 @@ void MidiDriver_ADLIB_Multisource::recalculateVolumes(uint8 channel, uint8 sourc
 MidiDriver_ADLIB_Multisource::InstrumentInfo MidiDriver_ADLIB_Multisource::determineInstrument(uint8 channel, uint8 source, uint8 note) {
 	InstrumentInfo instrument = { 0, nullptr, 0 };
 
-	if (channel == MIDI_RHYTHM_CHANNEL) {
+	if (!_channel10Melodic && channel == MIDI_RHYTHM_CHANNEL) {
 		// On the rhythm channel, the note played indicates which instrument
 		// should be used.
 		if (note < _rhythmBankFirstNote || note > _rhythmBankLastNote)
diff --git a/audio/adlib_ms.h b/audio/adlib_ms.h
index 3e9a8459ee4..115fe87b10b 100644
--- a/audio/adlib_ms.h
+++ b/audio/adlib_ms.h
@@ -212,6 +212,45 @@ struct AdLibBnkInstrumentDefinition {
 	void toOplInstrumentDefinition(OplInstrumentDefinition &instrumentDef);
 } PACKED_STRUCT;
 
+/**
+ * Instrument definition for an OPL2 chip in the format used by the IBK
+ * instrument bank file format. This format is also used by the SBI and CMF
+ * file formats.
+ */
+struct AdLibIbkInstrumentDefinition {
+	uint8 o0FreqMultMisc;
+	uint8 o1FreqMultMisc;
+	uint8 o0Level;
+	uint8 o1Level;
+	uint8 o0DecayAttack;
+	uint8 o1DecayAttack;
+	uint8 o0ReleaseSustain;
+	uint8 o1ReleaseSustain;
+	uint8 o0WaveformSelect;
+	uint8 o1WaveformSelect;
+	uint8 connectionFeedback;
+	/**
+	 * Rhythm note type. 0: melodic, 6: bass drum, 7: snare drum, 8: tom tom, 9: cymbal, 10: hi hat
+	 */
+	uint8 rhythmType;
+	/**
+	 * Number of semitones to transpose a note using this instrument.
+	 */
+	int8 transpose;
+	uint8 rhythmNote;
+	uint8 padding1;
+	uint8 padding2;
+
+	/**
+	 * Copies the data in this AdLib BNK instrument definition to the specified
+	 * OplInstrumentDefinition struct.
+	 *
+	 * @param instrumentDef The instrument definition to which the data should
+	 * be copied.
+	 */
+	void toOplInstrumentDefinition(OplInstrumentDefinition &instrumentDef);
+} PACKED_STRUCT;
+
 #include "common/pack-end.h" // END STRUCT PACKING
 
 /**
@@ -1150,6 +1189,9 @@ protected:
 	InstrumentWriteMode _instrumentWriteMode;
 	// Controls response to rhythm note off events when rhythm mode is active.
 	bool _rhythmModeIgnoreNoteOffs;
+	// Controls whether MIDI channel 10 is treated as the rhythm channel or as
+	// a melodic channel.
+	bool _channel10Melodic;
 
 	// The default MIDI channel volume (set when opening the driver).
 	uint8 _defaultChannelVolume;
diff --git a/engines/darkseed/adlib_worx.cpp b/engines/darkseed/adlib_worx.cpp
new file mode 100644
index 00000000000..d705eabfbd7
--- /dev/null
+++ b/engines/darkseed/adlib_worx.cpp
@@ -0,0 +1,235 @@
+/* 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/>.
+ *
+ */
+
+#include "darkseed/adlib_worx.h"
+
+namespace Darkseed {
+
+AdLibIbkInstrumentDefinition MidiDriver_Worx_AdLib::WORX_INSTRUMENT_BANK[128] = {
+	// 0x00
+	{ 0x01, 0x01, 0x4f, 0x12, 0xf1, 0xd3, 0x50, 0x7c, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x02, 0x01, 0x50, 0x12, 0xf1, 0xd2, 0x50, 0x76, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x01, 0x4b, 0x17, 0xf1, 0xd2, 0x50, 0x76, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x13, 0x01, 0x50, 0x11, 0xf1, 0xd2, 0x50, 0x76, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x32, 0x01, 0x92, 0x8f, 0xff, 0xff, 0x11, 0x13, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x34, 0x03, 0x92, 0x0f, 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x34, 0x03, 0x92, 0x14, 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x53, 0x51, 0x4e, 0x00, 0xf1, 0xd2, 0x00, 0x86, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x08
+	{ 0x28, 0x21, 0xcf, 0x0d, 0xf8, 0xc0, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xe2, 0xe1, 0xca, 0x15, 0xf8, 0xc0, 0xe5, 0x0e, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x2c, 0xa1, 0xd4, 0x1c, 0xf9, 0xc0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x2b, 0x21, 0xca, 0x13, 0xf8, 0xc0, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x29, 0x21, 0xcd, 0x14, 0xf0, 0xe0, 0x91, 0x86, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x24, 0x21, 0xd0, 0x14, 0xf0, 0xe0, 0x01, 0x86, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x23, 0x21, 0xc8, 0x10, 0xf0, 0xe0, 0x01, 0x86, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x64, 0x61, 0xc9, 0x14, 0xb0, 0xf0, 0x01, 0x86, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x10
+	{ 0x33, 0x15, 0x85, 0x94, 0xa1, 0x72, 0x10, 0x23, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x15, 0x85, 0x94, 0xa1, 0x73, 0x10, 0x33, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x16, 0x81, 0x94, 0xa1, 0xc2, 0x30, 0x74, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x03, 0x02, 0x8a, 0x94, 0xf0, 0xf4, 0x7b, 0x7b, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x03, 0x01, 0x8a, 0x99, 0xf0, 0xf4, 0x7b, 0x7b, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x23, 0x01, 0x8a, 0x94, 0xf2, 0xf4, 0x7b, 0x7b, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x32, 0x12, 0x80, 0x95, 0x01, 0x72, 0x10, 0x33, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x32, 0x14, 0x80, 0x90, 0x01, 0x73, 0x10, 0x33, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x18
+	{ 0x31, 0x21, 0x16, 0x14, 0x73, 0x80, 0x8e, 0x9e, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x30, 0x21, 0x16, 0x10, 0x73, 0x80, 0x7e, 0x9e, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x21, 0x94, 0x15, 0x33, 0xa0, 0x73, 0x97, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x21, 0x94, 0x13, 0xd3, 0xa0, 0x73, 0x97, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x32, 0x45, 0x11, 0xf1, 0xf2, 0x53, 0x27, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x13, 0x15, 0x0c, 0x1a, 0xf2, 0xf2, 0x01, 0xb6, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x11, 0x11, 0x0c, 0x15, 0xf2, 0xf2, 0x01, 0xb6, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x11, 0x11, 0x0a, 0x10, 0xfe, 0xf2, 0x04, 0xbd, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x20
+	{ 0x16, 0xe1, 0x4d, 0x11, 0xfa, 0xf1, 0x11, 0xf1, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x16, 0xf1, 0x40, 0x17, 0xba, 0x24, 0x11, 0x31, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x61, 0xe1, 0xa7, 0x8e, 0x72, 0x50, 0x8e, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x18, 0xe1, 0x4d, 0x13, 0x32, 0x51, 0x13, 0xe3, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x17, 0x31, 0xc0, 0x92, 0x12, 0x13, 0x41, 0x31, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x03, 0x21, 0x8f, 0x90, 0xf5, 0xf3, 0x55, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x13, 0xe1, 0x4d, 0x12, 0xfa, 0xf1, 0x11, 0xf1, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x11, 0xf1, 0x43, 0x10, 0x20, 0x31, 0x15, 0xf8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x28
+	{ 0x11, 0xe4, 0x03, 0x52, 0x82, 0xf0, 0x97, 0xf2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x05, 0x14, 0x40, 0x0f, 0xd1, 0x51, 0x53, 0x71, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xf1, 0x21, 0x01, 0x12, 0x77, 0x81, 0x17, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xf1, 0xe1, 0x18, 0x17, 0x32, 0xf1, 0x11, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x73, 0x71, 0x48, 0x13, 0xf1, 0xf1, 0x53, 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x71, 0x61, 0x8d, 0x53, 0x71, 0x72, 0x11, 0x15, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xd7, 0xd2, 0x4f, 0x14, 0xf2, 0xf1, 0x61, 0xb2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x01, 0x11, 0x13, 0xf0, 0xf0, 0xff, 0xf8, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x30
+	{ 0x31, 0x61, 0x8b, 0x10, 0x41, 0x22, 0x11, 0x13, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x61, 0x8b, 0x10, 0xff, 0x44, 0x21, 0x15, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x61, 0x8b, 0x10, 0x41, 0x32, 0x11, 0x15, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x71, 0x21, 0x1c, 0x10, 0xfd, 0xe7, 0x13, 0xd6, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x71, 0x21, 0x1c, 0x10, 0x51, 0x54, 0x03, 0x67, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x71, 0x21, 0x1c, 0x10, 0x51, 0x54, 0x03, 0x17, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x71, 0x21, 0x1c, 0x10, 0x54, 0x53, 0x15, 0x49, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x71, 0x61, 0x56, 0x10, 0x51, 0x54, 0x03, 0x17, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x38
+	{ 0x71, 0x21, 0x1c, 0x10, 0x51, 0x54, 0x03, 0x17, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x02, 0x01, 0x29, 0x90, 0xf5, 0xf2, 0x75, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x02, 0x01, 0x29, 0x90, 0xf0, 0xf4, 0x75, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x11, 0x49, 0x10, 0xf1, 0xf1, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x11, 0x89, 0x10, 0xf1, 0xf1, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x02, 0x11, 0x89, 0x10, 0xf1, 0xf1, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x02, 0x11, 0x80, 0x10, 0xf1, 0xf1, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x08, 0x40, 0x50, 0xf1, 0xf1, 0x53, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x40
+	{ 0x21, 0x21, 0x15, 0x90, 0xd3, 0xc3, 0x2c, 0x2c, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x21, 0x18, 0x90, 0xd4, 0xc4, 0xf2, 0x8a, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x11, 0x4e, 0x10, 0xf0, 0xf4, 0x7b, 0xc8, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x01, 0x11, 0x44, 0x10, 0xf0, 0xf3, 0xab, 0xab, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x53, 0x11, 0x0e, 0x10, 0xf4, 0xf1, 0xc8, 0xbb, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x53, 0x11, 0x0b, 0x10, 0xf2, 0xf2, 0xc8, 0xc5, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x21, 0x21, 0x15, 0x10, 0xb4, 0x94, 0x4c, 0xac, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x21, 0x21, 0x15, 0x10, 0x94, 0x64, 0x1c, 0xac, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x48
+	{ 0x21, 0xa1, 0x16, 0x90, 0x77, 0x60, 0x8f, 0x2a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x21, 0xa1, 0x19, 0x90, 0x77, 0x60, 0xbf, 0x2a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xa1, 0xe2, 0x13, 0x90, 0xd6, 0x60, 0xaf, 0x2a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xa2, 0xe2, 0x1d, 0x90, 0x95, 0x60, 0x24, 0x2a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x32, 0x61, 0x9a, 0x90, 0x51, 0x60, 0x19, 0x39, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xa4, 0xe2, 0x12, 0x90, 0xf4, 0x60, 0x30, 0x2a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x21, 0x21, 0x16, 0x10, 0x63, 0x63, 0x0e, 0x0e, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x21, 0x16, 0x10, 0x63, 0x63, 0x0a, 0x0b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x50
+	{ 0x21, 0x21, 0x1b, 0x10, 0x63, 0x63, 0x0a, 0x0b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x20, 0x21, 0x1b, 0x10, 0x63, 0x63, 0x0a, 0x0b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x32, 0x61, 0x1c, 0x90, 0x82, 0x60, 0x18, 0x07, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x32, 0xe1, 0x18, 0x90, 0x51, 0x62, 0x14, 0x36, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x22, 0xc3, 0x10, 0x87, 0x8b, 0x17, 0x0e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x71, 0x22, 0xc3, 0x14, 0x8e, 0x8b, 0x17, 0x0e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x70, 0x22, 0x8d, 0x10, 0x6e, 0x6b, 0x17, 0x0e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x24, 0x31, 0x4f, 0x10, 0xf2, 0x52, 0x06, 0x06, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x58
+	{ 0x31, 0x61, 0x1b, 0x10, 0x64, 0xd0, 0x07, 0x67, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x61, 0x1b, 0x10, 0x61, 0xd2, 0x06, 0x36, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x61, 0x1f, 0x10, 0x31, 0x50, 0x06, 0x36, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x61, 0x1f, 0x10, 0x41, 0xa0, 0x06, 0x36, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x21, 0x21, 0x9a, 0x90, 0x53, 0xa0, 0x56, 0x16, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x21, 0x21, 0x9a, 0x90, 0x53, 0xa0, 0x56, 0x16, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x61, 0x21, 0x19, 0x10, 0x53, 0xa0, 0x58, 0x18, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x61, 0x21, 0x19, 0x10, 0x73, 0xa0, 0x57, 0x17, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x60
+	{ 0x21, 0x21, 0x1b, 0x10, 0x71, 0xa1, 0xa6, 0x96, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x85, 0xa1, 0x91, 0x10, 0xf5, 0xf0, 0x44, 0x45, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x07, 0x61, 0x51, 0x10, 0xf5, 0xf0, 0x33, 0x25, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x13, 0x11, 0x8c, 0x90, 0xff, 0xff, 0x21, 0x03, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x38, 0xb1, 0x8c, 0x50, 0xf3, 0xf5, 0x0d, 0x33, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x87, 0x22, 0x91, 0x10, 0xf5, 0xf0, 0x55, 0x54, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xb3, 0x90, 0x4a, 0x10, 0xb6, 0xd1, 0x32, 0x31, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x04, 0xc2, 0x00, 0x10, 0xfe, 0xf6, 0xf0, 0xb5, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x68
+	{ 0x05, 0x01, 0x4e, 0x90, 0xda, 0xf0, 0x15, 0x13, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x32, 0x44, 0x10, 0xf2, 0xf0, 0x9a, 0x27, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xb0, 0xd7, 0xc4, 0x90, 0xa4, 0x40, 0x02, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xca, 0xcc, 0x84, 0x10, 0xf0, 0x59, 0xf0, 0x62, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x30, 0x35, 0x35, 0x10, 0xf5, 0xf0, 0xf0, 0x9b, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xb4, 0xd7, 0x87, 0x90, 0xa4, 0x40, 0x02, 0x42, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x07, 0x05, 0x40, 0x00, 0x09, 0xf6, 0x53, 0x96, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x09, 0x01, 0x4e, 0x10, 0xda, 0xf1, 0x25, 0x15, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x70
+	{ 0x06, 0x00, 0x09, 0x10, 0xf4, 0xf6, 0xa0, 0x46, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x07, 0x00, 0x00, 0x10, 0xf0, 0x5c, 0xf0, 0xdc, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x1c, 0x0c, 0x1e, 0x10, 0xe5, 0x5d, 0x5b, 0xfa, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x11, 0x01, 0x8a, 0x50, 0xf1, 0xf1, 0x11, 0xb3, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x00, 0x00, 0x40, 0x10, 0xd1, 0xf2, 0x53, 0x56, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x32, 0x11, 0x44, 0x10, 0xf8, 0xf5, 0xff, 0x7f, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x00, 0x02, 0x40, 0x10, 0x09, 0xf7, 0x53, 0x94, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x11, 0x01, 0x86, 0x90, 0xf2, 0xa0, 0xa8, 0xa8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	// 0x78
+	{ 0x00, 0x13, 0x50, 0x10, 0xf2, 0xf2, 0x70, 0x72, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0xf0, 0xe0, 0x00, 0xd0, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x07, 0x12, 0x4f, 0x10, 0xf2, 0xf2, 0x60, 0x72, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x00, 0x00, 0x0b, 0x10, 0xa8, 0xd6, 0x4c, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x00, 0x00, 0x0d, 0x10, 0xe8, 0xa5, 0xef, 0xff, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x31, 0x16, 0x87, 0x90, 0xa1, 0x7d, 0x11, 0x46, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x30, 0x10, 0x90, 0x10, 0xf4, 0xf4, 0x49, 0x33, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
+	{ 0x24, 0x31, 0x54, 0x10, 0x55, 0x50, 0xfd, 0x2d, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }
+};
+
+MidiDriver_Worx_AdLib::MidiDriver_Worx_AdLib(OPL::Config::OplType oplType, int timerFrequency) :
+	MidiDriver_ADLIB_Multisource::MidiDriver_ADLIB_Multisource(oplType, timerFrequency) {
+
+	_instrumentBank = new OplInstrumentDefinition[128];
+
+	for (int i = 0; i < 128; i++) {
+		WORX_INSTRUMENT_BANK[i].toOplInstrumentDefinition(_instrumentBank[i]);
+	}
+
+	_defaultChannelVolume = 0x7F;
+	_channel10Melodic = true;
+}
+
+MidiDriver_Worx_AdLib::~MidiDriver_Worx_AdLib() {
+	delete[] _instrumentBank;
+}
+
+uint8 MidiDriver_Worx_AdLib::allocateOplChannel(uint8 channel, uint8 source, uint8 instrumentId) {
+	uint8 allocatedChannel = 0xFF;
+
+	_allocationMutex.lock();
+
+	uint8 unusedChannel = 0xFF, unallocatedChannel = 0xFF, unusedAllocatedChannel = 0xFF;
+	for (int i = 0; i < _numMelodicChannels; i++) {
+		uint8 oplChannel = _melodicChannels[i];
+		if (_activeNotes[oplChannel].channelAllocated && _activeNotes[oplChannel].source == source && _activeNotes[oplChannel].channel == channel &&
+				!_activeNotes[oplChannel].noteActive && unusedChannel == 0xFF) {
+			unusedChannel = oplChannel;
+			break;
+		}
+		if (!_activeNotes[oplChannel].channelAllocated && unallocatedChannel == 0xFF) {
+			unallocatedChannel = oplChannel;
+		}
+		if (_activeNotes[oplChannel].channelAllocated && !(_activeNotes[oplChannel].source == source && _activeNotes[oplChannel].channel == channel) &&
+				!_activeNotes[oplChannel].noteActive && unusedAllocatedChannel == 0xFF) {
+			unusedAllocatedChannel = oplChannel;
+		}
+	}
+
+	if (unusedChannel != 0xFF) {
+		allocatedChannel = unusedChannel;
+	}
+	else if (unallocatedChannel != 0xFF) {
+		allocatedChannel = unallocatedChannel;
+	}
+	else if (unusedAllocatedChannel != 0xFF) {
+		allocatedChannel = unusedAllocatedChannel;
+	}
+	else {
+		_allocationMutex.unlock();
+		return allocatedChannel;
+	}
+
+	_activeNotes[allocatedChannel].channelAllocated = true;
+	_activeNotes[allocatedChannel].source = source;
+	_activeNotes[allocatedChannel].channel = channel;
+
+	_allocationMutex.unlock();
+
+	return allocatedChannel;
+}
+
+} // namespace Darkseed
diff --git a/engines/darkseed/adlib_worx.h b/engines/darkseed/adlib_worx.h
new file mode 100644
index 00000000000..46f581cd2e3
--- /dev/null
+++ b/engines/darkseed/adlib_worx.h
@@ -0,0 +1,43 @@
+/* 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 DARKSEED_ADLIB_WORX_H
+#define DARKSEED_ADLIB_WORX_H
+
+#include "audio/adlib_ms.h"
+
+namespace Darkseed {
+
+class MidiDriver_Worx_AdLib : public MidiDriver_ADLIB_Multisource {
+private:
+	static AdLibIbkInstrumentDefinition WORX_INSTRUMENT_BANK[];
+
+public:
+	MidiDriver_Worx_AdLib(OPL::Config::OplType oplType, int timerFrequency);
+	~MidiDriver_Worx_AdLib();
+
+protected:
+	uint8 allocateOplChannel(uint8 channel, uint8 source, uint8 instrumentId) override;
+};
+
+} // namespace Darkseed
+
+#endif // DARKSEED_ADLIB_WORX_H
diff --git a/engines/darkseed/cutscene.cpp b/engines/darkseed/cutscene.cpp
index 40afb2900d5..8fd0368b65a 100644
--- a/engines/darkseed/cutscene.cpp
+++ b/engines/darkseed/cutscene.cpp
@@ -167,6 +167,7 @@ bool Cutscene::introScene() {
 		}
 		break;
 	case 15: {
+		g_engine->_sound->playMusic(StartMusicId::kCredits);
 		g_engine->_screen->clear();
 		g_engine->_screen->clearPalette();
 		g_engine->_screen->makeAllDirty();
@@ -396,9 +397,17 @@ bool Cutscene::introScene() {
 			return true;
 		}
 		break;
-	case 50: // TODO wait for music.
+	case 50:
+		if (g_engine->_sound->isPlayingMusic()) {
+			if (g_engine->_isLeftMouseClicked || g_engine->_isRightMouseClicked) {
+				g_engine->zeroMouseButtons();
+				_movieStep = 51;
+			}
+			return true;
+		}
 		break;
 	case 51:
+		g_engine->_sound->stopMusic();
 		g_engine->fadeOut();
 		break;
 	case 52:
@@ -448,7 +457,7 @@ bool Cutscene::embryoInsertedScene() {
 		break;
 	}
 	case 6:
-		// TODO play implant music here.
+		g_engine->_sound->playMusic(StartMusicId::kImplant);
 		registTime();
 		g_engine->fadeIn(_palette);
 		break;
@@ -511,6 +520,7 @@ bool Cutscene::embryoInsertedScene() {
 		}
 		break;
 	case 16:
+		g_engine->_sound->stopMusic();
 		g_engine->fadeOut();
 		break;
 	case 17:
diff --git a/engines/darkseed/darkseed.cpp b/engines/darkseed/darkseed.cpp
index 9cc98fd9c94..263c41cc88f 100644
--- a/engines/darkseed/darkseed.cpp
+++ b/engines/darkseed/darkseed.cpp
@@ -59,6 +59,9 @@ Common::String DarkseedEngine::getGameId() const {
 Common::Error DarkseedEngine::run() {
 	initGraphics(640, 350);
 	_sound = new Sound(_mixer);
+	if (_sound->init() > 0) {
+		return Common::kAudioDeviceInitFailed;
+	}
 	_screen = new Graphics::Screen();
 	_tosText = new TosText();
 	_tosText->load();
@@ -377,6 +380,12 @@ void DarkseedEngine::wait() {
 	}
 }
 
+void DarkseedEngine::syncSoundSettings() {
+	Engine::syncSoundSettings();
+
+	_sound->syncSoundSettings();
+}
+
 static constexpr uint8 walkToDirTbl[] = {
 	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
 	0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
diff --git a/engines/darkseed/darkseed.h b/engines/darkseed/darkseed.h
index f3a1da0434c..4e191547ece 100644
--- a/engines/darkseed/darkseed.h
+++ b/engines/darkseed/darkseed.h
@@ -151,6 +151,8 @@ public:
 
 	void wait();
 
+	void syncSoundSettings() override;
+
 public:
 	DarkseedEngine(OSystem *syst, const ADGameDescription *gameDesc);
 	~DarkseedEngine() override;
diff --git a/engines/darkseed/module.mk b/engines/darkseed/module.mk
index c6fa3787ed1..9408516237e 100644
--- a/engines/darkseed/module.mk
+++ b/engines/darkseed/module.mk
@@ -1,6 +1,7 @@
 MODULE := engines/darkseed
 
 MODULE_OBJS = \
+	adlib_worx.o \
 	animation.o \
 	anm.o \
 	console.o \
@@ -13,6 +14,7 @@ MODULE_OBJS = \
 	inventory.o \
 	metaengine.o \
 	morph.o \
+	music.o \
 	nsp.o \
 	objects.o \
 	pal.o \
diff --git a/engines/darkseed/music.cpp b/engines/darkseed/music.cpp
new file mode 100644
index 00000000000..898ae548add
--- /dev/null
+++ b/engines/darkseed/music.cpp
@@ -0,0 +1,196 @@
+/* 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/>.
+ *
+ */
+
+#include "darkseed/music.h"
+#include "darkseed/darkseed.h"
+
+namespace Darkseed {
+
+MusicPlayer::MusicPlayer(DarkseedEngine* vm) :
+	_vm(vm),
+	_driver(nullptr),
+	_paused(false),
+	_deviceType(MT_NULL),
+	_parser(nullptr),
+	_musicData(nullptr) {
+}
+
+MusicPlayer::~MusicPlayer() {
+	stop();
+	if (_driver) {
+		_driver->setTimerCallback(nullptr, nullptr);
+		_driver->close();
+	}
+
+	Common::StackLock lock(_mutex);
+
+	if (_parser)
+		delete _parser;
+	if (_musicData)
+		delete[] _musicData;
+	if (_driver) {
+		delete _driver;
+		_driver = nullptr;
+	}
+}
+
+int MusicPlayer::open() {
+	assert(!_driver);
+
+	int devFlags = MDT_ADLIB; // | MDT_PCSPK;
+	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(devFlags);
+	_deviceType = MidiDriver::getMusicType(dev);
+
+	if (!_vm->isCdVersion()) {
+		// TODO Initialize driver and parser for floppy version
+		_driver = new MidiDriver_NULL_Multisource();
+	} else {
+		switch (_deviceType) {
+			case MT_ADLIB:
+				// TODO Verify timer frequency
+				_driver = new MidiDriver_Worx_AdLib(OPL::Config::kOpl2, 250);
+				// Some tracks do not set instruments and expect instrument 0
+				// to be set on each channel. Make sure this is done every time
+				// a track starts.
+				_driver->setControllerDefault(MidiDriver_Multisource::CONTROLLER_DEFAULT_PROGRAM);
+				break;
+			case MT_PCSPK:
+				// TODO Implement PC speaker driver
+			default:
+				_driver = new MidiDriver_NULL_Multisource();
+				break;
+		}
+
+		_parser = MidiParser::createParser_SMF(0);
+	}
+
+	_driver->property(MidiDriver::PROP_USER_VOLUME_SCALING, true);
+	if (_parser)
+		_parser->property(MidiParser::mpDisableAutoStartPlayback, true);
+
+	int returnCode = _driver->open();
+	if (returnCode != 0)
+		error("MusicPlayer::open - Failed to open MIDI driver - error code %d.", returnCode);
+
+	syncSoundSettings();
+
+	if (_parser) {
+		_parser->setMidiDriver(_driver);
+		_parser->setTimerRate(_driver->getBaseTempo());
+		_driver->setTimerCallback(_parser, &_parser->timerCallback);
+	}
+
+	return 0;
+}
+
+void MusicPlayer::onTimer(void *data) {
+	MusicPlayer *p = (MusicPlayer *)data;
+	Common::StackLock lock(p->_mutex);
+
+	if (p->_parser) {
+		p->_parser->onTimer();
+	}
+}
+
+bool MusicPlayer::isPlaying() {
+	Common::StackLock lock(_mutex);
+	return _parser && _parser->isPlaying();
+}
+
+void MusicPlayer::stop() {
+	Common::StackLock lock(_mutex);
+
+	if (_parser) {
+		_parser->stopPlaying();
+		if (_driver) {
+			_driver->deinitSource(0);
+		}
+	}
+}
+
+void MusicPlayer::pause(bool pause) {
+	Common::StackLock lock(_mutex);
+
+	if (_paused == pause || !_parser)
+		return;
+
+	_paused = pause;
+
+	if (_paused) {
+		_parser->pausePlaying();
+	} else {
+		_parser->resumePlaying();
+	}
+}
+
+void MusicPlayer::syncSoundSettings() {
+	if (_driver)
+		_driver->syncSoundSettings();
+}
+
+void MusicPlayer::setLoop(bool loop) {
+	Common::StackLock lock(_mutex);
+
+	if (_parser)
+		_parser->property(MidiParser::mpAutoLoop, loop);
+}
+
+void MusicPlayer::load(Common::SeekableReadStream *in, int32 size) {
+	Common::StackLock lock(_mutex);
+
+	if (!_parser)
+		return;
+
+	if (size < 0) {
+		// Use the parser to determine the size of the MIDI data.
+		int64 startPos = in->pos();
+		size = _parser->determineDataSize(in);
+		if (size < 0) {
+			warning("MusicPlayer::load - Could not determine size of music data");
+			return;
+		}
+		// determineDataSize might move the stream position, so return it to
+		// the original position.
+		in->seek(startPos);
+	}
+
+	_parser->unloadMusic();
+	if (_musicData) {
+		delete[] _musicData;
+	}
+
+	_musicData = new byte[size];
+	in->read(_musicData, size);
+
+	_parser->loadMusic(_musicData, size);
+}
+
+void MusicPlayer::play(bool loop) {
+	Common::StackLock lock(_mutex);
+
+	if (!_parser)
+		return;
+
+	_parser->property(MidiParser::mpAutoLoop, loop);
+	_parser->startPlaying();
+}
+
+} // namespace Darkseed
diff --git a/engines/darkseed/music.h b/engines/darkseed/music.h
new file mode 100644
index 00000000000..b04184e10f0
--- /dev/null
+++ b/engines/darkseed/music.h
@@ -0,0 +1,72 @@
+/* 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 DARKSEED_MUSIC_H
+#define DARKSEED_MUSIC_H
+
+#include "darkseed/adlib_worx.h"
+
+#include "audio/mididrv_ms.h"
+#include "audio/midiparser.h"
+#include "common/mutex.h"
+
+namespace Darkseed {
+
+class DarkseedEngine;
+
+class MusicPlayer {
+protected:
+	DarkseedEngine *_vm;
+
+	Common::Mutex _mutex;
+	MidiDriver_Multisource *_driver;
+
+	MidiParser *_parser;
+	byte *_musicData;
+
+	bool _paused;
+
+	static void onTimer(void *data);
+
+public:
+	MusicPlayer(DarkseedEngine *vm);
+	~MusicPlayer();
+
+	int open();
+
+	void load(Common::SeekableReadStream *in, int32 size = -1);
+
+	void play(bool loop = false);
+	void setLoop(bool loop);
+	bool isPlaying();
+	void stop();
+	void pause(bool pause);
+
+	void syncSoundSettings();
+
+private:
+	// The type of the music device selected for playback.
+	MusicType _deviceType;
+};
+
+} // namespace Darkseed
+
+#endif // DARKSEED_MUSIC_H
diff --git a/engines/darkseed/sound.cpp b/engines/darkseed/sound.cpp
index c585fd86cf5..2008193ad23 100644
--- a/engines/darkseed/sound.cpp
+++ b/engines/darkseed/sound.cpp
@@ -57,11 +57,42 @@ static constexpr char musicDosCDFilenameTbl[][14] = {
 	"walktown.mid"
 };
 
+static constexpr char startMusicDosFloppyFilenameTbl[][14] = {
+	"credits",
+	"alien",
+	"implant",
+	"launch",
+	"night2",
+	"night3",
+	"book",
+	"doll"
+};
+
+static constexpr char startMusicDosCDFilenameTbl[][14] = {
+	"openingt.mid",
+	"alienmou.mid",
+	"mindfuck.mid",
+	"spaceshi.mid",
+	"mindfuck.mid",
+	"zombie.mid",
+	"booktran.mid",
+	"babydoll.mid"
+};
+
 Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer) {
+	_musicPlayer = new MusicPlayer(g_engine);
 	_didSpeech.resize(978);
 	resetSpeech();
 }
 
+Sound::~Sound() {
+	delete _musicPlayer;
+}
+
+int Sound::init() {
+	return _musicPlayer->open();
+}
+
 void Sound::playTosSpeech(int tosIdx) {
 	if (!g_engine->isCdVersion() || _didSpeech[tosIdx] == 1) {
 		return;
@@ -84,7 +115,7 @@ bool Sound::isPlayingSpeech() const {
 }
 
 bool Sound::isPlayingMusic() {
-	return _isPlayingMusic;
+	return _musicPlayer->isPlaying();
 }
 
 void Sound::waitForSpeech() {
@@ -106,17 +137,42 @@ void Sound::playMusic(MusicId musicId) {
 	int filenameIdx = static_cast<uint8>(musicId) - 1;
 	playMusic(g_engine->isCdVersion()
 		? musicDosCDFilenameTbl[filenameIdx]
-		: musicDosFloppyFilenameTbl[filenameIdx]);
+		: musicDosFloppyFilenameTbl[filenameIdx],
+		true);
 }
 
-void Sound::playMusic(Common::String const &filename) {
+void Sound::playMusic(StartMusicId musicId) {
+	int filenameIdx = static_cast<uint8>(musicId);
+	playMusic(g_engine->isCdVersion()
+		? startMusicDosCDFilenameTbl[filenameIdx]
+		: startMusicDosFloppyFilenameTbl[filenameIdx]);
+}
+
+void Sound::playMusic(Common::String const &filename, bool loop) {
 	debug("Loading music: %s", filename.c_str());
-	_isPlayingMusic = true;
-	// TODO load music.
+	Common::File file;
+	Common::Path path;
+	if (!g_engine->isCdVersion()) {
+		path = Common::Path(filename);
+	} else {
+		path = Common::Path("sound").join(filename);
+	}
+	if (!file.open(path)) {
+		debug("Failed to load %s", path.toString().c_str());
+		return;
+	}
+	_musicPlayer->load(&file, file.size());
+	file.close();
+
+	_musicPlayer->play(loop);
 }
 
 void Sound::stopMusic() {
-	_isPlayingMusic = false;
+	_musicPlayer->stop();
+}
+
+void Sound::syncSoundSettings() {
+	_musicPlayer->syncSoundSettings();
 }
 
 Common::Error Sound::sync(Common::Serializer &s) {
diff --git a/engines/darkseed/sound.h b/engines/darkseed/sound.h
index 7f3836e8c73..e90662e9854 100644
--- a/engines/darkseed/sound.h
+++ b/engines/darkseed/sound.h
@@ -22,6 +22,8 @@
 #ifndef DARKSEED_SOUND_H
 #define DARKSEED_SOUND_H
 
+#include "darkseed/music.h"
+
 #include "audio/mixer.h"
 #include "common/array.h"
 #include "common/error.h"
@@ -44,14 +46,28 @@ enum class MusicId : uint8 {
 	kTown,
 };
 
+enum class StartMusicId : uint8 {
+	kCredits = 0,
+	kAlien,
+	kImplant,
+	kLaunch,
+	kNight2,
+	kNight3,
+	kBook,
+	kDoll
+};
+
 class Sound {
 	Audio::Mixer *_mixer;
 	Audio::SoundHandle _speechHandle;
+	MusicPlayer *_musicPlayer;
 	Common::Array<uint8> _didSpeech;
-	bool _isPlayingMusic = false;
 
 public:
 	explicit Sound(Audio::Mixer *mixer);
+	~Sound();
+
+	int init();
 
 	Common::Error sync(Common::Serializer &s);
 
@@ -61,8 +77,10 @@ public:
 	void waitForSpeech();
 	void resetSpeech();
 	void playMusic(MusicId musicId);
-	void playMusic(Common::String const &filename);
+	void playMusic(StartMusicId musicId);
+	void playMusic(Common::String const &filename, bool loop = false);
 	void stopMusic();
+	void syncSoundSettings();
 };
 
 } // namespace Darkseed




More information about the Scummvm-git-logs mailing list