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