3D Audio GSoC:
[blender.git] / intern / audaspace / intern / AUD_SoftwareDevice.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * Copyright 2009-2011 Jörg Hermann Müller
7  *
8  * This file is part of AudaSpace.
9  *
10  * Audaspace is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * AudaSpace 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 Audaspace; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file audaspace/intern/AUD_SoftwareDevice.cpp
28  *  \ingroup audaspaceintern
29  */
30
31
32 #include "AUD_SoftwareDevice.h"
33 #include "AUD_IReader.h"
34 #include "AUD_Mixer.h"
35 #include "AUD_IFactory.h"
36 #ifdef WITH_SAMPLERATE
37 #include "AUD_SRCResampleReader.h"
38 #else
39 #include "AUD_LinearResampleReader.h"
40 #endif
41
42 #include <cstring>
43 #include <cmath>
44 #include <limits>
45
46 typedef enum
47 {
48         AUD_RENDER_DISTANCE = 0x01,
49         AUD_RENDER_DOPPLER = 0x02,
50         AUD_RENDER_CONE = 0x04,
51         AUD_RENDER_VOLUME = 0x08
52 } AUD_RenderFlags;
53
54 #define AUD_PITCH_MAX 10
55
56 /******************************************************************************/
57 /********************** AUD_SoftwareHandle Handle Code ************************/
58 /******************************************************************************/
59
60 AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_PitchReader> pitch, AUD_Reference<AUD_ChannelMapperReader> mapper, bool keep) :
61         m_reader(reader), m_pitch(pitch), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_volume(1.0f), m_loopcount(0),
62         m_relative(false), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits<float>::max()),
63         m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0),
64         m_flags(AUD_RENDER_CONE), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device)
65 {
66 }
67
68 #include <iostream>
69
70 void AUD_SoftwareDevice::AUD_SoftwareHandle::update()
71 {
72         int flags = 0;
73
74         AUD_Vector3 SL;
75         if(m_relative)
76                 SL = m_location;
77         else
78                 SL = m_device->m_location - m_location;
79         float distance = SL * SL;
80
81         if(distance > 0)
82                 distance = sqrt(distance);
83         else
84                 flags |= AUD_RENDER_DOPPLER | AUD_RENDER_DISTANCE;
85
86         if(m_pitch->getSpecs().channels != AUD_CHANNELS_MONO)
87         {
88                 m_volume = m_user_volume;
89                 m_pitch->setPitch(m_user_pitch);
90                 return;
91         }
92
93         flags = ~(flags | m_flags | m_device->m_flags);
94
95         // Doppler and Pitch
96
97         if(flags & AUD_RENDER_DOPPLER)
98         {
99                 float vls;
100                 if(m_relative)
101                         vls = 0;
102                 else
103                         vls = SL * m_device->m_velocity / distance;
104                 float vss = SL * m_velocity / distance;
105                 float max = m_device->m_speed_of_sound / m_device->m_doppler_factor;
106                 if(vss >= max)
107                 {
108                         m_pitch->setPitch(AUD_PITCH_MAX);
109                 }
110                 else
111                 {
112                         if(vls > max)
113                                 vls = max;
114
115                         m_pitch->setPitch((m_device->m_speed_of_sound - m_device->m_doppler_factor * vls) / (m_device->m_speed_of_sound - m_device->m_doppler_factor * vss) * m_user_pitch);
116                 }
117         }
118         else
119                 m_pitch->setPitch(m_user_pitch);
120
121         if(flags & AUD_RENDER_VOLUME)
122         {
123                 // Distance
124
125                 if(flags & AUD_RENDER_DISTANCE)
126                 {
127                         if(m_device->m_distance_model == AUD_DISTANCE_MODEL_INVERSE_CLAMPED || m_device->m_distance_model == AUD_DISTANCE_MODEL_LINEAR_CLAMPED || m_device->m_distance_model == AUD_DISTANCE_MODEL_EXPONENT_CLAMPED)
128                         {
129                                 distance = AUD_MAX(AUD_MIN(m_distance_max, distance), m_distance_reference);
130                         }
131
132                         switch(m_device->m_distance_model)
133                         {
134                         case AUD_DISTANCE_MODEL_INVERSE:
135                         case AUD_DISTANCE_MODEL_INVERSE_CLAMPED:
136                                 m_volume = m_distance_reference / (m_distance_reference + m_attenuation * (distance - m_distance_reference));
137                                 break;
138                         case AUD_DISTANCE_MODEL_LINEAR:
139                         case AUD_DISTANCE_MODEL_LINEAR_CLAMPED:
140                         {
141                                 float temp = m_distance_max - m_distance_reference;
142                                 if(temp == 0)
143                                 {
144                                         if(distance > m_distance_reference)
145                                                 m_volume = 0.0f;
146                                         else
147                                                 m_volume = 1.0f;
148                                 }
149                                 else
150                                         m_volume = 1.0f - m_attenuation * (distance - m_distance_reference) / (m_distance_max - m_distance_reference);
151                                 break;
152                         }
153                         case AUD_DISTANCE_MODEL_EXPONENT:
154                         case AUD_DISTANCE_MODEL_EXPONENT_CLAMPED:
155                                 if(m_distance_reference == 0)
156                                         m_volume = 0;
157                                 else
158                                         m_volume = pow(distance / m_distance_reference, -m_attenuation);
159                                 break;
160                         default:
161                                 m_volume = 1.0f;
162                         }
163                 }
164                 else
165                         m_volume = 1.0f;
166
167                 // Cone
168
169                 if(flags & AUD_RENDER_CONE)
170                 {
171                         AUD_Vector3 SZ = m_orientation.getLookAt();
172
173                         float phi = acos(SZ * SL / (SZ.length() * SL.length()));
174                         float t = (phi - m_cone_angle_inner)/(m_cone_angle_outer - m_cone_angle_inner);
175
176                         if(t > 0)
177                         {
178                                 if(t > 1)
179                                         m_volume *= m_cone_volume_outer;
180                                 else
181                                         m_volume *= 1 + t * (m_cone_volume_outer - 1);
182                         }
183                 }
184
185                 // Volume
186
187                 m_volume *= m_user_volume;
188         }
189
190         // 3D Cue
191
192         AUD_Quaternion orientation;
193
194         if(!m_relative)
195                 orientation = m_device->m_orientation;
196
197         AUD_Vector3 Z = orientation.getLookAt();
198         AUD_Vector3 N = orientation.getUp();
199         AUD_Vector3 A = N * ((SL * N) / (N * N)) - SL;
200
201         float Asquare = A * A;
202
203         if(Asquare > 0)
204         {
205                 float phi = acos(Z * A/ (Z.length() * sqrt(Asquare)));
206                 if(N.cross(Z) * A > 0)
207                         phi = -phi;
208
209                 m_mapper->setMonoAngle(phi);
210         }
211         else
212                 m_mapper->setMonoAngle(0);
213 }
214
215 bool AUD_SoftwareDevice::AUD_SoftwareHandle::pause()
216 {
217         if(m_status)
218         {
219                 m_device->lock();
220
221                 if(m_status == AUD_STATUS_PLAYING)
222                 {
223                         m_device->m_playingSounds.remove(this);
224                         m_device->m_pausedSounds.push_back(this);
225
226                         if(m_device->m_playingSounds.empty())
227                                 m_device->playing(m_device->m_playback = false);
228                         m_status = AUD_STATUS_PAUSED;
229                         m_device->unlock();
230
231                         return true;
232                 }
233
234                 m_device->unlock();
235         }
236
237         return false;
238 }
239
240 bool AUD_SoftwareDevice::AUD_SoftwareHandle::resume()
241 {
242         if(m_status)
243         {
244                 m_device->lock();
245
246                 if(m_status == AUD_STATUS_PAUSED)
247                 {
248                         m_device->m_pausedSounds.remove(this);
249                         m_device->m_playingSounds.push_back(this);
250
251                         if(!m_device->m_playback)
252                                 m_device->playing(m_device->m_playback = true);
253                         m_status = AUD_STATUS_PLAYING;
254                         m_device->unlock();
255                         return true;
256                 }
257
258                 m_device->unlock();
259         }
260
261         return false;
262 }
263
264 bool AUD_SoftwareDevice::AUD_SoftwareHandle::stop()
265 {
266         if(!m_status)
267                 return false;
268
269         m_device->lock();
270
271         if(m_status == AUD_STATUS_PLAYING)
272         {
273                 m_device->m_playingSounds.remove(this);
274
275                 if(m_device->m_playingSounds.empty())
276                         m_device->playing(m_device->m_playback = false);
277         }
278         else
279                 m_device->m_pausedSounds.remove(this);
280
281         m_device->unlock();
282         m_status = AUD_STATUS_INVALID;
283         return true;
284 }
285
286 bool AUD_SoftwareDevice::AUD_SoftwareHandle::getKeep()
287 {
288         if(m_status)
289                 return m_keep;
290
291         return false;
292 }
293
294 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setKeep(bool keep)
295 {
296         if(!m_status)
297                 return false;
298
299         m_device->lock();
300
301         m_keep = keep;
302
303         m_device->unlock();
304
305         return true;
306 }
307
308 bool AUD_SoftwareDevice::AUD_SoftwareHandle::seek(float position)
309 {
310         if(!m_status)
311                 return false;
312
313         m_device->lock();
314
315         m_reader->seek((int)(position * m_reader->getSpecs().rate));
316
317         m_device->unlock();
318
319         return true;
320 }
321
322 float AUD_SoftwareDevice::AUD_SoftwareHandle::getPosition()
323 {
324         if(!m_status)
325                 return 0.0f;
326
327         m_device->lock();
328
329         float position = m_reader->getPosition() / (float)m_device->m_specs.rate;
330
331         m_device->unlock();
332
333         return position;
334 }
335
336 AUD_Status AUD_SoftwareDevice::AUD_SoftwareHandle::getStatus()
337 {
338         return m_status;
339 }
340
341 float AUD_SoftwareDevice::AUD_SoftwareHandle::getVolume()
342 {
343         return m_user_volume;
344 }
345
346 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolume(float volume)
347 {
348         if(!m_status)
349                 return false;
350         m_user_volume = volume;
351
352         if(volume == 0)
353         {
354                 m_volume = volume;
355                 m_flags |= AUD_RENDER_VOLUME;
356         }
357         else
358                 m_flags &= ~AUD_RENDER_VOLUME;
359
360         return true;
361 }
362
363 float AUD_SoftwareDevice::AUD_SoftwareHandle::getPitch()
364 {
365         return m_user_pitch;
366 }
367
368 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setPitch(float pitch)
369 {
370         if(!m_status)
371                 return false;
372         m_user_pitch = pitch;
373         return true;
374 }
375
376 int AUD_SoftwareDevice::AUD_SoftwareHandle::getLoopCount()
377 {
378         if(!m_status)
379                 return 0;
380         return m_loopcount;
381 }
382
383 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setLoopCount(int count)
384 {
385         if(!m_status)
386                 return false;
387         m_loopcount = count;
388         return true;
389 }
390
391 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setStopCallback(stopCallback callback, void* data)
392 {
393         if(!m_status)
394                 return false;
395
396         m_device->lock();
397
398         m_stop = callback;
399         m_stop_data = data;
400
401         m_device->unlock();
402
403         return true;
404 }
405
406
407
408 /******************************************************************************/
409 /******************** AUD_SoftwareHandle 3DHandle Code ************************/
410 /******************************************************************************/
411
412 AUD_Vector3 AUD_SoftwareDevice::AUD_SoftwareHandle::getSourceLocation()
413 {
414         if(!m_status)
415                 return AUD_Vector3();
416
417         return m_location;
418 }
419
420 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setSourceLocation(const AUD_Vector3& location)
421 {
422         if(!m_status)
423                 return false;
424
425         m_location = location;
426
427         return true;
428 }
429
430 AUD_Vector3 AUD_SoftwareDevice::AUD_SoftwareHandle::getSourceVelocity()
431 {
432         if(!m_status)
433                 return AUD_Vector3();
434
435         return m_velocity;
436 }
437
438 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setSourceVelocity(const AUD_Vector3& velocity)
439 {
440         if(!m_status)
441                 return false;
442
443         m_velocity = velocity;
444
445         return true;
446 }
447
448 AUD_Quaternion AUD_SoftwareDevice::AUD_SoftwareHandle::getSourceOrientation()
449 {
450         if(!m_status)
451                 return AUD_Quaternion();
452
453         return m_orientation;
454 }
455
456 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setSourceOrientation(const AUD_Quaternion& orientation)
457 {
458         if(!m_status)
459                 return false;
460
461         m_orientation = orientation;
462
463         return true;
464 }
465
466 bool AUD_SoftwareDevice::AUD_SoftwareHandle::isRelative()
467 {
468         if(!m_status)
469                 return false;
470
471         return m_relative;
472 }
473
474 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setRelative(bool relative)
475 {
476         if(!m_status)
477                 return false;
478
479         m_relative = relative;
480
481         return true;
482 }
483
484 float AUD_SoftwareDevice::AUD_SoftwareHandle::getVolumeMaximum()
485 {
486         if(!m_status)
487                 return std::numeric_limits<float>::quiet_NaN();
488
489         return m_volume_max;
490 }
491
492 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolumeMaximum(float volume)
493 {
494         if(!m_status)
495                 return false;
496
497         m_volume_max = volume;
498
499         return true;
500 }
501
502 float AUD_SoftwareDevice::AUD_SoftwareHandle::getVolumeMinimum()
503 {
504         if(!m_status)
505                 return std::numeric_limits<float>::quiet_NaN();;
506
507         return m_volume_min;
508 }
509
510 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolumeMinimum(float volume)
511 {
512         if(!m_status)
513                 return false;
514
515         m_volume_min = volume;
516
517         return true;
518 }
519
520 float AUD_SoftwareDevice::AUD_SoftwareHandle::getDistanceMaximum()
521 {
522         if(!m_status)
523                 return std::numeric_limits<float>::quiet_NaN();
524
525         return m_distance_max;
526 }
527
528 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setDistanceMaximum(float distance)
529 {
530         if(!m_status)
531                 return false;
532
533         m_distance_max = distance;
534
535         return true;
536 }
537
538 float AUD_SoftwareDevice::AUD_SoftwareHandle::getDistanceReference()
539 {
540         if(!m_status)
541                 return std::numeric_limits<float>::quiet_NaN();
542
543         return m_distance_reference;
544 }
545
546 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setDistanceReference(float distance)
547 {
548         if(!m_status)
549                 return false;
550
551         m_distance_reference = distance;
552
553         return true;
554 }
555
556 float AUD_SoftwareDevice::AUD_SoftwareHandle::getAttenuation()
557 {
558         if(!m_status)
559                 return std::numeric_limits<float>::quiet_NaN();
560
561         return m_attenuation;
562 }
563
564 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setAttenuation(float factor)
565 {
566         if(!m_status)
567                 return false;
568
569         m_attenuation = factor;
570
571         if(factor == 0)
572                 m_flags |= AUD_RENDER_DISTANCE;
573         else
574                 m_flags &= ~AUD_RENDER_DISTANCE;
575
576         return true;
577 }
578
579 float AUD_SoftwareDevice::AUD_SoftwareHandle::getConeAngleOuter()
580 {
581         if(!m_status)
582                 return std::numeric_limits<float>::quiet_NaN();
583
584         return m_cone_angle_outer * 360.0f / M_PI;
585 }
586
587 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setConeAngleOuter(float angle)
588 {
589         if(!m_status)
590                 return false;
591
592         m_cone_angle_outer = angle * M_PI / 360.0f;
593
594         return true;
595 }
596
597 float AUD_SoftwareDevice::AUD_SoftwareHandle::getConeAngleInner()
598 {
599         if(!m_status)
600                 return std::numeric_limits<float>::quiet_NaN();
601
602         return m_cone_angle_inner * 360.0f / M_PI;
603 }
604
605 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setConeAngleInner(float angle)
606 {
607         if(!m_status)
608                 return false;
609
610         if(angle >= 360)
611                 m_flags |= AUD_RENDER_CONE;
612         else
613                 m_flags &= ~AUD_RENDER_CONE;
614
615         m_cone_angle_inner = angle * M_PI / 360.0f;
616
617         return true;
618 }
619
620 float AUD_SoftwareDevice::AUD_SoftwareHandle::getConeVolumeOuter()
621 {
622         if(!m_status)
623                 return std::numeric_limits<float>::quiet_NaN();;
624
625         return m_cone_volume_outer;
626 }
627
628 bool AUD_SoftwareDevice::AUD_SoftwareHandle::setConeVolumeOuter(float volume)
629 {
630         if(!m_status)
631                 return false;
632
633         m_cone_volume_outer = volume;
634
635         return true;
636 }
637
638 /******************************************************************************/
639 /**************************** IDevice Code ************************************/
640 /******************************************************************************/
641
642 void AUD_SoftwareDevice::create()
643 {
644         m_playback = false;
645         m_volume = 1.0f;
646         m_mixer = new AUD_Mixer(m_specs);
647         m_speed_of_sound = 343.0f;
648         m_doppler_factor = 1.0f;
649         m_distance_model = AUD_DISTANCE_MODEL_INVERSE_CLAMPED;
650         m_flags = 0;
651
652         pthread_mutexattr_t attr;
653         pthread_mutexattr_init(&attr);
654         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
655
656         pthread_mutex_init(&m_mutex, &attr);
657
658         pthread_mutexattr_destroy(&attr);
659 }
660
661 void AUD_SoftwareDevice::destroy()
662 {
663         if(m_playback)
664                 playing(m_playback = false);
665
666         while(!m_playingSounds.empty())
667                 m_playingSounds.front()->stop();
668
669         while(!m_pausedSounds.empty())
670                 m_pausedSounds.front()->stop();
671
672         pthread_mutex_destroy(&m_mutex);
673 }
674
675 void AUD_SoftwareDevice::mix(data_t* buffer, int length)
676 {
677         m_buffer.assureSize(length * AUD_SAMPLE_SIZE(m_specs));
678
679         lock();
680
681         {
682                 AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> sound;
683                 int len;
684                 int pos;
685                 bool eos;
686                 std::list<AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> > stopSounds;
687                 sample_t* buf = m_buffer.getBuffer();
688
689                 m_mixer->clear(length);
690
691                 // for all sounds
692                 AUD_HandleIterator it = m_playingSounds.begin();
693                 while(it != m_playingSounds.end())
694                 {
695                         sound = *it;
696                         // increment the iterator to make sure it's valid,
697                         // in case the sound gets deleted after stopping
698                         ++it;
699
700                         // get the buffer from the source
701                         pos = 0;
702                         len = length;
703
704                         // update 3D Info
705                         sound->update();
706
707                         sound->m_reader->read(len, eos, buf);
708
709                         // in case of looping
710                         while(pos + len < length && sound->m_loopcount && eos)
711                         {
712                                 m_mixer->mix(buf, pos, len, sound->m_volume);
713
714                                 pos += len;
715
716                                 if(sound->m_loopcount > 0)
717                                         sound->m_loopcount--;
718
719                                 sound->m_reader->seek(0);
720
721                                 len = length - pos;
722                                 sound->m_reader->read(len, eos, buf);
723
724                                 // prevent endless loop
725                                 if(!len)
726                                         break;
727                         }
728
729                         m_mixer->mix(buf, pos, len, sound->m_volume);
730
731                         // in case the end of the sound is reached
732                         if(eos && !sound->m_loopcount)
733                         {
734                                 if(sound->m_stop)
735                                         sound->m_stop(sound->m_stop_data);
736
737                                 if(sound->m_keep)
738                                         sound->pause();
739                                 else
740                                         stopSounds.push_back(sound);
741                         }
742                 }
743
744                 // superpose
745                 m_mixer->read(buffer, m_volume);
746
747                 // cleanup
748                 while(!stopSounds.empty())
749                 {
750                         sound = stopSounds.front();
751                         stopSounds.pop_front();
752                         sound->stop();
753                 }
754         }
755
756         unlock();
757 }
758
759 AUD_DeviceSpecs AUD_SoftwareDevice::getSpecs() const
760 {
761         return m_specs;
762 }
763
764 AUD_Reference<AUD_IHandle> AUD_SoftwareDevice::play(AUD_Reference<AUD_IReader> reader, bool keep)
765 {
766         // prepare the reader
767         // pitch
768
769         AUD_Reference<AUD_PitchReader> pitch = new AUD_PitchReader(reader, 1);
770         reader = AUD_Reference<AUD_IReader>(pitch);
771
772         // resample
773         #ifdef WITH_SAMPLERATE
774                 reader = new AUD_SRCResampleReader(reader, m_specs.specs);
775         #else
776                 reader = new AUD_LinearResampleReader(reader, m_specs.specs);
777         #endif
778
779         // rechannel
780         AUD_Reference<AUD_ChannelMapperReader> mapper = new AUD_ChannelMapperReader(reader, m_specs.channels);
781         reader = AUD_Reference<AUD_IReader>(mapper);
782
783         if(reader.isNull())
784                 return NULL;
785
786         // play sound
787         AUD_Reference<AUD_SoftwareDevice::AUD_SoftwareHandle> sound = new AUD_SoftwareDevice::AUD_SoftwareHandle(this, reader, pitch, mapper, keep);
788
789         lock();
790         m_playingSounds.push_back(sound);
791
792         if(!m_playback)
793                 playing(m_playback = true);
794         unlock();
795
796         return AUD_Reference<AUD_IHandle>(sound);
797 }
798
799 AUD_Reference<AUD_IHandle> AUD_SoftwareDevice::play(AUD_Reference<AUD_IFactory> factory, bool keep)
800 {
801         return play(factory->createReader(), keep);
802 }
803
804 void AUD_SoftwareDevice::lock()
805 {
806         pthread_mutex_lock(&m_mutex);
807 }
808
809 void AUD_SoftwareDevice::unlock()
810 {
811         pthread_mutex_unlock(&m_mutex);
812 }
813
814 float AUD_SoftwareDevice::getVolume() const
815 {
816         return m_volume;
817 }
818
819 void AUD_SoftwareDevice::setVolume(float volume)
820 {
821         m_volume = volume;
822 }
823
824 /******************************************************************************/
825 /**************************** 3D Device Code **********************************/
826 /******************************************************************************/
827
828 AUD_Vector3 AUD_SoftwareDevice::getListenerLocation() const
829 {
830         return m_location;
831 }
832
833 void AUD_SoftwareDevice::setListenerLocation(const AUD_Vector3& location)
834 {
835         m_location = location;
836 }
837
838 AUD_Vector3 AUD_SoftwareDevice::getListenerVelocity() const
839 {
840         return m_velocity;
841 }
842
843 void AUD_SoftwareDevice::setListenerVelocity(const AUD_Vector3& velocity)
844 {
845         m_velocity = velocity;
846 }
847
848 AUD_Quaternion AUD_SoftwareDevice::getListenerOrientation() const
849 {
850         return m_orientation;
851 }
852
853 void AUD_SoftwareDevice::setListenerOrientation(const AUD_Quaternion& orientation)
854 {
855         m_orientation = orientation;
856 }
857
858 float AUD_SoftwareDevice::getSpeedOfSound() const
859 {
860         return m_speed_of_sound;
861 }
862
863 void AUD_SoftwareDevice::setSpeedOfSound(float speed)
864 {
865         m_speed_of_sound = speed;
866 }
867
868 float AUD_SoftwareDevice::getDopplerFactor() const
869 {
870         return m_doppler_factor;
871 }
872
873 void AUD_SoftwareDevice::setDopplerFactor(float factor)
874 {
875         m_doppler_factor = factor;
876         if(factor == 0)
877                 m_flags |= AUD_RENDER_DOPPLER;
878         else
879                 m_flags &= ~AUD_RENDER_DOPPLER;
880 }
881
882 AUD_DistanceModel AUD_SoftwareDevice::getDistanceModel() const
883 {
884         return m_distance_model;
885 }
886
887 void AUD_SoftwareDevice::setDistanceModel(AUD_DistanceModel model)
888 {
889         m_distance_model = model;
890         if(model == AUD_DISTANCE_MODEL_INVALID)
891                 m_flags |= AUD_RENDER_DISTANCE;
892         else
893                 m_flags &= ~AUD_RENDER_DISTANCE;
894 }