Changeset - r19015:cc992f00083d
[Not reviewed]
master
0 4 0
michi_cc - 13 years ago 2012-02-04 13:28:44
michi_cc@openttd.org
(svn r23882) -Codechange: Delay parsing of NewGRF sound effects until first usage.
4 files changed with 183 insertions and 167 deletions:
0 comments (0 inline, 0 general)
src/newgrf.cpp
Show inline comments
 
@@ -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 *
 
	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 *b
 
	sound->priority = 0;
 
}
 

	
 
/* 'Action 0xFE' */
 
static void GRFImportBlock(ByteReader *buf)
 
{
 
	if (_cur.data_blocks == 0) {
 
		grfmsg(2, "GRFImportBlock: Unexpected import block, skipping");
 
		return;
 
	}
 

	
 
	_cur.data_blocks--;
 

	
 
	/* 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");
 
	}
 

	
 
	switch (_cur.data_type) {
 
		case GDT_SOUND: ImportGRFSound(buf); break;
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
static void LoadGRFSound(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. */
 
static void LoadGRFSound(size_t offs)
 
{
 
	SoundEntry *sound = AllocateSound();
 

	
 
	if (buf->ReadDWord() != BSWAP32('RIFF')) {
 
		grfmsg(1, "LoadGRFSound: Missing RIFF header");
 
		return;
 
	}
 

	
 
	uint32 total_size = buf->ReadDWord();
 
	if (total_size > buf->Remaining()) {
 
		grfmsg(1, "LoadGRFSound: RIFF was truncated");
 
		return;
 
	}
 

	
 
	if (buf->ReadDWord() != BSWAP32('WAVE')) {
 
		grfmsg(1, "LoadGRFSound: Invalid RIFF type");
 
		return;
 
	}
 

	
 
	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;
 

	
 
		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();
 

	
 
				/* The rest will be skipped */
 
				size -= 16;
 
				break;
 

	
 
			case 'atad': // 'data'
 
				sound->file_size   = size;
 
				sound->file_offset = FioGetPos() - buf->Remaining();
 
				sound->file_slot   = _cur.file_index;
 

	
 
				/* Set default volume and priority */
 
				sound->volume = 0x80;
 
				sound->priority = 0;
 

	
 
				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
 
	/* Set default volume and priority */
 
	sound->volume = 0x80;
 
	sound->priority = 0;
 

	
 
	sound->file_slot = _cur.file_index;
 
	sound->file_offset = offs;
 
}
 

	
 
/* Action 0x11 */
 
static void GRFSound(ByteReader *buf)
 
{
 
	/* <11> <num>
 
	 *
 
	 * W num      Number of sound files that follow */
 

	
 
	uint16 num = buf->ReadWord();
 

	
 
	if (_cur.grffile->sound_offset == 0) {
 
		_cur.grffile->sound_offset = GetNumSounds();
 
		_cur.grffile->num_sounds = num;
 
	}
 

	
 
	for (int i = 0; i < num; i++) {
 
		_cur.nfo_line++;
 

	
 
		size_t offs = FioGetPos();
 

	
 
		uint16 len = FioReadWord();
 
		byte type = FioReadByte();
 

	
 
		if (type != 0xFF) {
 
			grfmsg(1, "GRFSound: Unexpected RealSprite found, skipping");
 
			FioSkipBytes(7);
 
			SkipSpriteData(type, num - 8);
 
			continue;
 
		}
 

	
 
		byte action = FioReadByte();
 
		switch (action) {
 
			case 0xFF:
 
				LoadGRFSound(offs);
 
				FioSkipBytes(len - 1); // <type> is not included in the length for pseudo-sprites.
 
				break;
 

	
 
			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 */
 
				break;
 
		}
 

	
 
		/* Skip rest of chunk */
 
		for (; size > 0; size--) buf->ReadByte();
 
	}
 

	
 
	grfmsg(1, "LoadGRFSound: RIFF does not contain any sound data");
 

	
 
	/* Clear everything that was read */
 
	MemSetT(sound, 0);
 
				grfmsg(1, "GRFSound: Unexpected Action %x found, skipping", action);
 
				FioSkipBytes(len - 1);
 
				break;
 
		}
 
	}
 
}
 

	
 
/* 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);
 
}
 

	
 
/** Action 0x12 */
 
@@ -7575,36 +7515,6 @@ static void StaticGRFInfo(ByteReader *bu
 
	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 *bu
 
		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) {
src/newgrf_sound.cpp
Show inline comments
 
@@ -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.
src/newgrf_sound.h
Show inline comments
 
@@ -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);
src/sound.cpp
Show inline comments
 
@@ -159,9 +159,18 @@ static void StartSound(SoundID sound_id,
 
{
 
	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;
 

	
0 comments (0 inline, 0 general)