Files
2026-02-02 04:50:13 +01:00

168 lines
4.6 KiB
C++

/* 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 "audio/mididrv.h"
#include "common/error.h"
#include "common/file.h"
namespace AGOS {
// this reads and gets Accolade driver data
// we need it for channel mapping, instrument mapping and other things
// this driver data chunk gets passed to the actual music driver (MT32 / AdLib)
void MidiDriver_Accolade_readDriver(Common::String filename, MusicType requestedDriverType, byte *&driverData, uint16 &driverDataSize, bool &isMusicDrvFile) {
Common::File *driverStream = new Common::File();
isMusicDrvFile = false;
if (!driverStream->open(Common::Path(filename))) {
error("%s: unable to open file", filename.c_str());
}
if (filename == "INSTR.DAT") {
// INSTR.DAT: used by Elvira 1
uint32 streamSize = driverStream->size();
uint32 streamLeft = streamSize;
uint16 skipChunks = 0; // 1 for MT32, 0 for AdLib
uint16 chunkSize = 0;
switch (requestedDriverType) {
case MT_ADLIB:
skipChunks = 0;
break;
case MT_MT32:
skipChunks = 1; // Skip one entry for MT32
break;
case MT_CT460:
skipChunks = 2; // CT-460 data is the third entry
break;
default:
assert(0);
break;
}
do {
if (streamLeft < 2)
error("%s: unexpected EOF", filename.c_str());
chunkSize = driverStream->readUint16LE();
streamLeft -= 2;
if (streamLeft < chunkSize)
error("%s: unexpected EOF", filename.c_str());
if (skipChunks) {
// Skip the chunk
driverStream->skip(chunkSize);
streamLeft -= chunkSize;
skipChunks--;
}
} while (skipChunks);
// Seek over the ASCII string until there is a NUL terminator
byte curByte = 0;
do {
if (chunkSize == 0)
error("%s: no actual instrument data found", filename.c_str());
curByte = driverStream->readByte();
chunkSize--;
} while (curByte);
driverDataSize = chunkSize;
// Read the requested instrument data entry
driverData = new byte[driverDataSize];
driverStream->read(driverData, driverDataSize);
} else if (filename == "MUSIC.DRV") {
// MUSIC.DRV / used by Elvira 2 / Waxworks / Simon 1 demo
uint32 streamSize = driverStream->size();
uint32 streamLeft = streamSize;
uint16 getChunk = 0; // 4 for MT32, 2 for AdLib
switch (requestedDriverType) {
case MT_ADLIB:
getChunk = 2;
break;
case MT_MT32:
getChunk = 4;
break;
default:
assert(0);
break;
}
if (streamLeft < 2)
error("%s: unexpected EOF", filename.c_str());
uint16 chunkCount = driverStream->readUint16LE();
streamLeft -= 2;
if (getChunk >= chunkCount)
error("%s: required chunk not available", filename.c_str());
uint16 headerOffset = 2 + (28 * getChunk);
streamLeft -= (28 * getChunk);
if (streamLeft < 28)
error("%s: unexpected EOF", filename.c_str());
// Seek to required chunk
driverStream->seek(headerOffset);
driverStream->skip(20); // skip over name
streamLeft -= 20;
uint16 musicDrvSignature = driverStream->readUint16LE();
uint16 musicDrvType = driverStream->readUint16LE();
uint16 chunkOffset = driverStream->readUint16LE();
uint16 chunkSize = driverStream->readUint16LE();
// Security checks
if (musicDrvSignature != 0xFEDC)
error("%s: chunk signature mismatch", filename.c_str());
if (musicDrvType != 1)
error("%s: not a music driver", filename.c_str());
if (chunkOffset >= streamSize)
error("%s: driver chunk points outside of file", filename.c_str());
streamLeft = streamSize - chunkOffset;
if (streamLeft < chunkSize)
error("%s: driver chunk is larger than file", filename.c_str());
driverDataSize = chunkSize;
// Read the requested instrument data entry
driverData = new byte[driverDataSize];
driverStream->seek(chunkOffset);
driverStream->read(driverData, driverDataSize);
isMusicDrvFile = true;
}
driverStream->close();
delete driverStream;
}
} // End of namespace AGOS