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