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