Audaspace:
[blender-staging.git] / intern / audaspace / intern / AUD_SoftwareDevice.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN LGPL LICENSE BLOCK *****
5  *
6  * Copyright 2009 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 Lesser General Public License as published by
12  * the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * ***** END LGPL LICENSE BLOCK *****
24  */
25
26 #include "AUD_SoftwareDevice.h"
27 #include "AUD_IReader.h"
28 #include "AUD_DefaultMixer.h"
29 #include "AUD_IFactory.h"
30
31 #include <cstring>
32 #include <limits>
33
34 /// Saves the data for playback.
35 struct AUD_SoftwareHandle : AUD_Handle
36 {
37         /// The reader source.
38         AUD_IReader* reader;
39
40         /// Whether to keep the source if end of it is reached.
41         bool keep;
42
43         /// The volume of the source.
44         float volume;
45
46         /// The loop count of the source.
47         int loopcount;
48 };
49
50 typedef std::list<AUD_SoftwareHandle*>::iterator AUD_HandleIterator;
51
52 void AUD_SoftwareDevice::create()
53 {
54         m_playback = false;
55         m_volume = 1.0f;
56         m_mixer = new AUD_DefaultMixer(m_specs);
57
58         pthread_mutexattr_t attr;
59         pthread_mutexattr_init(&attr);
60         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
61
62         pthread_mutex_init(&m_mutex, &attr);
63
64         pthread_mutexattr_destroy(&attr);
65 }
66
67 void AUD_SoftwareDevice::destroy()
68 {
69         if(m_playback)
70                 playing(m_playback = false);
71
72         delete m_mixer;
73
74         AUD_SoftwareHandle* handle;
75
76         // delete all playing sounds
77         while(!m_playingSounds.empty())
78         {
79                 handle = m_playingSounds.front();
80                 m_playingSounds.pop_front();
81                 delete handle->reader;
82                 delete handle;
83         }
84
85         // delete all paused sounds
86         while(!m_pausedSounds.empty())
87         {
88                 handle = m_pausedSounds.front();
89                 m_pausedSounds.pop_front();
90                 delete handle->reader;
91                 delete handle;
92         }
93
94         pthread_mutex_destroy(&m_mutex);
95 }
96
97 void AUD_SoftwareDevice::mix(data_t* buffer, int length)
98 {
99         lock();
100
101         {
102                 AUD_SoftwareHandle* sound;
103                 int len;
104                 int pos;
105                 sample_t* buf;
106                 std::list<AUD_SoftwareHandle*> stopSounds;
107                 std::list<AUD_Buffer*> tempBufs;
108                 AUD_Buffer* tempbuf;
109                 int samplesize = AUD_SAMPLE_SIZE(m_specs);
110
111                 // for all sounds
112                 AUD_HandleIterator it = m_playingSounds.begin();
113                 while(it != m_playingSounds.end())
114                 {
115                         sound = *it;
116                         // increment the iterator to make sure it's valid,
117                         // in case the sound gets deleted after stopping
118                         ++it;
119
120                         // get the buffer from the source
121                         pos = 0;
122                         len = length;
123                         sound->reader->read(len, buf);
124
125                         // in case of looping
126                         while(pos + len < length && sound->loopcount)
127                         {
128                                 tempbuf = new AUD_Buffer(len * samplesize);
129                                 memcpy(tempbuf->getBuffer(), buf, len * samplesize);
130                                 tempBufs.push_back(tempbuf);
131                                 m_mixer->add(tempbuf->getBuffer(), pos, len, sound->volume);
132
133                                 pos += len;
134
135                                 if(sound->loopcount > 0)
136                                         sound->loopcount--;
137
138                                 sound->reader->seek(0);
139
140                                 len = length - pos;
141                                 sound->reader->read(len, buf);
142
143                                 // prevent endless loop
144                                 if(!len)
145                                         break;
146                         }
147
148                         m_mixer->add(buf, pos, len, sound->volume);
149                         pos += len;
150
151                         // in case the end of the sound is reached
152                         if(pos < length)
153                         {
154                                 if(sound->keep)
155                                         pause(sound);
156                                 else
157                                         stopSounds.push_back(sound);
158                         }
159                 }
160
161                 // superpose
162                 m_mixer->superpose(buffer, length, m_volume);
163
164                 // cleanup
165                 while(!stopSounds.empty())
166                 {
167                         sound = stopSounds.front();
168                         stopSounds.pop_front();
169                         stop(sound);
170                 }
171
172                 while(!tempBufs.empty())
173                 {
174                         tempbuf = tempBufs.front();
175                         tempBufs.pop_front();
176                         delete tempbuf;
177                 }
178         }
179
180         unlock();
181 }
182
183 bool AUD_SoftwareDevice::isValid(AUD_Handle* handle)
184 {
185         for(AUD_HandleIterator i = m_playingSounds.begin();
186                 i != m_playingSounds.end(); i++)
187                 if(*i == handle)
188                         return true;
189         for(AUD_HandleIterator i = m_pausedSounds.begin();
190                 i != m_pausedSounds.end(); i++)
191                 if(*i == handle)
192                         return true;
193         return false;
194 }
195
196 AUD_DeviceSpecs AUD_SoftwareDevice::getSpecs() const
197 {
198         return m_specs;
199 }
200
201 AUD_Handle* AUD_SoftwareDevice::play(AUD_IFactory* factory, bool keep)
202 {
203         AUD_IReader* reader = factory->createReader();
204
205         if(reader == NULL)
206                 AUD_THROW(AUD_ERROR_READER);
207
208         // prepare the reader
209         reader = m_mixer->prepare(reader);
210         if(reader == NULL)
211                 return NULL;
212
213         // play sound
214         AUD_SoftwareHandle* sound = new AUD_SoftwareHandle;
215         sound->keep = keep;
216         sound->reader = reader;
217         sound->volume = 1.0f;
218         sound->loopcount = 0;
219
220         lock();
221         m_playingSounds.push_back(sound);
222
223         if(!m_playback)
224                 playing(m_playback = true);
225         unlock();
226
227         return sound;
228 }
229
230 bool AUD_SoftwareDevice::pause(AUD_Handle* handle)
231 {
232         bool result = false;
233
234         lock();
235
236         // only songs that are played can be paused
237         for(AUD_HandleIterator i = m_playingSounds.begin();
238                 i != m_playingSounds.end(); i++)
239         {
240                 if(*i == handle)
241                 {
242                         m_pausedSounds.push_back(*i);
243                         m_playingSounds.erase(i);
244                         if(m_playingSounds.empty())
245                                 playing(m_playback = false);
246                         result = true;
247                         break;
248                 }
249         }
250
251         unlock();
252
253         return result;
254 }
255
256 bool AUD_SoftwareDevice::resume(AUD_Handle* handle)
257 {
258         bool result = false;
259
260         lock();
261
262         // only songs that are paused can be resumed
263         for(AUD_HandleIterator i = m_pausedSounds.begin();
264                 i != m_pausedSounds.end(); i++)
265         {
266                 if(*i == handle)
267                 {
268                         m_playingSounds.push_back(*i);
269                         m_pausedSounds.erase(i);
270                         if(!m_playback)
271                                 playing(m_playback = true);
272                         result = true;
273                         break;
274                 }
275         }
276
277         unlock();
278
279         return result;
280 }
281
282 bool AUD_SoftwareDevice::stop(AUD_Handle* handle)
283 {
284         bool result = false;
285
286         lock();
287
288         for(AUD_HandleIterator i = m_playingSounds.begin();
289                 i != m_playingSounds.end(); i++)
290         {
291                 if(*i == handle)
292                 {
293                         delete (*i)->reader;
294                         delete *i;
295                         m_playingSounds.erase(i);
296                         if(m_playingSounds.empty())
297                                 playing(m_playback = false);
298                         result = true;
299                         break;
300                 }
301         }
302         if(!result)
303         {
304                 for(AUD_HandleIterator i = m_pausedSounds.begin();
305                         i != m_pausedSounds.end(); i++)
306                 {
307                         if(*i == handle)
308                         {
309                                 delete (*i)->reader;
310                                 delete *i;
311                                 m_pausedSounds.erase(i);
312                                 result = true;
313                                 break;
314                         }
315                 }
316         }
317
318         unlock();
319
320         return result;
321 }
322
323 bool AUD_SoftwareDevice::getKeep(AUD_Handle* handle)
324 {
325         bool result = false;
326
327         lock();
328
329         if(isValid(handle))
330                 result = ((AUD_SoftwareHandle*)handle)->keep;
331
332         unlock();
333
334         return result;
335 }
336
337 bool AUD_SoftwareDevice::setKeep(AUD_Handle* handle, bool keep)
338 {
339         bool result = false;
340
341         lock();
342
343         if(isValid(handle))
344         {
345                 ((AUD_SoftwareHandle*)handle)->keep = keep;
346                 result = true;
347         }
348
349         unlock();
350
351         return result;
352 }
353
354 bool AUD_SoftwareDevice::seek(AUD_Handle* handle, float position)
355 {
356         lock();
357
358         bool result = false;
359
360         if(isValid(handle))
361         {
362                 AUD_IReader* reader = ((AUD_SoftwareHandle*)handle)->reader;
363                 reader->seek((int)(position * reader->getSpecs().rate));
364                 result = true;
365         }
366
367         unlock();
368
369         return result;
370 }
371
372 float AUD_SoftwareDevice::getPosition(AUD_Handle* handle)
373 {
374         lock();
375
376         float position = 0.0f;
377
378         if(isValid(handle))
379         {
380                 AUD_SoftwareHandle* h = (AUD_SoftwareHandle*)handle;
381                 position = h->reader->getPosition() / (float)m_specs.rate;
382         }
383
384         unlock();
385
386         return position;
387 }
388
389 AUD_Status AUD_SoftwareDevice::getStatus(AUD_Handle* handle)
390 {
391         AUD_Status status = AUD_STATUS_INVALID;
392
393         lock();
394
395         for(AUD_HandleIterator i = m_playingSounds.begin();
396                 i != m_playingSounds.end(); i++)
397         {
398                 if(*i == handle)
399                 {
400                         status = AUD_STATUS_PLAYING;
401                         break;
402                 }
403         }
404         if(status == AUD_STATUS_INVALID)
405         {
406                 for(AUD_HandleIterator i = m_pausedSounds.begin();
407                         i != m_pausedSounds.end(); i++)
408                 {
409                         if(*i == handle)
410                         {
411                                 status = AUD_STATUS_PAUSED;
412                                 break;
413                         }
414                 }
415         }
416
417         unlock();
418
419         return status;
420 }
421
422 void AUD_SoftwareDevice::lock()
423 {
424         pthread_mutex_lock(&m_mutex);
425 }
426
427 void AUD_SoftwareDevice::unlock()
428 {
429         pthread_mutex_unlock(&m_mutex);
430 }
431
432 float AUD_SoftwareDevice::getVolume() const
433 {
434         return m_volume;
435 }
436
437 void AUD_SoftwareDevice::setVolume(float volume)
438 {
439         m_volume = volume;
440 }
441
442 float AUD_SoftwareDevice::getVolume(AUD_Handle* handle)
443 {
444         lock();
445         float result = std::numeric_limits<float>::quiet_NaN();
446         if(isValid(handle))
447                 result = ((AUD_SoftwareHandle*)handle)->volume;
448         unlock();
449         return result;
450 }
451
452 bool AUD_SoftwareDevice::setVolume(AUD_Handle* handle, float volume)
453 {
454         lock();
455         bool result = isValid(handle);
456         if(result)
457                 ((AUD_SoftwareHandle*)handle)->volume = volume;
458         unlock();
459         return result;
460 }
461
462 float AUD_SoftwareDevice::getPitch(AUD_Handle* handle)
463 {
464         return std::numeric_limits<float>::quiet_NaN();
465 }
466
467 bool AUD_SoftwareDevice::setPitch(AUD_Handle* handle, float pitch)
468 {
469         return false;
470 }
471
472 int AUD_SoftwareDevice::getLoopCount(AUD_Handle* handle)
473 {
474         lock();
475         int result = 0;
476         if(isValid(handle))
477                 result = ((AUD_SoftwareHandle*)handle)->loopcount;
478         unlock();
479         return result;
480 }
481
482 bool AUD_SoftwareDevice::setLoopCount(AUD_Handle* handle, int count)
483 {
484         lock();
485         bool result = isValid(handle);
486         if(result)
487                 ((AUD_SoftwareHandle*)handle)->loopcount = count;
488         unlock();
489         return result;
490 }