[Scummvm-git-logs] scummvm master -> c585f5b8d073f07ef6dc61b454f0b8f507f92ac9
lotharsm
mail at serra.me
Sat Apr 10 14:10:13 UTC 2021
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
357744069c MT32: Update munt emulation code to libmt32emu 2.5.0
24a27f6568 MT32: Fix definitions
c585f5b8d0 NEWS: Mention version bump to mt32emu 2.5.0
Commit: 357744069c2d4fc4e3ee5effdd948f8e3c1aa20b
https://github.com/scummvm/scummvm/commit/357744069c2d4fc4e3ee5effdd948f8e3c1aa20b
Author: Lothar Serra Mari (mail at serra.me)
Date: 2021-04-10T16:09:54+02:00
Commit Message:
MT32: Update munt emulation code to libmt32emu 2.5.0
Changed paths:
A audio/softsynth/mt32/VersionTagging.cpp
A audio/softsynth/mt32/VersionTagging.h
A audio/softsynth/mt32/mt32emu.pc.in
audio/softsynth/mt32/FileStream.cpp
audio/softsynth/mt32/ROMInfo.cpp
audio/softsynth/mt32/ROMInfo.h
audio/softsynth/mt32/Synth.h
audio/softsynth/mt32/TVP.cpp
audio/softsynth/mt32/c_interface/c_interface.cpp
audio/softsynth/mt32/c_interface/c_interface.h
audio/softsynth/mt32/c_interface/c_types.h
audio/softsynth/mt32/c_interface/cpp_interface.h
audio/softsynth/mt32/config.h
audio/softsynth/mt32/globals.h
audio/softsynth/mt32/mt32emu.h
diff --git a/audio/softsynth/mt32/FileStream.cpp b/audio/softsynth/mt32/FileStream.cpp
index 91bd27994a..65e3c8a623 100644
--- a/audio/softsynth/mt32/FileStream.cpp
+++ b/audio/softsynth/mt32/FileStream.cpp
@@ -21,10 +21,6 @@
#include "internals.h"
-// Disable MSVC STL exceptions
-#ifdef _MSC_VER
-#define _HAS_EXCEPTIONS 0
-#endif
#include "FileStream.h"
namespace MT32Emu {
diff --git a/audio/softsynth/mt32/ROMInfo.cpp b/audio/softsynth/mt32/ROMInfo.cpp
index db4f7f5872..b960427c8d 100644
--- a/audio/softsynth/mt32/ROMInfo.cpp
+++ b/audio/softsynth/mt32/ROMInfo.cpp
@@ -19,26 +19,66 @@
#include "internals.h"
+#include "File.h"
#include "ROMInfo.h"
namespace MT32Emu {
-static const ROMInfo *getKnownROMInfoFromList(Bit32u index) {
- // Known ROMs
- static const ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, NULL};
- static const ROMInfo CTRL_MT32_V1_05 = {65536, "e17a3a6d265bf1fa150312061134293d2b58288c", ROMInfo::Control, "ctrl_mt32_1_05", "MT-32 Control v1.05", ROMInfo::Full, NULL};
- static const ROMInfo CTRL_MT32_V1_06 = {65536, "a553481f4e2794c10cfe597fef154eef0d8257de", ROMInfo::Control, "ctrl_mt32_1_06", "MT-32 Control v1.06", ROMInfo::Full, NULL};
- static const ROMInfo CTRL_MT32_V1_07 = {65536, "b083518fffb7f66b03c23b7eb4f868e62dc5a987", ROMInfo::Control, "ctrl_mt32_1_07", "MT-32 Control v1.07", ROMInfo::Full, NULL};
- static const ROMInfo CTRL_MT32_BLUER = {65536, "7b8c2a5ddb42fd0732e2f22b3340dcf5360edf92", ROMInfo::Control, "ctrl_mt32_bluer", "MT-32 Control BlueRidge", ROMInfo::Full, NULL};
+namespace {
+
+struct ROMInfoList {
+ const ROMInfo * const *romInfos;
+ const Bit32u itemCount;
+};
+
+struct ROMInfoLists {
+ ROMInfoList mt32_1_04;
+ ROMInfoList mt32_1_05;
+ ROMInfoList mt32_1_06;
+ ROMInfoList mt32_1_07;
+ ROMInfoList mt32_bluer;
+ ROMInfoList mt32_2_04;
+ ROMInfoList cm32l_1_00;
+ ROMInfoList cm32l_1_02;
+ ROMInfoList fullROMInfos;
+ ROMInfoList partialROMInfos;
+ ROMInfoList allROMInfos;
+};
+
+}
+
+#define _CALC_ARRAY_LENGTH(x) Bit32u(sizeof (x) / sizeof *(x) - 1)
+
+static const ROMInfoLists &getROMInfoLists() {
+ static ROMInfo CTRL_MT32_V1_04_A = {32768, "9cd4858014c4e8a9dff96053f784bfaac1092a2e", ROMInfo::Control, "ctrl_mt32_1_04_a", "MT-32 Control v1.04", ROMInfo::Mux0, NULL};
+ static ROMInfo CTRL_MT32_V1_04_B = {32768, "fe8db469b5bfeb37edb269fd47e3ce6d91014652", ROMInfo::Control, "ctrl_mt32_1_04_b", "MT-32 Control v1.04", ROMInfo::Mux1, &CTRL_MT32_V1_04_A};
+ static ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, NULL};
+ static ROMInfo CTRL_MT32_V1_05_A = {32768, "57a09d80d2f7ca5b9734edbe9645e6e700f83701", ROMInfo::Control, "ctrl_mt32_1_05_a", "MT-32 Control v1.05", ROMInfo::Mux0, NULL};
+ static ROMInfo CTRL_MT32_V1_05_B = {32768, "52e3c6666db9ef962591a8ee99be0cde17f3a6b6", ROMInfo::Control, "ctrl_mt32_1_05_b", "MT-32 Control v1.05", ROMInfo::Mux1, &CTRL_MT32_V1_05_A};
+ static ROMInfo CTRL_MT32_V1_05 = {65536, "e17a3a6d265bf1fa150312061134293d2b58288c", ROMInfo::Control, "ctrl_mt32_1_05", "MT-32 Control v1.05", ROMInfo::Full, NULL};
+ static ROMInfo CTRL_MT32_V1_06_A = {32768, "cc83bf23cee533097fb4c7e2c116e43b50ebacc8", ROMInfo::Control, "ctrl_mt32_1_06_a", "MT-32 Control v1.06", ROMInfo::Mux0, NULL};
+ static ROMInfo CTRL_MT32_V1_06_B = {32768, "bf4f15666bc46679579498386704893b630c1171", ROMInfo::Control, "ctrl_mt32_1_06_b", "MT-32 Control v1.06", ROMInfo::Mux1, &CTRL_MT32_V1_06_A};
+ static ROMInfo CTRL_MT32_V1_06 = {65536, "a553481f4e2794c10cfe597fef154eef0d8257de", ROMInfo::Control, "ctrl_mt32_1_06", "MT-32 Control v1.06", ROMInfo::Full, NULL};
+ static ROMInfo CTRL_MT32_V1_07_A = {32768, "13f06b38f0d9e0fc050b6503ab777bb938603260", ROMInfo::Control, "ctrl_mt32_1_07_a", "MT-32 Control v1.07", ROMInfo::Mux0, NULL};
+ static ROMInfo CTRL_MT32_V1_07_B = {32768, "c55e165487d71fa88bd8c5e9c083bc456c1a89aa", ROMInfo::Control, "ctrl_mt32_1_07_b", "MT-32 Control v1.07", ROMInfo::Mux1, &CTRL_MT32_V1_07_A};
+ static ROMInfo CTRL_MT32_V1_07 = {65536, "b083518fffb7f66b03c23b7eb4f868e62dc5a987", ROMInfo::Control, "ctrl_mt32_1_07", "MT-32 Control v1.07", ROMInfo::Full, NULL};
+ static ROMInfo CTRL_MT32_BLUER_A = {32768, "11a6ae5d8b6ee328b371af7f1e40b82125aa6b4d", ROMInfo::Control, "ctrl_mt32_bluer_a", "MT-32 Control BlueRidge", ROMInfo::Mux0, NULL};
+ static ROMInfo CTRL_MT32_BLUER_B = {32768, "e0934320d7cbb5edfaa29e0d01ae835ef620085b", ROMInfo::Control, "ctrl_mt32_bluer_b", "MT-32 Control BlueRidge", ROMInfo::Mux1, &CTRL_MT32_BLUER_A};
+ static ROMInfo CTRL_MT32_BLUER = {65536, "7b8c2a5ddb42fd0732e2f22b3340dcf5360edf92", ROMInfo::Control, "ctrl_mt32_bluer", "MT-32 Control BlueRidge", ROMInfo::Full, NULL};
static const ROMInfo CTRL_MT32_V2_04 = {131072, "2c16432b6c73dd2a3947cba950a0f4c19d6180eb", ROMInfo::Control, "ctrl_mt32_2_04", "MT-32 Control v2.04", ROMInfo::Full, NULL};
static const ROMInfo CTRL_CM32L_V1_00 = {65536, "73683d585cd6948cc19547942ca0e14a0319456d", ROMInfo::Control, "ctrl_cm32l_1_00", "CM-32L/LAPC-I Control v1.00", ROMInfo::Full, NULL};
static const ROMInfo CTRL_CM32L_V1_02 = {65536, "a439fbb390da38cada95a7cbb1d6ca199cd66ef8", ROMInfo::Control, "ctrl_cm32l_1_02", "CM-32L/LAPC-I Control v1.02", ROMInfo::Full, NULL};
- static const ROMInfo PCM_MT32 = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_mt32", "MT-32 PCM ROM", ROMInfo::Full, NULL};
- static const ROMInfo PCM_CM32L = {1048576, "289cc298ad532b702461bfc738009d9ebe8025ea", ROMInfo::PCM, "pcm_cm32l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::Full, NULL};
+ static ROMInfo PCM_MT32_L = {262144, "3a1e19b0cd4036623fd1d1d11f5f25995585962b", ROMInfo::PCM, "pcm_mt32_l", "MT-32 PCM ROM", ROMInfo::FirstHalf, NULL};
+ static ROMInfo PCM_MT32_H = {262144, "2cadb99d21a6a4a6f5b61b6218d16e9b43f61d01", ROMInfo::PCM, "pcm_mt32_h", "MT-32 PCM ROM", ROMInfo::SecondHalf, &PCM_MT32_L};
+ static ROMInfo PCM_MT32 = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_mt32", "MT-32 PCM ROM", ROMInfo::Full, NULL};
+ // Alias of PCM_MT32 ROM, only useful for pairing with PCM_CM32L_H.
+ static ROMInfo PCM_CM32L_L = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_cm32l_l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::FirstHalf, NULL};
+ static ROMInfo PCM_CM32L_H = {524288, "3ad889fde5db5b6437cbc2eb6e305312fec3df93", ROMInfo::PCM, "pcm_cm32l_h", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::SecondHalf, &PCM_CM32L_L};
+ static ROMInfo PCM_CM32L = {1048576, "289cc298ad532b702461bfc738009d9ebe8025ea", ROMInfo::PCM, "pcm_cm32l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::Full, NULL};
- static const ROMInfo * const ROM_INFOS[] = {
+ static const ROMInfo * const FULL_ROM_INFOS[] = {
&CTRL_MT32_V1_04,
&CTRL_MT32_V1_05,
&CTRL_MT32_V1_06,
@@ -49,15 +89,74 @@ static const ROMInfo *getKnownROMInfoFromList(Bit32u index) {
&CTRL_CM32L_V1_02,
&PCM_MT32,
&PCM_CM32L,
- NULL};
+ NULL
+ };
+ static const ROMInfo * const PARTIAL_ROM_INFOS[] = {
+ &CTRL_MT32_V1_04_A, &CTRL_MT32_V1_04_B,
+ &CTRL_MT32_V1_05_A, &CTRL_MT32_V1_05_B,
+ &CTRL_MT32_V1_06_A, &CTRL_MT32_V1_06_B,
+ &CTRL_MT32_V1_07_A, &CTRL_MT32_V1_07_B,
+ &CTRL_MT32_BLUER_A, &CTRL_MT32_BLUER_B,
+ &PCM_MT32_L, &PCM_MT32_H,
+ &PCM_CM32L_L, &PCM_CM32L_H,
+ NULL
+ };
+ static const ROMInfo *ALL_ROM_INFOS[_CALC_ARRAY_LENGTH(FULL_ROM_INFOS) + _CALC_ARRAY_LENGTH(PARTIAL_ROM_INFOS) + 1];
+
+ if (CTRL_MT32_V1_04_A.pairROMInfo == NULL) {
+ CTRL_MT32_V1_04_A.pairROMInfo = &CTRL_MT32_V1_04_B;
+ CTRL_MT32_V1_05_A.pairROMInfo = &CTRL_MT32_V1_05_B;
+ CTRL_MT32_V1_06_A.pairROMInfo = &CTRL_MT32_V1_06_B;
+ CTRL_MT32_V1_07_A.pairROMInfo = &CTRL_MT32_V1_07_B;
+ CTRL_MT32_BLUER_A.pairROMInfo = &CTRL_MT32_BLUER_B;
+ PCM_MT32_L.pairROMInfo = &PCM_MT32_H;
+ PCM_CM32L_L.pairROMInfo = &PCM_CM32L_H;
- return ROM_INFOS[index];
+ memcpy(&ALL_ROM_INFOS[0], FULL_ROM_INFOS, sizeof FULL_ROM_INFOS);
+ memcpy(&ALL_ROM_INFOS[_CALC_ARRAY_LENGTH(FULL_ROM_INFOS)], PARTIAL_ROM_INFOS, sizeof PARTIAL_ROM_INFOS); // Includes NULL terminator.
+ }
+
+ static const ROMInfo * const MT32_V1_04_ROMS[] = {&CTRL_MT32_V1_04, &PCM_MT32, &CTRL_MT32_V1_04_A, &CTRL_MT32_V1_04_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V1_05_ROMS[] = {&CTRL_MT32_V1_05, &PCM_MT32, &CTRL_MT32_V1_05_A, &CTRL_MT32_V1_05_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V1_06_ROMS[] = {&CTRL_MT32_V1_06, &PCM_MT32, &CTRL_MT32_V1_06_A, &CTRL_MT32_V1_06_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V1_07_ROMS[] = {&CTRL_MT32_V1_07, &PCM_MT32, &CTRL_MT32_V1_07_A, &CTRL_MT32_V1_07_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_BLUER_ROMS[] = {&CTRL_MT32_BLUER, &PCM_MT32, &CTRL_MT32_BLUER_A, &CTRL_MT32_BLUER_B, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const MT32_V2_04_ROMS[] = {&CTRL_MT32_V2_04, &PCM_MT32, &PCM_MT32_L, &PCM_MT32_H, NULL};
+ static const ROMInfo * const CM32L_V1_00_ROMS[] = {&CTRL_CM32L_V1_00, &PCM_CM32L, &PCM_CM32L_L, &PCM_CM32L_H, NULL};
+ static const ROMInfo * const CM32L_V1_02_ROMS[] = {&CTRL_CM32L_V1_02, &PCM_CM32L, &PCM_CM32L_L, &PCM_CM32L_H, NULL};
+
+ static const ROMInfoLists romInfoLists = {
+ {MT32_V1_04_ROMS, _CALC_ARRAY_LENGTH(MT32_V1_04_ROMS)},
+ {MT32_V1_05_ROMS, _CALC_ARRAY_LENGTH(MT32_V1_05_ROMS)},
+ {MT32_V1_06_ROMS, _CALC_ARRAY_LENGTH(MT32_V1_06_ROMS)},
+ {MT32_V1_07_ROMS, _CALC_ARRAY_LENGTH(MT32_V1_07_ROMS)},
+ {MT32_BLUER_ROMS, _CALC_ARRAY_LENGTH(MT32_BLUER_ROMS)},
+ {MT32_V2_04_ROMS, _CALC_ARRAY_LENGTH(MT32_V2_04_ROMS)},
+ {CM32L_V1_00_ROMS, _CALC_ARRAY_LENGTH(CM32L_V1_00_ROMS)},
+ {CM32L_V1_02_ROMS, _CALC_ARRAY_LENGTH(CM32L_V1_02_ROMS)},
+ {FULL_ROM_INFOS, _CALC_ARRAY_LENGTH(FULL_ROM_INFOS)},
+ {PARTIAL_ROM_INFOS, _CALC_ARRAY_LENGTH(PARTIAL_ROM_INFOS)},
+ {ALL_ROM_INFOS, _CALC_ARRAY_LENGTH(ALL_ROM_INFOS)}
+ };
+ return romInfoLists;
}
-const ROMInfo* ROMInfo::getROMInfo(File *file) {
+static const ROMInfo * const *getKnownROMInfoList() {
+ return getROMInfoLists().allROMInfos.romInfos;
+}
+
+static const ROMInfo *getKnownROMInfoFromList(Bit32u index) {
+ return getKnownROMInfoList()[index];
+}
+
+const ROMInfo *ROMInfo::getROMInfo(File *file) {
+ return getROMInfo(file, getKnownROMInfoList());
+}
+
+const ROMInfo *ROMInfo::getROMInfo(File *file, const ROMInfo * const *romInfos) {
size_t fileSize = file->getSize();
- for (Bit32u i = 0; getKnownROMInfoFromList(i) != NULL; i++) {
- const ROMInfo *romInfo = getKnownROMInfoFromList(i);
+ for (Bit32u i = 0; romInfos[i] != NULL; i++) {
+ const ROMInfo *romInfo = romInfos[i];
if (fileSize == romInfo->fileSize && !strcmp(file->getSHA1(), romInfo->sha1Digest)) {
return romInfo;
}
@@ -69,17 +168,11 @@ void ROMInfo::freeROMInfo(const ROMInfo *romInfo) {
(void) romInfo;
}
-static Bit32u getROMCount() {
- Bit32u count;
- for(count = 0; getKnownROMInfoFromList(count) != NULL; count++) {
- }
- return count;
-}
-
-const ROMInfo** ROMInfo::getROMInfoList(Bit32u types, Bit32u pairTypes) {
- const ROMInfo **romInfoList = new const ROMInfo*[getROMCount() + 1];
+const ROMInfo **ROMInfo::getROMInfoList(Bit32u types, Bit32u pairTypes) {
+ Bit32u romCount = getROMInfoLists().allROMInfos.itemCount; // Excludes the NULL terminator.
+ const ROMInfo **romInfoList = new const ROMInfo*[romCount + 1];
const ROMInfo **currentROMInList = romInfoList;
- for (Bit32u i = 0; getKnownROMInfoFromList(i) != NULL; i++) {
+ for (Bit32u i = 0; i < romCount; i++) {
const ROMInfo *romInfo = getKnownROMInfoFromList(i);
if ((types & (1 << romInfo->type)) && (pairTypes & (1 << romInfo->pairType))) {
*currentROMInList++ = romInfo;
@@ -93,27 +186,153 @@ void ROMInfo::freeROMInfoList(const ROMInfo **romInfoList) {
delete[] romInfoList;
}
-ROMImage::ROMImage(File *useFile) : file(useFile), romInfo(ROMInfo::getROMInfo(file))
+const ROMInfo * const *ROMInfo::getAllROMInfos(Bit32u *itemCount) {
+ if (itemCount != NULL) *itemCount = getROMInfoLists().allROMInfos.itemCount;
+ return getROMInfoLists().allROMInfos.romInfos;
+}
+
+const ROMInfo * const *ROMInfo::getFullROMInfos(Bit32u *itemCount) {
+ if (itemCount != NULL) *itemCount = getROMInfoLists().fullROMInfos.itemCount;
+ return getROMInfoLists().fullROMInfos.romInfos;
+}
+
+const ROMInfo * const *ROMInfo::getPartialROMInfos(Bit32u *itemCount) {
+ if (itemCount != NULL) *itemCount = getROMInfoLists().partialROMInfos.itemCount;
+ return getROMInfoLists().partialROMInfos.romInfos;
+}
+
+const ROMImage *ROMImage::makeFullROMImage(Bit8u *data, size_t dataSize) {
+ return new ROMImage(new ArrayFile(data, dataSize), true, getKnownROMInfoList());
+}
+
+const ROMImage *ROMImage::appendImages(const ROMImage *romImageLow, const ROMImage *romImageHigh) {
+ const Bit8u *romDataLow = romImageLow->getFile()->getData();
+ const Bit8u *romDataHigh = romImageHigh->getFile()->getData();
+ size_t partSize = romImageLow->getFile()->getSize();
+ Bit8u *data = new Bit8u[2 * partSize];
+ memcpy(data, romDataLow, partSize);
+ memcpy(data + partSize, romDataHigh, partSize);
+ const ROMImage *romImageFull = makeFullROMImage(data, 2 * partSize);
+ if (romImageFull->getROMInfo() == NULL) {
+ freeROMImage(romImageFull);
+ return NULL;
+ }
+ return romImageFull;
+}
+
+const ROMImage *ROMImage::interleaveImages(const ROMImage *romImageEven, const ROMImage *romImageOdd) {
+ const Bit8u *romDataEven = romImageEven->getFile()->getData();
+ const Bit8u *romDataOdd = romImageOdd->getFile()->getData();
+ size_t partSize = romImageEven->getFile()->getSize();
+ Bit8u *data = new Bit8u[2 * partSize];
+ Bit8u *writePtr = data;
+ for (size_t romDataIx = 0; romDataIx < partSize; romDataIx++) {
+ *(writePtr++) = romDataEven[romDataIx];
+ *(writePtr++) = romDataOdd[romDataIx];
+ }
+ const ROMImage *romImageFull = makeFullROMImage(data, 2 * partSize);
+ if (romImageFull->getROMInfo() == NULL) {
+ freeROMImage(romImageFull);
+ return NULL;
+ }
+ return romImageFull;
+}
+
+ROMImage::ROMImage(File *useFile, bool useOwnFile, const ROMInfo * const *romInfos) :
+ file(useFile), ownFile(useOwnFile), romInfo(ROMInfo::getROMInfo(file, romInfos))
{}
ROMImage::~ROMImage() {
ROMInfo::freeROMInfo(romInfo);
+ if (ownFile) {
+ const Bit8u *data = file->getData();
+ delete file;
+ delete data;
+ }
+}
+
+const ROMImage *ROMImage::makeROMImage(File *file) {
+ return new ROMImage(file, false, getKnownROMInfoList());
}
-const ROMImage* ROMImage::makeROMImage(File *file) {
- return new ROMImage(file);
+const ROMImage *ROMImage::makeROMImage(File *file, const ROMInfo * const *romInfos) {
+ return new ROMImage(file, false, romInfos);
+}
+
+const ROMImage *ROMImage::makeROMImage(File *file1, File *file2) {
+ const ROMInfo * const *partialROMInfos = getROMInfoLists().partialROMInfos.romInfos;
+ const ROMImage *image1 = makeROMImage(file1, partialROMInfos);
+ const ROMImage *image2 = makeROMImage(file2, partialROMInfos);
+ const ROMImage *fullImage = image1->getROMInfo() == NULL || image2->getROMInfo() == NULL ? NULL : mergeROMImages(image1, image2);
+ freeROMImage(image1);
+ freeROMImage(image2);
+ return fullImage;
}
void ROMImage::freeROMImage(const ROMImage *romImage) {
delete romImage;
}
-File* ROMImage::getFile() const {
+const ROMImage *ROMImage::mergeROMImages(const ROMImage *romImage1, const ROMImage *romImage2) {
+ if (romImage1->romInfo->pairROMInfo != romImage2->romInfo) {
+ return NULL;
+ }
+ switch (romImage1->romInfo->pairType) {
+ case ROMInfo::FirstHalf:
+ return appendImages(romImage1, romImage2);
+ case ROMInfo::SecondHalf:
+ return appendImages(romImage2, romImage1);
+ case ROMInfo::Mux0:
+ return interleaveImages(romImage1, romImage2);
+ case ROMInfo::Mux1:
+ return interleaveImages(romImage2, romImage1);
+ default:
+ break;
+ }
+ return NULL;
+}
+
+File *ROMImage::getFile() const {
return file;
}
-const ROMInfo* ROMImage::getROMInfo() const {
+bool ROMImage::isFileUserProvided() const {
+ return !ownFile;
+}
+
+const ROMInfo *ROMImage::getROMInfo() const {
return romInfo;
}
+const MachineConfiguration * const *MachineConfiguration::getAllMachineConfigurations(Bit32u *itemCount) {
+ static const ROMInfoLists &romInfoLists = getROMInfoLists();
+ static const MachineConfiguration MT32_1_04 = MachineConfiguration("mt32_1_04", romInfoLists.mt32_1_04.romInfos, romInfoLists.mt32_1_04.itemCount);
+ static const MachineConfiguration MT32_1_05 = MachineConfiguration("mt32_1_05", romInfoLists.mt32_1_05.romInfos, romInfoLists.mt32_1_05.itemCount);
+ static const MachineConfiguration MT32_1_06 = MachineConfiguration("mt32_1_06", romInfoLists.mt32_1_06.romInfos, romInfoLists.mt32_1_06.itemCount);
+ static const MachineConfiguration MT32_1_07 = MachineConfiguration("mt32_1_07", romInfoLists.mt32_1_07.romInfos, romInfoLists.mt32_1_07.itemCount);
+ static const MachineConfiguration MT32_BLUER = MachineConfiguration("mt32_bluer", romInfoLists.mt32_bluer.romInfos, romInfoLists.mt32_bluer.itemCount);
+ static const MachineConfiguration MT32_2_04 = MachineConfiguration("mt32_2_04", romInfoLists.mt32_2_04.romInfos, romInfoLists.mt32_2_04.itemCount);
+ static const MachineConfiguration CM32L_1_00 = MachineConfiguration("cm32l_1_00", romInfoLists.cm32l_1_00.romInfos, romInfoLists.cm32l_1_00.itemCount);
+ static const MachineConfiguration CM32L_1_02 = MachineConfiguration("cm32l_1_02", romInfoLists.cm32l_1_02.romInfos, romInfoLists.cm32l_1_02.itemCount);
+ static const MachineConfiguration * const MACHINE_CONFIGURATIONS[] = {
+ &MT32_1_04, &MT32_1_05, &MT32_1_06, &MT32_1_07, &MT32_BLUER, &MT32_2_04, &CM32L_1_00, &CM32L_1_02, NULL
+ };
+
+ if (itemCount != NULL) *itemCount = _CALC_ARRAY_LENGTH(MACHINE_CONFIGURATIONS);
+ return MACHINE_CONFIGURATIONS;
+}
+
+MachineConfiguration::MachineConfiguration(const char *useMachineID, const ROMInfo * const *useROMInfos, Bit32u useROMInfosCount) :
+ machineID(useMachineID), romInfos(useROMInfos), romInfosCount(useROMInfosCount)
+{}
+
+const char *MachineConfiguration::getMachineID() const {
+ return machineID;
+}
+
+const ROMInfo * const *MachineConfiguration::getCompatibleROMInfos(Bit32u *itemCount) const {
+ if (itemCount != NULL) *itemCount = romInfosCount;
+ return romInfos;
+}
+
} // namespace MT32Emu
diff --git a/audio/softsynth/mt32/ROMInfo.h b/audio/softsynth/mt32/ROMInfo.h
index af36844957..1e52ee78d3 100644
--- a/audio/softsynth/mt32/ROMInfo.h
+++ b/audio/softsynth/mt32/ROMInfo.h
@@ -34,11 +34,28 @@ public:
enum Type {PCM, Control, Reverb} type;
const char *shortName;
const char *description;
- enum PairType {Full, FirstHalf, SecondHalf, Mux0, Mux1} pairType;
- ROMInfo *pairROMInfo;
-
- // Returns a ROMInfo struct by inspecting the size and the SHA1 hash
- MT32EMU_EXPORT static const ROMInfo* getROMInfo(File *file);
+ enum PairType {
+ // Complete ROM image ready to use with Synth.
+ Full,
+ // ROM image contains data that occupies lower addresses. Needs pairing before use.
+ FirstHalf,
+ // ROM image contains data that occupies higher addresses. Needs pairing before use.
+ SecondHalf,
+ // ROM image contains data that occupies even addresses. Needs pairing before use.
+ Mux0,
+ // ROM image contains data that occupies odd addresses. Needs pairing before use.
+ Mux1
+ } pairType;
+ // NULL for Full images or a pointer to the corresponding other image for pairing.
+ const ROMInfo *pairROMInfo;
+
+ // Returns a ROMInfo struct by inspecting the size and the SHA1 hash of the file
+ // among all the known ROMInfos.
+ MT32EMU_EXPORT static const ROMInfo *getROMInfo(File *file);
+
+ // Returns a ROMInfo struct by inspecting the size and the SHA1 hash of the file
+ // among the ROMInfos listed in the NULL-terminated list romInfos.
+ MT32EMU_EXPORT_V(2.5) static const ROMInfo *getROMInfo(File *file, const ROMInfo * const *romInfos);
// Currently no-op
MT32EMU_EXPORT static void freeROMInfo(const ROMInfo *romInfo);
@@ -46,33 +63,111 @@ public:
// Allows retrieving a NULL-terminated list of ROMInfos for a range of types and pairTypes
// (specified by bitmasks)
// Useful for GUI/console app to output information on what ROMs it supports
- MT32EMU_EXPORT static const ROMInfo** getROMInfoList(Bit32u types, Bit32u pairTypes);
+ // The caller must free the returned list with freeROMInfoList when finished.
+ MT32EMU_EXPORT static const ROMInfo **getROMInfoList(Bit32u types, Bit32u pairTypes);
- // Frees the list of ROMInfos given
+ // Frees the list of ROMInfos given that has been created by getROMInfoList.
MT32EMU_EXPORT static void freeROMInfoList(const ROMInfo **romInfos);
+
+ // Returns an immutable NULL-terminated list of all (full and partial) supported ROMInfos.
+ // For convenience, this method also can fill the number of non-NULL items present in the list
+ // if a non-NULL value is provided in optional argument itemCount.
+ MT32EMU_EXPORT_V(2.5) static const ROMInfo * const *getAllROMInfos(Bit32u *itemCount = NULL);
+ // Returns an immutable NULL-terminated list of all supported full ROMInfos.
+ // For convenience, this method also can fill the number of non-NULL items present in the list
+ // if a non-NULL value is provided in optional argument itemCount.
+ MT32EMU_EXPORT_V(2.5) static const ROMInfo * const *getFullROMInfos(Bit32u *itemCount = NULL);
+ // Returns an immutable NULL-terminated list of all supported partial ROMInfos.
+ // For convenience, this method also can fill the number of non-NULL items present in the list
+ // if a non-NULL value is provided in optional argument itemCount.
+ MT32EMU_EXPORT_V(2.5) static const ROMInfo * const *getPartialROMInfos(Bit32u *itemCount = NULL);
};
-// Synth::open() is to require a full control ROMImage and a full PCM ROMImage to work
+// Synth::open() requires a full control ROMImage and a compatible full PCM ROMImage to work
class ROMImage {
-private:
- File * const file;
- const ROMInfo * const romInfo;
-
- ROMImage(File *file);
- ~ROMImage();
-
public:
// Creates a ROMImage object given a ROMInfo and a File. Keeps a reference
// to the File and ROMInfo given, which must be freed separately by the user
- // after the ROMImage is freed
- MT32EMU_EXPORT static const ROMImage* makeROMImage(File *file);
+ // after the ROMImage is freed.
+ // CAVEAT: This method always prefers full ROM images over partial ones.
+ // Because the lower half of CM-32L/CM-64/LAPC-I PCM ROM is essentially the full
+ // MT-32 PCM ROM, it is therefore aliased. In this case a partial image can only be
+ // created by the overridden method makeROMImage(File *, const ROMInfo * const *).
+ MT32EMU_EXPORT static const ROMImage *makeROMImage(File *file);
+
+ // Same as the method above but only permits creation of a ROMImage if the file content
+ // matches one of the ROMs described in a NULL-terminated list romInfos. This list can be
+ // created using e.g. method ROMInfo::getROMInfoList.
+ MT32EMU_EXPORT_V(2.5) static const ROMImage *makeROMImage(File *file, const ROMInfo * const *romInfos);
+
+ // Creates a ROMImage object given a couple of files that contain compatible partial ROM images.
+ // The files aren't referenced by the resulting ROMImage and may be freed anytime afterwards.
+ // The file in the resulting image will be automatically freed along with the ROMImage.
+ // If the given files contain incompatible partial images, NULL is returned.
+ MT32EMU_EXPORT_V(2.5) static const ROMImage *makeROMImage(File *file1, File *file2);
// Must only be done after all Synths using the ROMImage are deleted
MT32EMU_EXPORT static void freeROMImage(const ROMImage *romImage);
+ // Checks whether the given ROMImages are pairable and merges them into a full image, if possible.
+ // If the check fails, NULL is returned.
+ MT32EMU_EXPORT_V(2.5) static const ROMImage *mergeROMImages(const ROMImage *romImage1, const ROMImage *romImage2);
+
MT32EMU_EXPORT File *getFile() const;
+
+ // Returns true in case this ROMImage is built with a user provided File that has to be deallocated separately.
+ // For a ROMImage created via merging two partial ROMImages, this method returns false.
+ MT32EMU_EXPORT_V(2.5) bool isFileUserProvided() const;
MT32EMU_EXPORT const ROMInfo *getROMInfo() const;
+
+private:
+ static const ROMImage *makeFullROMImage(Bit8u *data, size_t dataSize);
+ static const ROMImage *appendImages(const ROMImage *romImageLow, const ROMImage *romImageHigh);
+ static const ROMImage *interleaveImages(const ROMImage *romImageEven, const ROMImage *romImageOdd);
+
+ File * const file;
+ const bool ownFile;
+ const ROMInfo * const romInfo;
+
+ ROMImage(File *file, bool ownFile, const ROMInfo * const *romInfos);
+ ~ROMImage();
+
+ // Make ROMIMage an identity class.
+ ROMImage(const ROMImage &);
+ ROMImage &operator=(const ROMImage &);
+};
+
+class MachineConfiguration {
+public:
+ // Returns an immutable NULL-terminated list of all supported machine configurations.
+ // For convenience, this method also can fill the number of non-NULL items present in the list
+ // if a non-NULL value is provided in optional argument itemCount.
+ MT32EMU_EXPORT_V(2.5) static const MachineConfiguration * const *getAllMachineConfigurations(Bit32u *itemCount = NULL);
+
+ // Returns a string identifier of this MachineConfiguration.
+ MT32EMU_EXPORT_V(2.5) const char *getMachineID() const;
+
+ // Returns an immutable NULL-terminated list of ROMInfos that are compatible with this
+ // MachineConfiguration. That means the respective ROMImages can be successfully used together
+ // by the emulation engine. Calling ROMInfo::getROMInfo or ROMImage::makeROMImage with this list
+ // supplied enables identification of all files containing desired ROM images while filtering out
+ // any incompatible ones.
+ // For convenience, this method also can fill the number of non-NULL items present in the list
+ // if a non-NULL value is provided in optional argument itemCount.
+ MT32EMU_EXPORT_V(2.5) const ROMInfo * const *getCompatibleROMInfos(Bit32u *itemCount = NULL) const;
+
+private:
+ const char * const machineID;
+ const ROMInfo * const * const romInfos;
+ const Bit32u romInfosCount;
+
+ MachineConfiguration(const char *machineID, const ROMInfo * const *romInfos, Bit32u romInfosCount);
+
+ // Make MachineConfiguration an identity class.
+ MachineConfiguration(const MachineConfiguration &);
+ ~MachineConfiguration() {}
+ MachineConfiguration &operator=(const MachineConfiguration &);
};
} // namespace MT32Emu
diff --git a/audio/softsynth/mt32/Synth.h b/audio/softsynth/mt32/Synth.h
index fc58ef363e..6b9e0c5871 100644
--- a/audio/softsynth/mt32/Synth.h
+++ b/audio/softsynth/mt32/Synth.h
@@ -291,8 +291,8 @@ public:
MT32EMU_EXPORT ~Synth();
// Used to initialise the MT-32. Must be called before any other function.
- // Returns true if initialization was sucessful, otherwise returns false.
- // controlROMImage and pcmROMImage represent Control and PCM ROM images for use by synth.
+ // Returns true if initialization was successful, otherwise returns false.
+ // controlROMImage and pcmROMImage represent full Control and PCM ROM images for use by synth.
// usePartialCount sets the maximum number of partials playing simultaneously for this session (optional).
// analogOutputMode sets the mode for emulation of analogue circuitry of the hardware units (optional).
MT32EMU_EXPORT bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, Bit32u usePartialCount = DEFAULT_MAX_PARTIALS, AnalogOutputMode analogOutputMode = AnalogOutputMode_COARSE);
@@ -391,7 +391,7 @@ public:
MT32EMU_EXPORT bool isMT32ReverbCompatibilityMode() const;
// Returns whether default reverb compatibility mode is the old MT-32 compatibility mode.
MT32EMU_EXPORT bool isDefaultReverbMT32Compatible() const;
- // If enabled, reverb buffers for all modes are keept around allocated all the time to avoid memory
+ // If enabled, reverb buffers for all modes are kept around allocated all the time to avoid memory
// allocating/freeing in the rendering thread, which may be required for realtime operation.
// Otherwise, reverb buffers that are not in use are deleted to save memory (the default behaviour).
MT32EMU_EXPORT void preallocateReverbMemory(bool enabled);
diff --git a/audio/softsynth/mt32/TVP.cpp b/audio/softsynth/mt32/TVP.cpp
index 9e62a0d4ab..42dbd7fab7 100644
--- a/audio/softsynth/mt32/TVP.cpp
+++ b/audio/softsynth/mt32/TVP.cpp
@@ -270,7 +270,7 @@ void TVP::setupPitchChange(int targetPitchOffset, Bit8u changeDuration) {
pitchOffsetDelta = -pitchOffsetDelta;
}
// We want to maximise the number of bits of the Bit16s "pitchOffsetChangePerBigTick" we use in order to get the best possible precision later
- Bit32u absPitchOffsetDelta = pitchOffsetDelta << 16;
+ Bit32u absPitchOffsetDelta = (pitchOffsetDelta & 0xFFFF) << 16;
Bit8u normalisationShifts = normalise(absPitchOffsetDelta); // FIXME: Double-check: normalisationShifts is usually between 0 and 15 here, unless the delta is 0, in which case it's 31
absPitchOffsetDelta = absPitchOffsetDelta >> 1; // Make room for the sign bit
@@ -337,13 +337,16 @@ void TVP::process() {
return;
}
// FIXME: Write explanation for this stuff
+ // NOTE: Value of shifts may happily exceed the maximum of 31 specified for the 8095 MCU.
+ // We assume the device performs a shift with the rightmost 5 bits of the counter regardless of argument size,
+ // since shift instructions of any size have the same maximum.
int rightShifts = shifts;
if (rightShifts > 13) {
rightShifts -= 13;
- negativeBigTicksRemaining = negativeBigTicksRemaining >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift
+ negativeBigTicksRemaining = negativeBigTicksRemaining >> (rightShifts & 0x1F); // PORTABILITY NOTE: Assumes arithmetic shift
rightShifts = 13;
}
- int newResult = (negativeBigTicksRemaining * pitchOffsetChangePerBigTick) >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift
+ int newResult = (negativeBigTicksRemaining * pitchOffsetChangePerBigTick) >> (rightShifts & 0x1F); // PORTABILITY NOTE: Assumes arithmetic shift
newResult += targetPitchOffsetWithoutLFO + lfoPitchOffset;
currentPitchOffset = newResult;
updatePitch();
diff --git a/audio/softsynth/mt32/VersionTagging.cpp b/audio/softsynth/mt32/VersionTagging.cpp
new file mode 100644
index 0000000000..a621d544c4
--- /dev/null
+++ b/audio/softsynth/mt32/VersionTagging.cpp
@@ -0,0 +1,30 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "globals.h"
+
+extern "C" {
+// Here's a list of all tagged minor library versions through global (potentially versioned) symbols.
+// An application that's been linked with an older library version will be able to find a matching tag,
+// while for an application linked with a newer library version there will be no match.
+
+MT32EMU_EXPORT_V(2.5) extern const volatile char mt32emu_2_5 = 0;
+
+#if MT32EMU_VERSION_MAJOR > 2 || MT32EMU_VERSION_MINOR > 5
+#error "Missing version tag definition for current library version"
+#endif
+}
diff --git a/audio/softsynth/mt32/VersionTagging.h b/audio/softsynth/mt32/VersionTagging.h
new file mode 100644
index 0000000000..ec63206a28
--- /dev/null
+++ b/audio/softsynth/mt32/VersionTagging.h
@@ -0,0 +1,46 @@
+/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher
+ * Copyright (C) 2011-2021 Dean Beeler, Jerome Fisher, Sergey V. Mikayev
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MT32EMU_VERSION_TAG_H
+#define MT32EMU_VERSION_TAG_H
+
+#include "globals.h"
+
+// This is intended to implement a simple check of a shared library version in runtime. Sadly, per-symbol versioning
+// is unavailable on many platforms, and even where it is, it's still not too easy to maintain for a C++ library.
+// Therefore, the goal here is just to ensure that the client application quickly bails out when attempted to run
+// with an older version of shared library, as well as to produce a more readable error message indicating a version mismatch
+// rather than a report about some missing symbols with unreadable mangled names.
+// This is an optional feature, since it adds some minor burden to both the library and client applications code,
+// albeit it is ought to work on platforms that do not implement symbol versioning.
+
+#define MT32EMU_REALLY_BUILD_VERSION_TAG(major, minor) mt32emu_ ## major ## _ ## minor
+// This macro expansion step permits resolution the actual version numbers.
+#define MT32EMU_BUILD_VERSION_TAG(major, minor) MT32EMU_REALLY_BUILD_VERSION_TAG(major, minor)
+#define MT32EMU_VERSION_TAG MT32EMU_BUILD_VERSION_TAG(MT32EMU_VERSION_MAJOR, MT32EMU_VERSION_MINOR)
+
+extern "C" {
+MT32EMU_EXPORT extern const volatile char MT32EMU_VERSION_TAG;
+}
+// This pulls the external reference in yet prevents it from being optimised out.
+static const volatile char mt32emu_version_tag = MT32EMU_VERSION_TAG;
+
+#undef MT32EMU_REALLY_BUILD_VERSION_TAG
+#undef MT32EMU_BUILD_VERSION_TAG
+#undef MT32EMU_VERSION_TAG
+
+#endif
diff --git a/audio/softsynth/mt32/c_interface/c_interface.cpp b/audio/softsynth/mt32/c_interface/c_interface.cpp
index 7b0d27ed59..e756b7b3fb 100644
--- a/audio/softsynth/mt32/c_interface/c_interface.cpp
+++ b/audio/softsynth/mt32/c_interface/c_interface.cpp
@@ -15,6 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <cstring>
+
#include "../globals.h"
#include "../Types.h"
#include "../File.h"
@@ -41,7 +43,7 @@ static mt32emu_service_version getSynthVersionID(mt32emu_service_i) {
return MT32EMU_SERVICE_VERSION_CURRENT;
}
-static const mt32emu_service_i_v3 SERVICE_VTABLE = {
+static const mt32emu_service_i_v4 SERVICE_VTABLE = {
getSynthVersionID,
mt32emu_get_supported_report_handler_version,
mt32emu_get_supported_midi_receiver_version,
@@ -118,7 +120,14 @@ static const mt32emu_service_i_v3 SERVICE_VTABLE = {
mt32emu_set_nice_partial_mixing_enabled,
mt32emu_is_nice_partial_mixing_enabled,
mt32emu_preallocate_reverb_memory,
- mt32emu_configure_midi_event_queue_sysex_storage
+ mt32emu_configure_midi_event_queue_sysex_storage,
+ mt32emu_get_machine_ids,
+ mt32emu_get_rom_ids,
+ mt32emu_identify_rom_data,
+ mt32emu_identify_rom_file,
+ mt32emu_merge_and_add_rom_data,
+ mt32emu_merge_and_add_rom_files,
+ mt32emu_add_machine_rom_file
};
} // namespace MT32Emu
@@ -295,30 +304,130 @@ private:
}
};
-static mt32emu_return_code addROMFile(mt32emu_data *data, File *file) {
- const ROMImage *image = ROMImage::makeROMImage(file);
- const ROMInfo *info = image->getROMInfo();
- if (info == NULL) {
- ROMImage::freeROMImage(image);
- return MT32EMU_RC_ROM_NOT_IDENTIFIED;
+static void fillROMInfo(mt32emu_rom_info *rom_info, const ROMInfo *controlROMInfo, const ROMInfo *pcmROMInfo) {
+ if (controlROMInfo != NULL) {
+ rom_info->control_rom_id = controlROMInfo->shortName;
+ rom_info->control_rom_description = controlROMInfo->description;
+ rom_info->control_rom_sha1_digest = controlROMInfo->sha1Digest;
+ } else {
+ rom_info->control_rom_id = NULL;
+ rom_info->control_rom_description = NULL;
+ rom_info->control_rom_sha1_digest = NULL;
}
- if (info->type == ROMInfo::Control) {
- if (data->controlROMImage != NULL) {
- delete data->controlROMImage->getFile();
- ROMImage::freeROMImage(data->controlROMImage);
+ if (pcmROMInfo != NULL) {
+ rom_info->pcm_rom_id = pcmROMInfo->shortName;
+ rom_info->pcm_rom_description = pcmROMInfo->description;
+ rom_info->pcm_rom_sha1_digest = pcmROMInfo->sha1Digest;
+ } else {
+ rom_info->pcm_rom_id = NULL;
+ rom_info->pcm_rom_description = NULL;
+ rom_info->pcm_rom_sha1_digest = NULL;
+ }
+}
+
+static const MachineConfiguration *findMachineConfiguration(const char *machine_id) {
+ Bit32u configurationCount;
+ const MachineConfiguration * const *configurations = MachineConfiguration::getAllMachineConfigurations(&configurationCount);
+ for (Bit32u i = 0; i < configurationCount; i++) {
+ if (!strcmp(configurations[i]->getMachineID(), machine_id)) return configurations[i];
+ }
+ return NULL;
+}
+
+static mt32emu_return_code identifyROM(mt32emu_rom_info *rom_info, File *romFile, const char *machineID) {
+ const ROMInfo *romInfo;
+ if (machineID == NULL) {
+ romInfo = ROMInfo::getROMInfo(romFile);
+ } else {
+ const MachineConfiguration *configuration = findMachineConfiguration(machineID);
+ if (configuration == NULL) {
+ fillROMInfo(rom_info, NULL, NULL);
+ return MT32EMU_RC_MACHINE_NOT_IDENTIFIED;
}
- data->controlROMImage = image;
- return MT32EMU_RC_ADDED_CONTROL_ROM;
- } else if (info->type == ROMInfo::PCM) {
- if (data->pcmROMImage != NULL) {
- delete data->pcmROMImage->getFile();
- ROMImage::freeROMImage(data->pcmROMImage);
+ romInfo = ROMInfo::getROMInfo(romFile, configuration->getCompatibleROMInfos());
+ }
+ if (romInfo == NULL) {
+ fillROMInfo(rom_info, NULL, NULL);
+ return MT32EMU_RC_ROM_NOT_IDENTIFIED;
+ }
+ if (romInfo->type == ROMInfo::Control) fillROMInfo(rom_info, romInfo, NULL);
+ else if (romInfo->type == ROMInfo::PCM) fillROMInfo(rom_info, NULL, romInfo);
+ else fillROMInfo(rom_info, NULL, NULL);
+ return MT32EMU_RC_OK;
+}
+
+static bool isROMInfoCompatible(const MachineConfiguration *machineConfiguration, const ROMInfo *romInfo) {
+ Bit32u romCount;
+ const ROMInfo * const *compatibleROMInfos = machineConfiguration->getCompatibleROMInfos(&romCount);
+ for (Bit32u i = 0; i < romCount; i++) {
+ if (romInfo == compatibleROMInfos[i]) return true;
+ }
+ return false;
+}
+
+static mt32emu_return_code replaceOrMergeROMImage(const ROMImage *&contextROMImage, const ROMImage *newROMImage, const MachineConfiguration *machineConfiguration, mt32emu_return_code addedFullROM, mt32emu_return_code addedPartialROM) {
+ if (contextROMImage != NULL) {
+ if (machineConfiguration != NULL) {
+ const ROMImage *mergedROMImage = ROMImage::mergeROMImages(contextROMImage, newROMImage);
+ if (mergedROMImage != NULL) {
+ if (newROMImage->isFileUserProvided()) delete newROMImage->getFile();
+ ROMImage::freeROMImage(newROMImage);
+ if (contextROMImage->isFileUserProvided()) delete contextROMImage->getFile();
+ ROMImage::freeROMImage(contextROMImage);
+ contextROMImage = mergedROMImage;
+ return addedFullROM;
+ }
+ if (newROMImage->getROMInfo() == contextROMImage->getROMInfo()
+ || (newROMImage->getROMInfo()->pairType != ROMInfo::Full
+ && isROMInfoCompatible(machineConfiguration, contextROMImage->getROMInfo()))) {
+ ROMImage::freeROMImage(newROMImage);
+ return MT32EMU_RC_OK;
+ }
}
- data->pcmROMImage = image;
- return MT32EMU_RC_ADDED_PCM_ROM;
+ if (contextROMImage->isFileUserProvided()) delete contextROMImage->getFile();
+ ROMImage::freeROMImage(contextROMImage);
+ }
+ contextROMImage = newROMImage;
+ return newROMImage->getROMInfo()->pairType == ROMInfo::Full ? addedFullROM: addedPartialROM;
+}
+
+static mt32emu_return_code addROMFiles(mt32emu_data *data, File *file1, File *file2 = NULL, const MachineConfiguration *machineConfiguration = NULL) {
+ const ROMImage *romImage;
+ if (machineConfiguration != NULL) {
+ romImage = ROMImage::makeROMImage(file1, machineConfiguration->getCompatibleROMInfos());
+ } else {
+ romImage = file2 == NULL ? ROMImage::makeROMImage(file1, ROMInfo::getFullROMInfos()) : ROMImage::makeROMImage(file1, file2);
+ }
+ if (romImage == NULL) return MT32EMU_RC_ROMS_NOT_PAIRABLE;
+ const ROMInfo *info = romImage->getROMInfo();
+ if (info == NULL) {
+ ROMImage::freeROMImage(romImage);
+ return MT32EMU_RC_ROM_NOT_IDENTIFIED;
+ }
+ switch (info->type) {
+ case ROMInfo::Control:
+ return replaceOrMergeROMImage(data->controlROMImage, romImage, machineConfiguration, MT32EMU_RC_ADDED_CONTROL_ROM, MT32EMU_RC_ADDED_PARTIAL_CONTROL_ROM);
+ case ROMInfo::PCM:
+ return replaceOrMergeROMImage(data->pcmROMImage, romImage, machineConfiguration, MT32EMU_RC_ADDED_PCM_ROM, MT32EMU_RC_ADDED_PARTIAL_PCM_ROM);
+ default:
+ ROMImage::freeROMImage(romImage);
+ return MT32EMU_RC_OK; // No support for reverb ROM yet.
+ }
+}
+
+static mt32emu_return_code createFileStream(const char *filename, FileStream *&fileStream) {
+ mt32emu_return_code rc;
+ fileStream = new FileStream;
+ if (!fileStream->open(filename)) {
+ rc = MT32EMU_RC_FILE_NOT_FOUND;
+ } else if (fileStream->getSize() == 0) {
+ rc = MT32EMU_RC_FILE_NOT_LOADED;
+ } else {
+ return MT32EMU_RC_OK;
}
- ROMImage::freeROMImage(image);
- return MT32EMU_RC_OK; // No support for reverb ROM yet.
+ delete fileStream;
+ fileStream = NULL;
+ return rc;
}
} // namespace MT32Emu
@@ -329,7 +438,7 @@ extern "C" {
mt32emu_service_i mt32emu_get_service_i() {
mt32emu_service_i i;
- i.v3 = &SERVICE_VTABLE;
+ i.v4 = &SERVICE_VTABLE;
return i;
}
@@ -357,6 +466,53 @@ mt32emu_analog_output_mode mt32emu_get_best_analog_output_mode(const double targ
return mt32emu_analog_output_mode(SampleRateConverter::getBestAnalogOutputMode(target_samplerate));
}
+size_t mt32emu_get_machine_ids(const char **machine_ids, size_t machine_ids_size) {
+ Bit32u configurationCount;
+ const MachineConfiguration * const *configurations = MachineConfiguration::getAllMachineConfigurations(&configurationCount);
+ if (machine_ids != NULL) {
+ for (Bit32u i = 0; i < machine_ids_size; i++) {
+ machine_ids[i] = i < configurationCount ? configurations[i]->getMachineID() : NULL;
+ }
+ }
+ return configurationCount;
+}
+
+size_t mt32emu_get_rom_ids(const char **rom_ids, size_t rom_ids_size, const char *machine_id) {
+ const ROMInfo * const *romInfos;
+ Bit32u romCount;
+ if (machine_id != NULL) {
+ const MachineConfiguration *configuration = findMachineConfiguration(machine_id);
+ if (configuration != NULL) {
+ romInfos = configuration->getCompatibleROMInfos(&romCount);
+ } else {
+ romInfos = NULL;
+ romCount = 0U;
+ }
+ } else {
+ romInfos = ROMInfo::getAllROMInfos(&romCount);
+ }
+ if (rom_ids != NULL) {
+ for (size_t i = 0; i < rom_ids_size; i++) {
+ rom_ids[i] = i < romCount ? romInfos[i]->shortName : NULL;
+ }
+ }
+ return romCount;
+}
+
+mt32emu_return_code mt32emu_identify_rom_data(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id) {
+ ArrayFile romFile = ArrayFile(data, data_size);
+ return identifyROM(rom_info, &romFile, machine_id);
+}
+
+mt32emu_return_code mt32emu_identify_rom_file(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id) {
+ FileStream *fs;
+ mt32emu_return_code rc = createFileStream(filename, fs);
+ if (fs == NULL) return rc;
+ rc = identifyROM(rom_info, fs, machine_id);
+ delete fs;
+ return rc;
+}
+
mt32emu_context mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data) {
mt32emu_data *data = new mt32emu_data;
data->reportHandler = (report_handler.v0 != NULL) ? new DelegatingReportHandlerAdapter(report_handler, instance_data) : new ReportHandler;
@@ -384,12 +540,12 @@ void mt32emu_free_context(mt32emu_context data) {
data->srcState = NULL;
if (data->controlROMImage != NULL) {
- delete data->controlROMImage->getFile();
+ if (data->controlROMImage->isFileUserProvided()) delete data->controlROMImage->getFile();
ROMImage::freeROMImage(data->controlROMImage);
data->controlROMImage = NULL;
}
if (data->pcmROMImage != NULL) {
- delete data->pcmROMImage->getFile();
+ if (data->pcmROMImage->isFileUserProvided()) delete data->pcmROMImage->getFile();
ROMImage::freeROMImage(data->pcmROMImage);
data->pcmROMImage = NULL;
}
@@ -403,48 +559,58 @@ void mt32emu_free_context(mt32emu_context data) {
}
mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest) {
- if (sha1_digest == NULL) return addROMFile(context, new ArrayFile(data, data_size));
- return addROMFile(context, new ArrayFile(data, data_size, *sha1_digest));
+ if (sha1_digest == NULL) return addROMFiles(context, new ArrayFile(data, data_size));
+ return addROMFiles(context, new ArrayFile(data, data_size, *sha1_digest));
}
mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename) {
- mt32emu_return_code rc = MT32EMU_RC_OK;
- FileStream *fs = new FileStream;
- if (fs->open(filename)) {
- if (fs->getData() != NULL) {
- rc = addROMFile(context, fs);
- if (rc > 0) return rc;
- } else {
- rc = MT32EMU_RC_FILE_NOT_LOADED;
+ FileStream *fs;
+ mt32emu_return_code rc = createFileStream(filename, fs);
+ if (fs != NULL) rc = addROMFiles(context, fs);
+ if (rc <= MT32EMU_RC_OK) delete fs;
+ return rc;
+}
+
+mt32emu_return_code mt32emu_merge_and_add_rom_data(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest) {
+ ArrayFile *file1 = part1_sha1_digest == NULL ? new ArrayFile(part1_data, part1_data_size) : new ArrayFile(part1_data, part1_data_size, *part1_sha1_digest);
+ ArrayFile *file2 = part2_sha1_digest == NULL ? new ArrayFile(part2_data, part2_data_size) : new ArrayFile(part2_data, part2_data_size, *part2_sha1_digest);
+ mt32emu_return_code rc = addROMFiles(context, file1, file2);
+ delete file1;
+ delete file2;
+ return rc;
+}
+
+mt32emu_return_code mt32emu_merge_and_add_rom_files(mt32emu_context context, const char *part1_filename, const char *part2_filename) {
+ FileStream *fs1;
+ mt32emu_return_code rc = createFileStream(part1_filename, fs1);
+ if (fs1 != NULL) {
+ FileStream *fs2;
+ rc = createFileStream(part2_filename, fs2);
+ if (fs2 != NULL) {
+ rc = addROMFiles(context, fs1, fs2);
+ delete fs2;
}
- } else {
- rc = MT32EMU_RC_FILE_NOT_FOUND;
+ delete fs1;
}
- delete fs;
+ return rc;
+}
+
+mt32emu_return_code mt32emu_add_machine_rom_file(mt32emu_context context, const char *machine_id, const char *filename) {
+ const MachineConfiguration *machineConfiguration = findMachineConfiguration(machine_id);
+ if (machineConfiguration == NULL) return MT32EMU_RC_MACHINE_NOT_IDENTIFIED;
+
+ FileStream *fs;
+ mt32emu_return_code rc = createFileStream(filename, fs);
+ if (fs == NULL) return rc;
+ rc = addROMFiles(context, fs, NULL, machineConfiguration);
+ if (rc <= MT32EMU_RC_OK) delete fs;
return rc;
}
void mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info) {
- const ROMInfo *romInfo = context->controlROMImage == NULL ? NULL : context->controlROMImage->getROMInfo();
- if (romInfo != NULL) {
- rom_info->control_rom_id = romInfo->shortName;
- rom_info->control_rom_description = romInfo->description;
- rom_info->control_rom_sha1_digest = romInfo->sha1Digest;
- } else {
- rom_info->control_rom_id = NULL;
- rom_info->control_rom_description = NULL;
- rom_info->control_rom_sha1_digest = NULL;
- }
- romInfo = context->pcmROMImage == NULL ? NULL : context->pcmROMImage->getROMInfo();
- if (romInfo != NULL) {
- rom_info->pcm_rom_id = romInfo->shortName;
- rom_info->pcm_rom_description = romInfo->description;
- rom_info->pcm_rom_sha1_digest = romInfo->sha1Digest;
- } else {
- rom_info->pcm_rom_id = NULL;
- rom_info->pcm_rom_description = NULL;
- rom_info->pcm_rom_sha1_digest = NULL;
- }
+ const ROMInfo *controlROMInfo = context->controlROMImage == NULL ? NULL : context->controlROMImage->getROMInfo();
+ const ROMInfo *pcmROMInfo = context->pcmROMImage == NULL ? NULL : context->pcmROMImage->getROMInfo();
+ fillROMInfo(rom_info, controlROMInfo, pcmROMInfo);
}
void mt32emu_set_partial_count(mt32emu_context context, const mt32emu_bit32u partial_count) {
diff --git a/audio/softsynth/mt32/c_interface/c_interface.h b/audio/softsynth/mt32/c_interface/c_interface.h
index cb1afeeedc..14e7263b39 100644
--- a/audio/softsynth/mt32/c_interface/c_interface.h
+++ b/audio/softsynth/mt32/c_interface/c_interface.h
@@ -24,7 +24,9 @@
#include "c_types.h"
#undef MT32EMU_EXPORT
+#undef MT32EMU_EXPORT_V
#define MT32EMU_EXPORT MT32EMU_EXPORT_ATTRIBUTE
+#define MT32EMU_EXPORT_V(symbol_version_tag) MT32EMU_EXPORT
#ifdef __cplusplus
extern "C" {
@@ -39,7 +41,9 @@ MT32EMU_EXPORT mt32emu_service_i mt32emu_get_service_i(void);
#if MT32EMU_EXPORTS_TYPE == 2
#undef MT32EMU_EXPORT
+#undef MT32EMU_EXPORT_V
#define MT32EMU_EXPORT
+#define MT32EMU_EXPORT_V(symbol_version_tag) MT32EMU_EXPORT
#endif
/**
@@ -54,6 +58,8 @@ MT32EMU_EXPORT mt32emu_report_handler_version mt32emu_get_supported_report_handl
*/
MT32EMU_EXPORT mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version(void);
+/* === Utility === */
+
/**
* Returns library version as an integer in format: 0x00MMmmpp, where:
* MM - major version number
@@ -80,6 +86,45 @@ MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_stereo_output_samplerate(const mt32emu
*/
MT32EMU_EXPORT mt32emu_analog_output_mode mt32emu_get_best_analog_output_mode(const double target_samplerate);
+/* === ROM handling === */
+
+/**
+ * Retrieves a list of identifiers (as C-strings) of supported machines. Argument machine_ids points to the array of size
+ * machine_ids_size to be filled.
+ * Returns the number of identifiers available for retrieval. The size of the target array to be allocated can be found
+ * by passing NULL in argument machine_ids; argument machine_ids_size is ignored in this case.
+ */
+MT32EMU_EXPORT_V(2.5) size_t mt32emu_get_machine_ids(const char **machine_ids, size_t machine_ids_size);
+/**
+ * Retrieves a list of identifiers (as C-strings) of supported ROM images. Argument rom_ids points to the array of size
+ * rom_ids_size to be filled. Optional argument machine_id can be used to indicate a specific machine to retrieve ROM identifiers
+ * for; if NULL, identifiers of all the ROM images supported by the emulation engine are retrieved.
+ * Returns the number of ROM identifiers available for retrieval. The size of the target array to be allocated can be found
+ * by passing NULL in argument rom_ids; argument rom_ids_size is ignored in this case. If argument machine_id contains
+ * an unrecognised value, 0 is returned.
+ */
+MT32EMU_EXPORT_V(2.5) size_t mt32emu_get_rom_ids(const char **rom_ids, size_t rom_ids_size, const char *machine_id);
+
+/**
+ * Identifies a ROM image the provided data array contains by its SHA1 digest. Optional argument machine_id can be used to indicate
+ * a specific machine to identify the ROM image for; if NULL, the ROM image is identified for any supported machine.
+ * A mt32emu_rom_info structure supplied in argument rom_info is filled in accordance with the provided ROM image; unused fields
+ * are filled with NULLs. If the content of the ROM image is not identified successfully (e.g. when the ROM image is incompatible
+ * with the specified machine), all fields of rom_info are filled with NULLs.
+ * Returns MT32EMU_RC_OK upon success or a negative error code otherwise.
+ */
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_identify_rom_data(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id);
+/**
+ * Loads the content of the file specified by argument filename and identifies a ROM image the file contains by its SHA1 digest.
+ * Optional argument machine_id can be used to indicate a specific machine to identify the ROM image for; if NULL, the ROM image
+ * is identified for any supported machine.
+ * A mt32emu_rom_info structure supplied in argument rom_info is filled in accordance with the provided ROM image; unused fields
+ * are filled with NULLs. If the content of the file is not identified successfully (e.g. when the ROM image is incompatible
+ * with the specified machine), all fields of rom_info are filled with NULLs.
+ * Returns MT32EMU_RC_OK upon success or a negative error code otherwise.
+ */
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_identify_rom_file(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id);
+
/* == Context-dependent functions == */
/** Initialises a new emulation context and installs custom report handler if non-NULL. */
@@ -89,21 +134,64 @@ MT32EMU_EXPORT mt32emu_context mt32emu_create_context(mt32emu_report_handler_i r
MT32EMU_EXPORT void mt32emu_free_context(mt32emu_context context);
/**
- * Adds new ROM identified by its SHA1 digest to the emulation context replacing previously added ROM of the same type if any.
- * Argument sha1_digest can be NULL, in this case the digest will be computed using the actual ROM data.
+ * Adds a new full ROM data image identified by its SHA1 digest to the emulation context replacing previously added ROM of the same
+ * type if any. Argument sha1_digest can be NULL, in this case the digest will be computed using the actual ROM data.
* If sha1_digest is set to non-NULL, it is assumed being correct and will not be recomputed.
- * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of mt32emu_open_synth().
+ * The provided data array is NOT copied and used directly for efficiency. The caller should not deallocate it while the emulation
+ * context is referring to the ROM data.
+ * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of
+ * mt32emu_open_synth().
* Returns positive value upon success.
*/
MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest);
/**
- * Loads a ROM file, identify it by SHA1 digest, and adds it to the emulation context replacing previously added ROM of the same type if any.
- * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of mt32emu_open_synth().
+ * Loads a ROM file that contains a full ROM data image, identifies it by the SHA1 digest, and adds it to the emulation context
+ * replacing previously added ROM of the same type if any.
+ * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of
+ * mt32emu_open_synth().
* Returns positive value upon success.
*/
MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename);
+/**
+ * Merges a pair of compatible ROM data image parts into a full image and adds it to the emulation context replacing previously
+ * added ROM of the same type if any. Each partial image is identified by its SHA1 digest. Arguments partN_sha1_digest can be NULL,
+ * in this case the digest will be computed using the actual ROM data. If a non-NULL SHA1 value is provided, it is assumed being
+ * correct and will not be recomputed. The provided data arrays may be deallocated as soon as the function completes.
+ * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of
+ * mt32emu_open_synth().
+ * Returns positive value upon success.
+ */
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_merge_and_add_rom_data(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest);
+
+/**
+ * Loads a pair of files that contains compatible parts of a full ROM image, identifies them by the SHA1 digest, merges these
+ * parts into a full ROM image and adds it to the emulation context replacing previously added ROM of the same type if any.
+ * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of
+ * mt32emu_open_synth().
+ * Returns positive value upon success.
+ */
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_merge_and_add_rom_files(mt32emu_context context, const char *part1_filename, const char *part2_filename);
+
+/**
+ * Loads a file that contains a ROM image of a specific machine, identifies it by the SHA1 digest, and adds it to the emulation
+ * context. The ROM image can only be identified successfully if it is compatible with the specified machine.
+ * Full and partial ROM images are supported and handled according to the following rules:
+ * - a file with any compatible ROM image is added if none (of the same type) exists in the emulation context;
+ * - a file with any compatible ROM image replaces any image of the same type that is incompatible with the specified machine;
+ * - a file with a full ROM image replaces the previously added partial ROM of the same type;
+ * - a file with a partial ROM image is merged with the previously added ROM image if pairable;
+ * - otherwise, the file is ignored.
+ * The described behaviour allows the caller application to traverse a directory with ROM files attempting to add each one in turn.
+ * As soon as both the full control and the full PCM ROM images are added and / or merged, the iteration can be stopped.
+ * This function doesn't immediately change the state of already opened synth. Newly added ROMs will take effect upon next call of
+ * mt32emu_open_synth().
+ * Returns a positive value in case changes have been made, MT32EMU_RC_OK if the file has been ignored or a negative error code
+ * upon failure.
+ */
+MT32EMU_EXPORT_V(2.5) mt32emu_return_code mt32emu_add_machine_rom_file(mt32emu_context context, const char *machine_id, const char *filename);
+
/**
* Fills in mt32emu_rom_info structure with identifiers and descriptions of control and PCM ROM files identified and added to the synth context.
* If one of the ROM files is not loaded and identified yet, NULL is returned in the corresponding fields of the mt32emu_rom_info structure.
@@ -172,7 +260,7 @@ MT32EMU_EXPORT mt32emu_boolean mt32emu_is_open(mt32emu_const_context context);
* Returns actual sample rate of the fully processed output stereo signal.
* If samplerate conversion is used (i.e. when mt32emu_set_stereo_output_samplerate() has been invoked with a non-zero value),
* the returned value is the desired output samplerate rounded down to the closest integer.
- * Otherwise, the output samplerate is choosen depending on the emulation mode of stereo analog circuitry of hardware units.
+ * Otherwise, the output samplerate is chosen depending on the emulation mode of stereo analog circuitry of hardware units.
* See comment for mt32emu_analog_output_mode for more info.
*/
MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context);
@@ -330,7 +418,7 @@ MT32EMU_EXPORT mt32emu_boolean mt32emu_is_mt32_reverb_compatibility_mode(mt32emu
MT32EMU_EXPORT mt32emu_boolean mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context);
/**
- * If enabled, reverb buffers for all modes are keept around allocated all the time to avoid memory
+ * If enabled, reverb buffers for all modes are kept around allocated all the time to avoid memory
* allocating/freeing in the rendering thread, which may be required for realtime operation.
* Otherwise, reverb buffers that are not in use are deleted to save memory (the default behaviour).
*/
diff --git a/audio/softsynth/mt32/c_interface/c_types.h b/audio/softsynth/mt32/c_interface/c_types.h
index eb96b2bb67..6bcf077553 100644
--- a/audio/softsynth/mt32/c_interface/c_types.h
+++ b/audio/softsynth/mt32/c_interface/c_types.h
@@ -45,6 +45,8 @@ typedef enum {
MT32EMU_RC_OK = 0,
MT32EMU_RC_ADDED_CONTROL_ROM = 1,
MT32EMU_RC_ADDED_PCM_ROM = 2,
+ MT32EMU_RC_ADDED_PARTIAL_CONTROL_ROM = 3,
+ MT32EMU_RC_ADDED_PARTIAL_PCM_ROM = 4,
/* Definite error occurred. */
MT32EMU_RC_ROM_NOT_IDENTIFIED = -1,
@@ -53,6 +55,8 @@ typedef enum {
MT32EMU_RC_MISSING_ROMS = -4,
MT32EMU_RC_NOT_OPENED = -5,
MT32EMU_RC_QUEUE_FULL = -6,
+ MT32EMU_RC_ROMS_NOT_PAIRABLE = -7,
+ MT32EMU_RC_MACHINE_NOT_IDENTIFIED = -8,
/* Undefined error occurred. */
MT32EMU_RC_FAILED = -100
@@ -122,7 +126,8 @@ typedef enum {
MT32EMU_SERVICE_VERSION_1 = 1,
MT32EMU_SERVICE_VERSION_2 = 2,
MT32EMU_SERVICE_VERSION_3 = 3,
- MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_3
+ MT32EMU_SERVICE_VERSION_4 = 4,
+ MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_4
} mt32emu_service_version;
/* === Report Handler Interface === */
@@ -312,6 +317,16 @@ typedef union mt32emu_service_i mt32emu_service_i;
void (*preallocateReverbMemory)(mt32emu_const_context context, const mt32emu_boolean enabled); \
void (*configureMIDIEventQueueSysexStorage)(mt32emu_const_context context, const mt32emu_bit32u storage_buffer_size);
+#define MT32EMU_SERVICE_I_V4 \
+ size_t (*getMachineIDs)(const char **machine_ids, size_t machine_ids_size); \
+ size_t (*getROMIDs)(const char **rom_ids, size_t rom_ids_size, const char *machine_id); \
+ mt32emu_return_code (*identifyROMData)(mt32emu_rom_info *rom_info, const mt32emu_bit8u *data, size_t data_size, const char *machine_id); \
+ mt32emu_return_code (*identifyROMFile)(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id); \
+\
+ mt32emu_return_code (*mergeAndAddROMData)(mt32emu_context context, const mt32emu_bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const mt32emu_bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest); \
+ mt32emu_return_code (*mergeAndAddROMFiles)(mt32emu_context context, const char *part1_filename, const char *part2_filename); \
+ mt32emu_return_code (*addMachineROMFile)(mt32emu_context context, const char *machine_id, const char *filename);
+
typedef struct {
MT32EMU_SERVICE_I_V0
} mt32emu_service_i_v0;
@@ -334,6 +349,14 @@ typedef struct {
MT32EMU_SERVICE_I_V3
} mt32emu_service_i_v3;
+typedef struct {
+ MT32EMU_SERVICE_I_V0
+ MT32EMU_SERVICE_I_V1
+ MT32EMU_SERVICE_I_V2
+ MT32EMU_SERVICE_I_V3
+ MT32EMU_SERVICE_I_V4
+} mt32emu_service_i_v4;
+
/**
* Extensible interface for all the library services.
* Union intended to view an interface of any subsequent version as any parent interface not requiring a cast.
@@ -344,11 +367,13 @@ union mt32emu_service_i {
const mt32emu_service_i_v1 *v1;
const mt32emu_service_i_v2 *v2;
const mt32emu_service_i_v3 *v3;
+ const mt32emu_service_i_v4 *v4;
};
#undef MT32EMU_SERVICE_I_V0
#undef MT32EMU_SERVICE_I_V1
#undef MT32EMU_SERVICE_I_V2
#undef MT32EMU_SERVICE_I_V3
+#undef MT32EMU_SERVICE_I_V4
#endif /* #ifndef MT32EMU_C_TYPES_H */
diff --git a/audio/softsynth/mt32/c_interface/cpp_interface.h b/audio/softsynth/mt32/c_interface/cpp_interface.h
index c9417488b1..aa28327e87 100644
--- a/audio/softsynth/mt32/c_interface/cpp_interface.h
+++ b/audio/softsynth/mt32/c_interface/cpp_interface.h
@@ -41,10 +41,17 @@ mt32emu_service_i mt32emu_get_service_i();
#define mt32emu_get_library_version_string i.v0->getLibraryVersionString
#define mt32emu_get_stereo_output_samplerate i.v0->getStereoOutputSamplerate
#define mt32emu_get_best_analog_output_mode iV1()->getBestAnalogOutputMode
+#define mt32emu_get_machine_ids iV4()->getMachineIDs
+#define mt32emu_get_rom_ids iV4()->getROMIDs
+#define mt32emu_identify_rom_data iV4()->identifyROMData
+#define mt32emu_identify_rom_file iV4()->identifyROMFile
#define mt32emu_create_context i.v0->createContext
#define mt32emu_free_context i.v0->freeContext
#define mt32emu_add_rom_data i.v0->addROMData
#define mt32emu_add_rom_file i.v0->addROMFile
+#define mt32emu_merge_and_add_rom_data iV4()->mergeAndAddROMData
+#define mt32emu_merge_and_add_rom_files iV4()->mergeAndAddROMFiles
+#define mt32emu_add_machine_rom_file iV4()->addMachineROMFile
#define mt32emu_get_rom_info i.v0->getROMInfo
#define mt32emu_set_partial_count i.v0->setPartialCount
#define mt32emu_set_analog_output_mode i.v0->setAnalogOutputMode
@@ -196,6 +203,11 @@ public:
Bit32u getStereoOutputSamplerate(const AnalogOutputMode analog_output_mode) { return mt32emu_get_stereo_output_samplerate(static_cast<mt32emu_analog_output_mode>(analog_output_mode)); }
AnalogOutputMode getBestAnalogOutputMode(const double target_samplerate) { return static_cast<AnalogOutputMode>(mt32emu_get_best_analog_output_mode(target_samplerate)); }
+ size_t getMachineIDs(const char **machine_ids, size_t machine_ids_size) { return mt32emu_get_machine_ids(machine_ids, machine_ids_size); }
+ size_t getROMIDs(const char **rom_ids, size_t rom_ids_size, const char *machine_id) { return mt32emu_get_rom_ids(rom_ids, rom_ids_size, machine_id); }
+ mt32emu_return_code identifyROMData(mt32emu_rom_info *rom_info, const Bit8u *data, size_t data_size, const char *machine_id) { return mt32emu_identify_rom_data(rom_info, data, data_size, machine_id); }
+ mt32emu_return_code identifyROMFile(mt32emu_rom_info *rom_info, const char *filename, const char *machine_id) { return mt32emu_identify_rom_file(rom_info, filename, machine_id); }
+
// Context-dependent methods
mt32emu_context getContext() { return c; }
@@ -204,6 +216,10 @@ public:
void freeContext() { if (c != NULL) { mt32emu_free_context(c); c = NULL; } }
mt32emu_return_code addROMData(const Bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest = NULL) { return mt32emu_add_rom_data(c, data, data_size, sha1_digest); }
mt32emu_return_code addROMFile(const char *filename) { return mt32emu_add_rom_file(c, filename); }
+ mt32emu_return_code mergeAndAddROMData(const Bit8u *part1_data, size_t part1_data_size, const Bit8u *part2_data, size_t part2_data_size) { return mt32emu_merge_and_add_rom_data(c, part1_data, part1_data_size, NULL, part2_data, part2_data_size, NULL); }
+ mt32emu_return_code mergeAndAddROMData(const Bit8u *part1_data, size_t part1_data_size, const mt32emu_sha1_digest *part1_sha1_digest, const Bit8u *part2_data, size_t part2_data_size, const mt32emu_sha1_digest *part2_sha1_digest) { return mt32emu_merge_and_add_rom_data(c, part1_data, part1_data_size, part1_sha1_digest, part2_data, part2_data_size, part2_sha1_digest); }
+ mt32emu_return_code mergeAndAddROMFiles(const char *part1_filename, const char *part2_filename) { return mt32emu_merge_and_add_rom_files(c, part1_filename, part2_filename); }
+ mt32emu_return_code addMachineROMFile(const char *machine_id, const char *filename) { return mt32emu_add_machine_rom_file(c, machine_id, filename); }
void getROMInfo(mt32emu_rom_info *rom_info) { mt32emu_get_rom_info(c, rom_info); }
void setPartialCount(const Bit32u partial_count) { mt32emu_set_partial_count(c, partial_count); }
void setAnalogOutputMode(const AnalogOutputMode analog_output_mode) { mt32emu_set_analog_output_mode(c, static_cast<mt32emu_analog_output_mode>(analog_output_mode)); }
@@ -294,7 +310,11 @@ private:
const mt32emu_service_i_v1 *iV1() { return (getVersionID() < MT32EMU_SERVICE_VERSION_1) ? NULL : i.v1; }
const mt32emu_service_i_v2 *iV2() { return (getVersionID() < MT32EMU_SERVICE_VERSION_2) ? NULL : i.v2; }
const mt32emu_service_i_v3 *iV3() { return (getVersionID() < MT32EMU_SERVICE_VERSION_3) ? NULL : i.v3; }
+ const mt32emu_service_i_v4 *iV4() { return (getVersionID() < MT32EMU_SERVICE_VERSION_4) ? NULL : i.v4; }
#endif
+
+ Service(const Service &); // prevent copy-construction
+ Service& operator=(const Service &); // prevent assignment
};
namespace CppInterfaceImpl {
@@ -424,10 +444,17 @@ static mt32emu_midi_receiver_i getMidiReceiverThunk() {
#undef mt32emu_get_library_version_string
#undef mt32emu_get_stereo_output_samplerate
#undef mt32emu_get_best_analog_output_mode
+#undef mt32emu_get_machine_ids
+#undef mt32emu_get_rom_ids
+#undef mt32emu_identify_rom_data
+#undef mt32emu_identify_rom_file
#undef mt32emu_create_context
#undef mt32emu_free_context
#undef mt32emu_add_rom_data
#undef mt32emu_add_rom_file
+#undef mt32emu_merge_and_add_rom_data
+#undef mt32emu_merge_and_add_rom_files
+#undef mt32emu_add_machine_rom_file
#undef mt32emu_get_rom_info
#undef mt32emu_set_partial_count
#undef mt32emu_set_analog_output_mode
diff --git a/audio/softsynth/mt32/config.h b/audio/softsynth/mt32/config.h
index 3c16e05d0d..8d37d70883 100644
--- a/audio/softsynth/mt32/config.h
+++ b/audio/softsynth/mt32/config.h
@@ -18,10 +18,10 @@
#ifndef MT32EMU_CONFIG_H
#define MT32EMU_CONFIG_H
-#define MT32EMU_VERSION "2.4.2"
+#define MT32EMU_VERSION "2.5.0"
#define MT32EMU_VERSION_MAJOR 2
-#define MT32EMU_VERSION_MINOR 4
-#define MT32EMU_VERSION_PATCH 2
+#define MT32EMU_VERSION_MINOR 5
+#define MT32EMU_VERSION_PATCH 0
/* Library Exports Configuration
*
@@ -33,6 +33,35 @@
* is exported, and thus the client application may ONLY use MT32EMU_API_TYPE 2.
* 3: All the available API types are provided by the library build.
*/
-#define MT32EMU_EXPORTS_TYPE 0
+#define MT32EMU_EXPORTS_TYPE 0
+/* Type of library build.
+ *
+ * For shared library builds, MT32EMU_SHARED is defined, so that compiler-specific attributes are assigned
+ * to all the exported symbols as appropriate. MT32EMU_SHARED is undefined for static library builds.
+ */
+ at libmt32emu_SHARED_DEFINITION@
+
+/* Whether the library is built as a shared object with a version tag to enable runtime version checks. */
+#define MT32EMU_WITH_VERSION_TAGGING @libmt32emu_RUNTIME_VERSION_CHECK@
+
+/* Automatic runtime check of the shared library version in client applications.
+ *
+ * When the shared library is built with version tagging enabled, the client application may rely on an automatic
+ * version check that ensures forward compatibility. See VersionTagging.h for more info.
+ * 0: Disables the automatic runtime version check in the client application. Implied for static library builds
+ * and when version tagging is not used in a shared object.
+ * 1: Enables an automatic runtime version check in client applications that utilise low-level C++ API,
+ * i.e. when MT32EMU_API_TYPE 0. Client applications that rely on the C-compatible API are supposed
+ * to check the version of the shared object by other means (e.g. using versioned C symbols, etc.).
+ * 2: Enables an automatic runtime version check for C++ and C client applications.
+ */
+#if MT32EMU_WITH_VERSION_TAGGING
+# ifndef MT32EMU_RUNTIME_VERSION_CHECK
+# define MT32EMU_RUNTIME_VERSION_CHECK @libmt32emu_RUNTIME_VERSION_CHECK@
+# endif
+#else
+# undef MT32EMU_RUNTIME_VERSION_CHECK
#endif
+
+#endif /* #ifndef MT32EMU_CONFIG_H */
diff --git a/audio/softsynth/mt32/globals.h b/audio/softsynth/mt32/globals.h
index 81f6cdbc7e..79b7ae5eb4 100644
--- a/audio/softsynth/mt32/globals.h
+++ b/audio/softsynth/mt32/globals.h
@@ -20,7 +20,11 @@
#include "config.h"
-/* Support for compiling shared library. */
+/* Support for compiling shared library.
+ * MT32EMU_SHARED and mt32emu_EXPORTS are defined when building a shared library.
+ * MT32EMU_SHARED should also be defined for Windows platforms that provides for a small performance benefit,
+ * and it _must_ be defined along with MT32EMU_RUNTIME_VERSION_CHECK when using MSVC.
+ */
#ifdef MT32EMU_SHARED
# if defined _WIN32 || defined __CYGWIN__ || defined __OS2__
# ifdef _MSC_VER
@@ -37,7 +41,11 @@
# endif /* #ifdef mt32emu_EXPORTS */
# endif /* #ifdef _MSC_VER */
# else /* #if defined _WIN32 || defined __CYGWIN__ || defined __OS2__ */
-# define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((visibility("default")))
+# ifdef mt32emu_EXPORTS
+# define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((visibility("default")))
+# else /* #ifdef mt32emu_EXPORTS */
+# define MT32EMU_EXPORT_ATTRIBUTE
+# endif /* #ifdef mt32emu_EXPORTS */
# endif /* #if defined _WIN32 || defined __CYGWIN__ || defined __OS2__ */
#else /* #ifdef MT32EMU_SHARED */
# define MT32EMU_EXPORT_ATTRIBUTE
@@ -49,6 +57,12 @@
#define MT32EMU_EXPORT MT32EMU_EXPORT_ATTRIBUTE
#endif
+/* Facilitates easier tracking of the library version when an external symbol was introduced.
+ * Particularly useful for shared library builds on POSIX systems that support symbol versioning,
+ * so that the version map file can be generated automatically.
+ */
+#define MT32EMU_EXPORT_V(symbol_version_tag) MT32EMU_EXPORT
+
/* Useful constants */
/* Sample rate to use in mixing. With the progress of development, we've found way too many thing dependent.
diff --git a/audio/softsynth/mt32/mt32emu.h b/audio/softsynth/mt32/mt32emu.h
index 0ebd74731e..399ddae069 100644
--- a/audio/softsynth/mt32/mt32emu.h
+++ b/audio/softsynth/mt32/mt32emu.h
@@ -37,28 +37,23 @@
*/
#ifdef MT32EMU_API_TYPE
-#if MT32EMU_API_TYPE == 0 && (MT32EMU_EXPORTS_TYPE == 1 || MT32EMU_EXPORTS_TYPE == 2)
-#error Incompatible setting MT32EMU_API_TYPE=0
-#elif MT32EMU_API_TYPE == 1 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2)
-#error Incompatible setting MT32EMU_API_TYPE=1
-#elif MT32EMU_API_TYPE == 2 && (MT32EMU_EXPORTS_TYPE == 0)
-#error Incompatible setting MT32EMU_API_TYPE=2
-#elif MT32EMU_API_TYPE == 3 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2)
-#error Incompatible setting MT32EMU_API_TYPE=3
-#endif
+# if MT32EMU_API_TYPE == 0 && (MT32EMU_EXPORTS_TYPE == 1 || MT32EMU_EXPORTS_TYPE == 2)
+# error Incompatible setting MT32EMU_API_TYPE=0
+# elif MT32EMU_API_TYPE == 1 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2)
+# error Incompatible setting MT32EMU_API_TYPE=1
+# elif MT32EMU_API_TYPE == 2 && (MT32EMU_EXPORTS_TYPE == 0)
+# error Incompatible setting MT32EMU_API_TYPE=2
+# elif MT32EMU_API_TYPE == 3 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2)
+# error Incompatible setting MT32EMU_API_TYPE=3
+# endif
#else /* #ifdef MT32EMU_API_TYPE */
-#if 0 < MT32EMU_EXPORTS_TYPE && MT32EMU_EXPORTS_TYPE < 3
-#define MT32EMU_API_TYPE MT32EMU_EXPORTS_TYPE
-#else
-#define MT32EMU_API_TYPE 0
-#endif
+# if 0 < MT32EMU_EXPORTS_TYPE && MT32EMU_EXPORTS_TYPE < 3
+# define MT32EMU_API_TYPE MT32EMU_EXPORTS_TYPE
+# else
+# define MT32EMU_API_TYPE 0
+# endif
#endif /* #ifdef MT32EMU_API_TYPE */
-/* MT32EMU_SHARED should be defined when building shared library, especially for Windows platforms. */
-/*
-#define MT32EMU_SHARED
-*/
-
#include "globals.h"
#if !defined(__cplusplus) || MT32EMU_API_TYPE == 1
@@ -79,6 +74,14 @@
#include "MidiStreamParser.h"
#include "SampleRateConverter.h"
+#if MT32EMU_RUNTIME_VERSION_CHECK == 1
+#include "VersionTagging.h"
+#endif
+
#endif /* #if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 */
+#if MT32EMU_RUNTIME_VERSION_CHECK == 2
+#include "VersionTagging.h"
+#endif
+
#endif /* #ifndef MT32EMU_MT32EMU_H */
diff --git a/audio/softsynth/mt32/mt32emu.pc.in b/audio/softsynth/mt32/mt32emu.pc.in
new file mode 100644
index 0000000000..95ddf6fa1d
--- /dev/null
+++ b/audio/softsynth/mt32/mt32emu.pc.in
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/@LIB_INSTALL_DIR@
+includedir=${prefix}/include
+
+Name: @PROJECT_NAME@
+Description: @libmt32emu_DESCRIPTION@
+URL: @libmt32emu_URL@
+Version: @libmt32emu_VERSION@
+Requires.private: @libmt32emu_PC_REQUIRES_PRIVATE@
+Libs: -L${libdir} -lmt32emu
+Cflags: -I${includedir}
Commit: 24a27f6568e426f2c3f4948c1013f7644de8a88a
https://github.com/scummvm/scummvm/commit/24a27f6568e426f2c3f4948c1013f7644de8a88a
Author: Lothar Serra Mari (mail at serra.me)
Date: 2021-04-10T16:09:54+02:00
Commit Message:
MT32: Fix definitions
Changed paths:
audio/softsynth/mt32/config.h
diff --git a/audio/softsynth/mt32/config.h b/audio/softsynth/mt32/config.h
index 8d37d70883..bc3a168837 100644
--- a/audio/softsynth/mt32/config.h
+++ b/audio/softsynth/mt32/config.h
@@ -40,10 +40,10 @@
* For shared library builds, MT32EMU_SHARED is defined, so that compiler-specific attributes are assigned
* to all the exported symbols as appropriate. MT32EMU_SHARED is undefined for static library builds.
*/
- at libmt32emu_SHARED_DEFINITION@
+#undef MT32EMU_SHARED
/* Whether the library is built as a shared object with a version tag to enable runtime version checks. */
-#define MT32EMU_WITH_VERSION_TAGGING @libmt32emu_RUNTIME_VERSION_CHECK@
+#define MT32EMU_WITH_VERSION_TAGGING 0
/* Automatic runtime check of the shared library version in client applications.
*
Commit: c585f5b8d073f07ef6dc61b454f0b8f507f92ac9
https://github.com/scummvm/scummvm/commit/c585f5b8d073f07ef6dc61b454f0b8f507f92ac9
Author: Lothar Serra Mari (mail at serra.me)
Date: 2021-04-10T16:09:54+02:00
Commit Message:
NEWS: Mention version bump to mt32emu 2.5.0
Changed paths:
NEWS.md
doc/de/NEUES.md
diff --git a/NEWS.md b/NEWS.md
index db2fad6984..5832902813 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -23,7 +23,7 @@ For a more comprehensive changelog of the latest experimental code, see:
General:
- Switched ScummVM GUI output to UTF-32.
- - Updated the Roland MT-32 emulation code to the Munt project's mt32emu 2.4.2.
+ - Updated the Roland MT-32 emulation code to the Munt project's mt32emu 2.5.0.
- Updated Dropbox Cloud Storage to use the new Dropbox OAuth workflow.
- Major extension to the number of supported graphics scalers.
- Display path to scummvm configuration file in GUI -> Options -> Paths
diff --git a/doc/de/NEUES.md b/doc/de/NEUES.md
index 95e42eec71..babadcb550 100644
--- a/doc/de/NEUES.md
+++ b/doc/de/NEUES.md
@@ -24,7 +24,7 @@ Programmcodes finden Sie auf Englisch unter:
Allgemein:
- Die ScummVM-Benutzeroberfläche unterstützt nun UTF-32.
- - Code der Roland MT-32-Emulation auf mt32emu 2.4.2 des Munt-Projekts aktualisiert.
+ - Code der Roland MT-32-Emulation auf mt32emu 2.5.0 des Munt-Projekts aktualisiert.
- Unterstützung für die neue OAuth-Implementierung von Dropbox hinzugefügt.
- Umfangreiche Verbesserungen an den unterstützten Grafik-Scalern vorgenommen.
- Der Pfad zur ScummVM-Konfigurationsdatei wird nun in der GUI unter Optionen -> Pfade angezeigt.
More information about the Scummvm-git-logs
mailing list