00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdsound.h"
00027
00028 #include "sample_bank.h"
00029 #include "driver/sound_driver.h"
00030 #include "driver/buffer.h"
00031 #include "nel/misc/path.h"
00032 #include "nel/misc/file.h"
00033 #include "async_file_manager_sound.h"
00034 #include "background_sound_manager.h"
00035 #include "sound_bank.h"
00036
00037
00038 using namespace std;
00039 using namespace NLMISC;
00040
00041
00042 namespace NLSOUND {
00043
00045 uint32 ASYNC_LOADING_SPLIT = 10;
00046
00047 CSampleBank::TSampleBankContainer CSampleBank::_Banks;
00048 uint CSampleBank::_LoadedSize = 0;
00049
00050 CSampleBank::TVirtualBankCont CSampleBank::_VirtualBanks;
00051
00052
00053
00054
00055 void CSampleBank::init(NLGEORGES::UFormElm *mixerConfig)
00056 {
00057 NL_ALLOC_CONTEXT(NLSOUND_CSampleBank);
00058 if (mixerConfig == 0)
00059 return;
00060
00061 NLGEORGES::UFormElm *virtualBanks;
00062 mixerConfig->getNodeByName(&virtualBanks, ".VirtualBanks");
00063 if (virtualBanks == 0)
00064 return;
00065
00066 uint size;
00067 virtualBanks->getArraySize(size);
00068
00069 for (uint i=0; i<size; ++i)
00070 {
00071 NLGEORGES::UFormElm *virtualBank;
00072 virtualBanks->getArrayNode(&virtualBank, i);
00073
00074 if (virtualBank != 0)
00075 {
00076 std::vector<TFilteredBank> vfb;
00077 std::string virtualName;
00078 virtualBank->getValueByName(virtualName, ".VirtualName");
00079 NLGEORGES::UFormElm *realBanks;
00080 virtualBank->getNodeByName(&realBanks, ".FilteredBank");
00081 if (realBanks != 0)
00082 {
00083 uint size2;
00084 realBanks->getArraySize(size2);
00085
00086 for (uint j=0; j<size2; ++j)
00087 {
00088 TFilteredBank fb;
00089 std::string bankName;
00090 NLGEORGES::UFormElm *realBank;
00091 realBank->getArrayNode(&realBank, j);
00092
00093 realBank->getValueByName(bankName, ".SampleBank");
00094 fb.BankName = CStringMapper::map(bankName);
00095 realBank->getValueByName(fb.Filter, ".Filter");
00096
00097 vfb.push_back(fb);
00098 }
00099 }
00100
00101 if (!vfb.empty())
00102 {
00103 _VirtualBanks.insert(std::make_pair(NLMISC::CStringMapper::map(virtualName), vfb));
00104
00105 new CSampleBank(virtualName, NULL);
00106 }
00107 }
00108 }
00109 }
00110
00111
00112
00113
00114
00115 CSampleBank *CSampleBank::findSampleBank(const NLMISC::TStringId &filename)
00116 {
00117 TSampleBankContainer::iterator it(_Banks.find(filename));
00118
00119 if (it != _Banks.end())
00120 return it->second;
00121
00122 return NULL;
00123 }
00124
00125
00126
00127 IBuffer* CSampleBank::get(const NLMISC::TStringId &name)
00128 {
00129 IBuffer* buffer;
00130 TSampleBankContainer::iterator iter;
00131
00132 for (iter = _Banks.begin(); iter != _Banks.end(); ++iter)
00133 {
00134 buffer = iter->second->getSample(name);
00135 if (buffer != 0)
00136 {
00137 return buffer;
00138 }
00139 }
00140
00141
00142 return 0;
00143 }
00144
00145 void CSampleBank::reload(bool async)
00146 {
00147 TSampleBankContainer::iterator first(_Banks.begin()), last(_Banks.end());
00148
00149 for (; first != last; ++first)
00150 {
00151 first->second->unload();
00152 first->second->load(async);
00153 }
00154 }
00155
00156
00157 void CSampleBank::getLoadedSampleBankInfo(std::vector<std::pair<std::string, uint> > &result)
00158 {
00159 result.clear();
00160
00161 TSampleBankContainer::iterator first(_Banks.begin()), last(_Banks.end());
00162 for (; first != last; ++first)
00163 {
00164 std::pair<std::string, uint> p;
00165 if (first->second->isLoaded())
00166 {
00167 p.first = NLMISC::CStringMapper::unmap(first->first);
00168 p.second = first->second->getSize();
00169 result.push_back(p);
00170 }
00171 }
00172 }
00173
00174
00175
00176
00177
00178
00179
00180 CSampleBank::CSampleBank(const std::string& name, ISoundDriver *sd)
00181 : _SoundDriver(sd), _Name(CStringMapper::map(name)), _Loaded(false), _LoadingDone(true), _ByteSize(0)
00182 {
00183
00184 _Banks.insert(make_pair(_Name, this));
00185 }
00186
00187
00188
00189
00190 CSampleBank::~CSampleBank()
00191 {
00192 CAudioMixerUser::instance()->unregisterUpdate(this);
00193 while (!_LoadingDone)
00194 {
00195
00196 nlSleep(100);
00197 }
00198
00199 if (_Loaded)
00200 unload();
00201
00202
00203 TSampleBankContainer::iterator iter(_Banks.begin()), end(_Banks.end());
00204
00205 for (; iter != end; ++iter)
00206 {
00207 if (iter->second == this)
00208 {
00209 _Banks.erase(iter);
00210 break;
00211 }
00212 }
00213
00214
00215
00216 while (!_Samples.empty())
00217 {
00218 delete _Samples.begin()->second;
00219 _Samples.erase(_Samples.begin());
00220 }
00221
00222 _Samples.clear();
00223 }
00224
00225
00226
00227
00228 void CSampleBank::load(bool async)
00229 {
00230
00231
00232 TVirtualBankCont::iterator it(_VirtualBanks.find(_Name));
00233 if (it != _VirtualBanks.end())
00234 {
00235
00236 nlinfo("Loading virtual sample bank %s", CStringMapper::unmap(_Name).c_str());
00237
00238 CAudioMixerUser *mixer = CAudioMixerUser::instance();
00239 const CAudioMixerUser::TBackgroundFlags &flags = mixer->getBackgroundFlags();
00240
00241 for (uint i=0; i<it->second.size(); ++i)
00242 {
00243 if (flags.Flags[it->second[i].Filter])
00244 {
00245 CSampleBank *bank = findSampleBank(it->second[i].BankName);
00246 if (bank)
00247 bank->load(async);
00248 }
00249 }
00250 }
00251
00252 nlinfo("Loading sample bank %s %", CStringMapper::unmap(_Name).c_str(), async?"":"Asynchronously");
00253
00254 vector<string> filenames;
00255
00256
00257 if (_Loaded)
00258 {
00259 nlwarning("Trying to load an already loaded bank : %s", CStringMapper::unmap(_Name).c_str ());
00260 return;
00261 }
00262
00263
00264
00265 string bankName(CStringMapper::unmap(_Name)+".sample_bank");
00266 string filename = CPath::lookup(bankName);
00267 if (filename.empty())
00268 {
00269 nlwarning("Trying to load an unknown sample bank [%s]", bankName.c_str());
00270 return;
00271 }
00272
00273 try
00274 {
00275
00276 CIFile sampleBank(filename);
00277
00278 CAudioMixerUser::TSampleBankHeader sbh;
00279 sampleBank.serial(sbh);
00280 _LoadingDone = false;
00281
00282 sint32 seekStart = sampleBank.getPos();
00283
00284
00285 uint8 *data = 0;
00286 uint i;
00287 for (i=0; i<sbh.Name.size(); ++i)
00288 {
00289 IBuffer *ibuffer = _SoundDriver->createBuffer();
00290 nlassert(ibuffer);
00291
00292 TStringId nameId = CStringMapper::map(CFile::getFilenameWithoutExtension(sbh.Name[i]));
00293 ibuffer->presetName(nameId);
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326 if (CAudioMixerUser::instance()->useAPDCM())
00327 {
00328 data = (uint8*) realloc(data, sbh.SizeAdpcm[i]);
00329 sampleBank.seek(seekStart + sbh.OffsetAdpcm[i], CIFile::begin);
00330 sampleBank.serialBuffer(data, sbh.SizeAdpcm[i]);
00331 _SoundDriver->readRawBuffer(ibuffer, sbh.Name[i], data, sbh.SizeAdpcm[i], Mono16ADPCM, sbh.Freq[i]);
00332 }
00333 else
00334 {
00335 data = (uint8*) realloc(data, sbh.SizeMono16[i]);
00336 sampleBank.seek(seekStart + sbh.OffsetMono16[i], CIFile::begin);
00337 sampleBank.serialBuffer(data, sbh.SizeMono16[i]);
00338 _SoundDriver->readRawBuffer(ibuffer, sbh.Name[i], data, sbh.SizeMono16[i], Mono16, sbh.Freq[i]);
00339 }
00340
00341 _ByteSize += ibuffer->getSize();
00342
00343 _Samples[nameId] = ibuffer;
00344
00345
00346 CSoundBank::instance()->bufferLoaded(nameId, ibuffer);
00347 }
00348 free(data);
00349
00350 _LoadedSize += _ByteSize;
00351 }
00352 catch(Exception &e)
00353 {
00354
00355 nlwarning("Exception %s during loading of sample bank %s", e.what(), filename.c_str());
00356 CAudioMixerUser *mixer = CAudioMixerUser::instance();
00357
00358 if (mixer->getPackedSheetUpdate())
00359 {
00360 nlinfo("Deleting offending sound bank, you need to restart to recreate it!");
00361 CFile::deleteFile(filename);
00362 }
00363 }
00364
00365 _Loaded = true;
00366 _LoadingDone = true;
00367
00368
00369
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460 }
00461
00462 void CSampleBank::onUpdate()
00463 {
00464 if (_SplitLoadDone)
00465 {
00466 nldebug("Some samples have been loaded");
00467 if (_LoadList.empty())
00468 {
00469
00470 TSampleTable::iterator first(_Samples.begin()), last(_Samples.end());
00471 for (; first != last; ++first)
00472 {
00473 _ByteSize += first->second->getSize();
00474 }
00475
00476 _LoadedSize += _ByteSize;
00477
00478
00479 CAudioMixerUser::instance()->unregisterUpdate(this);
00480 _LoadingDone = true;
00481
00482
00483 CAudioMixerUser::instance()->getBackgroundSoundManager()->updateBackgroundStatus();
00484
00485 nlinfo("Sample bank %s loaded.", CStringMapper::unmap(_Name).c_str());
00486 }
00487 else
00488 {
00489 _SplitLoadDone = false;
00490 for (uint i=0; i<ASYNC_LOADING_SPLIT && !_LoadList.empty(); ++i)
00491 {
00492 CAsyncFileManagerSound::getInstance().loadWavFile(_LoadList.front().first, CStringMapper::unmap(_LoadList.front().second)+".wav");
00493 _LoadList.pop_front();
00494 }
00495
00496 CAsyncFileManagerSound::getInstance().signal(&_SplitLoadDone);
00497 }
00498 }
00499 }
00500
00501
00502
00503 bool CSampleBank::unload()
00504 {
00505 vector<IBuffer*> vec;
00506 TSampleTable::iterator it;
00507
00508 if (!_Loaded)
00509 {
00510 nlwarning("Trying to unload an already unloaded bank : %s", CStringMapper::unmap(_Name).c_str ());
00511 return true;
00512 }
00513
00514
00515 if (!_LoadingDone)
00516 return false;
00517
00518 nlinfo("Unloading sample bank %s", CStringMapper::unmap(_Name).c_str());
00519
00520 for (it = _Samples.begin(); it != _Samples.end(); ++it)
00521 {
00522 IBuffer *buffer = it->second;
00523 if (buffer)
00524 {
00525 const NLMISC::TStringId & bufferName = buffer->getName();
00526
00527
00528 CAudioMixerUser::instance()->bufferUnloaded(buffer);
00529
00530 CSoundBank::instance()->bufferUnloaded(bufferName);
00531
00532
00533 it->second = NULL;
00534 delete buffer;
00535 }
00536 }
00537
00538 _Loaded = false;
00539
00540 _LoadedSize -= _ByteSize;
00541 _ByteSize = 0;
00542
00543 return true;
00544 }
00545
00546
00547
00548 bool CSampleBank::isLoaded()
00549 {
00550 return _Loaded;
00551 }
00552
00553
00554
00555 IBuffer* CSampleBank::getSample(const NLMISC::TStringId &name)
00556 {
00557 {
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 }
00572
00573
00574 TSampleTable::iterator iter = _Samples.find(name);
00575 if ( iter == _Samples.end() )
00576 {
00577 return 0;
00578 }
00579 else
00580 {
00581 return (*iter).second;
00582 }
00583 }
00584
00585
00586
00587 uint CSampleBank::countSamples()
00588 {
00589 return _Samples.size();
00590 }
00591
00592
00593
00594 uint CSampleBank::getSize()
00595 {
00596 uint size = 0;
00597
00598 TSampleTable::const_iterator iter;
00599 for (iter = _Samples.begin(); iter != _Samples.end(); iter++)
00600 {
00601 size += (*iter).second->getSize();
00602 }
00603
00604 return size;
00605 }
00606
00607 void CSampleBank::releaseAll()
00608 {
00609 nldebug( "SampleBanks: Releasing..." );
00610
00611 while (!_Banks.empty())
00612 {
00613 delete _Banks.begin()->second;
00614 }
00615 nldebug( "SampleBanks: Released" );
00616 }
00617
00618
00619
00620 }
00621