Added shared lib project.
[camargo/neiasound.git] / src / nSoundSystem.cpp
1 // Copyright (C) 2015 Lucas Pires Camargo
2 // 
3 // This file is part of neiasound - Qt-style OpenAL wrapper for games.
4 // 
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 // 
9 // 1. Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // 
12 // 2. Redistributions in binary form must reproduce the above copyright notice,
13 // this list of conditions and the following disclaimer in the documentation
14 // and/or other materials provided with the distribution.
15 // 
16 // THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS
17 // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19 // NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "nSoundSystem.h"
27 #include "nSoundSource.h"
28 #include "nSoundBuffer.h"
29 #include "nSoundListener.h"
30 #include "nSoundStreamer.h"
31 #include "nSoundStreamerPlaylist.h"
32
33 #include <AL/al.h>
34 #include <AL/alc.h>
35 #include <AL/alext.h>
36
37 #include "util/nEfxHelper.h"
38 #include <QSettings>
39 #include <QUuid>
40
41 nSoundSystem::nSoundSystem(QObject *parent) :
42     QObject(parent), m_success(false)
43 {
44     qDebug("nSoundSystem initializing.");
45
46     m_context = 0;
47     m_device = 0;
48
49     m_device = alcOpenDevice(0); //default device
50     if(!m_device)
51         throw QString("Error creating OpenAL device.");
52
53     int attributes[] = {ALC_FREQUENCY, 44100, 0};
54     m_context = alcCreateContext(m_device, attributes);
55     if(!m_context)
56         throw QString("Error creating OpenAL context.");
57
58     alcMakeContextCurrent(m_context);
59     if( alGetError()!=AL_NO_ERROR)
60         qWarning("nSoundSystem::nSoundSystem(): Failed to set context as current.");
61
62     if(!nEfxHelper::initialize(m_device))
63         qWarning("nSoundSystem::nSoundSystem(): nEfxHelper initialization failed.");
64
65     m_listener = new nSoundListener(this);
66     m_success = true;
67
68 #ifdef ANDROID
69 #ifdef MOB
70     alcDeviceEnableHrtfMOB( m_device, false );
71 #endif
72 #endif
73
74     alcGetIntegerv(m_device, ALC_MAX_AUXILIARY_SENDS, 1, &m_numSends);
75     
76     nSoundSource::_resetRoleGains();
77     QSettings settings;
78     settings.beginGroup("Audio");
79     setMasterGain(settings.value("MasterGain", 100).toFloat()/100.0f);
80     settings.endGroup();
81
82 }
83
84 nSoundSystem::~nSoundSystem()
85 {
86     // ensure deletion of resources in right order
87     QHash<QString, nSoundSource*> sources = m_sources;
88     QHash<QString, nSoundBuffer*> buffers = m_buffers;
89     QHash<QString, nSoundStreamer*> streamers = m_streamers;
90
91     foreach(nSoundStreamer * streamer, streamers)
92     {
93         destroyStreamer(streamer);
94     }
95
96     foreach(nSoundSource * source, sources)
97     {
98         destroySource(source);
99     }
100
101     foreach(nSoundBuffer * buffer, buffers)
102     {
103         destroyBuffer(buffer);
104     }
105
106
107     alcMakeContextCurrent(0);
108     alcDestroyContext(m_context);
109     alcCloseDevice(m_device);
110 }
111
112 void nSoundSystem::update(qreal frameTime)
113 {
114
115     m_listener->update(frameTime);
116
117 //    Not necessary anymore, streamers update themselves in owned threads.
118
119 //    foreach(nSoundStreamer * streamer, m_streamers)
120 //    {
121 //        streamer->update(frameTime);
122 //    }
123
124     QList<nSoundSource*> toDestroy;
125     foreach(nSoundSource * source, m_sources)
126     {
127         if(!source->update(frameTime))
128             toDestroy.append(source);
129     }
130
131     foreach (nSoundSource * source, toDestroy) {
132         destroySource(source);
133     }
134 }
135
136 // SOUND STUFF METHODS
137
138 qreal nSoundSystem::masterGain()
139 {
140     float ret;
141     alGetListenerf(AL_GAIN, &ret);
142     return ret;
143 }
144
145 void nSoundSystem::setMasterGain(qreal gain)
146 {
147     alListenerf(AL_GAIN, gain);
148
149     emit masterGainChanged(gain);
150 }
151
152 // SOURCE METHODS
153
154 nSoundSource * nSoundSystem::createSource(QString name, nSoundSourceRole role)
155 {
156     if(name.isEmpty())
157     {
158         name = QString("nSoundSource_%1").arg(QUuid::createUuid().toString());
159     }
160
161     nSoundSource * src;
162     try{
163         src = new nSoundSource(name, role, this);
164         m_sources.insert(name, src);
165         return src;
166     }catch(...)
167     {
168         return 0;
169     }
170 }
171
172 nSoundSource * nSoundSystem::source(QString name)
173 {
174     return m_sources.value(name, 0);
175 }
176
177 bool nSoundSystem::destroySource(QString name)
178 {
179     nSoundSource * src = m_sources.value(name, 0);
180     if(!src) return false;
181     m_sources.remove(name);
182     delete src;
183     return true;
184 }
185
186 bool nSoundSystem::destroySource(nSoundSource * source)
187 {
188     nSoundSource * src = m_sources.value(source->objectName(), 0);
189     if(!src) return false;
190     m_sources.remove(source->objectName());
191     delete src;
192     return true;
193 }
194
195
196 // BUFFER METHODS
197
198 nSoundBuffer * nSoundSystem::createBuffer(QString name)
199 {
200     if(name.isEmpty()) qWarning("Creating nSoundBuffer with empty name.");
201
202     nSoundBuffer * buf = new nSoundBuffer(name, this);
203     m_buffers.insert(name, buf);
204     return buf;
205 }
206
207 nSoundBuffer * nSoundSystem::buffer(QString name)
208 {
209     return m_buffers.value(name, 0);
210 }
211
212 bool nSoundSystem::destroyBuffer(QString name)
213 {
214     nSoundBuffer * buf = m_buffers.value(name, 0);
215     if(!buf) return false;
216     m_buffers.remove(name);
217     delete buf;
218     return true;
219 }
220
221 bool nSoundSystem::destroyBuffer(nSoundBuffer * buffer)
222 {
223     nSoundBuffer * buf = m_buffers.value(buffer->objectName(), 0);
224     if(!buf) return false;
225     m_buffers.remove(buffer->objectName());
226     delete buf;
227     return true;
228 }
229
230
231 // STREAMER METHODS
232
233 nSoundStreamer * nSoundSystem::createStreamer(QString name, nSoundSource * source, nSoundStreamerPlaylist * playlist)
234 {
235     if(name.isEmpty()) qWarning("Creating nSoundStreamer with an empty name.");
236
237     nSoundStreamer * streamer = new nSoundStreamer(name, source, playlist, this);
238     playlist->setParent(streamer);
239     m_streamers.insert(name, streamer);
240     return streamer;
241 }
242
243 nSoundStreamerPlaylist *nSoundSystem::createStreamerPlaylist(QObject *parent)
244 {
245     return new nSoundStreamerPlaylist(parent);
246 }
247
248 nSoundStreamer * nSoundSystem::streamer(QString name)
249 {
250     return m_streamers.value(name, 0);
251 }
252
253 bool nSoundSystem::destroyStreamer(QString name)
254 {
255     nSoundStreamer * streamer = m_streamers.value(name, 0);
256     if(!streamer) return false;
257     m_streamers.remove(name);
258     delete streamer;
259     return true;
260 }
261
262 bool nSoundSystem::destroyStreamer(nSoundStreamer * streamer)
263 {
264     nSoundStreamer * strm = m_streamers.value(streamer->objectName(), 0);
265     if(!strm) return false;
266     m_streamers.remove(strm->objectName());
267     delete strm;
268     return true;
269 }