00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "stdsound.h"
00028
00029 #include "nel/misc/file.h"
00030 #include "nel/misc/i_xml.h"
00031 #include "nel/misc/path.h"
00032
00033 #include "nel/ligo/primitive.h"
00034
00035 #include "nel/sound/u_source.h"
00036
00037 #include "background_sound_manager.h"
00038 #include <algorithm>
00039
00040 using namespace std;
00041 using namespace NLMISC;
00042 using namespace NLLIGO;
00043
00044
00045 namespace NLSOUND {
00046
00047
00048 const float INSIDE_FALLOF = 10.0f;
00049
00050
00051
00052
00053 CBackgroundSoundManager::CBackgroundSoundManager()
00054 : _LastPosition(0,0,0), _Playing(false)
00055 {
00056 }
00057
00058 CBackgroundSoundManager::~CBackgroundSoundManager()
00059 {
00060 unload();
00061 }
00062
00063 const UAudioMixer::TBackgroundFlags &CBackgroundSoundManager::getBackgroundFlags()
00064 {
00065 return _BackgroundFlags;
00066 }
00067
00068 void CBackgroundSoundManager::setBackgroundFlags(const UAudioMixer::TBackgroundFlags &backgroundFlags)
00069 {
00070 _BackgroundFlags = backgroundFlags;
00071 }
00072
00073 void CBackgroundSoundManager::addSound(const std::string &soundName, const std::vector<NLLIGO::CPrimVector> &points, bool isPath)
00074 {
00075 CAudioMixerUser *mixer = CAudioMixerUser::instance();
00076 uint layerId = 0;
00077 uint n = 0;
00078 string name;
00079
00080 n = std::count(soundName.begin(), soundName.end(), '-');
00081
00082 if (n == 2)
00083 {
00084
00085 uint32 pos1 = soundName.find ("-");
00086 if(pos1 == string::npos)
00087 {
00088 nlwarning ("zone have the malformated name '%s' missing -name-", soundName.c_str());
00089 return;
00090 }
00091 pos1++;
00092
00093 uint32 pos2 = soundName.find ("-", pos1);
00094 if(pos2 == string::npos)
00095 {
00096 nlwarning ("zone have the malformated name '%s' missing -name-", soundName.c_str());
00097 return;
00098 }
00099
00100 name = soundName.substr(pos1, pos2-pos1);
00101 }
00102 else if (n == 3)
00103 {
00104
00105 uint32 pos1 = soundName.find ("-");
00106 uint32 pos2 = soundName.find ("-", pos1+1);
00107 if(pos1 == string::npos || pos2 == string::npos)
00108 {
00109 nlwarning ("zone have the malformated name '%s' missing -layerId- or -name-", soundName.c_str());
00110 return;
00111 }
00112 pos1++;
00113
00114 uint32 pos3 = soundName.find ("-", pos2+1);
00115 if(pos3 == string::npos)
00116 {
00117 nlwarning ("zone have the malformated name '%s' missing -name-", soundName.c_str());
00118 return;
00119 }
00120
00121 char id = soundName[pos1];
00122
00123
00124 if (id < 'a')
00125 id = id + ('a' - 'A');
00126
00127 layerId = id - 'a';
00128
00129 NLMISC::clamp(layerId, 0u, BACKGROUND_LAYER-1);
00130 pos2++;
00131
00132 name = soundName.substr(pos2, pos3-pos2);
00133 }
00134 else
00135 {
00136 nlwarning ("zone have the malformated name '%s", soundName.c_str());
00137 return;
00138 }
00139
00140
00141 TSoundData sd;
00142
00143 sd.SoundName = name;
00144 sd.Sound = mixer->getSoundId(sd.SoundName);
00145 sd.Source = 0;
00146
00147
00148 sd.Points.resize (points.size ());
00149 for (uint i=0; i<points.size (); i++)
00150 sd.Points[i] = points[i];
00151
00152 sd.Selected = false;
00153 sd.IsPath = isPath;
00154
00155 if (sd.Sound != 0)
00156 {
00157
00158
00159 CVector vmin(FLT_MAX, FLT_MAX, 0), vmax(-FLT_MAX, -FLT_MAX, 0);
00160
00161 vector<CVector>::iterator first(sd.Points.begin()), last(sd.Points.end());
00162 for (; first != last; ++first)
00163 {
00164 vmin.x = min(first->x, vmin.x);
00165 vmin.y = min(first->y, vmin.y);
00166 vmax.x = max(first->x, vmax.x);
00167 vmax.y = max(first->y, vmax.y);
00168 }
00169 sd.MaxBox = vmax;
00170 sd.MinBox = vmin;
00171
00172
00173 sd.Surface = (vmax.x - vmin.x) * (vmax.y - vmin.y);
00174
00175
00176 float dist = sd.Sound->getMaxDistance();
00177 sd.MaxBox.x += dist;
00178 sd.MaxBox.y += dist;
00179 sd.MinBox.x -= dist;
00180 sd.MinBox.y -= dist;
00181
00182 sd.MaxDist = dist;
00183
00184
00185
00186 _Layers[layerId].push_back(sd);
00187 }
00188 else
00189 {
00190 nlwarning ("The sound '%s' can't be loaded", sd.SoundName.c_str());
00191 }
00192 }
00193
00194
00195 void CBackgroundSoundManager::loadSamplesFromRegion(const NLLIGO::CPrimRegion ®ion)
00196 {
00197 _Banks.clear();
00198
00199 for (uint i=0; i< region.VZones.size(); ++i)
00200 {
00201 if (region.VZones[i].VPoints.size() > 2)
00202 {
00203 TBanksData bd;
00204 uint pointCount = region.VZones[i].VPoints.size ();
00205 bd.Points.resize (pointCount);
00206 for (uint j=0; j<pointCount; j++)
00207 {
00208 bd.Points[j] = region.VZones[i].VPoints[j];
00209 }
00210
00211
00212 CVector vmin(FLT_MAX, FLT_MAX, 0), vmax(-FLT_MAX, -FLT_MAX, 0);
00213
00214 vector<CVector>::iterator first(bd.Points.begin()), last(bd.Points.end());
00215 for (; first != last; ++first)
00216 {
00217 vmin.x = min(first->x, vmin.x);
00218 vmin.y = min(first->y, vmin.y);
00219 vmax.x = max(first->x, vmax.x);
00220 vmax.y = max(first->y, vmax.y);
00221 }
00222 bd.MaxBox = vmax;
00223 bd.MinBox = vmin;
00224
00225
00226 std::vector<std::string> splitted = split(region.VZones[i].Name, '-');
00227
00228 if (splitted.size() > 2)
00229 {
00230 for (uint j=1; j<splitted.size()-1; ++j)
00231 {
00232 bd.Banks.push_back(splitted[j]);
00233 }
00234
00235
00236 _Banks.push_back(bd);
00237 }
00238 else
00239 {
00240 nlwarning ("A sample bank patatoid name did'nt contains banks name '%s'", region.VZones[i].Name.c_str());
00241 }
00242 }
00243 else
00244 {
00245 nlwarning ("A sample bank patatoid have less than 3 points '%s'", region.VZones[i].Name.c_str());
00246 }
00247 }
00248 }
00249
00250 void CBackgroundSoundManager::loadEffecsFromRegion(const NLLIGO::CPrimRegion ®ion)
00251 {
00252 }
00253
00254 void CBackgroundSoundManager::loadSoundsFromRegion(const CPrimRegion ®ion)
00255 {
00256 uint i;
00257
00258 bool oldState = _Playing;
00259 unload();
00260
00261 for (i = 0; i < region.VZones.size(); i++)
00262 {
00263 if(region.VZones[i].VPoints.size()>2)
00264 {
00265 addSound(region.VZones[i].Name, region.VZones[i].VPoints, false);
00266 }
00267 else
00268 {
00269 nlwarning ("A background sound patatoid have less than 3 points '%s'", region.VZones[i].Name.c_str());
00270 }
00271 }
00272
00273 for (i = 0; i < region.VPaths.size(); i++)
00274 {
00275 if(region.VPaths[i].VPoints.size() > 1)
00276 {
00277 addSound(region.VPaths[i].Name, region.VPaths[i].VPoints, true);
00278 }
00279 else
00280 {
00281 nlwarning ("A background sound path have less than 2 points '%s'", region.VPaths[i].Name.c_str());
00282 }
00283 }
00284 for (i = 0; i < region.VPoints.size(); i++)
00285 {
00286 std::vector<CPrimVector> points;
00287 points.push_back(region.VPoints[i].Point);
00288
00289 addSound(region.VPoints[i].Name, points, false);
00290 }
00291
00292
00293
00294 if (oldState)
00295 play();
00296 }
00297
00298 void CBackgroundSoundManager::load (const string &continent)
00299 {
00300
00301 {
00302 CIFile file;
00303 CPrimRegion region;
00304 string fn = continent+"_audio.prim";
00305
00306 nlinfo ("loading '%s'", fn.c_str());
00307
00308 string path = CPath::lookup(fn, false);
00309
00310 if(!path.empty() && file.open (path))
00311 {
00312 CIXml xml;
00313 xml.init (file);
00314 region.serial(xml);
00315 file.close ();
00316
00317 nlinfo ("Region '%s' contains %d zones for the background sounds", continent.c_str(), region.VZones.size());
00318
00319 loadSoundsFromRegion(region);
00320 }
00321 }
00322
00323 {
00324 CIFile file;
00325 CPrimRegion region;
00326 string fn = continent+"_effects.prim";
00327
00328 nlinfo ("loading '%s'", fn.c_str());
00329
00330 string path = CPath::lookup(fn, false);
00331
00332 if(!path.empty() && file.open (path))
00333 {
00334 CIXml xml;
00335 xml.init (file);
00336 region.serial(xml);
00337 file.close ();
00338
00339 nlinfo ("Region '%s' contains %d zones for the background effetcs", continent.c_str(), region.VZones.size());
00340
00341 loadEffecsFromRegion(region);
00342 }
00343 }
00344
00345 {
00346 CIFile file;
00347 CPrimRegion region;
00348 string fn = continent+"_samples.prim";
00349
00350 nlinfo ("loading '%s'", fn.c_str());
00351
00352 string path = CPath::lookup(fn, false);
00353
00354 if(!path.empty() && file.open (path))
00355 {
00356 CIXml xml;
00357 xml.init (file);
00358 region.serial(xml);
00359 file.close ();
00360
00361 nlinfo ("Region '%s' contains %d zones for the background samples banks", continent.c_str(), region.VZones.size());
00362
00363 loadSamplesFromRegion(region);
00364 }
00365 }
00366 }
00367
00368
00369 void CBackgroundSoundManager::play ()
00370 {
00371 if (_Playing)
00372 return;
00373
00374 _Playing = true;
00375
00376 updateBackgroundStatus();
00377 }
00378
00379
00380 void CBackgroundSoundManager::stop ()
00381 {
00382 if(!_Playing)
00383 return;
00384 CAudioMixerUser *mixer = CAudioMixerUser::instance();
00385
00386 for (uint i=0; i<BACKGROUND_LAYER; ++i)
00387 {
00388
00389 std::vector<TSoundData>::iterator first(_Layers[i].begin()), last(_Layers[i].end());
00390 for (; first != last; ++first)
00391 {
00392 if (first->Source != 0 && first->Source->isPlaying())
00393 first->Source->stop();
00394 }
00395 }
00396
00397 _Playing = false;
00398 }
00399
00400 void CBackgroundSoundManager::unload ()
00401 {
00402 stop();
00403
00404 CAudioMixerUser *mixer = CAudioMixerUser::instance();
00405
00406 for (uint i=0; i<BACKGROUND_LAYER; ++i)
00407 {
00408
00409 std::vector<TSoundData>::iterator first(_Layers[i].begin()), last(_Layers[i].end());
00410 for (; first != last; ++first)
00411 {
00412 if (first->Source)
00413
00414 delete first->Source;
00415 }
00416
00417
00418 _Layers[i].clear();
00419 }
00420 }
00421
00422 void CBackgroundSoundManager::setListenerPosition (const CVector &listenerPosition)
00423 {
00424 if (_LastPosition == listenerPosition)
00425 {
00426 return;
00427 }
00428 _LastPosition = listenerPosition;
00429
00430 updateBackgroundStatus();
00431 }
00432
00433 void CBackgroundSoundManager::updateBackgroundStatus()
00434 {
00435 if (!_Playing)
00436 return;
00437
00438 CAudioMixerUser *mixer = CAudioMixerUser::instance();
00439
00440
00441 CVector listener = _LastPosition;
00442 listener.z = 0.0f;
00443
00444
00445 {
00446
00447 std::set<std::string> newBanks;
00448
00449 std::vector<TBanksData>::iterator first(_Banks.begin()), last(_Banks.end());
00450 for (; first != last; ++first)
00451 {
00452 if (listener.x >= first->MinBox.x && listener.x <= first->MaxBox.x
00453 && listener.y >= first->MinBox.y && listener.y <= first->MaxBox.y
00454 )
00455 {
00456
00457 if (CPrimZone::contains(listener, first->Points))
00458 {
00459
00460 newBanks.insert(first->Banks.begin(), first->Banks.end());
00461 }
00462 }
00463 }
00464
00465 std::set<std::string> noChange;
00466 std::set_intersection(_LoadedBanks.begin(), _LoadedBanks.end(), newBanks.begin(), newBanks.end(), std::inserter(noChange, noChange.end()));
00467
00468 std::set<std::string> loadList;
00469 std::set_difference(newBanks.begin(), newBanks.end(), noChange.begin(), noChange.end(), std::inserter(loadList, loadList.end()));
00470
00471 std::set<std::string> unloadList;
00472 std::set_difference(_LoadedBanks.begin(), _LoadedBanks.end(), newBanks.begin(), newBanks.end(), std::inserter(unloadList, unloadList.end()));
00473
00474
00475 {
00476 std::set<std::string>::iterator first(loadList.begin()), last(loadList.end());
00477 for (; first != last; ++first)
00478 {
00479 mixer->loadSampleBank(true, *first);
00480 }
00481 _LoadedBanks.insert(loadList.begin(), loadList.end());
00482 }
00483 {
00484 std::set<std::string>::iterator first(unloadList.begin()), last(unloadList.end());
00485 for (; first != last; ++first)
00486 {
00487 if (mixer->unloadSampleBank(*first))
00488 {
00489
00490 _LoadedBanks.erase(*first);
00491 }
00492 }
00493 }
00494 }
00495
00496
00497 for (uint i=0; i<BACKGROUND_LAYER; ++i)
00498 {
00499 vector<TSoundData> &layer = _Layers[i];
00500 vector<uint> selectedIndex;
00501 vector<uint> leaveIndex;
00502
00503 selectedIndex.reserve(layer.size());
00504 leaveIndex.reserve(layer.size());
00505
00506
00507 vector<TSoundData>::iterator first(layer.begin()), last(layer.end());
00508 for (uint count = 0; first != last; ++first, ++count)
00509 {
00510 if (listener.x >= first->MinBox.x && listener.x <= first->MaxBox.x
00511 && listener.y >= first->MinBox.y && listener.y <= first->MaxBox.y
00512
00513 )
00514 {
00515
00516 selectedIndex.push_back(count);
00517 }
00518 else
00519 {
00520
00521
00522 if (first->Selected && first->Source != 0)
00523 {
00524
00525 leaveIndex.push_back(count);
00526 }
00527 }
00528 }
00529
00530
00531 {
00532 vector<uint>::iterator first(leaveIndex.begin()), last(leaveIndex.end());
00533 for (; first != last; ++first)
00534 {
00535 TSoundData &sd = layer[*first];
00536 sd.Selected = false;
00537 if (sd.Source->isPlaying())
00538 sd.Source->stop();
00539 }
00540 }
00541
00542 {
00544 map<float, TSoundStatus> status;
00545
00546
00547 {
00548 vector<uint>::iterator first(selectedIndex.begin()), last(selectedIndex.end());
00549 for (; first != last; ++first)
00550 {
00551 TSoundData &sd = layer[*first];
00552 CVector pos;
00553 float gain;
00554 float distance;
00555
00556
00557
00558 if(CPrimZone::contains(listener, sd.Points, distance, pos, sd.IsPath))
00559 {
00560 pos = _LastPosition;
00561 gain = 1.0f;
00562
00563 }
00564 else
00565 {
00566 if (distance < sd.MaxDist)
00567 {
00568
00569 gain = (sd.MaxDist - distance) / sd.MaxDist;
00570 }
00571 else
00572 {
00573
00574 gain = 0;
00575 }
00576
00577 }
00578
00579
00580 status.insert(make_pair(sd.Surface, TSoundStatus(sd, pos, gain, distance)));
00581 }
00582 }
00583
00584 {
00585
00586
00587
00588 float maskFactor = 1.0f;
00589
00590 map<float, TSoundStatus>::iterator first(status.begin()), last(status.end());
00591 for (; first != last; ++first)
00592 {
00593 TSoundStatus &ss = first->second;
00594
00595 if (maskFactor > 0.0f && ss.Gain > 0)
00596 {
00597 float gain = maskFactor * ss.Gain;
00598
00599
00600 ss.SoundData.Selected = true;
00601
00602 if (ss.Gain == 1)
00603 {
00604
00605 maskFactor -= first->second.Distance / INSIDE_FALLOF;
00606 clamp(maskFactor, 0.0f, 1.0f);
00607 }
00608
00609
00610
00611 if (ss.SoundData.Source == 0)
00612 {
00613
00614 ss.SoundData.Source = mixer->createSource(ss.SoundData.Sound, false);
00615 }
00616 if (ss.SoundData.Source != 0)
00617 {
00618
00619 ss.SoundData.Source->setRelativeGain(gain);
00620
00621 ss.Position.z += 5.0f;
00622 ss.SoundData.Source->setPos(ss.Position);
00623
00624
00625 if (!ss.SoundData.Source->isPlaying())
00626 {
00627
00628 ss.SoundData.Source->play();
00629 }
00630 }
00631 }
00632 else if (ss.SoundData.Source != 0 && ss.SoundData.Source->isPlaying())
00633 {
00634
00635 ss.SoundData.Source->stop();
00636 }
00637 }
00638 }
00639 }
00640 }
00641 }
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 CVector CBackgroundSoundManager::getZoneSourcePos(uint32 zone)
00666 {
00667
00668
00669
00670
00671
00672
00673 return CVector();
00674 }
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 }
00750