TapestryEngine

A 2D Platformer Game Engine
Log | Files | Refs

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