/* 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 . * */ #include "audio/adlib_hmisos.h" const byte MidiDriver_ADLIB_HMISOS::INSTRUMENT_BANK_SIGNATURE[8] = { 0x00, 0x00, 'A', 'D', 'L', 'I', 'B', '-' }; MidiDriver_ADLIB_HMISOS::MidiDriver_ADLIB_HMISOS(OPL::Config::OplType oplType, int timerFrequency) : MidiDriver_ADLIB_Multisource(oplType, timerFrequency) { memset(_sosInstrumentBank, 0, sizeof(_sosInstrumentBank)); memset(_sosRhythmBank, 0, sizeof(_sosRhythmBank)); _instrumentWriteMode = INSTRUMENT_WRITE_MODE_NOTE_ON; _modulationDepth = MODULATION_DEPTH_LOW; _vibratoDepth = VIBRATO_DEPTH_LOW; _rhythmModeRewriteSharedRegister = true; } int MidiDriver_ADLIB_HMISOS::open() { return MidiDriver_ADLIB_Multisource::open(); } bool MidiDriver_ADLIB_HMISOS::loadInstrumentBanks(Common::SeekableReadStream *instrumentBankStream, Common::SeekableReadStream *rhythmBankStream) { int numInstruments = loadInstrumentBank(instrumentBankStream, false); if (numInstruments < 0) return false; _instrumentBank = _sosInstrumentBank; if (rhythmBankStream != nullptr) { numInstruments = loadInstrumentBank(rhythmBankStream, true); if (numInstruments < 0) return false; _rhythmBank = _sosRhythmBank; _rhythmBankFirstNote = 0; _rhythmBankLastNote = numInstruments; } return true; } int MidiDriver_ADLIB_HMISOS::loadInstrumentBank(Common::SeekableReadStream *stream, bool rhythmBank) { OplInstrumentDefinition *instrumentBank = rhythmBank ? _sosRhythmBank : _sosInstrumentBank; byte signature[8]; stream->read(signature, 8); if (memcmp(INSTRUMENT_BANK_SIGNATURE, signature, 8)) { warning("Invalid HMI SOS AdLib instrument bank signature"); return -1; } uint16 instrumentsUsed = stream->readUint16LE(); if (instrumentsUsed > 128) instrumentsUsed = 128; //uint16 instrumentsTotal = stream->readUint16LE(); stream->skip(2); uint32 namesOffset = stream->readUint32LE(); uint32 instDataOffset = stream->readUint32LE(); stream->seek(namesOffset, SEEK_SET); byte rhythmNotes[128]; for (uint16 i = 0; i < instrumentsUsed; i++) { stream->skip(2); // Instrument data offset // The flags byte is used to specify the rhythm note rhythmNotes[i] = stream->readByte(); stream->skip(9); // Instrument name } stream->seek(instDataOffset, SEEK_SET); AdLibBnkInstrumentDefinition bnkInstDef; for (uint16 i = 0; i < instrumentsUsed; i++) { stream->skip(2); // Instrument type and voice number bnkInstDef.operator0.keyScalingLevel = stream->readByte(); bnkInstDef.operator0.frequencyMultiplier = stream->readByte(); bnkInstDef.operator0.feedback = stream->readByte(); bnkInstDef.operator0.attack = stream->readByte(); bnkInstDef.operator0.sustain = stream->readByte(); bnkInstDef.operator0.envelopeGainType = stream->readByte(); bnkInstDef.operator0.decay = stream->readByte(); bnkInstDef.operator0.release = stream->readByte(); bnkInstDef.operator0.level = stream->readByte(); bnkInstDef.operator0.amplitudeModulation = stream->readByte(); bnkInstDef.operator0.vibrato = stream->readByte(); bnkInstDef.operator0.keyScalingRate = stream->readByte(); // Connection bit in SOS BNK is not flipped bnkInstDef.operator0.connection = stream->readByte() == 0 ? 1 : 0; bnkInstDef.operator1.keyScalingLevel = stream->readByte(); bnkInstDef.operator1.frequencyMultiplier = stream->readByte(); bnkInstDef.operator1.feedback = stream->readByte(); bnkInstDef.operator1.attack = stream->readByte(); bnkInstDef.operator1.sustain = stream->readByte(); bnkInstDef.operator1.envelopeGainType = stream->readByte(); bnkInstDef.operator1.decay = stream->readByte(); bnkInstDef.operator1.release = stream->readByte(); bnkInstDef.operator1.level = stream->readByte(); bnkInstDef.operator1.amplitudeModulation = stream->readByte(); bnkInstDef.operator1.vibrato = stream->readByte(); bnkInstDef.operator1.keyScalingRate = stream->readByte(); bnkInstDef.operator1.connection = stream->readByte() == 0 ? 1 : 0; bnkInstDef.waveformSelect0 = stream->readByte(); bnkInstDef.waveformSelect1 = stream->readByte(); bnkInstDef.toOplInstrumentDefinition(instrumentBank[i]); instrumentBank[i].rhythmNote = rhythmNotes[i]; } return instrumentsUsed; }