Bunch of small fixes for warnings and whatnot....
[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 #ifdef USE_FMOD
311                         // fmod wants these set before playing the sample
312                         if (pObject->IsModified())
313                         {
314                                 m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode());
315                                 m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd());
316                         }
317
318                         // ok, properties Set. now see if it must play
319                         if (pObject->GetPlaystate() == SND_MUST_PLAY)
320                         {
321                                 m_audiodevice->PlayObject(id);
322                                 pObject->SetPlaystate(SND_PLAYING);
323                                 pObject->InitRunning();
324 //                              printf("start play: %d\n", tijd);
325                         }
326 #endif
327                         if (pObject->Is3D())
328                         {
329                                 // Get the global positions and velocity vectors
330                                 // of the listener and soundobject
331                                 MT_Vector3 op = pObject->GetPosition();
332                                 MT_Vector3 lp = m_listener.GetPosition();
333                                 MT_Vector3 position = op - lp;
334                                 
335                                 // Calculate relative velocity in global coordinates
336                                 // of the sound with respect to the listener.
337                                 MT_Vector3 ov = pObject->GetVelocity();
338                                 MT_Vector3 lv = m_listener.GetVelocity();
339                                 MT_Vector3 velocity = ov - lv;
340                                 
341                                 // Now map the object position and velocity into 
342                                 // the local coordinates of the listener.
343                                 MT_Matrix3x3 lo = m_listener.GetOrientation();
344                                 
345                                 MT_Vector3 local_sound_pos = position * lo;
346                                 MT_Vector3 local_sound_vel = velocity * lo;
347                                 
348                                 m_audiodevice->SetObjectTransform(
349                                         id,
350                                         local_sound_pos,
351                                         local_sound_vel,
352                                         pObject->GetOrientation(), // make relative to listener! 
353                                         lp,
354                                         pObject->GetRollOffFactor());
355                         }
356                         else
357                         {
358                                 m_audiodevice->ObjectIs2D(id);
359                         }
360                         
361                         // update the situation
362                         if (pObject->IsModified())
363                         {
364                                 m_audiodevice->SetObjectPitch(id, pObject->GetPitch());
365                                 m_audiodevice->SetObjectGain(id, pObject->GetGain());
366                                 m_audiodevice->SetObjectMinGain(id, pObject->GetMinGain());
367                                 m_audiodevice->SetObjectMaxGain(id, pObject->GetMaxGain());
368                                 m_audiodevice->SetObjectReferenceDistance(id, pObject->GetReferenceDistance());
369                                 m_audiodevice->SetObjectRollOffFactor(id, pObject->GetRollOffFactor());
370                                 m_audiodevice->SetObjectLoop(id, pObject->GetLoopMode());
371                                 m_audiodevice->SetObjectLoopPoints(id, pObject->GetLoopStart(), pObject->GetLoopEnd());
372                                 pObject->SetModified(false);
373                         }
374
375                         pObject->AddRunning();
376
377 #ifdef ONTKEVER                         
378                         STR_String naam = pObject->GetObjectName();
379                         STR_String sample = pObject->GetSampleName();
380                         
381                         int id = pObject->GetId();
382                         int buffer = pObject->GetBuffer();
383                         
384                         float gain = pObject->GetGain();
385                         float pitch = pObject->GetPitch();
386                         float timestamp = pObject->GetTimestamp();
387                         
388                         printf("naam: %s, sample: %s \n", naam.Ptr(), sample.Ptr());
389                         printf("id: %d, buffer: %d \n", id, buffer);
390                         printf("gain: %f, pitch: %f, ts: %f \n\n", gain, pitch, timestamp);
391 #endif
392 #ifdef USE_OPENAL
393                         // ok, properties Set. now see if it must play
394                         if (pObject->GetPlaystate() == SND_MUST_PLAY)
395                         {
396                                 m_audiodevice->PlayObject(id);
397                                 pObject->SetPlaystate(SND_PLAYING);
398                                 //break;
399                         }
400 #endif
401
402                         // check to see if the sound is still playing
403                         // if not: release its id
404                         int playstate = m_audiodevice->GetPlayState(id);
405 #ifdef ONTKEVER
406                         if (playstate != 2)
407                                 printf("%d - ",playstate);
408 #endif
409
410                         if ((playstate == SND_STOPPED) && !pObject->GetLoopMode())
411                         {
412                                 RemoveActiveObject(pObject);
413                         }
414                 }
415         }
416 }
417
418
419
420 void SND_Scene::UpdateCD()
421 {
422         if (m_audiodevice)
423         {
424                 SND_CDObject* pCD = SND_CDObject::Instance();
425
426                 if (pCD)
427                 {
428                         int playstate = pCD->GetPlaystate();
429                         
430                         switch (playstate)
431                         {
432                         case SND_MUST_PLAY:
433                                 {
434                                         // initialize the cd only when you need it
435                                         m_audiodevice->SetCDGain(pCD->GetGain());
436                                         m_audiodevice->SetCDPlaymode(pCD->GetPlaymode());
437                                         m_audiodevice->PlayCD(pCD->GetTrack());
438                                         pCD->SetPlaystate(SND_PLAYING);
439                                         pCD->SetUsed();
440                                         break;
441                                 }
442                         case SND_MUST_PAUSE:
443                                 {
444                                         m_audiodevice->PauseCD(true);
445                                         pCD->SetPlaystate(SND_PAUSED);
446                                         break;
447                                 }
448                         case SND_MUST_RESUME:
449                                 {
450                                         m_audiodevice->PauseCD(false);
451                                         pCD->SetPlaystate(SND_PLAYING);
452                                         break;
453                                 }
454                         case SND_MUST_STOP:
455                                 {
456                                         m_audiodevice->StopCD();
457                                         pCD->SetPlaystate(SND_STOPPED);
458                                         break;
459                                 }
460                         default:
461                                 {
462                                 }
463                         }
464                         
465                         // this one is only for realtime modifying settings
466                         if (pCD->IsModified())
467                         {
468                                 m_audiodevice->SetCDGain(pCD->GetGain());
469                                 pCD->SetModified(false);
470                         }
471                 }
472         }
473 }
474
475
476
477 void SND_Scene::Proceed()
478 {
479         if (m_audio && m_audioplayback)
480         {
481                 m_audiodevice->MakeCurrent();
482
483                 UpdateListener();
484                 UpdateActiveObects();
485                 UpdateCD();
486
487 //              m_audiodevice->UpdateDevice();
488         }
489 }
490
491
492 void SND_Scene::DeleteObject(SND_SoundObject* pObject) 
493 {
494 #ifdef ONTKEVER
495         printf("SND_Scene::DeleteObject\n");
496 #endif
497         
498         if (pObject)
499         {
500                 if (m_audiodevice)
501                         m_audiodevice->ClearId(pObject);
502                 
503                 // must remove object from m_activeList
504                 std::set<SND_SoundObject*>::iterator set_it;
505                 set_it = m_soundobjects.find(pObject);
506                 
507                 if (set_it != m_soundobjects.end())
508                         m_soundobjects.erase(set_it);
509                 
510                 // release the memory
511                 delete pObject;
512                 pObject = NULL;
513         }
514 }
515
516
517
518 void SND_Scene::RemoveAllObjects()
519 {
520 #ifdef ONTKEVER
521         printf("SND_Scene::RemoveAllObjects\n");
522 #endif
523
524         StopAllObjects();
525
526         std::set<SND_SoundObject*>::iterator it = m_soundobjects.begin();
527
528         while (it != m_soundobjects.end())
529         {
530                 delete (*it);
531                 it++;
532         }
533
534         m_soundobjects.clear();
535 }
536
537
538
539 void SND_Scene::StopAllObjects()
540 {
541         if (m_audio)
542         {
543 #ifdef ONTKEVER
544                 printf("SND_Scene::StopAllObjects\n");
545 #endif
546                 
547                 SND_SoundObject* pObject;
548                 
549                 for (pObject = (SND_SoundObject*)m_activeobjects.getHead();
550                 !pObject->isTail();
551                 pObject = (SND_SoundObject*)pObject->getNext())
552                 {
553                         m_audiodevice->ClearId(pObject);
554                 }
555         }
556 }
557
558
559
560 SND_SoundListener* SND_Scene::GetListener()
561 {
562         return &m_listener;
563 }