2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r19323...
[blender.git] / intern / SoundSystem / intern / SND_Scene.cpp
1 /*
2 * SND_Scene.cpp
3 *
4 * The scene for sounds.
5 *
6 * $Id$
7 *
8  * ***** BEGIN GPL LICENSE BLOCK *****
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  *
24  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
25  * All rights reserved.
26  *
27  * The Original Code is: all of this file.
28  *
29  * Contributor(s): none yet.
30  *
31  * ***** END GPL LICENSE BLOCK *****
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #ifdef WIN32
39 #pragma warning (disable:4786) // Get rid of stupid stl-visual compiler debug warning
40 #endif //WIN32
41
42 #include "SND_Scene.h"
43 #include "SND_DependKludge.h"
44 #include "SND_IAudioDevice.h"
45
46 #include <stdlib.h>
47 #include <iostream>
48
49 //static unsigned int tijd = 0;
50
51 SND_Scene::SND_Scene(SND_IAudioDevice* audiodevice)
52                                          : m_audiodevice(audiodevice)
53 {
54         if (m_audiodevice)
55                 m_wavecache = m_audiodevice->GetWaveCache();
56
57         if (!m_wavecache || !audiodevice)
58         {
59                 m_audio = false;
60         }
61         else
62         {
63                 //if so, go ahead!
64                 m_audio = true;
65 #ifdef ONTKEVER
66                 printf("SND_Scene::SND_Scene() m_audio == true\n");
67 #endif
68                 m_audiodevice->InitListener();
69         }
70
71         IsPlaybackWanted();
72 }
73
74
75
76 SND_Scene::~SND_Scene()
77 {
78         StopAllObjects();
79 }
80
81
82
83 // check if audioplayback is wanted
84 bool SND_Scene::IsPlaybackWanted()
85 {
86     /* Removed the functionality for checking if noaudio was provided on */
87     /* the commandline. */
88         if (m_audiodevice && m_wavecache)
89         {
90                 m_audioplayback = true;
91         }
92         else
93         {
94                 StopAllObjects();
95                 m_audioplayback = false;
96         }
97
98         return m_audioplayback;
99 }
100
101
102
103 int SND_Scene::LoadSample(const STR_String& samplename,
104                                                    void* memlocation,
105                                                    int size)
106 {
107         int result = -1;
108
109         if (m_audiodevice)
110         {
111                 SND_WaveSlot* waveslot = m_audiodevice->LoadSample(samplename, memlocation, size);
112
113                 if (waveslot)
114                         result = waveslot->GetBuffer();
115         }
116
117         return result;
118 }
119
120
121
122 void SND_Scene::RemoveAllSamples()
123 {
124         if (m_audio && m_audiodevice)
125                 m_audiodevice->RemoveAllSamples();
126 }
127
128
129
130 bool SND_Scene::CheckBuffer(SND_SoundObject* pObject)
131 {
132         bool result = false;
133
134         if (pObject && m_wavecache)
135         {
136                 SND_WaveSlot* waveslot = m_wavecache->GetWaveSlot(pObject->GetSampleName());
137                 
138                 if (waveslot)
139                 {
140                         pObject->SetBuffer(waveslot->GetBuffer());
141
142                         result = true;
143                 }
144         }
145
146         return result;
147 }
148
149
150
151 bool SND_Scene::IsSampleLoaded(STR_String& samplename)
152 {
153         bool result = false;
154
155         if (samplename && m_wavecache)
156         {
157                 SND_WaveSlot* waveslot = m_wavecache->GetWaveSlot(samplename);
158
159                 if (waveslot && waveslot->IsLoaded())
160                         result = true;
161         }
162
163         return result;
164 }
165
166
167
168 void SND_Scene::AddObject(SND_SoundObject* pObject)
169 {
170         if (m_audio)
171         {
172                 STR_String samplename = pObject->GetSampleName();
173                 SND_WaveSlot* slot = NULL;
174                 
175                 // don't add the object if no valid sample is referenced
176                 if (samplename != "")
177                 {       
178                         // check if the sample is already loaded
179                         slot = m_wavecache->GetWaveSlot(samplename);
180                 }
181                 
182                 if (slot)
183                 {
184                         pObject->SetBuffer(slot->GetBuffer());
185                         
186                         // needed for expected lifespan of the sample, but ain't necesary anymore i think
187                         MT_Scalar samplelength = slot->GetNumberOfSamples();
188                         MT_Scalar samplerate = slot->GetSampleRate();
189                         MT_Scalar soundlength = samplelength/samplerate;
190                         pObject->SetLength(soundlength);
191                         
192                         // add the object to the list
193                         m_soundobjects.insert((SND_SoundObject*)pObject);
194                 }
195         }
196 }
197
198
199
200 void SND_Scene::SetListenerTransform(const MT_Vector3& pos,
201                                                                          const MT_Vector3& vel,
202                                                                          const MT_Matrix3x3& ori)
203 {
204         if (m_audio)
205         {
206                 GetListener()->SetPosition(pos);
207                 GetListener()->SetVelocity(vel);
208                 GetListener()->SetOrientation(ori);
209         }
210 }
211
212
213
214 void SND_Scene::UpdateListener()
215 {
216         // process the listener if modified
217         if (m_listener.IsModified())
218         {
219                 m_audiodevice->SetListenerGain(m_listener.GetGain());
220                 m_audiodevice->SetDopplerVelocity(m_listener.GetDopplerVelocity());
221                 m_audiodevice->SetDopplerFactor(m_listener.GetDopplerFactor());
222                 m_listener.SetModified(false);
223         }
224 }
225
226
227
228 void SND_Scene::AddActiveObject(SND_SoundObject* pObject, MT_Scalar curtime)
229 {
230         if (m_audio)
231         {
232                 if (pObject)
233                 {
234 #ifdef ONTKEVER
235                         printf("SND_Scene::AddActiveObject\n");
236 #endif
237                         
238                         // first check if the object is already on the list
239                         if (pObject->IsActive())
240                         {
241                                 pObject->SetTimeStamp(curtime);
242                                 pObject->StartSound();
243                         }
244                         else
245                         {       
246                                 pObject->SetTimeStamp(curtime);
247                                 
248                                 // compute the expected lifespan
249                                 pObject->SetLifeSpan();
250                                 
251                                 // lets give the new active-to-be object an id
252                                 if (m_audiodevice->GetNewId(pObject))
253                                 {
254                                         // and add the object
255                                         m_activeobjects.addTail(pObject);
256                                         pObject->StartSound();
257                                         pObject->SetActive(true);
258                                 }
259                         }
260                 }
261         }
262 }
263
264
265
266 void SND_Scene::RemoveActiveObject(SND_SoundObject* pObject)
267 {
268         if (m_audio)
269         {
270                 if (pObject)
271                 {
272 #ifdef ONTKEVER
273                         printf("SND_Scene::RemoveActiveObject\n");
274 #endif
275                         // if inactive, remove it from the list
276                         if (pObject->IsActive())
277                         {       
278                                 // first make sure it is stopped
279                                 m_audiodevice->ClearId(pObject);
280                         }
281                 }
282         }
283 }
284
285
286
287 void SND_Scene::UpdateActiveObects()
288 {
289 //      ++tijd;
290
291         SND_SoundObject* pObject;
292         // update only the objects that need to be updated
293         for (pObject = (SND_SoundObject*)m_activeobjects.getHead();
294                                         !pObject->isTail();
295                                         pObject = (SND_SoundObject*)pObject->getNext())
296         {
297                 int id = pObject->GetId();
298                 
299                 if (id >= 0)
300                 {
301                         if (pObject->Is3D())
302                         {
303                                 // Get the global positions and velocity vectors
304                                 // of the listener and soundobject
305                                 MT_Vector3 op = pObject->GetPosition();
306                                 MT_Vector3 lp = m_listener.GetPosition();
307                                 MT_Vector3 position = op - lp;
308                                 
309                                 // Calculate relative velocity in global coordinates
310                                 // of the sound with respect to the listener.
311                                 MT_Vector3 ov = pObject->GetVelocity();
312                                 MT_Vector3 lv = m_listener.GetVelocity();
313                                 MT_Vector3 velocity = ov - lv;
314                                 
315                                 // Now map the object position and velocity into 
316                                 // the local coordinates of the listener.
317                                 MT_Matrix3x3 lo = m_listener.GetOrientation();
318                                 
319                                 MT_Vector3 local_sound_pos = position * lo;
320                                 MT_Vector3 local_sound_vel = velocity * lo;
321                                 
322                                 m_audiodevice->SetObjectTransform(
323                                         id,
324                                         local_sound_pos,
325                                         local_sound_vel,
326                                         pObject->GetOrientation(), // make relative to listener! 
327                                         lp,
328                                         pObject->GetRollOffFactor());
329                         }
330                         else
331                         {
332                                 m_audiodevice->ObjectIs2D(id);
333                         }
334                         
335                         // update the situation
336                         if (pObject->IsModified())
337                         {
338                                 m_audiodevice->SetObjectPitch(id, pObject->GetPitch());
339                                 m_audiodevice->SetObjectGain(id, pObject->GetGain());
340                                 m_audiodevice->SetObjectMinGain(id, pObject->GetMinGain());
341                                 m_audiodevice->SetObjectMaxGain(id, pObject->GetMaxGain());
342                                 m_audiodevice->SetObjectReferenceDistance(id, pObject->GetReferenceDistance());
343                                 m_audiodevice->SetObjectRollOffFactor(id, pObject->GetRollOffFactor());
344                                 m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode());
345                                 m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd());
346                                 pObject->SetModified(false);
347                         }
348
349                         pObject->AddRunning();
350
351 #ifdef ONTKEVER                         
352                         STR_String naam = pObject->GetObjectName();
353                         STR_String sample = pObject->GetSampleName();
354                         
355                         int id = pObject->GetId();
356                         int buffer = pObject->GetBuffer();
357                         
358                         float gain = pObject->GetGain();
359                         float pitch = pObject->GetPitch();
360                         float timestamp = pObject->GetTimestamp();
361                         
362                         printf("naam: %s, sample: %s \n", naam.Ptr(), sample.Ptr());
363                         printf("id: %d, buffer: %d \n", id, buffer);
364                         printf("gain: %f, pitch: %f, ts: %f \n\n", gain, pitch, timestamp);
365 #endif
366 #ifdef USE_OPENAL
367                         // ok, properties Set. now see if it must play
368                         switch (pObject->GetPlaystate()){
369                         case SND_MUST_PLAY:
370                                 m_audiodevice->PlayObject(id);
371                                 pObject->SetPlaystate(SND_PLAYING);
372                                 break;
373                         case SND_MUST_STOP:
374                                 RemoveActiveObject(pObject);
375                                 break;
376                         case SND_MUST_PAUSE:
377                                 m_audiodevice->PauseObject(id);
378                                 pObject->SetPlaystate(SND_PAUSED);
379                                 break;
380                         }
381 #endif
382
383                         // check to see if the sound is still playing
384                         // if not: release its id
385                         int playstate = m_audiodevice->GetPlayState(id);
386 #ifdef ONTKEVER
387                         if (playstate != 2)
388                                 printf("%d - ",playstate);
389 #endif
390
391                         if ((playstate == SND_STOPPED) && !pObject->GetLoopMode())
392                         {
393                                 RemoveActiveObject(pObject);
394                         }
395                 }
396         }
397 }
398
399
400
401 void SND_Scene::UpdateCD()
402 {
403         if (m_audiodevice)
404         {
405                 SND_CDObject* pCD = SND_CDObject::Instance();
406
407                 if (pCD)
408                 {
409                         int playstate = pCD->GetPlaystate();
410                         
411                         switch (playstate)
412                         {
413                         case SND_MUST_PLAY:
414                                 {
415                                         // initialize the cd only when you need it
416                                         m_audiodevice->SetCDGain(pCD->GetGain());
417                                         m_audiodevice->SetCDPlaymode(pCD->GetPlaymode());
418                                         m_audiodevice->PlayCD(pCD->GetTrack());
419                                         pCD->SetPlaystate(SND_PLAYING);
420                                         pCD->SetUsed();
421                                         break;
422                                 }
423                         case SND_MUST_PAUSE:
424                                 {
425                                         m_audiodevice->PauseCD(true);
426                                         pCD->SetPlaystate(SND_PAUSED);
427                                         break;
428                                 }
429                         case SND_MUST_RESUME:
430                                 {
431                                         m_audiodevice->PauseCD(false);
432                                         pCD->SetPlaystate(SND_PLAYING);
433                                         break;
434                                 }
435                         case SND_MUST_STOP:
436                                 {
437                                         m_audiodevice->StopCD();
438                                         pCD->SetPlaystate(SND_STOPPED);
439                                         break;
440                                 }
441                         default:
442                                 {
443                                 }
444                         }
445                         
446                         // this one is only for realtime modifying settings
447                         if (pCD->IsModified())
448                         {
449                                 m_audiodevice->SetCDGain(pCD->GetGain());
450                                 pCD->SetModified(false);
451                         }
452                 }
453         }
454 }
455
456
457
458 void SND_Scene::Proceed()
459 {
460         if (m_audio && m_audioplayback)
461         {
462                 m_audiodevice->MakeCurrent();
463
464                 UpdateListener();
465                 UpdateActiveObects();
466                 UpdateCD();
467
468 //              m_audiodevice->UpdateDevice();
469         }
470 }
471
472
473 void SND_Scene::DeleteObject(SND_SoundObject* pObject) 
474 {
475 #ifdef ONTKEVER
476         printf("SND_Scene::DeleteObject\n");
477 #endif
478         
479         if (pObject)
480         {
481                 if (m_audiodevice)
482                         m_audiodevice->ClearId(pObject);
483                 
484                 // must remove object from m_activeList
485                 std::set<SND_SoundObject*>::iterator set_it;
486                 set_it = m_soundobjects.find(pObject);
487                 
488                 if (set_it != m_soundobjects.end())
489                         m_soundobjects.erase(set_it);
490                 
491                 // release the memory
492                 delete pObject;
493                 pObject = NULL;
494         }
495 }
496
497
498
499 void SND_Scene::RemoveAllObjects()
500 {
501 #ifdef ONTKEVER
502         printf("SND_Scene::RemoveAllObjects\n");
503 #endif
504
505         StopAllObjects();
506
507         std::set<SND_SoundObject*>::iterator it = m_soundobjects.begin();
508
509         while (it != m_soundobjects.end())
510         {
511                 delete (*it);
512                 it++;
513         }
514
515         m_soundobjects.clear();
516 }
517
518
519
520 void SND_Scene::StopAllObjects()
521 {
522         if (m_audio)
523         {
524 #ifdef ONTKEVER
525                 printf("SND_Scene::StopAllObjects\n");
526 #endif
527                 
528                 SND_SoundObject* pObject;
529                 
530                 for (pObject = (SND_SoundObject*)m_activeobjects.getHead();
531                 !pObject->isTail();
532                 pObject = (SND_SoundObject*)pObject->getNext())
533                 {
534                         m_audiodevice->ClearId(pObject);
535                 }
536         }
537 }
538
539
540
541 SND_SoundListener* SND_Scene::GetListener()
542 {
543         return &m_listener;
544 }