Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / sound / sound_bank.cpp
blob38088b6daea5381bde5a8d2dcd8cc6768d13dbbc
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Matt RAYKOWSKI (sfb) <matt.raykowski@gmail.com>
6 // Copyright (C) 2012-2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 //
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "stdsound.h"
23 #include "nel/sound/sound_bank.h"
24 #include "nel/sound/simple_sound.h"
25 #include "nel/sound/complex_sound.h"
26 #include "nel/sound/context_sound.h"
27 #include "nel/sound/background_sound.h"
28 #include "nel/sound/music_sound.h"
29 #include "nel/sound/stream_sound.h"
30 #include "nel/sound/stream_file_sound.h"
32 #include "nel/georges/u_form_loader.h"
33 #include "nel/georges/u_form_elm.h"
34 #include "nel/georges/u_form.h"
35 #include "nel/misc/path.h"
36 #include "nel/sound/driver/buffer.h"
38 #include "nel/georges/load_form.h"
40 #ifdef DEBUG_NEW
41 #define new DEBUG_NEW
42 #endif
44 using namespace std;
45 using namespace NLMISC;
46 using namespace NLGEORGES;
49 namespace NLSOUND {
51 void CSoundBank::bufferUnloaded(const NLMISC::TStringId &bufferName)
53 TBufferAssocContainer::iterator it(_BufferAssoc.find(bufferName));
55 if (it != _BufferAssoc.end())
57 // ok, found some sound associated with this buffer.
58 // update all sounds.
59 TSimpleSoundContainer::iterator first(it->second.begin()), last(it->second.end());
60 for (; first != last; ++first)
62 // remove the associated buffer.
63 CSimpleSound *ss = const_cast<CSimpleSound*>(*(first));
64 ss->setBuffer(NULL);
69 //void CSoundBank::bufferLoaded(const std::string bufferName, IBuffer *buffer)
70 void CSoundBank::bufferLoaded(const NLMISC::TStringId &/* bufferName */, IBuffer *buffer)
72 // std::map<std::string, std::vector<TBufferAssoc> >::iterator it(_BufferAssoc.find(buffer->getName()));
73 TBufferAssocContainer::iterator it(_BufferAssoc.find(buffer->getName()));
75 if (it != _BufferAssoc.end())
77 // ok, found some sound associated with this buffer.
78 // update all sounds.
79 TSimpleSoundContainer::iterator first(it->second.begin()), last(it->second.end());
80 for (; first != last; ++first)
82 CSimpleSound *ss = const_cast<CSimpleSound*>(*(it->second.begin()));
83 // restore the associated buffer.
84 ss->setBuffer(buffer);
90 void CSoundBank::registerBufferAssoc(CSimpleSound *sound, IBuffer *buffer)
92 if (buffer != NULL)
94 const NLMISC::TStringId &bufferName = buffer->getName();
95 _BufferAssoc[bufferName].insert(sound);
99 void CSoundBank::unregisterBufferAssoc(CSimpleSound *sound, IBuffer * buffer)
101 if (buffer != NULL)
103 const TStringId &bufferName = buffer->getName();
104 TBufferAssocContainer::iterator it(_BufferAssoc.find(bufferName));
106 if (it != _BufferAssoc.end())
108 TSimpleSoundContainer::iterator it2(it->second.find(sound));
110 nlassert(it2 != it->second.end());
111 it->second.erase(it2);
113 if (it->second.empty())
115 // last sound refenrecing this buffer
116 _BufferAssoc.erase(it);
125 * Destructor
127 CSoundBank::~CSoundBank()
129 unload();
132 void CSoundBank::addSound(CSound *sound)
134 std::pair<TSoundTable::iterator, bool> ret;
135 ret = _Sounds.insert(make_pair(sound->getName(), sound));
136 nlassert(ret.second);
139 void CSoundBank::removeSound(const NLMISC::TStringId &name)
141 _Sounds.erase(name);
145 /** Pseudo serializer for packed sheet loading/saving.
146 * This class act as a wrapper to create sound from
147 * xml document being read, call the serialisation method
148 * to read/write packed sheet and to delete sounds that are
149 * no more needed.
151 class CSoundSerializer
153 public:
154 /// The sound beeing managed by this serializer.
155 CSound *Sound;
157 /// Default constructor.
158 CSoundSerializer()
159 : Sound(0)
162 // load the values using the george sheet (called by GEORGE::loadForm)
163 void readGeorges (const NLMISC::CSmartPtr<NLGEORGES::UForm> &form, const std::string &name)
165 // just call the sound creation method with the xml form.
166 Sound = CSound::createSound(name, form->getRootNode());
168 // success ?
169 // if (_Sound != 0)
170 // CSoundBank::instance()->addSound(_Sound);
173 // load/save the values using the serial system (called by GEORGE::loadForm)
174 void serial (NLMISC::IStream &s)
176 if (s.isReading())
178 // read the first item to find the type
179 CSound::TSOUND_TYPE type = CSound::SOUND_SIMPLE;
180 s.serialEnum(type);
181 // read the sound name
182 // std::string name;
183 // s.serial(name);
185 // Instantiate the corresponding sound.
186 switch(CSound::TSOUND_TYPE(type))
188 case CSound::SOUND_SIMPLE:
189 Sound = new CSimpleSound();
190 break;
191 case CSound::SOUND_COMPLEX:
192 Sound = new CComplexSound();
193 break;
194 case CSound::SOUND_CONTEXT:
195 Sound = new CContextSound();
196 break;
197 case CSound::SOUND_BACKGROUND:
198 Sound = new CBackgroundSound();
199 break;
200 case CSound::SOUND_MUSIC:
201 Sound = new CMusicSound();
202 break;
203 case CSound::SOUND_STREAM:
204 Sound = new CStreamSound();
205 break;
206 case CSound::SOUND_STREAM_FILE:
207 Sound = new CStreamFileSound();
208 break;
209 default:
210 Sound = 0;
213 // nlassert(_Sound != 0);
214 if (Sound)
216 // read the sound data
217 Sound->serial(s);
218 // CSoundBank::instance()->addSound(_Sound);
221 else
223 if (Sound == 0)
225 // the sound doesn't exist
226 uint32 i = std::numeric_limits<uint32>::max();
227 s.serialEnum(i);
228 // s.serial(std::string("bad sound"));
230 else
232 // write the sound type.
233 CSound::TSOUND_TYPE type = Sound->getSoundType();
234 s.serialEnum(type);
235 // write the sound name
236 // s.serial(const_cast<std::string&>(_Sound->getName()));
238 // and write the sound data
239 Sound->serial(s);
244 /** called by GEORGE::loadForm when a sheet read from the packed sheet is no more in
245 * the directories.
247 void removed()
249 if (Sound != 0)
251 // we remove the sound from the bank and delete it.
252 // CSoundBank::instance()->removeSound(_Sound->getName());
253 delete Sound;
257 // return the version of this class, increments this value when the content of this class changed
258 static uint getVersion () { return 3; }
262 /** Load all the sound samples.
264 * Can throw EPathNotFound or ESoundFileNotFound (check Exception)
266 void CSoundBank::load(const std::string &packedSheetDir, bool packedSheetUpdate)
268 // this structure is fill by the loadForm() function and will contain all you need
269 std::map<std::string, CSoundSerializer> Container;
270 nlassert(!_Loaded);
271 // Just call the GEORGE::loadFrom method to read all available sounds
272 ::loadForm("sound", packedSheetDir + "sounds.packed_sheets", Container, packedSheetUpdate, false);
273 _Loaded = true;
275 // add all the loaded sound in the sound banks
276 std::map<std::string, CSoundSerializer>::iterator first(Container.begin()), last(Container.end());
277 for (; first != last; ++first)
279 if (first->second.Sound != 0)
280 addSound(first->second.Sound);
283 Container.clear();
288 * Unload all the sound samples in this bank.
290 void CSoundBank::unload()
292 nlassert(_Loaded);
294 TSoundTable::iterator first(_Sounds.begin()), last(_Sounds.end());
295 for (; first != last; ++first)
297 delete first->second;
300 _Sounds.clear();
301 _Loaded = false;
303 /* vector<CSound*> vec;
306 TSoundTable::iterator map_iter;
308 for (map_iter = _Sounds.begin(); map_iter != _Sounds.end(); ++map_iter)
310 // We can't delete directly second because the map is based on second->getName()
311 vec.push_back( (*map_iter).second );
314 _Sounds.clear();
316 vector<CSound*>::iterator vec_iter;
318 for (vec_iter = vec.begin(); vec_iter != vec.end(); ++vec_iter)
320 CSound *sound = *vec_iter;
321 delete sound;
324 _Loaded = false;
329 * Returns true if the samples in this bank have been loaded.
331 bool CSoundBank::isLoaded()
333 return _Loaded;
337 * Return a sound sample corresponding to a name.
339 CSound* CSoundBank::getSound(const NLMISC::TStringId &name)
341 // Find sound
342 TSoundTable::iterator iter = _Sounds.find(name);
343 if ( iter == _Sounds.end() )
345 return 0;
347 else
349 return (*iter).second;
354 * Return the names of the sounds
356 void CSoundBank::getNames( std::vector<NLMISC::TStringId> &names )
358 TSoundTable::const_iterator iter;
359 for (iter = _Sounds.begin(); iter != _Sounds.end(); ++iter)
361 names.push_back((*iter).first);
362 //nlwarning("getting sound %s", (*iter).first);
367 * Return the number of buffers in this bank.
369 uint CSoundBank::countSounds()
371 return (uint)_Sounds.size();
375 } // namespace NLSOUND