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