1 /*
2 Copyright (c) 2009 Peter "Corsix" Cawley
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22 
23 #ifndef CORSIX_TH_TH_SOUND_H_
24 #define CORSIX_TH_TH_SOUND_H_
25 #include "config.h"
26 
27 #include <SDL.h>
28 #ifdef CORSIX_TH_USE_SDL_MIXER
29 #include <SDL_mixer.h>
30 #endif
31 
32 //! Utility class for accessing Theme Hospital's SOUND-0.DAT
33 class sound_archive {
34  public:
35   sound_archive();
36   ~sound_archive();
37 
38   bool load_from_th_file(const uint8_t* pData, size_t iDataLength);
39 
40   //! Returns the number of sounds present in the archive
41   size_t get_number_of_sounds() const;
42 
43   //! Gets the name of the sound at a given index
44   const char* get_sound_name(size_t iIndex) const;
45 
46   //! Gets the duration (in milliseconds) of the sound at a given index
47   size_t get_sound_duration(size_t iIndex);
48 
49   //! Opens the sound at a given index into an SDL_RWops structure
50   /*!
51       The caller is responsible for closing/freeing the result.
52   */
53   SDL_RWops* load_sound(size_t iIndex);
54 
55  private:
56 #if CORSIX_TH_USE_PACK_PRAGMAS
57 #pragma pack(push)
58 #pragma pack(1)
59 #endif
60   struct sound_dat_file_header {
61     uint8_t unknown1[50];
62     uint32_t table_position;
63     uint32_t unknown2;
64     uint32_t table_length;
65     uint32_t table_position2;
66     uint8_t unknown3[112];
67     uint32_t table_position3;
68     uint32_t table_length2;
69     uint8_t unknown4[48];
70   } CORSIX_TH_PACKED_FLAGS;
71 
72   struct sound_dat_sound_info {
73     char sound_name[18];
74     uint32_t position;
75     uint32_t unknown1;
76     uint32_t length;
77     uint16_t unknown2;
78   } CORSIX_TH_PACKED_FLAGS;
79 #if CORSIX_TH_USE_PACK_PRAGMAS
80 #pragma pack(pop)
81 #endif
82 
83   // TODO: header is only used in one function, should not be class variable.
84   sound_dat_file_header header;
85   sound_dat_sound_info* sound_files;
86   uint8_t* data;
87   size_t sound_file_count;
88 };
89 
90 class sound_player {
91  public:
92   sound_player();
93   ~sound_player();
94 
95   static sound_player* get_singleton();
96 
97   void populate_from(sound_archive* pArchive);
98 
99   void play(size_t iIndex, double dVolume);
100   void play_at(size_t iIndex, int iX, int iY);
101   void play_at(size_t iIndex, double dVolume, int iX, int iY);
102   void set_sound_effect_volume(double dVolume);
103   void set_sound_effects_enabled(bool bOn);
104   void set_camera(int iX, int iY, int iRadius);
105   int reserve_channel();
106   void release_channel(int iChannel);
107 
108  private:
109 #ifdef CORSIX_TH_USE_SDL_MIXER
110   static sound_player* singleton;
111   static void on_channel_finished(int iChannel);
112 
113   inline void play_raw(size_t iIndex, int iVolume);
114 
115   Mix_Chunk** sounds;
116   size_t sound_count;
117   uint32_t available_channels_bitmap;  ///< The bit index corresponding to a
118                                        ///< channel is 1 if the channel is
119                                        ///< available and 0 if it is reserved
120                                        ///< or in use.
121   int camera_x;
122   int camera_y;
123   double camera_radius;
124   double master_volume;
125   double sound_effect_volume;
126   int positionless_volume;
127   bool sound_effects_enabled;
128 #endif  // CORSIX_TH_USE_SDL_MIXER
129 };
130 
131 #endif  // CORSIX_TH_TH_SOUND_H_
132