(svn r6532) - Feature: Add support for NewGRF sound effects. Currently sound priority isn't supported.

This commit is contained in:
2006-09-27 18:17:01 +00:00
parent 3ded010d91
commit 653e7fa548
19 changed files with 404 additions and 32 deletions

189
newgrf.c
View File

@@ -25,6 +25,8 @@
#include "table/sprites.h"
#include "date.h"
#include "currency.h"
#include "sound.h"
#include "newgrf_sound.h"
#include "newgrf_spritegroup.h"
/* TTDPatch extended GRF format codec
@@ -58,6 +60,14 @@ static uint32 _ttdpatch_flags[8];
static byte *_preload_sprite = NULL;
typedef enum GrfDataType {
GDT_SOUND,
} GrfDataType;
static byte _grf_data_blocks;
static GrfDataType _grf_data_type;
typedef enum grfspec_feature {
GSF_TRAIN,
GSF_ROAD,
@@ -1182,6 +1192,67 @@ static bool GlobalVarChangeInfo(uint gvid, int numinfo, int prop, byte **bufp, i
return ret;
}
static bool SoundEffectChangeInfo(uint sid, int numinfo, int prop, byte **bufp, int len)
{
byte *buf = *bufp;
int i;
bool ret = false;
if (_cur_grffile->sound_offset == 0) {
grfmsg(GMS_WARN, "SoundEffectChangeInfo: No effects defined, skipping.");
return false;
}
switch (prop) {
case 0x08: /* Relative volume */
FOR_EACH_OBJECT {
uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
if (sound >= GetNumSounds()) {
grfmsg(GMS_WARN, "SoundEffectChangeInfo: Sound %d not defined (max %d)", sound, GetNumSounds());
} else {
GetSound(sound)->volume = grf_load_byte(&buf);
}
}
break;
case 0x09: /* Priority */
FOR_EACH_OBJECT {
uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
if (sound >= GetNumSounds()) {
grfmsg(GMS_WARN, "SoundEffectChangeInfo: Sound %d not defined (max %d)", sound, GetNumSounds());
} else {
GetSound(sound)->priority = grf_load_byte(&buf);
}
}
break;
case 0x0A: /* Override old sound */
FOR_EACH_OBJECT {
uint sound = sid + i + _cur_grffile->sound_offset - GetNumOriginalSounds();
uint orig_sound = grf_load_byte(&buf);
if (sound >= GetNumSounds() || orig_sound >= GetNumSounds()) {
grfmsg(GMS_WARN, "SoundEffectChangeInfo: Sound %d or %d not defined (max %d)", sound, orig_sound, GetNumSounds());
} else {
FileEntry *newfe = GetSound(sound);
FileEntry *oldfe = GetSound(orig_sound);
/* Literally copy the data of the new sound over the original */
memcpy(oldfe, newfe, sizeof(*oldfe));
}
}
break;
default:
ret = true;
}
*bufp = buf;
return ret;
}
/* Action 0x00 */
static void FeatureChangeInfo(byte *buf, int len)
{
@@ -1214,7 +1285,7 @@ static void FeatureChangeInfo(byte *buf, int len)
/* GSF_INDUSTRYTILES */NULL,
/* GSF_INDUSTRIES */ NULL,
/* GSF_CARGOS */ NULL,
/* GSF_SOUNDFX */ NULL,
/* GSF_SOUNDFX */ SoundEffectChangeInfo,
};
uint8 feature;
@@ -2708,6 +2779,113 @@ static void DefineGotoLabel(byte *buf, int len)
grfmsg(GMS_NOTICE, "DefineGotoLabel: GOTO target with label 0x%02X", label->label);
}
/* Action 0x11 */
static void GRFSound(byte *buf, int len)
{
/* <11> <num>
*
* W num Number of sound files that follow */
uint16 num;
check_length(len, 1, "GRFSound");
buf++;
num = grf_load_word(&buf);
_grf_data_blocks = num;
_grf_data_type = GDT_SOUND;
if (_cur_grffile->sound_offset == 0) _cur_grffile->sound_offset = GetNumSounds();
}
static void LoadGRFSound(byte *buf, int len)
{
byte *buf_start = buf;
FileEntry *se;
/* Allocate a sound entry. This is done even if the data is not loaded
* so that the indices used elsewhere are still correct. */
se = AllocateFileEntry();
if (grf_load_dword(&buf) != 'FFIR') {
grfmsg(GMS_WARN, "LoadGRFSound: Missing RIFF header");
return;
}
/* Size of file -- we ignore this */
grf_load_dword(&buf);
if (grf_load_dword(&buf) != 'EVAW') {
grfmsg(GMS_WARN, "LoadGRFSound: Invalid RIFF type");
return;
}
for (;;) {
uint32 tag = grf_load_dword(&buf);
uint32 size = grf_load_dword(&buf);
switch (tag) {
case ' tmf': /* 'fmt ' */
/* Audio format, must be 1 (PCM) */
if (grf_load_word(&buf) != 1) {
grfmsg(GMS_WARN, "LoadGRFSound: Invalid audio format");
return;
}
se->channels = grf_load_word(&buf);
se->rate = grf_load_dword(&buf);
grf_load_dword(&buf);
grf_load_word(&buf);
se->bits_per_sample = grf_load_word(&buf);
/* Consume any extra bytes */
for (; size > 16; size--) grf_load_byte(&buf);
break;
case 'atad': /* 'data' */
se->file_size = size;
se->file_offset = FioGetPos() - (len - (buf - buf_start)) + 1;
se->file_offset |= _file_index << 24;
/* Set default volume and priority */
se->volume = 0x80;
se->priority = 0;
grfmsg(GMS_NOTICE, "LoadGRFSound: channels %u, sample rate %u, bits per sample %u, length %u", se->channels, se->rate, se->bits_per_sample, size);
return;
default:
se->file_size = 0;
return;
}
}
}
/* 'Action 0xFF' */
static void GRFDataBlock(byte *buf, int len)
{
byte name_len;
const char *name;
if (_grf_data_blocks == 0) {
grfmsg(GMS_WARN, "GRFDataBlock: unexpected data block, skipping.");
return;
}
buf++;
name_len = grf_load_byte(&buf);
name = (const char *)buf;
buf += name_len + 1;
grfmsg(GMS_NOTICE, "GRFDataBlock: block name '%s'...", name);
_grf_data_blocks--;
switch (_grf_data_type) {
case GDT_SOUND: LoadGRFSound(buf, len - name_len - 2); break;
default: NOT_REACHED(); break;
}
}
static void InitializeGRFSpecial(void)
{
_ttdpatch_flags[0] = ((_patches.always_small_airport ? 1 : 0) << 0x0C) // keepsmallairport
@@ -2878,6 +3056,7 @@ static void ResetNewGRFData(void)
_traininfo_vehicle_pitch = 0;
_traininfo_vehicle_width = 29;
InitializeSoundPool();
InitializeSpriteGroupPool();
}
@@ -2986,7 +3165,7 @@ static void DecodeSpecialSprite(uint num, uint stage)
/* We need a pre-stage to set up GOTO labels of Action 0x10 because the grf
* is not in memory and scanning the file every time would be too expensive.
* In other stages we skip action 0x10 since it's already dealt with. */
static const uint32 action_mask[] = {0x10000, 0x0000FB40, 0x0000FFFF};
static const uint32 action_mask[] = {0x10000, 0x0002FB40, 0x0000FFFF};
static const SpecialSpriteHandler handlers[] = {
/* 0x00 */ FeatureChangeInfo,
@@ -3006,6 +3185,7 @@ static void DecodeSpecialSprite(uint num, uint stage)
/* 0x0E */ GRFInhibit,
/* 0x0F */ NULL, // TODO implement
/* 0x10 */ DefineGotoLabel,
/* 0x11 */ GRFSound,
};
byte* buf;
@@ -3029,7 +3209,10 @@ static void DecodeSpecialSprite(uint num, uint stage)
action = buf[0];
if (action >= lengthof(handlers)) {
if (action == 0xFF) {
DEBUG(grf, 7) ("Handling data block in stage %d", stage);
GRFDataBlock(buf, num);
} else if (action >= lengthof(handlers)) {
DEBUG(grf, 7) ("Skipping unknown action 0x%02X", action);
} else if (!HASBIT(action_mask[stage], action)) {
DEBUG(grf, 7) ("Skipping action 0x%02X in stage %d", action, stage);