e5d42a916048a1128be40b282cb6d734df3446ca.svn-base (6652B)
1 #ifndef SOUND_H 2 #define SOUND_H 3 4 #include "Utils.h" 5 #include "Console.h" 6 #include "Event.h" 7 8 #define MAX_VOL_RANGE 300.0 9 #define MIN_VOL_RANGE 1500.0 10 #define FADE_DISTANCE (MIN_VOL_RANGE - MAX_VOL_RANGE) 11 12 Mix_Music* LoadMusic(char* filename); 13 Mix_Chunk* LoadSound(char* filename); 14 15 class ChannelManager 16 { 17 public: 18 19 ChannelManager() {} 20 21 int AssignChannel() 22 { 23 for (int i = 0; i < (int)mChannels.size(); i++) 24 { 25 if ( (mChannels.at(i) = false) && (Mix_Playing(i) == false)) 26 { 27 return i; 28 } 29 } 30 mChannels.push_back(true); 31 Mix_AllocateChannels(mChannels.size()); 32 return (mChannels.size() - 1); 33 } 34 35 void FreeChannel(int channel) 36 { 37 mChannels.at(channel) = false; 38 } 39 40 bool PlaySound(int channel, Mix_Chunk* snd, int distance = -1); //outdated 41 42 bool PlayLoop(int channel, Mix_Chunk* snd, int distance = -1); //outdated 43 44 protected: 45 46 std::vector<bool> mChannels; 47 }; 48 49 class PointSound //A sound that plays at a point and attenuates with distance 50 { 51 public: 52 53 PointSound(int x, int y, Mix_Chunk* sound, int id) : mX(x), mY(y), mSound(sound), mID(id), mSpawnDate(gTime->GetCurrentCycle()) 54 { 55 //mFeed.EventProcess(Event(SPAWN, (void*)&mSoundChannel)); 56 } 57 58 ~PointSound() 59 { 60 //mFeed.EventProcess(Event(SOUND_COMPLETE, (void*)this)); 61 } 62 63 int setID(int id) 64 { 65 return mID = id; 66 } 67 68 int GetID() 69 { 70 return mID; 71 } 72 73 Mix_Chunk* GetChunk() 74 { 75 return mSound; 76 } 77 78 void SetChannel(int chan) 79 { 80 mSoundChannel = chan; 81 } 82 83 int GetChannel() 84 { 85 return mSoundChannel; 86 } 87 88 int GetX() 89 { 90 return mX; 91 } 92 93 int GetY() 94 { 95 return mY; 96 } 97 98 int GetSpawnDate() 99 { 100 return mSpawnDate; 101 } 102 103 bool PlayPointSound(int listen_x, int listen_y) 104 { 105 if (Mix_Playing(mSoundChannel) == false) 106 { 107 int dist = CalcDistance(mX, mY, listen_x, listen_y); 108 109 if (dist >= MIN_VOL_RANGE) //If the sound is out of hearing range 110 { 111 //gCons->ConsPrintf("Sound out of range\n\n"); 112 return false; 113 } 114 else 115 { 116 Mix_PlayChannel(mSoundChannel, mSound, 0); 117 if (dist <= MAX_VOL_RANGE) //if the sound is within range to play for no attenuation 118 { 119 //gCons->ConsPrintf("Sound within maximum volume range\n\n"); 120 Mix_SetDistance(mSoundChannel, 0); 121 } 122 else //between min and max volume ranges 123 { 124 int fade = int(((float)(dist - MAX_VOL_RANGE) / FADE_DISTANCE) * 255.0); 125 126 //gCons->ConsPrintf("Attenuation value: %i\n\n", fade); 127 Mix_SetDistance(mSoundChannel, fade); 128 } 129 } 130 131 return true; 132 } 133 else 134 { 135 mFeed.EventProcess(Event(SOUND_COMPLETE, this)); //not sure this should be called here 136 } 137 return false; 138 } 139 140 void FadeOut(int fade_time) 141 { 142 Mix_FadeOutChannel(mSoundChannel, fade_time); 143 } 144 145 EventFeed mFeed; 146 147 protected: 148 149 int mX; 150 int mY; 151 Mix_Chunk* mSound; 152 153 int mSoundChannel; 154 155 int mID; 156 157 int mSpawnDate; 158 }; 159 160 class RegionSound //Sounds that can be heard in a retangular region 161 { 162 public: 163 164 RegionSound(SDL_Rect region, int id) : mRegion(region), mID(id) 165 { 166 //mFeed.EventProcess(Event(SPAWN, (void*)&mSoundChannel)); 167 } 168 169 ~RegionSound() 170 { 171 //mFeed.EventProcess(Event(SOUND_COMPLETE, (void*)this)); 172 } 173 174 int setID(int id) 175 { 176 return mID = id; 177 } 178 179 int GetID() 180 { 181 return mID; 182 } 183 184 void SetChannel(int chan) 185 { 186 mSoundChannel = chan; 187 } 188 189 int GetChannel() 190 { 191 return mSoundChannel; 192 } 193 194 bool LogTrack(Mix_Chunk* snd) 195 { 196 mLoops.push_back(snd); 197 return true; 198 } 199 200 bool PlayRegionSound(SDL_Rect* pos) 201 { 202 if (DetectCenterPointIntersect(&mRegion, pos) == false) 203 { 204 Mix_FadeOutChannel(mSoundChannel, 5000); 205 } 206 else 207 { 208 if (Mix_Playing(mSoundChannel) == false) 209 { 210 for (int i = 0; i < (int)mLoops.size(); i++) 211 { 212 Mix_FadeInChannel(mSoundChannel, mLoops.at(i), -1, 5000); 213 } 214 return true; 215 } 216 } 217 return false; 218 } 219 220 EventFeed mFeed; 221 222 protected: 223 224 SDL_Rect mRegion; 225 226 std::vector<Mix_Chunk*> mLoops; 227 228 int mSoundChannel; 229 230 int mID; 231 }; 232 233 class SoundManager : public EventReceiver //needs to have functions moved to cpp 234 { 235 public: 236 237 SoundManager() 238 { 239 mChannelManager = ChannelManager(); 240 mMusic_Channel = mChannelManager.AssignChannel(); 241 } 242 243 ~SoundManager() 244 { 245 mChannelManager.FreeChannel(mMusic_Channel); 246 } 247 248 bool LogSoundData(Mix_Chunk* snd, char* name) 249 { 250 mSoundData.push_back(snd); 251 mNames.push_back(name); 252 return true; 253 } 254 255 Mix_Chunk* GetSoundData(char* name) 256 { 257 for (int i = 0; i < (int)mNames.size(); i++) 258 { 259 if (!strcmp(name, mNames.at(i))) 260 { 261 return mSoundData.at(i); 262 } 263 } 264 return NULL; 265 } 266 267 268 269 PointSound* SpawnPointSound(int x, int y, char* name) 270 { 271 PointSound* ps = new PointSound(x,y,GetSoundData(name), (int)(mEffects.size()) ); 272 ps->SetChannel(mChannelManager.AssignChannel()); 273 ps->mFeed.Subscribe(this); 274 mEffects.push_back(ps); 275 276 FadeDuplicates(ps->GetChunk(), 0); 277 278 return ps; 279 } 280 281 RegionSound* SpawnRegionSound(SDL_Rect region) 282 { 283 RegionSound* rs = new RegionSound(region, (int)(mRegions.size())); 284 rs->SetChannel(mChannelManager.AssignChannel()); 285 rs->mFeed.Subscribe(this); 286 mRegions.push_back(rs); 287 288 return rs; 289 } 290 291 bool ClearPointSound(PointSound* ps) 292 { 293 mChannelManager.FreeChannel(ps->GetChannel()); 294 295 mEffects.erase(mEffects.begin() + ps->GetID()); 296 297 for (int i = 0; i < (int)(mEffects.size()); i++) 298 { 299 mEffects.at(i)->setID(i); 300 } 301 302 return false; 303 } 304 305 std::vector<PointSound*>* GetPointSounds() 306 { 307 return &mEffects; 308 } 309 310 ChannelManager* GetChannelManager() 311 { 312 return &mChannelManager; 313 } 314 315 bool FadeDuplicates(Mix_Chunk* snd, int max_dupes) //This function does the job but its really expensive, Would work better with improved memory management 316 { 317 std::vector<int> dupes; 318 for (int i = 0; i < (int)mEffects.size(); i++) 319 { 320 if (snd == mEffects.at(i)->GetChunk()) 321 { 322 dupes.push_back(i); 323 } 324 } 325 326 for (int k = (int)dupes.size(); k > max_dupes;) 327 { 328 int oldest_index = -1; 329 int oldest = gTime->GetCurrentCycle(); 330 for (int j = 0; j < (int)dupes.size(); j++) 331 { 332 if (mEffects.at(dupes.at(j))->GetSpawnDate() <= oldest) //if mEffects[j] is older than mEffects[j - 1] 333 { 334 oldest = mEffects.at(dupes.at(j))->GetSpawnDate(); 335 oldest_index = j; 336 } 337 } 338 if (oldest_index == -1) 339 { 340 return false; 341 } 342 mEffects.at(dupes.at(oldest_index))->FadeOut(1); 343 //gCons->ConsPrintf("Sound Faded\n"); 344 dupes.erase(dupes.begin() + oldest_index); 345 k = (int)dupes.size(); 346 } 347 return true; 348 } 349 350 bool UpdatePointSounds(int listen_x, int listen_y); 351 352 bool UpdateRegionSounds(SDL_Rect* pos); 353 354 bool EventProcess(Event eve); 355 356 protected: 357 358 ChannelManager mChannelManager; 359 360 std::vector<Mix_Chunk*> mSoundData; 361 std::vector<char*> mNames; 362 363 std::vector<PointSound*> mEffects; 364 std::vector<RegionSound*> mRegions; 365 366 int mMusic_Channel; 367 368 }; 369 370 #endif