1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/sound/sample_bank.h"
23 #include "nel/sound/sample_bank_manager.h"
24 #include "nel/sound/driver/sound_driver.h"
25 #include "nel/sound/driver/buffer.h"
26 #include "nel/misc/path.h"
27 #include "nel/misc/file.h"
28 #include "nel/sound/async_file_manager_sound.h"
29 #include "nel/sound/background_sound_manager.h"
30 #include "nel/sound/sound_bank.h"
34 using namespace NLMISC
;
39 /// Constante for the number of file to load asynchronously at a time.
40 uint32 ASYNC_LOADING_SPLIT
= 10; // 10 file by 10 file
43 // ********************************************************
45 CSampleBank::CSampleBank(NLMISC::TStringId name
, CSampleBankManager
*sampleBankManager
)
46 : _SampleBankManager(sampleBankManager
), _Name(name
), _Loaded(false), _LoadingDone(true), _ByteSize(0)
48 _SampleBankManager
->m_Banks
.insert(make_pair(name
, this));
52 // ********************************************************
54 CSampleBank::~CSampleBank()
56 _SampleBankManager
->m_AudioMixer
->unregisterUpdate(this);
59 // need to wait for loading end.
66 // remove the bank from the list of known banks
67 for (CSampleBankManager::TSampleBankContainer::iterator
68 it(_SampleBankManager
->m_Banks
.begin()),
69 end(_SampleBankManager
->m_Banks
.end()); it
!= end
; ++it
)
71 if (it
->second
== this)
73 _SampleBankManager
->m_Banks
.erase(it
);
79 // delete all the samples.
80 while (!_Samples
.empty())
82 delete _Samples
.begin()->second
;
83 _Samples
.erase(_Samples
.begin());
90 // ********************************************************
92 void CSampleBank::load(bool async
)
94 // TODO : add async loading support !
96 CSampleBankManager::TVirtualBankCont::iterator
it(_SampleBankManager
->m_VirtualBanks
.find(_Name
));
97 if (it
!= _SampleBankManager
->m_VirtualBanks
.end())
99 // this is a virtual sample bank !
100 nlinfo("Loading virtual sample bank %s", CStringMapper::unmap(_Name
).c_str());
102 const CAudioMixerUser::TBackgroundFlags
&flags
= _SampleBankManager
->m_AudioMixer
->getBackgroundFlags();
104 for (uint i
=0; i
<it
->second
.size(); ++i
)
106 if (flags
.Flags
[it
->second
[i
].Filter
])
108 CSampleBank
*bank
= _SampleBankManager
->findSampleBank(it
->second
[i
].BankName
);
115 //nlinfo("Loading sample bank %s %", CStringMapper::unmap(_Name).c_str(), async?"":"Asynchronously");
117 vector
<string
> filenames
;
118 // vector<string>::iterator iter;
122 nlwarning("Trying to load an already loaded bank : %s", CStringMapper::unmap(_Name
).c_str ());
127 // Load the sample bank from the builded sample_bank file.
128 string
bankName(CStringMapper::unmap(_Name
)+".sample_bank");
129 string filename
= CPath::lookup(bankName
, false);
130 if (filename
.empty())
132 nlwarning("Could not find sample bank [%s]", bankName
.c_str());
139 CIFile
sampleBank(filename
);
141 CAudioMixerUser::TSampleBankHeader sbh
;
142 sampleBank
.serial(sbh
);
143 _LoadingDone
= false;
145 sint32 seekStart
= sampleBank
.getPos();
150 for (i
=0; i
<sbh
.Name
.size(); ++i
)
152 IBuffer
*ibuffer
= _SampleBankManager
->m_AudioMixer
->getSoundDriver()->createBuffer();
155 TStringId nameId
= CStringMapper::map(CFile::getFilenameWithoutExtension(sbh
.Name
[i
]));
156 ibuffer
->setName(nameId
);
159 sint16 *data16 = new sint16[sbh.NbSample[i]];
160 IBuffer::TADPCMState state;
161 state.PreviousSample = 0;
164 for (count=0; count+1024<sbh.NbSample[i]; count+=1024)
166 IBuffer::decodeADPCM(data+count/2, data16+count, 1024, state);
168 IBuffer::decodeADPCM(data+count/2, data16+count, sbh.NbSample[i]-count, state);
170 state.PreviousSample = 0;
172 sint16 *data16_2 = new sint16[sbh.NbSample[i]];
173 IBuffer::decodeADPCM(data, data16_2, sbh.NbSample[i], state);
175 for (uint j=0; j<sbh.NbSample[i]; ++j)
177 if (data16[j] != data16_2[j])
179 nlwarning("Sample differ at %u", j);
183 _SoundDriver->readRawBuffer(ibuffer, sbh.Name[i], (uint8*)data16, sbh.NbSample[i]*2, Mono16, sbh.Freq[i]);
189 if (_SampleBankManager
->m_AudioMixer
->useAPDCM())
191 data
= (uint8
*) realloc(data
, sbh
.SizeAdpcm
[i
]);
192 sampleBank
.seek(seekStart
+ sbh
.OffsetAdpcm
[i
], CIFile::begin
);
193 sampleBank
.serialBuffer(data
, sbh
.SizeAdpcm
[i
]);
194 ibuffer
->setFormat(IBuffer::FormatDviAdpcm
, 1, 16, sbh
.Freq
[i
]);
195 if (!ibuffer
->fill(data
, sbh
.SizeAdpcm
[i
]))
196 nlwarning("AM: ibuffer->fill returned false with FormatADPCM");
200 data
= (uint8
*) realloc(data
, sbh
.SizeMono16
[i
]);
201 sampleBank
.seek(seekStart
+ sbh
.OffsetMono16
[i
], CIFile::begin
);
202 sampleBank
.serialBuffer(data
, sbh
.SizeMono16
[i
]);
203 ibuffer
->setFormat(IBuffer::FormatPcm
, 1, 16, sbh
.Freq
[i
]);
204 if (!ibuffer
->fill(data
, sbh
.SizeMono16
[i
]))
205 nlwarning("AM: ibuffer->fill returned false with FormatPCM");
208 _ByteSize
+= ibuffer
->getSize();
210 _Samples
[nameId
] = ibuffer
;
212 // Warn the sound bank that the sample are available.
213 CAudioMixerUser::getInstance()->getSoundBank()->bufferLoaded(nameId
, ibuffer
);
217 _SampleBankManager
->m_LoadedSize
+= _ByteSize
;
219 catch(const Exception
&e
)
222 nlwarning("Exception %s during loading of sample bank %s", e
.what(), filename
.c_str());
224 if (_SampleBankManager
->m_AudioMixer
->getPackedSheetUpdate())
226 nlinfo("Deleting offending sound bank, you need to restart to recreate it!");
227 CFile::deleteFile(filename
);
236 ///////////////////////////////////////// OLD Version //////////////////////////////////////
239 std::string list = CPath::lookup(CStringMapper::unmap(_Name)+CAudioMixerUser::SampleBankListExt, false);
242 nlwarning("File %s not found to load sample bank %s", (CStringMapper::unmap(_Name)+CAudioMixerUser::SampleBankListExt).c_str(), CStringMapper::unmap(_Name).c_str());
247 NLMISC::CIFile sampleBankList(list);
248 sampleBankList.serialCont(filenames);
250 for (iter = filenames.begin(); iter != filenames.end(); iter++)
252 IBuffer* ibuffer = NULL;
255 ibuffer = _SoundDriver->createBuffer();
258 // std::string sampleName(CFile::getFilenameWithoutExtension(*iter));
259 NLMISC::TStringId sampleName(CStringMapper::map(CFile::getFilenameWithoutExtension(*iter)));
263 ibuffer->presetName(sampleName);
264 nldebug("Preloading sample [%s]", CStringMapper::unmap(sampleName).c_str());
268 std::string fullName = NLMISC::CPath::lookup(*iter, false);
269 if (!fullName.empty())
271 NLMISC::CIFile ifile(fullName);
272 uint size = ifile.getFileSize();
273 uint8 *buffer = new uint8[ifile.getFileSize()];
274 ifile.serialBuffer(buffer, size);
276 _SoundDriver->readWavBuffer(ibuffer, fullName, buffer, size);
277 _ByteSize += ibuffer->getSize();
282 _Samples[sampleName] = ibuffer ;
284 // Warn the sound bank that the sample are available.
285 CSoundBank::instance()->bufferLoaded(sampleName, ibuffer);
287 catch (const ESoundDriver &e)
289 if (ibuffer != NULL) {
293 nlwarning("Problem with file '%s': %s", (*iter).c_str(), e.what());
302 // compute the sample bank size.
303 _LoadedSize += _ByteSize;
307 // fill the loading list.
308 TSampleTable::iterator first(_Samples.begin()), last(_Samples.end());
309 for (; first != last; ++first)
311 _LoadList.push_back(make_pair(first->second, first->first));
313 _SplitLoadDone = false;
314 // send the first files
315 for (uint i=0; i<ASYNC_LOADING_SPLIT && !_LoadList.empty(); ++i)
317 CAsyncFileManagerSound::getInstance().loadWavFile(_LoadList.front().first, CStringMapper::unmap(_LoadList.front().second)+".wav");
318 _LoadList.pop_front();
320 // add a end loading event...
321 CAsyncFileManagerSound::getInstance().signal(&_SplitLoadDone);
322 // and register for update on the mixer
323 CAudioMixerUser::instance()->registerUpdate(this);
328 void CSampleBank::onUpdate()
332 nldebug("Some samples have been loaded");
333 if (_LoadList
.empty())
335 // all the samples are loaded, we can compute the bank size.
336 TSampleTable::iterator
first(_Samples
.begin()), last(_Samples
.end());
337 for (; first
!= last
; ++first
)
339 _ByteSize
+= first
->second
->getSize();
342 _SampleBankManager
->m_LoadedSize
+= _ByteSize
;
345 _SampleBankManager
->m_AudioMixer
->unregisterUpdate(this);
348 // Force an update in the background manager (can restar stopped sound).
349 _SampleBankManager
->m_AudioMixer
->getBackgroundSoundManager()->updateBackgroundStatus();
351 nlinfo("Sample bank %s loaded.", CStringMapper::unmap(_Name
).c_str());
355 _SplitLoadDone
= false;
356 for (uint i
=0; i
<ASYNC_LOADING_SPLIT
&& !_LoadList
.empty(); ++i
)
358 CAsyncFileManagerSound::getInstance().loadWavFile(_LoadList
.front().first
, CStringMapper::unmap(_LoadList
.front().second
)+".wav");
359 _LoadList
.pop_front();
361 // add a end loading event...
362 CAsyncFileManagerSound::getInstance().signal(&_SplitLoadDone
);
367 // ********************************************************
369 bool CSampleBank::unload()
371 vector
<IBuffer
*> vec
;
372 TSampleTable::iterator it
;
376 nlwarning("Trying to unload an already unloaded bank : %s", CStringMapper::unmap(_Name
).c_str ());
380 // need to wait end of load ?
384 //nlinfo("Unloading sample bank %s", CStringMapper::unmap(_Name).c_str());
386 for (it
= _Samples
.begin(); it
!= _Samples
.end(); ++it
)
388 IBuffer
*buffer
= it
->second
;
391 const NLMISC::TStringId
& bufferName
= buffer
->getName();
393 CAudioMixerUser
*audioMixer
= _SampleBankManager
->m_AudioMixer
;
394 // Warn the mixer to stop any track playing this buffer.
395 audioMixer
->bufferUnloaded(buffer
);
397 // Warn the sound banks about this buffer.
398 audioMixer
->getSoundBank()->bufferUnloaded(bufferName
);
408 _SampleBankManager
->m_LoadedSize
-= _ByteSize
;
414 // ********************************************************
416 bool CSampleBank::isLoaded()
421 // ********************************************************
423 IBuffer
* CSampleBank::getSample(const NLMISC::TStringId
&name
)
426 /* // dump the sample list.
427 TSampleTable::iterator it (_Samples.begin()), last(_Samples.end());
430 // while (first != last)
431 for (it = _Samples.begin(); it != _Samples.end(); ++it)
433 s += std::string(" [")+it->first+"] ";
437 nldebug("getSample(%s) : sample list = [%s]", name, s.c_str());
442 TSampleTable::iterator iter
= _Samples
.find(name
);
443 if ( iter
== _Samples
.end() )
449 return (*iter
).second
;
453 // ********************************************************
455 uint
CSampleBank::countSamples()
457 return (uint
)_Samples
.size();
460 // ********************************************************
462 uint
CSampleBank::getSize()
466 TSampleTable::const_iterator iter
;
467 for (iter
= _Samples
.begin(); iter
!= _Samples
.end(); iter
++)
469 size
+= (*iter
).second
->getSize();
477 } // namespace NLSOUND