Feature: Decoder for DOS version music
This is based on reverse-engineering the TTD DOS driver for General MIDI music.
This commit is contained in:

committed by
Michael Lutz

parent
f946b3da56
commit
2ae9df7248
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
strecpy(this->songinfo[i].songname, item->value, lastof(this->songinfo[i].songname));
|
||||
this->songinfo[i].tracknr = j++;
|
||||
this->num_available++;
|
||||
|
||||
this->songinfo[i].tracknr = j++;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
Reference in New Issue
Block a user