summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpeter1138 <peter1138@openttd.org>2006-09-27 18:17:01 +0000
committerpeter1138 <peter1138@openttd.org>2006-09-27 18:17:01 +0000
commit8b2e4e970ad3379fb294934e7720128986220d0e (patch)
tree89f67db5c4825d95a0c5687363b43db1311ffae7
parentdef6a391a0cca03132a4cdfea2f7bd53a3a25bdf (diff)
downloadopenttd-8b2e4e970ad3379fb294934e7720128986220d0e.tar.xz
(svn r6532) - Feature: Add support for NewGRF sound effects. Currently sound priority isn't supported.
-rw-r--r--Makefile1
-rw-r--r--aircraft_cmd.c9
-rw-r--r--newgrf.c189
-rw-r--r--newgrf.h2
-rw-r--r--newgrf_callbacks.h3
-rw-r--r--newgrf_engine.c2
-rw-r--r--newgrf_engine.h1
-rw-r--r--newgrf_sound.c73
-rw-r--r--newgrf_sound.h25
-rw-r--r--openttd.vcproj6
-rw-r--r--openttd_vs80.vcproj8
-rw-r--r--roadveh_cmd.c17
-rw-r--r--ship_cmd.c11
-rw-r--r--sound.c40
-rw-r--r--sound.h12
-rw-r--r--train_cmd.c15
-rw-r--r--tunnelbridge_cmd.c4
-rw-r--r--vehicle.c17
-rw-r--r--vehicle.h1
19 files changed, 404 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index c8afd3685..a7da3ac32 100644
--- a/Makefile
+++ b/Makefile
@@ -697,6 +697,7 @@ SRCS += network_udp.c
SRCS += newgrf.c
SRCS += newgrf_cargo.c
SRCS += newgrf_engine.c
+SRCS += newgrf_sound.c
SRCS += newgrf_spritegroup.c
SRCS += newgrf_station.c
SRCS += newgrf_text.c
diff --git a/aircraft_cmd.c b/aircraft_cmd.c
index e9ed824b4..d7c8a31bd 100644
--- a/aircraft_cmd.c
+++ b/aircraft_cmd.c
@@ -23,6 +23,7 @@
#include "newgrf_engine.h"
#include "newgrf_callbacks.h"
#include "newgrf_text.h"
+#include "newgrf_sound.h"
#include "date.h"
static bool AirportMove(Vehicle *v, const AirportFTAClass *Airport);
@@ -858,7 +859,9 @@ static void ServiceAircraft(Vehicle *v)
static void PlayAircraftSound(const Vehicle* v)
{
- SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v);
+ if (!PlayVehicleSound(v, VSE_START)) {
+ SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v);
+ }
}
static bool UpdateAircraftSpeed(Vehicle *v)
@@ -1426,7 +1429,9 @@ static void AircraftLand(Vehicle *v)
static void AircraftLandAirplane(Vehicle *v)
{
AircraftLand(v);
- SndPlayVehicleFx(SND_17_SKID_PLANE, v);
+ if (!PlayVehicleSound(v, VSE_TOUCHDOWN)) {
+ SndPlayVehicleFx(SND_17_SKID_PLANE, v);
+ }
MaybeCrashAirplane(v);
}
diff --git a/newgrf.c b/newgrf.c
index 6a552066d..0db17f0e7 100644
--- a/newgrf.c
+++ b/newgrf.c
@@ -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);
diff --git a/newgrf.h b/newgrf.h
index 5618fbdae..2d91fc5cc 100644
--- a/newgrf.h
+++ b/newgrf.h
@@ -39,6 +39,8 @@ typedef struct GRFFile {
int spritegroups_count;
struct SpriteGroup **spritegroups;
+ uint sound_offset;
+
StationSpec **stations;
uint32 param[0x80];
diff --git a/newgrf_callbacks.h b/newgrf_callbacks.h
index d7a91c04b..a52455a7c 100644
--- a/newgrf_callbacks.h
+++ b/newgrf_callbacks.h
@@ -45,6 +45,9 @@ enum CallbackID {
/* Called when the player (or AI) tries to start or stop a vehicle. Mainly
* used for preventing a vehicle from leaving the depot. */
CBID_VEHICLE_START_STOP_CHECK = 0x31,
+
+ /* Called to play a special sound effect */
+ CBID_VEHICLE_SOUND_EFFECT = 0x33,
};
/**
diff --git a/newgrf_engine.c b/newgrf_engine.c
index 800be6523..8629d0470 100644
--- a/newgrf_engine.c
+++ b/newgrf_engine.c
@@ -651,7 +651,7 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by
}
case 0x46: /* Motion counter */
- return 0;
+ return v->motion_counter;
case 0x47: { /* Vehicle cargo info */
/* Format: ccccwwtt
diff --git a/newgrf_engine.h b/newgrf_engine.h
index 8b88a9c77..7edfc957b 100644
--- a/newgrf_engine.h
+++ b/newgrf_engine.h
@@ -3,6 +3,7 @@
#ifndef NEWGRF_ENGINE_H
#define NEWGRF_ENGINE_H
+#include "newgrf.h"
#include "direction.h"
#include "newgrf_cargo.h"
diff --git a/newgrf_sound.c b/newgrf_sound.c
new file mode 100644
index 000000000..7d746f712
--- /dev/null
+++ b/newgrf_sound.c
@@ -0,0 +1,73 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "pool.h"
+#include "sound.h"
+#include "engine.h"
+#include "vehicle.h"
+#include "newgrf_callbacks.h"
+#include "newgrf_engine.h"
+#include "newgrf_sound.h"
+
+enum {
+ SOUND_POOL_BLOCK_SIZE_BITS = 3, /* (1 << 3) == 8 items */
+ SOUND_POOL_MAX_BLOCKS = 1000,
+};
+
+static uint _sound_count = 0;
+static MemoryPool _sound_pool = { "Sound", SOUND_POOL_MAX_BLOCKS, SOUND_POOL_BLOCK_SIZE_BITS, sizeof(FileEntry), NULL, NULL, 0, 0, NULL };
+
+
+/* Allocate a new FileEntry */
+FileEntry *AllocateFileEntry(void)
+{
+ if (_sound_count == _sound_pool.total_items) {
+ if (!AddBlockToPool(&_sound_pool)) return NULL;
+ }
+
+ return (FileEntry*)GetItemFromPool(&_sound_pool, _sound_count++);
+}
+
+
+void InitializeSoundPool(void)
+{
+ CleanPool(&_sound_pool);
+ _sound_count = 0;
+
+ /* Copy original sound data to the pool */
+ SndCopyToPool();
+}
+
+
+FileEntry *GetSound(uint index)
+{
+ if (index >= _sound_count) return NULL;
+ return (FileEntry*)GetItemFromPool(&_sound_pool, index);
+}
+
+
+uint GetNumSounds(void)
+{
+ return _sound_count;
+}
+
+
+bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event)
+{
+ const GRFFile *file = GetEngineGRF(v->engine_type);
+ uint16 callback;
+
+ /* If the engine has no GRF ID associated it can't ever play any new sounds */
+ if (file == NULL) return false;
+
+ /* Check that the vehicle type uses the sound effect callback */
+ if (!HASBIT(EngInfo(v->engine_type)->callbackmask, CBM_SOUND_EFFECT)) return false;
+
+ callback = GetVehicleCallback(CBID_VEHICLE_SOUND_EFFECT, event, 0, v->engine_type, v);
+ if (callback == CALLBACK_FAILED) return false;
+ if (callback >= GetNumOriginalSounds()) callback += file->sound_offset - GetNumOriginalSounds();
+
+ SndPlayVehicleFx(callback, v);
+ return true;
+}
diff --git a/newgrf_sound.h b/newgrf_sound.h
new file mode 100644
index 000000000..ec2727fb1
--- /dev/null
+++ b/newgrf_sound.h
@@ -0,0 +1,25 @@
+/* $Id$ */
+
+#ifndef NEWGRF_SOUND_H
+#define NEWGRF_SOUND_H
+
+typedef enum VehicleSoundEvents {
+ VSE_START = 1,
+ VSE_TUNNEL = 2,
+ VSE_BREAKDOWN = 3,
+ VSE_RUNNING = 4,
+ VSE_TOUCHDOWN = 5,
+ VSE_TRAIN_EFFECT = 6,
+ VSE_RUNNING_16 = 7,
+ VSE_STOPPED_16 = 8,
+ VSE_LOAD_UNLOAD = 9,
+} VehicleSoundEvent;
+
+
+FileEntry *AllocateFileEntry(void);
+void InitializeSoundPool(void);
+FileEntry *GetSound(uint index);
+uint GetNumSounds(void);
+bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event);
+
+#endif /* NEWGRF_SOUND_H */
diff --git a/openttd.vcproj b/openttd.vcproj
index b78a47e35..77aee0c7b 100644
--- a/openttd.vcproj
+++ b/openttd.vcproj
@@ -304,6 +304,9 @@
RelativePath=".\newgrf_engine.c">
</File>
<File
+ RelativePath=".\newgrf_sound.c">
+ </File>
+ <File
RelativePath=".\newgrf_spritegroup.c">
</File>
<File
@@ -551,6 +554,9 @@
RelativePath=".\newgrf_engine.h">
</File>
<File
+ RelativePath=".\newgrf_sound.h">
+ </File>
+ <File
RelativePath=".\newgrf_spritegroup.h">
</File>
<File
diff --git a/openttd_vs80.vcproj b/openttd_vs80.vcproj
index 85c7ed734..073f7509b 100644
--- a/openttd_vs80.vcproj
+++ b/openttd_vs80.vcproj
@@ -653,6 +653,10 @@
>
</File>
<File
+ RelativePath=".\newgrf_sound.c"
+ >
+ </File>
+ <File
RelativePath=".\newgrf_spritegroup.c"
>
</File>
@@ -1028,6 +1032,10 @@
>
</File>
<File
+ RelativePath=".\newgrf_sound.h"
+ >
+ </File>
+ <File
RelativePath=".\newgrf_spritegroup.h"
>
</File>
diff --git a/roadveh_cmd.c b/roadveh_cmd.c
index ef3cf4e10..e8f0d2884 100644
--- a/roadveh_cmd.c
+++ b/roadveh_cmd.c
@@ -26,6 +26,7 @@
#include "newgrf_callbacks.h"
#include "newgrf_engine.h"
#include "newgrf_text.h"
+#include "newgrf_sound.h"
#include "yapf/yapf.h"
#include "date.h"
@@ -621,8 +622,10 @@ static void HandleBrokenRoadVeh(Vehicle *v)
InvalidateWindow(WC_VEHICLE_VIEW, v->index);
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
- SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
- SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, v);
+ if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
+ SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
+ SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, v);
+ }
if (!(v->vehstatus & VS_HIDDEN)) {
Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
@@ -760,10 +763,12 @@ static void HandleRoadVehLoading(Vehicle *v)
static void StartRoadVehSound(const Vehicle* v)
{
- SoundFx s = RoadVehInfo(v->engine_type)->sfx;
- if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0)
- s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
- SndPlayVehicleFx(s, v);
+ if (!PlayVehicleSound(v, VSE_START)) {
+ SoundFx s = RoadVehInfo(v->engine_type)->sfx;
+ if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0)
+ s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
+ SndPlayVehicleFx(s, v);
+ }
}
typedef struct RoadVehFindData {
diff --git a/ship_cmd.c b/ship_cmd.c
index 371a51e7f..f39e5d6ac 100644
--- a/ship_cmd.c
+++ b/ship_cmd.c
@@ -25,6 +25,7 @@
#include "debug.h"
#include "newgrf_callbacks.h"
#include "newgrf_text.h"
+#include "newgrf_sound.h"
#include "date.h"
static const uint16 _ship_sprites[] = {0x0E5D, 0x0E55, 0x0E65, 0x0E6D};
@@ -173,8 +174,10 @@ static void HandleBrokenShip(Vehicle *v)
InvalidateWindow(WC_VEHICLE_VIEW, v->index);
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
- SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
- SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
+ if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
+ SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
+ SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
+ }
if (!(v->vehstatus & VS_HIDDEN)) {
Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
@@ -198,7 +201,9 @@ static void MarkShipDirty(Vehicle *v)
static void PlayShipSound(Vehicle *v)
{
- SndPlayVehicleFx(ShipVehInfo(v->engine_type)->sfx, v);
+ if (!PlayVehicleSound(v, VSE_START)) {
+ SndPlayVehicleFx(ShipVehInfo(v->engine_type)->sfx, v);
+ }
}
static void ProcessShipOrder(Vehicle *v)
diff --git a/sound.c b/sound.c
index c3eacd685..f8d194c97 100644
--- a/sound.c
+++ b/sound.c
@@ -10,14 +10,7 @@
#include "window.h"
#include "viewport.h"
#include "fileio.h"
-
-typedef struct FileEntry {
- uint32 file_offset;
- uint32 file_size;
- uint16 rate;
- uint8 bits_per_sample;
- uint8 channels;
-} FileEntry;
+#include "newgrf_sound.h"
static uint _file_count;
static FileEntry *_files;
@@ -100,14 +93,19 @@ static void OpenBankFile(const char *filename)
}
}
+uint GetNumOriginalSounds(void)
+{
+ return _file_count;
+}
+
static bool SetBankSource(MixerChannel *mc, uint bank)
{
const FileEntry *fe;
int8 *mem;
uint i;
- if (bank >= _file_count) return false;
- fe = &_files[bank];
+ if (bank >= GetNumSounds()) return false;
+ fe = GetSound(bank);
if (fe->file_size == 0) return false;
@@ -180,6 +178,20 @@ static const byte _sound_idx[] = {
72,
};
+void SndCopyToPool(void)
+{
+ uint i;
+
+ for (i = 0; i < _file_count; i++) {
+ FileEntry *orig = &_files[_sound_idx[i]];
+ FileEntry *fe = AllocateFileEntry();
+
+ memcpy(fe, orig, sizeof(*orig));
+ fe->volume = _sound_base_vol[i];
+ fe->priority = 0;
+ }
+}
+
static void SndPlayScreenCoordFx(SoundFx sound, int x, int y)
{
const Window *w;
@@ -195,9 +207,9 @@ static void SndPlayScreenCoordFx(SoundFx sound, int x, int y)
int left = (x - vp->virtual_left);
StartSound(
- _sound_idx[sound],
+ sound,
left / (vp->virtual_width / ((PANNING_LEVELS << 1) + 1)) - PANNING_LEVELS,
- (_sound_base_vol[sound] * msf.effect_vol * _vol_factor_by_zoom[vp->zoom]) >> 15
+ (GetSound(sound)->volume * msf.effect_vol * _vol_factor_by_zoom[vp->zoom]) >> 15
);
return;
}
@@ -225,8 +237,8 @@ void SndPlayVehicleFx(SoundFx sound, const Vehicle *v)
void SndPlayFx(SoundFx sound)
{
StartSound(
- _sound_idx[sound],
+ sound,
0,
- (_sound_base_vol[sound] * msf.effect_vol) >> 7
+ (GetSound(sound)->volume * msf.effect_vol) >> 7
);
}
diff --git a/sound.h b/sound.h
index 9f9edaddc..fd5638558 100644
--- a/sound.h
+++ b/sound.h
@@ -16,7 +16,18 @@ typedef struct MusicFileSettings {
VARDEF MusicFileSettings msf;
+typedef struct FileEntry {
+ uint32 file_offset;
+ uint32 file_size;
+ uint16 rate;
+ uint8 bits_per_sample;
+ uint8 channels;
+ uint8 volume;
+ uint8 priority;
+} FileEntry;
+
bool SoundInitialize(const char *filename);
+uint GetNumOriginalSounds(void);
typedef enum SoundFx {
SND_02_SPLAT, // 0 == 0x00 !
@@ -97,5 +108,6 @@ typedef enum SoundFx {
void SndPlayTileFx(SoundFx sound, TileIndex tile);
void SndPlayVehicleFx(SoundFx sound, const Vehicle *v);
void SndPlayFx(SoundFx sound);
+void SndCopyToPool(void);
#endif /* SOUND_H */
diff --git a/train_cmd.c b/train_cmd.c
index d3533ac39..44becd117 100644
--- a/train_cmd.c
+++ b/train_cmd.c
@@ -27,6 +27,7 @@
#include "train.h"
#include "newgrf_callbacks.h"
#include "newgrf_engine.h"
+#include "newgrf_sound.h"
#include "newgrf_text.h"
#include "direction.h"
#include "yapf/yapf.h"
@@ -2021,6 +2022,7 @@ static const int8 _vehicle_smoke_pos[8] = {
static void HandleLocomotiveSmokeCloud(const Vehicle* v)
{
const Vehicle* u;
+ bool sound = false;
if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2)
return;
@@ -2068,6 +2070,7 @@ static void HandleLocomotiveSmokeCloud(const Vehicle* v)
// steam smoke.
if (GB(v->tick_counter, 0, 4) == 0) {
CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
+ sound = true;
}
break;
@@ -2075,6 +2078,7 @@ static void HandleLocomotiveSmokeCloud(const Vehicle* v)
// diesel smoke
if (u->cur_speed <= 40 && CHANCE16(15, 128)) {
CreateEffectVehicleRel(v, 0, 0, 10, EV_DIESEL_SMOKE);
+ sound = true;
}
break;
@@ -2082,10 +2086,13 @@ static void HandleLocomotiveSmokeCloud(const Vehicle* v)
// blue spark
if (GB(v->tick_counter, 0, 2) == 0 && CHANCE16(1, 45)) {
CreateEffectVehicleRel(v, 0, 0, 10, EV_ELECTRIC_SPARK);
+ sound = true;
}
break;
}
} while ((v = v->next) != NULL);
+
+ if (sound) PlayVehicleSound(u, VSE_TRAIN_EFFECT);
}
static void TrainPlayLeaveStationSound(const Vehicle* v)
@@ -2098,6 +2105,8 @@ static void TrainPlayLeaveStationSound(const Vehicle* v)
EngineID engtype = v->engine_type;
+ if (PlayVehicleSound(v, VSE_START)) return;
+
switch (GetEngine(engtype)->railtype) {
case RAILTYPE_RAIL:
case RAILTYPE_ELECTRIC:
@@ -3262,8 +3271,10 @@ static void HandleBrokenTrain(Vehicle *v)
InvalidateWindow(WC_VEHICLE_VIEW, v->index);
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
- SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
- SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
+ if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
+ SndPlayVehicleFx((_opt.landscape != LT_CANDY) ?
+ SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
+ }
if (!(v->vehstatus & VS_HIDDEN)) {
Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
diff --git a/tunnelbridge_cmd.c b/tunnelbridge_cmd.c
index e16e1f4d7..c7c56a37f 100644
--- a/tunnelbridge_cmd.c
+++ b/tunnelbridge_cmd.c
@@ -28,6 +28,7 @@
#include "water_map.h"
#include "yapf/yapf.h"
#include "date.h"
+#include "newgrf_sound.h"
#include "table/bridge_land.h"
@@ -1361,8 +1362,9 @@ static uint32 VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y
if (v->u.rail.track != 0x40 && dir == vdir) {
if (IsFrontEngine(v) && fc == _tunnel_fractcoord_1[dir]) {
- if (v->spritenum < 4)
+ if (!PlayVehicleSound(v, VSE_TUNNEL) && v->spritenum < 4) {
SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
+ }
return 0;
}
if (fc == _tunnel_fractcoord_2[dir]) {
diff --git a/vehicle.c b/vehicle.c
index e5cff4fdf..760ff64f2 100644
--- a/vehicle.c
+++ b/vehicle.c
@@ -33,6 +33,7 @@
#include "yapf/yapf.h"
#include "date.h"
#include "newgrf_engine.h"
+#include "newgrf_sound.h"
#define INVALID_COORD (-0x8000)
#define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
@@ -646,6 +647,22 @@ void CallVehicleTicks(void)
FOR_ALL_VEHICLES(v) {
_vehicle_tick_procs[v->type - 0x10](v);
+
+ switch (v->type) {
+ case VEH_Train:
+ case VEH_Road:
+ case VEH_Aircraft:
+ case VEH_Ship:
+ if (v->type == VEH_Train && IsTrainWagon(v)) continue;
+ if (v->type == VEH_Aircraft && v->subtype > 0) continue;
+
+ v->motion_counter += (v->direction & 1) ? (v->cur_speed * 3) / 4 : v->cur_speed;
+ /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */
+ if (GB(v->motion_counter, 0, 8) < v->cur_speed) PlayVehicleSound(v, VSE_RUNNING);
+
+ /* Play an alterate running sound every 16 ticks */
+ if (GB(v->tick_counter, 0, 4) == 0) PlayVehicleSound(v, v->cur_speed > 0 ? VSE_RUNNING_16 : VSE_STOPPED_16);
+ }
}
// now we handle all the vehicles that entered a depot this tick
diff --git a/vehicle.h b/vehicle.h
index 67961c468..c21c12477 100644
--- a/vehicle.h
+++ b/vehicle.h
@@ -174,6 +174,7 @@ struct Vehicle {
byte subspeed; // fractional speed
byte acceleration; // used by train & aircraft
byte progress;
+ uint32 motion_counter;
byte vehstatus; // Status
StationID last_station_visited;