summaryrefslogtreecommitdiff
path: root/src/music.cpp
diff options
context:
space:
mode:
authorNiels Martin Hansen <nielsm@indvikleren.dk>2018-03-14 15:55:40 +0100
committerMichael Lutz <michi@icosahedron.de>2018-06-05 22:58:35 +0200
commit2ae9df7248923c286e00dd1bf009275034137a7e (patch)
tree748cd2162311172f893838b84c6e723780b3e622 /src/music.cpp
parentf946b3da56b22c1fc32a9ffc9008374e4fb4f8c8 (diff)
downloadopenttd-2ae9df7248923c286e00dd1bf009275034137a7e.tar.xz
Feature: Decoder for DOS version music
This is based on reverse-engineering the TTD DOS driver for General MIDI music.
Diffstat (limited to 'src/music.cpp')
-rw-r--r--src/music.cpp90
1 files changed, 83 insertions, 7 deletions
diff --git a/src/music.cpp b/src/music.cpp
index 5bfe62ebd..e131c0210 100644
--- a/src/music.cpp
+++ b/src/music.cpp
@@ -11,11 +11,69 @@
#include "stdafx.h"
+
/** The type of set we're replacing */
#define SET_TYPE "music"
#include "base_media_func.h"
#include "safeguards.h"
+#include "fios.h"
+
+
+/**
+ * Read the name of a music CAT file entry.
+ * @param filename Name of CAT file to read from
+ * @param entrynum Index of entry whose name to read
+ * @return Pointer to string, caller is responsible for freeing memory,
+ * NULL if entrynum does not exist.
+ */
+char *GetMusicCatEntryName(const char *filename, size_t entrynum)
+{
+ if (!FioCheckFileExists(filename, BASESET_DIR)) return NULL;
+
+ FioOpenFile(CONFIG_SLOT, filename, BASESET_DIR);
+ uint32 ofs = FioReadDword();
+ size_t entry_count = ofs / 8;
+ if (entrynum < entry_count) {
+ FioSeekTo(entrynum * 8, SEEK_SET);
+ FioSeekTo(FioReadDword(), SEEK_SET);
+ byte namelen = FioReadByte();
+ char *name = MallocT<char>(namelen + 1);
+ FioReadBlock(name, namelen);
+ name[namelen] = '\0';
+ return name;
+ }
+ return NULL;
+}
+
+/**
+ * Read the full data of a music CAT file entry.
+ * @param filename Name of CAT file to read from.
+ * @param entrynum Index of entry to read
+ * @param[out] entrylen Receives length of data read
+ * @return Pointer to buffer with data read, caller is responsible for freeind memory,
+ * NULL if entrynum does not exist.
+ */
+byte *GetMusicCatEntryData(const char *filename, size_t entrynum, size_t &entrylen)
+{
+ entrylen = 0;
+ if (!FioCheckFileExists(filename, BASESET_DIR)) return NULL;
+
+ FioOpenFile(CONFIG_SLOT, filename, BASESET_DIR);
+ uint32 ofs = FioReadDword();
+ size_t entry_count = ofs / 8;
+ if (entrynum < entry_count) {
+ FioSeekTo(entrynum * 8, SEEK_SET);
+ size_t entrypos = FioReadDword();
+ entrylen = FioReadDword();
+ FioSeekTo(entrypos, SEEK_SET);
+ FioSkipBytes(FioReadByte());
+ byte *data = MallocT<byte>(entrylen);
+ FioReadBlock(data, entrylen);
+ return data;
+ }
+ return NULL;
+}
INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia<MusicSet>, MusicSet)
@@ -66,6 +124,7 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f
if (ret) {
this->num_available = 0;
IniGroup *names = ini->GetGroup("names");
+ IniGroup *catindex = ini->GetGroup("catindex");
for (uint i = 0, j = 1; i < lengthof(this->songinfo); i++) {
const char *filename = this->files[i].filename;
if (names == NULL || StrEmpty(filename)) {
@@ -74,9 +133,23 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f
}
this->songinfo[i].filename = filename; // non-owned pointer
- this->songinfo[i].filetype = MTT_STANDARDMIDI;
- IniItem *item = NULL;
+ IniItem *item = catindex->GetItem(_music_file_names[i], false);
+ if (item != NULL && !StrEmpty(item->value)) {
+ /* Song has a CAT file index, assume it's MPS MIDI format */
+ this->songinfo[i].filetype = MTT_MPSMIDI;
+ this->songinfo[i].cat_index = atoi(item->value);
+ char *songname = GetMusicCatEntryName(filename, this->songinfo[i].cat_index);
+ if (songname == NULL) {
+ DEBUG(grf, 0, "Base music set song missing from CAT file: %s/%d", filename, this->songinfo[i].cat_index);
+ return false;
+ }
+ strecpy(this->songinfo[i].songname, songname, lastof(this->songinfo[i].songname));
+ free(songname);
+ } else {
+ this->songinfo[i].filetype = MTT_STANDARDMIDI;
+ }
+
/* As we possibly add a path to the filename and we compare
* on the filename with the path as in the .obm, we need to
* keep stripping path elements until we find a match. */
@@ -89,14 +162,17 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f
if (item != NULL && !StrEmpty(item->value)) break;
}
- if (item == NULL || StrEmpty(item->value)) {
- DEBUG(grf, 0, "Base music set song name missing: %s", filename);
- return false;
+ if (this->songinfo[i].filetype == MTT_STANDARDMIDI) {
+ if (item != NULL && !StrEmpty(item->value)) {
+ strecpy(this->songinfo[i].songname, item->value, lastof(this->songinfo[i].songname));
+ } else {
+ DEBUG(grf, 0, "Base music set song name missing: %s", filename);
+ return false;
+ }
}
+ this->num_available++;
- strecpy(this->songinfo[i].songname, item->value, lastof(this->songinfo[i].songname));
this->songinfo[i].tracknr = j++;
- this->num_available++;
}
}
return ret;