summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/newgrf.cpp204
-rw-r--r--src/newgrf_sound.cpp98
-rw-r--r--src/newgrf_sound.h1
-rw-r--r--src/sound.cpp11
4 files changed, 165 insertions, 149 deletions
diff --git a/src/newgrf.cpp b/src/newgrf.cpp
index 3dc225735..d3287900d 100644
--- a/src/newgrf.cpp
+++ b/src/newgrf.cpp
@@ -73,10 +73,6 @@ static uint32 _ttdpatch_flags[8];
/** Indicates which are the newgrf features currently loaded ingame */
GRFLoadedFeatures _loaded_newgrf_features;
-enum GrfDataType {
- GDT_SOUND,
-};
-
static const uint MAX_SPRITEGROUP = UINT8_MAX; ///< Maximum GRF-local ID for a spritegroup.
/** Temporary data during loading of GRFs */
@@ -104,8 +100,6 @@ public:
/* Kind of return values when processing certain actions */
int skip_sprites; ///< Number of psuedo sprites to skip before processing the next one. (-1 to skip to end of file)
- byte data_blocks; ///< Number of binary include sprites to read before processing the next pseudo sprite.
- GrfDataType data_type; ///< Type of the binary include sprites to read.
/* Currently referenceable spritegroups */
SpriteGroup *spritegroups[MAX_SPRITEGROUP + 1];
@@ -115,7 +109,6 @@ public:
{
this->nfo_line = 0;
this->skip_sprites = 0;
- this->data_blocks = 0;
for (uint i = 0; i < GSF_END; i++) {
this->spritesets[i].clear();
@@ -6818,42 +6811,12 @@ static void DefineGotoLabel(ByteReader *buf)
grfmsg(2, "DefineGotoLabel: GOTO target with label 0x%02X", label->label);
}
-/* Action 0x11 */
-static void GRFSound(ByteReader *buf)
-{
- /* <11> <num>
- *
- * W num Number of sound files that follow */
-
- uint16 num = buf->ReadWord();
-
- _cur.data_blocks = num;
- _cur.data_type = GDT_SOUND;
-
- if (_cur.grffile->sound_offset == 0) {
- _cur.grffile->sound_offset = GetNumSounds();
- _cur.grffile->num_sounds = num;
- }
-}
-
-/* Action 0x11 (SKIP) */
-static void SkipAct11(ByteReader *buf)
-{
- /* <11> <num>
- *
- * W num Number of sound files that follow */
-
- _cur.skip_sprites = buf->ReadWord();
-
- grfmsg(3, "SkipAct11: Skipping %d sprites", _cur.skip_sprites);
-}
-
-static void ImportGRFSound(ByteReader *buf)
+static void ImportGRFSound()
{
const GRFFile *file;
SoundEntry *sound = AllocateSound();
- uint32 grfid = buf->ReadDWord();
- SoundID sound_id = buf->ReadWord();
+ uint32 grfid = FioReadDword();
+ SoundID sound_id = FioReadWord();
file = GetFileByGRFID(grfid);
if (file == NULL || file->sound_offset == 0) {
@@ -6875,102 +6838,79 @@ static void ImportGRFSound(ByteReader *buf)
sound->priority = 0;
}
-/* 'Action 0xFE' */
-static void GRFImportBlock(ByteReader *buf)
+static void LoadGRFSound(size_t offs)
{
- if (_cur.data_blocks == 0) {
- grfmsg(2, "GRFImportBlock: Unexpected import block, skipping");
- return;
- }
-
- _cur.data_blocks--;
+ SoundEntry *sound = AllocateSound();
- /* XXX 'Action 0xFE' isn't really specified. It is only mentioned for
- * importing sounds, so this is probably all wrong... */
- if (buf->ReadByte() != _cur.data_type) {
- grfmsg(1, "GRFImportBlock: Import type mismatch");
- }
+ /* Set default volume and priority */
+ sound->volume = 0x80;
+ sound->priority = 0;
- switch (_cur.data_type) {
- case GDT_SOUND: ImportGRFSound(buf); break;
- default: NOT_REACHED();
- }
+ sound->file_slot = _cur.file_index;
+ sound->file_offset = offs;
}
-static void LoadGRFSound(ByteReader *buf)
+/* Action 0x11 */
+static void GRFSound(ByteReader *buf)
{
- /* Allocate a sound entry. This is done even if the data is not loaded
- * so that the indices used elsewhere are still correct. */
- SoundEntry *sound = AllocateSound();
-
- if (buf->ReadDWord() != BSWAP32('RIFF')) {
- grfmsg(1, "LoadGRFSound: Missing RIFF header");
- return;
- }
+ /* <11> <num>
+ *
+ * W num Number of sound files that follow */
- uint32 total_size = buf->ReadDWord();
- if (total_size > buf->Remaining()) {
- grfmsg(1, "LoadGRFSound: RIFF was truncated");
- return;
- }
+ uint16 num = buf->ReadWord();
- if (buf->ReadDWord() != BSWAP32('WAVE')) {
- grfmsg(1, "LoadGRFSound: Invalid RIFF type");
- return;
+ if (_cur.grffile->sound_offset == 0) {
+ _cur.grffile->sound_offset = GetNumSounds();
+ _cur.grffile->num_sounds = num;
}
- while (total_size >= 8) {
- uint32 tag = buf->ReadDWord();
- uint32 size = buf->ReadDWord();
- total_size -= 8;
- if (total_size < size) {
- grfmsg(1, "LoadGRFSound: Invalid RIFF");
- return;
- }
- total_size -= size;
+ for (int i = 0; i < num; i++) {
+ _cur.nfo_line++;
- switch (tag) {
- case ' tmf': // 'fmt '
- /* Audio format, must be 1 (PCM) */
- if (size < 16 || buf->ReadWord() != 1) {
- grfmsg(1, "LoadGRFSound: Invalid audio format");
- return;
- }
- sound->channels = buf->ReadWord();
- sound->rate = buf->ReadDWord();
- buf->ReadDWord();
- buf->ReadWord();
- sound->bits_per_sample = buf->ReadWord();
+ size_t offs = FioGetPos();
- /* The rest will be skipped */
- size -= 16;
- break;
+ uint16 len = FioReadWord();
+ byte type = FioReadByte();
- case 'atad': // 'data'
- sound->file_size = size;
- sound->file_offset = FioGetPos() - buf->Remaining();
- sound->file_slot = _cur.file_index;
+ if (type != 0xFF) {
+ grfmsg(1, "GRFSound: Unexpected RealSprite found, skipping");
+ FioSkipBytes(7);
+ SkipSpriteData(type, num - 8);
+ continue;
+ }
- /* Set default volume and priority */
- sound->volume = 0x80;
- sound->priority = 0;
+ byte action = FioReadByte();
+ switch (action) {
+ case 0xFF:
+ LoadGRFSound(offs);
+ FioSkipBytes(len - 1); // <type> is not included in the length for pseudo-sprites.
+ break;
- grfmsg(2, "LoadGRFSound: channels %u, sample rate %u, bits per sample %u, length %u", sound->channels, sound->rate, sound->bits_per_sample, size);
- return; // the fmt chunk has to appear before data, so we are finished
+ case 0xFE:
+ /* XXX 'Action 0xFE' isn't really specified. It is only mentioned for
+ * importing sounds, so this is probably all wrong... */
+ if (FioReadByte() != 0) grfmsg(1, "GRFSound: Import type mismatch");
+ ImportGRFSound();
+ break;
default:
- /* Skip unknown chunks */
+ grfmsg(1, "GRFSound: Unexpected Action %x found, skipping", action);
+ FioSkipBytes(len - 1);
break;
}
-
- /* Skip rest of chunk */
- for (; size > 0; size--) buf->ReadByte();
}
+}
- grfmsg(1, "LoadGRFSound: RIFF does not contain any sound data");
+/* Action 0x11 (SKIP) */
+static void SkipAct11(ByteReader *buf)
+{
+ /* <11> <num>
+ *
+ * W num Number of sound files that follow */
- /* Clear everything that was read */
- MemSetT(sound, 0);
+ _cur.skip_sprites = buf->ReadWord();
+
+ grfmsg(3, "SkipAct11: Skipping %d sprites", _cur.skip_sprites);
}
/** Action 0x12 */
@@ -7575,36 +7515,6 @@ static void StaticGRFInfo(ByteReader *buf)
HandleNodes(buf, _tags_root);
}
-/** 'Action 0xFF' */
-static void GRFDataBlock(ByteReader *buf)
-{
- /* <FF> <name_len> <name> '\0' <data> */
-
- if (_cur.data_blocks == 0) {
- grfmsg(2, "GRFDataBlock: unexpected data block, skipping");
- return;
- }
-
- uint8 name_len = buf->ReadByte();
- const char *name = reinterpret_cast<const char *>(buf->Data());
- buf->Skip(name_len);
-
- /* Test string termination */
- if (buf->ReadByte() != 0) {
- grfmsg(2, "GRFDataBlock: Name not properly terminated");
- return;
- }
-
- grfmsg(2, "GRFDataBlock: block name '%s'...", name);
-
- _cur.data_blocks--;
-
- switch (_cur.data_type) {
- case GDT_SOUND: LoadGRFSound(buf); break;
- default: NOT_REACHED();
- }
-}
-
/**
* Set the current NewGRF as unsafe for static use
* @param buf Unused.
@@ -8627,11 +8537,9 @@ static void DecodeSpecialSprite(byte *buf, uint num, GrfLoadingStage stage)
byte action = bufp->ReadByte();
if (action == 0xFF) {
- grfmsg(7, "DecodeSpecialSprite: Handling data block in stage %d", stage);
- GRFDataBlock(bufp);
+ grfmsg(2, "DecodeSpecialSprite: Unexpected data block, skipping");
} else if (action == 0xFE) {
- grfmsg(7, "DecodeSpecialSprite: Handling import block in stage %d", stage);
- GRFImportBlock(bufp);
+ grfmsg(2, "DecodeSpecialSprite: Unexpected import block, skipping");
} else if (action >= lengthof(handlers)) {
grfmsg(7, "DecodeSpecialSprite: Skipping unknown action 0x%02X", action);
} else if (handlers[action][stage] == NULL) {
diff --git a/src/newgrf_sound.cpp b/src/newgrf_sound.cpp
index 47ddf2406..401c77386 100644
--- a/src/newgrf_sound.cpp
+++ b/src/newgrf_sound.cpp
@@ -16,6 +16,8 @@
#include "newgrf_sound.h"
#include "vehicle_base.h"
#include "sound_func.h"
+#include "fileio_func.h"
+#include "debug.h"
static SmallVector<SoundEntry, 8> _sounds;
@@ -52,6 +54,102 @@ uint GetNumSounds()
/**
+ * Extract meta data from a NewGRF sound.
+ * @param sound Sound to load.
+ * @return True if a valid sound was loaded.
+ */
+bool LoadNewGRFSound(SoundEntry *sound)
+{
+ if (sound->file_offset == SIZE_MAX || sound->file_slot == 0) return false;
+
+ FioSeekToFile(sound->file_slot, sound->file_offset);
+
+ /* Format: <num> <FF> <FF> <name_len> <name> '\0' <data> */
+
+ uint16 num = FioReadWord();
+ if (FioReadByte() != 0xFF) return false;
+ if (FioReadByte() != 0xFF) return false;
+
+ uint8 name_len = FioReadByte();
+ char *name = AllocaM(char, name_len + 1);
+ FioReadBlock(name, name_len + 1);
+
+ /* Test string termination */
+ if (name[name_len] != 0) {
+ DEBUG(grf, 2, "LoadNewGRFSound [%s]: Name not properly terminated", FioGetFilename(sound->file_slot));
+ return false;
+ }
+
+ DEBUG(grf, 2, "LoadNewGRFSound [%s]: Sound name '%s'...", FioGetFilename(sound->file_slot), name);
+
+ if (FioReadDword() != BSWAP32('RIFF')) {
+ DEBUG(grf, 1, "LoadNewGRFSound [%s]: Missing RIFF header", FioGetFilename(sound->file_slot));
+ return false;
+ }
+
+ uint32 total_size = FioReadDword();
+ if (total_size + name_len + 11 > num) { // The first FF in the sprite is not counted for <num>.
+ DEBUG(grf, 1, "LoadNewGRFSound [%s]: RIFF was truncated", FioGetFilename(sound->file_slot));
+ return false;
+ }
+
+ if (FioReadDword() != BSWAP32('WAVE')) {
+ DEBUG(grf, 1, "LoadNewGRFSound [%s]: Invalid RIFF type", FioGetFilename(sound->file_slot));
+ return false;
+ }
+
+ while (total_size >= 8) {
+ uint32 tag = FioReadDword();
+ uint32 size = FioReadDword();
+ total_size -= 8;
+ if (total_size < size) {
+ DEBUG(grf, 1, "LoadNewGRFSound [%s]: Invalid RIFF", FioGetFilename(sound->file_slot));
+ return false;
+ }
+ total_size -= size;
+
+ switch (tag) {
+ case ' tmf': // 'fmt '
+ /* Audio format, must be 1 (PCM) */
+ if (size < 16 || FioReadWord() != 1) {
+ DEBUG(grf, 1, "LoadGRFSound [%s]: Invalid audio format", FioGetFilename(sound->file_slot));
+ return false;
+ }
+ sound->channels = FioReadWord();
+ sound->rate = FioReadDword();
+ FioReadDword();
+ FioReadWord();
+ sound->bits_per_sample = FioReadWord();
+
+ /* The rest will be skipped */
+ size -= 16;
+ break;
+
+ case 'atad': // 'data'
+ sound->file_size = size;
+ sound->file_offset = FioGetPos();
+
+ DEBUG(grf, 2, "LoadNewGRFSound [%s]: channels %u, sample rate %u, bits per sample %u, length %u", FioGetFilename(sound->file_slot), sound->channels, sound->rate, sound->bits_per_sample, size);
+ return true; // the fmt chunk has to appear before data, so we are finished
+
+ default:
+ /* Skip unknown chunks */
+ break;
+ }
+
+ /* Skip rest of chunk */
+ if (size > 0) FioSkipBytes(size);
+ }
+
+ DEBUG(grf, 1, "LoadNewGRFSound [%s]: RIFF does not contain any sound data", FioGetFilename(sound->file_slot));
+
+ /* Clear everything that was read */
+ MemSetT(sound, 0);
+ return false;
+}
+
+
+/**
* Checks whether a NewGRF wants to play a different vehicle sound effect.
* @param v Vehicle to play sound effect for.
* @param event Trigger for the sound effect.
diff --git a/src/newgrf_sound.h b/src/newgrf_sound.h
index 2f2c034db..a6375cee4 100644
--- a/src/newgrf_sound.h
+++ b/src/newgrf_sound.h
@@ -32,6 +32,7 @@ enum VehicleSoundEvent {
SoundEntry *AllocateSound();
void InitializeSoundPool();
+bool LoadNewGRFSound(SoundEntry *sound);
SoundEntry *GetSound(SoundID sound_id);
uint GetNumSounds();
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event);
diff --git a/src/sound.cpp b/src/sound.cpp
index d572050bf..f792dfdff 100644
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -159,9 +159,18 @@ static void StartSound(SoundID sound_id, float pan, uint volume)
{
if (volume == 0) return;
- const SoundEntry *sound = GetSound(sound_id);
+ SoundEntry *sound = GetSound(sound_id);
if (sound == NULL) return;
+ /* NewGRF sound that wasn't loaded yet? */
+ if (sound->rate == 0 && sound->file_slot != 0) {
+ if (!LoadNewGRFSound(sound)) {
+ /* Mark as invalid. */
+ sound->file_slot = 0;
+ return;
+ }
+ }
+
/* Empty sound? */
if (sound->rate == 0) return;