8ef34f6659b00c4160791358571224407af393ac
[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
47 typedef std::list<AUD_SoftwareHandle*>::iterator AUD_HandleIterator;
48
49 void AUD_SoftwareDevice::create()
50 {
51         m_playingSounds = new std::list<AUD_SoftwareHandle*>();
52         m_pausedSounds = new std::list<AUD_SoftwareHandle*>();
53         m_playback = false;
54         m_volume = 1.0f;
55         m_mixer = new AUD_DefaultMixer(m_specs);
56
57         pthread_mutexattr_t attr;
58         pthread_mutexattr_init(&attr);
59         pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
60
61         pthread_mutex_init(&m_mutex, &attr);
62
63         pthread_mutexattr_destroy(&attr);
64 }
65
66 void AUD_SoftwareDevice::destroy()
67 {
68         if(m_playback)
69                 playing(m_playback = false);
70
71         delete m_mixer;
72
73         // delete all playing sounds
74         while(m_playingSounds->begin() != m_playingSounds->end())
75         {
76                 delete (*(m_playingSounds->begin()))->reader;
77                 delete *(m_playingSounds->begin());
78                 m_playingSounds->erase(m_playingSounds->begin());
79         }
80         delete m_playingSounds;
81
82         // delete all paused sounds
83         while(m_pausedSounds->begin() != m_pausedSounds->end())
84         {
85                 delete (*(m_pausedSounds->begin()))->reader;
86                 delete *(m_pausedSounds->begin());
87                 m_pausedSounds->erase(m_pausedSounds->begin());
88         }
89         delete m_pausedSounds;
90
91         pthread_mutex_destroy(&m_mutex);
92 }
93
94 void AUD_SoftwareDevice::mix(data_t* buffer, int length)
95 {
96         lock();
97
98         {
99                 AUD_SoftwareHandle* sound;
100                 int len;
101                 sample_t* buf;
102                 std::list<AUD_SoftwareHandle*> stopSounds;
103
104                 // for all sounds
105                 AUD_HandleIterator it = m_playingSounds->begin();
106                 while(it != m_playingSounds->end())
107                 {
108                         sound = *it;
109                         // increment the iterator to make sure it's valid,
110                         // in case the sound gets deleted after stopping
111                         ++it;
112
113                         // get the buffer from the source
114                         len = length;
115                         sound->reader->read(len, buf);
116
117                         m_mixer->add(buf, 0, len, sound->volume);
118
119                         // in case the end of the sound is reached
120                         if(len < length)
121                         {
122                                 if(sound->keep)
123                                         pause(sound);
124                                 else
125                                         stopSounds.push_back(sound);
126                         }
127                 }
128
129                 // superpose
130                 m_mixer->superpose(buffer, length, m_volume);
131
132                 while(!stopSounds.empty())
133                 {
134                         sound = stopSounds.front();
135                         stopSounds.pop_front();
136                         stop(sound);
137                 }
138         }
139
140         unlock();
141 }
142
143 bool AUD_SoftwareDevice::isValid(AUD_Handle* handle)
144 {
145         for(AUD_HandleIterator i = m_playingSounds->begin();
146                 i != m_playingSounds->end(); i++)
147                 if(*i == handle)
148                         return true;
149         for(AUD_HandleIterator i = m_pausedSounds->begin();
150                 i != m_pausedSounds->end(); i++)
151                 if(*i == handle)
152                         return true;
153         return false;
154 }
155
156 AUD_DeviceSpecs AUD_SoftwareDevice::getSpecs() const
157 {
158         return m_specs;
159 }
160
161 AUD_Handle* AUD_SoftwareDevice::play(AUD_IFactory* factory, bool keep)
162 {
163         AUD_IReader* reader = factory->createReader();
164
165         if(reader == NULL)
166                 AUD_THROW(AUD_ERROR_READER);
167
168         // prepare the reader
169         reader = m_mixer->prepare(reader);
170         if(reader == NULL)
171                 return NULL;
172
173         AUD_Specs rs = reader->getSpecs();
174
175         // play sound
176         AUD_SoftwareHandle* sound = new AUD_SoftwareHandle;
177         sound->keep = keep;
178         sound->reader = reader;
179         sound->volume = 1.0f;
180
181         lock();
182         m_playingSounds->push_back(sound);
183
184         if(!m_playback)
185                 playing(m_playback = true);
186         unlock();
187
188         return sound;
189 }
190
191 bool AUD_SoftwareDevice::pause(AUD_Handle* handle)
192 {
193         bool result = false;
194
195         lock();
196
197         // only songs that are played can be paused
198         for(AUD_HandleIterator i = m_playingSounds->begin();
199                 i != m_playingSounds->end(); i++)
200         {
201                 if(*i == handle)
202                 {
203                         m_pausedSounds->push_back(*i);
204                         m_playingSounds->erase(i);
205                         if(m_playingSounds->empty())
206                                 playing(m_playback = false);
207                         result = true;
208                         break;
209                 }
210         }
211
212         unlock();
213
214         return result;
215 }
216
217 bool AUD_SoftwareDevice::resume(AUD_Handle* handle)
218 {
219         bool result = false;
220
221         lock();
222
223         // only songs that are paused can be resumed
224         for(AUD_HandleIterator i = m_pausedSounds->begin();
225                 i != m_pausedSounds->end(); i++)
226         {
227                 if(*i == handle)
228                 {
229                         m_playingSounds->push_back(*i);
230                         m_pausedSounds->erase(i);
231                         if(!m_playback)
232                                 playing(m_playback = true);
233                         result = true;
234                         break;
235                 }
236         }
237
238         unlock();
239
240         return result;
241 }
242
243 bool AUD_SoftwareDevice::stop(AUD_Handle* handle)
244 {
245         bool result = false;
246
247         lock();
248
249         for(AUD_HandleIterator i = m_playingSounds->begin();
250                 i != m_playingSounds->end(); i++)
251         {
252                 if(*i == handle)
253                 {
254                         delete (*i)->reader;
255                         delete *i;
256                         m_playingSounds->erase(i);
257                         if(m_playingSounds->empty())
258                                 playing(m_playback = false);
259                         result = true;
260                         break;
261                 }
262         }
263         if(!result)
264         {
265                 for(AUD_HandleIterator i = m_pausedSounds->begin();
266                         i != m_pausedSounds->end(); i++)
267                 {
268                         if(*i == handle)
269                         {
270                                 delete (*i)->reader;
271                                 delete *i;
272                                 m_pausedSounds->erase(i);
273                                 result = true;
274                                 break;
275                         }
276                 }
277         }
278
279         unlock();
280
281         return result;
282 }
283
284 bool AUD_SoftwareDevice::getKeep(AUD_Handle* handle)
285 {
286         bool result = false;
287
288         lock();
289
290         if(isValid(handle))
291                 result = ((AUD_SoftwareHandle*)handle)->keep;
292
293         unlock();
294
295         return result;
296 }
297
298 bool AUD_SoftwareDevice::setKeep(AUD_Handle* handle, bool keep)
299 {
300         bool result = false;
301
302         lock();
303
304         if(isValid(handle))
305         {
306                 ((AUD_SoftwareHandle*)handle)->keep = keep;
307                 result = true;
308         }
309
310         unlock();
311
312         return result;
313 }
314
315 bool AUD_SoftwareDevice::seek(AUD_Handle* handle, float position)
316 {
317         lock();
318
319         bool result = false;
320
321         if(isValid(handle))
322         {
323                 AUD_IReader* reader = ((AUD_SoftwareHandle*)handle)->reader;
324                 reader->seek((int)(position * reader->getSpecs().rate));
325                 result = true;
326         }
327
328         unlock();
329
330         return result;
331 }
332
333 float AUD_SoftwareDevice::getPosition(AUD_Handle* handle)
334 {
335         lock();
336
337         float position = 0.0f;
338
339         if(isValid(handle))
340         {
341                 AUD_SoftwareHandle* h = (AUD_SoftwareHandle*)handle;
342                 position = h->reader->getPosition() / (float)m_specs.rate;
343         }
344
345         unlock();
346
347         return position;
348 }
349
350 AUD_Status AUD_SoftwareDevice::getStatus(AUD_Handle* handle)
351 {
352         AUD_Status status = AUD_STATUS_INVALID;
353
354         lock();
355
356         for(AUD_HandleIterator i = m_playingSounds->begin();
357                 i != m_playingSounds->end(); i++)
358         {
359                 if(*i == handle)
360                 {
361                         status = AUD_STATUS_PLAYING;
362                         break;
363                 }
364         }
365         if(status == AUD_STATUS_INVALID)
366         {
367                 for(AUD_HandleIterator i = m_pausedSounds->begin();
368                         i != m_pausedSounds->end(); i++)
369                 {
370                         if(*i == handle)
371                         {
372                                 status = AUD_STATUS_PAUSED;
373                                 break;
374                         }
375                 }
376         }
377
378         unlock();
379
380         return status;
381 }
382
383 void AUD_SoftwareDevice::lock()
384 {
385         pthread_mutex_lock(&m_mutex);
386 }
387
388 void AUD_SoftwareDevice::unlock()
389 {
390         pthread_mutex_unlock(&m_mutex);
391 }
392
393 float AUD_SoftwareDevice::getVolume() const
394 {
395         return m_volume;
396 }
397
398 void AUD_SoftwareDevice::setVolume(float volume)
399 {
400         m_volume = volume;
401 }
402
403 float AUD_SoftwareDevice::getVolume(AUD_Handle* handle)
404 {
405         lock();
406         float result = std::numeric_limits<float>::quiet_NaN();
407         if(isValid(handle))
408                 result = ((AUD_SoftwareHandle*)handle)->volume;
409         unlock();
410         return result;
411 }
412
413 bool AUD_SoftwareDevice::setVolume(AUD_Handle* handle, float volume)
414 {
415         lock();
416         bool result = isValid(handle);
417         if(result)
418                 ((AUD_SoftwareHandle*)handle)->volume = volume;
419         unlock();
420         return result;
421 }
422
423 float AUD_SoftwareDevice::getPitch(AUD_Handle* handle)
424 {
425         return std::numeric_limits<float>::quiet_NaN();
426 }
427
428 bool AUD_SoftwareDevice::setPitch(AUD_Handle* handle, float pitch)
429 {
430         return false;
431 }