Skip to main content

rpfm_lib/files/sound_events/
mod.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! Sound events configuration for older Total War games.
12//!
13//! This module handles the `sound_events` file found in Shogun 2, Napoleon, and Empire.
14//! These files define sound event categories, event records, ambience maps, and movie
15//! audio settings used by the game's audio system.
16//!
17//! These files are not versioned, so only the latest format per game is supported.
18
19use getset::*;
20use serde_derive::{Serialize, Deserialize};
21
22use crate::binary::{ReadBytes, WriteBytes};
23use crate::error::{Result, RLibError};
24use crate::files::{DecodeableExtraData, Decodeable, EncodeableExtraData, Encodeable};
25use crate::games::supported_games::{KEY_SHOGUN_2, KEY_EMPIRE};
26use crate::utils::check_size_mismatch;
27
28/// Path to the sound events file within a pack.
29pub const PATH: &str = "sounds_packed/sound_events";
30
31mod games;
32
33#[cfg(test)] mod sound_events_test;
34
35//---------------------------------------------------------------------------//
36//                              Enum & Structs
37//---------------------------------------------------------------------------//
38
39/// Sound events configuration for a game.
40///
41/// Contains the complete audio event system configuration including categories,
42/// event definitions, ambience mappings, and movie audio settings.
43///
44/// Note: Many fields in this format are not fully understood and are marked as `uk_*`.
45#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
46#[getset(get = "pub", get_mut = "pub", set = "pub")]
47pub struct SoundEvents {
48    /// Master volume level for all sounds.
49    master_volume: f32,
50    /// Sound categories (e.g., music, SFX, voice).
51    categories: Vec<Category>,
52    /// Unknown data section 1.
53    uk_1: Vec<Uk1>,
54    /// Unknown data section 4.
55    uk_4: Vec<Uk4>,
56    /// Unknown data section 5.
57    uk_5: Vec<Uk5>,
58    /// Unknown value 6.
59    uk_6: u32,
60    /// Unknown value 7.
61    uk_7: u32,
62    /// Unknown data section 8.
63    uk_8: Vec<Uk8>,
64    /// Event data parameters referenced by event records.
65    event_data: Vec<EventData>,
66    /// Sound event definitions.
67    event_records: Vec<EventRecord>,
68    /// Ambience sound mappings.
69    ambience_map: Vec<AmbienceMap>,
70    /// Unknown data section 3.
71    uk_3: Vec<Uk3>,
72    /// Movie audio configurations.
73    movies: Vec<Movie>,
74    /// Unknown data section 9.
75    uk_9: Vec<Uk9>,
76}
77
78/// A sound category definition.
79///
80/// Categories group related sounds together for volume control and management.
81#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
82#[getset(get = "pub", get_mut = "pub", set = "pub")]
83pub struct Category {
84    /// Name of the category.
85    name: String,
86    /// Unknown parameter (possibly volume or priority).
87    uk_1: f32,
88}
89
90/// Unknown data structure 1.
91#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
92#[getset(get = "pub", get_mut = "pub", set = "pub")]
93pub struct Uk1 {
94    /// Unknown value.
95    uk_1: i32,
96}
97
98/// Unknown data structure 4.
99#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
100#[getset(get = "pub", get_mut = "pub", set = "pub")]
101pub struct Uk4 {
102    /// Unknown value 1.
103    uk_1: i32,
104    /// Unknown value 2.
105    uk_2: i32,
106}
107
108/// Unknown data structure 5 with float parameters.
109#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
110#[getset(get = "pub", get_mut = "pub", set = "pub")]
111pub struct Uk5 {
112    /// Unknown float 1.
113    uk_1: f32,
114    /// Unknown float 2.
115    uk_2: f32,
116    /// Unknown float 3.
117    uk_3: f32,
118    /// Unknown float 4.
119    uk_4: f32,
120    /// Unknown float 5.
121    uk_5: f32,
122    /// Unknown float 6.
123    uk_6: f32,
124    /// Unknown float 7.
125    uk_7: f32,
126    /// Unknown float 8.
127    uk_8: f32,
128}
129
130/// Unknown data structure 8.
131#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
132#[getset(get = "pub", get_mut = "pub", set = "pub")]
133pub struct Uk8 {
134    /// Unknown value.
135    uk_1: u32,
136}
137
138/// Event data parameters.
139///
140/// Contains a large set of float parameters that define audio playback characteristics.
141/// The exact meaning of each parameter is not fully understood.
142#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
143#[getset(get = "pub", get_mut = "pub", set = "pub")]
144pub struct EventData {
145    /// Unknown parameter 1.
146    uk_1: f32,
147    /// Unknown parameter 2.
148    uk_2: f32,
149    /// Unknown parameter 3.
150    uk_3: f32,
151    /// Unknown parameter 4.
152    uk_4: f32,
153    /// Unknown parameter 5.
154    uk_5: f32,
155    /// Unknown parameter 6.
156    uk_6: f32,
157    /// Unknown parameter 7.
158    uk_7: f32,
159    /// Unknown parameter 8.
160    uk_8: f32,
161    /// Unknown parameter 9.
162    uk_9: f32,
163    /// Unknown parameter 10.
164    uk_10: f32,
165    /// Unknown parameter 11.
166    uk_11: f32,
167    /// Unknown parameter 12.
168    uk_12: f32,
169    /// Unknown parameter 13.
170    uk_13: f32,
171    /// Unknown parameter 14.
172    uk_14: f32,
173    /// Unknown parameter 15.
174    uk_15: f32,
175    /// Unknown parameter 16.
176    uk_16: f32,
177    /// Unknown parameter 17.
178    uk_17: f32,
179    /// Unknown parameter 18.
180    uk_18: f32,
181    /// Unknown parameter 19.
182    uk_19: f32,
183    /// Unknown parameter 20.
184    uk_20: f32,
185    /// Unknown parameter 21.
186    uk_21: f32,
187    /// Unknown parameter 22.
188    uk_22: f32,
189    /// Unknown parameter 23.
190    uk_23: f32,
191    /// Unknown parameter 24.
192    uk_24: f32,
193    /// Unknown parameter 25.
194    uk_25: f32,
195    /// Unknown parameter 26.
196    uk_26: f32,
197    /// Unknown parameter 27.
198    uk_27: f32,
199    /// Unknown parameter 28.
200    uk_28: f32,
201    /// Unknown parameter 29.
202    uk_29: f32,
203    /// Unknown parameter 30.
204    uk_30: f32,
205    /// Unknown parameter 31.
206    uk_31: f32,
207    /// Unknown parameter 32.
208    uk_32: f32,
209    /// Unknown parameter 33.
210    uk_33: f32,
211    /// Unknown parameter 34.
212    uk_34: f32,
213    /// Unknown parameter 35.
214    uk_35: f32,
215    /// Unknown parameter 36.
216    uk_36: f32,
217    /// Unknown parameter 37.
218    uk_37: f32,
219    /// Unknown parameter 38.
220    uk_38: f32,
221    /// Unknown parameter 39.
222    uk_39: f32,
223    /// Unknown parameter 40.
224    uk_40: f32,
225    /// Unknown parameter 41.
226    uk_41: f32,
227    /// Unknown parameter 42.
228    uk_42: f32,
229    /// Unknown parameter 43.
230    uk_43: f32,
231    /// Unknown parameter 44.
232    uk_44: f32,
233    /// Unknown parameter 45.
234    uk_45: f32,
235    /// Unknown parameter 46.
236    uk_46: f32,
237    /// Unknown parameter 47.
238    uk_47: f32,
239}
240
241/// A sound event record.
242///
243/// Defines a triggerable sound event that references sound files and event data parameters.
244#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
245#[getset(get = "pub", get_mut = "pub", set = "pub")]
246pub struct EventRecord {
247    /// Index of the category this event belongs to.
248    category: u32,
249    /// Optional name of the event.
250    name: Option<String>,
251    /// Unknown value 1.
252    uk_1: u32,
253    /// Unknown value 2.
254    uk_2: i32,
255    /// Unknown value 3.
256    uk_3: i32,
257    /// Index into the event_data array for this event's parameters.
258    event_data_index: u32,
259    /// Unknown value 4.
260    uk_4: u8,
261    /// List of sound file paths associated with this event.
262    sounds: Vec<String>,
263}
264
265/// An ambience map definition.
266///
267/// Maps ambience names to collections of ambience records for environmental audio.
268#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
269#[getset(get = "pub", get_mut = "pub", set = "pub")]
270pub struct AmbienceMap {
271    /// Name of the ambience map.
272    name: String,
273    /// Ambience records within this map.
274    records: Vec<AmbienceRecord>,
275}
276
277/// An ambience record within an ambience map.
278///
279/// Links to an event and contains spatial/volume parameters for ambient sounds.
280#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
281#[getset(get = "pub", get_mut = "pub", set = "pub")]
282pub struct AmbienceRecord {
283    /// Unknown value 1.
284    uk_1: u32,
285    /// Index into the event_records array.
286    event_index: u32,
287    /// Unknown float 3.
288    uk_3: f32,
289    /// Unknown float 4.
290    uk_4: f32,
291    /// Unknown float 5.
292    uk_5: f32,
293    /// Unknown float 6.
294    uk_6: f32,
295    /// Unknown float 7.
296    uk_7: f32,
297    /// Unknown float 8.
298    uk_8: f32,
299}
300
301/// Unknown data structure 3.
302#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
303#[getset(get = "pub", get_mut = "pub", set = "pub")]
304pub struct Uk3 {
305    /// Unknown value.
306    uk_1: i32,
307}
308
309/// Movie audio configuration.
310///
311/// Associates a movie file with its audio volume setting.
312#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
313#[getset(get = "pub", get_mut = "pub", set = "pub")]
314pub struct Movie {
315    /// Path to the movie file.
316    file: String,
317    /// Volume level for the movie's audio.
318    volume: f32,
319}
320
321/// Unknown data structure 9 with file reference.
322#[derive(Default, PartialEq, Clone, Debug, Getters, MutGetters, Setters, Serialize, Deserialize)]
323#[getset(get = "pub", get_mut = "pub", set = "pub")]
324pub struct Uk9 {
325    /// Path to a file.
326    file: String,
327    /// Unknown value.
328    uk_1: i32,
329}
330
331//---------------------------------------------------------------------------//
332//                              Implementations
333//---------------------------------------------------------------------------//
334
335impl Decodeable for SoundEvents {
336
337    fn decode<R: ReadBytes>(data: &mut R, extra_data: &Option<DecodeableExtraData>) -> Result<Self> {
338        let extra_data = extra_data.as_ref().ok_or(RLibError::DecodingMissingExtraData)?;
339        let game_info = extra_data.game_info.ok_or_else(|| RLibError::DecodingMissingExtraDataField("game_info".to_owned()))?;
340
341        let mut sound_events = Self::default();
342
343        match game_info.key() {
344            KEY_SHOGUN_2 => sound_events.read_sho2(data)?,
345            //KEY_NAPOLEON => {},
346            KEY_EMPIRE => sound_events.read_emp(data)?,
347            _ => return Err(RLibError::DecodingSoundPackedUnsupportedGame(game_info.key().to_string())),
348        }
349
350        // If we are not in the last byte, it means we didn't parse the entire file, which means this file is corrupt.
351        check_size_mismatch(data.stream_position()? as usize, data.len()? as usize)?;
352
353        Ok(sound_events)
354    }
355}
356
357impl Encodeable for SoundEvents {
358
359    fn encode<W: WriteBytes>(&mut self, buffer: &mut W, extra_data: &Option<EncodeableExtraData>) -> Result<()> {
360        let extra_data = extra_data.as_ref().ok_or(RLibError::EncodingMissingExtraData)?;
361        let game_info = extra_data.game_info.ok_or_else(|| RLibError::DecodingMissingExtraDataField("game_info".to_owned()))?;
362
363        match game_info.key() {
364            KEY_SHOGUN_2 => self.write_sho2(buffer),
365            //KEY_NAPOLEON => {},
366            KEY_EMPIRE => self.write_emp(buffer),
367            _ => Err(RLibError::EncodingSoundPackedUnsupportedGame(game_info.key().to_string())),
368        }
369    }
370}