1 /***************************************************************************
2 **                                                                        **
3 **  Polyphone, a soundfont editor                                         **
4 **  Copyright (C) 2013-2019 Davy Triponney                                **
5 **                2014      Andrea Celani                                 **
6 **                                                                        **
7 **  This program is free software: you can redistribute it and/or modify  **
8 **  it under the terms of the GNU General Public License as published by  **
9 **  the Free Software Foundation, either version 3 of the License, or     **
10 **  (at your option) any later version.                                   **
11 **                                                                        **
12 **  This program is distributed in the hope that it will be useful,       **
13 **  but WITHOUT ANY WARRANTY; without even the implied warranty of        **
14 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the          **
15 **  GNU General Public License for more details.                          **
16 **                                                                        **
17 **  You should have received a copy of the GNU General Public License     **
18 **  along with this program. If not, see http://www.gnu.org/licenses/.    **
19 **                                                                        **
20 ****************************************************************************
21 **           Author: Davy Triponney                                       **
22 **  Website/Contact: https://www.polyphone-soundfonts.com                 **
23 **             Date: 01.01.2013                                           **
24 ***************************************************************************/
25 
26 #include "soundengine.h"
27 #include <QThread>
28 
29 QList<SoundEngine*> SoundEngine::_listInstances = QList<SoundEngine*>();
30 int SoundEngine::_gainSmpl = 0;
31 bool SoundEngine::_isStereo = false;
32 bool SoundEngine::_isLoopEnabled = true;
33 
SoundEngine(unsigned int bufferSize)34 SoundEngine::SoundEngine(unsigned int bufferSize) : CircularBuffer(bufferSize, 2 * bufferSize)
35 {
36     _listInstances << this;
37     _dataTmpL = new float [8 * bufferSize];
38     _dataTmpR = new float [8 * bufferSize];
39 }
40 
~SoundEngine()41 SoundEngine::~SoundEngine()
42 {
43     _listInstances.removeOne(this);
44     delete [] _dataTmpL;
45     delete [] _dataTmpR;
46 }
47 
getNbVoices()48 int SoundEngine::getNbVoices()
49 {
50     _mutexVoices.lock();
51     int iRet = _listVoices.size();
52     _mutexVoices.unlock();
53     return iRet;
54 }
55 
addVoice(Voice * voice,QList<Voice * > friends)56 void SoundEngine::addVoice(Voice * voice, QList<Voice*> friends)
57 {
58     int key = voice->getKey();
59     if (key >= 0)
60     {
61         int exclusiveClass = voice->getExclusiveClass();
62         if (exclusiveClass != 0)
63             closeAll(exclusiveClass, voice->getPresetNumber(), friends);
64     }
65     else
66         voice->setLoopMode(_isLoopEnabled);
67 
68     // Find the less busy SoundEngine
69     int index = -1;
70     int minVoiceNumber = -1;
71     for (int i = 0; i < _listInstances.size(); i++)
72     {
73         int nbVoices = _listInstances.at(i)->getNbVoices();
74         if (minVoiceNumber == -1 || nbVoices < minVoiceNumber)
75         {
76             index = i;
77             minVoiceNumber = nbVoices;
78         }
79     }
80     if (index != -1)
81         _listInstances.at(index)->addVoiceInstance(voice);
82 
83     if (key < 0)
84         _listInstances.at(index)->setStereoInstance(_isStereo);
85 }
86 
addVoiceInstance(Voice * voice)87 void SoundEngine::addVoiceInstance(Voice * voice)
88 {
89     _mutexVoices.lock();
90     _listVoices << voice;
91     _mutexVoices.unlock();
92 }
93 
stopAllVoices()94 void SoundEngine::stopAllVoices()
95 {
96     for (int i = 0; i < _listInstances.size(); i++)
97         _listInstances.at(i)->stopAllVoicesInstance();
98 }
99 
stopAllVoicesInstance()100 void SoundEngine::stopAllVoicesInstance()
101 {
102     _mutexVoices.lock();
103     while (!_listVoices.isEmpty())
104     {
105         // Signal emitted for the sample player (voice -1)
106         if (_listVoices.last()->getKey() == -1)
107             emit(readFinished(_listVoices.last()->getToken()));
108 
109         delete _listVoices.takeLast();
110     }
111     _mutexVoices.unlock();
112 }
113 
syncNewVoices()114 void SoundEngine::syncNewVoices()
115 {
116     foreach (SoundEngine * engine, _listInstances)
117         engine->_mutexBuffer.lock();
118 
119     foreach (SoundEngine * engine, _listInstances)
120         engine->_mutexVoices.lock();
121 
122     // Current data length available in all buffers
123     QList<quint32> dataAvailable;
124     quint32 maxDataLength = 0;
125     for (int i = 0; i < _listInstances.size(); i++)
126     {
127         quint32 iTmp = _listInstances.at(i)->currentLengthAvailable();
128         if (iTmp > maxDataLength)
129             maxDataLength = iTmp;
130         dataAvailable << iTmp;
131     }
132 
133     // Synchronization of all new voices based on the greatest buffer length
134     for (int i = 0; i < _listInstances.size(); i++)
135         _listInstances.at(i)->syncNewVoicesInstance(maxDataLength - dataAvailable.at(i));
136 
137     foreach (SoundEngine * engine, _listInstances)
138         engine->_mutexVoices.unlock();
139 
140     foreach (SoundEngine * engine, _listInstances)
141         engine->_mutexBuffer.unlock();
142 }
143 
syncNewVoicesInstance(quint32 delay)144 void SoundEngine::syncNewVoicesInstance(quint32 delay)
145 {
146     int nbVoices = _listVoices.size();
147     for (int i = nbVoices - 1; i >= 0; i--)
148     {
149         // Check for started voice
150         if (!_listVoices.at(i)->isRunning())
151             _listVoices.at(i)->runVoice(delay);
152     }
153 }
154 
releaseNote(int numNote)155 void SoundEngine::releaseNote(int numNote)
156 {
157     foreach (SoundEngine * engine, _listInstances)
158         engine->_mutexBuffer.lock();
159 
160     foreach (SoundEngine * engine, _listInstances)
161         engine->_mutexVoices.lock();
162 
163     for (int i = 0; i < _listInstances.size(); i++)
164         _listInstances.at(i)->releaseNoteInstance(numNote);
165 
166     foreach (SoundEngine * engine, _listInstances)
167         engine->_mutexVoices.unlock();
168 
169     foreach (SoundEngine * engine, _listInstances)
170         engine->_mutexBuffer.unlock();
171 }
172 
releaseNoteInstance(int numNote)173 void SoundEngine::releaseNoteInstance(int numNote)
174 {
175     if (numNote == -1)
176     {
177         // Stop playing a sample
178         for (int i = 0; i < _listVoices.size(); i++)
179             if (_listVoices.at(i)->getKey() < 0)
180                 _listVoices.at(i)->release();
181     }
182     else
183     {
184         for (int i = 0; i < _listVoices.size(); i++)
185             if (_listVoices.at(i)->getKey() == numNote)
186                 _listVoices.at(i)->release();
187     }
188 }
189 
setGain(double gain)190 void SoundEngine::setGain(double gain)
191 {
192     for (int i = 0; i < _listInstances.size(); i++)
193         _listInstances.at(i)->setGainInstance(gain);
194 }
195 
setGainInstance(double gain)196 void SoundEngine::setGainInstance(double gain)
197 {
198     _mutexVoices.lock();
199     for (int i = 0; i < _listVoices.size(); i++)
200         if (_listVoices.at(i)->getKey() >= 0)
201             _listVoices.at(i)->setGain(gain);
202     _mutexVoices.unlock();
203 }
204 
setChorus(int level,int depth,int frequency)205 void SoundEngine::setChorus(int level, int depth, int frequency)
206 {
207     for (int i = 0; i < _listInstances.size(); i++)
208         _listInstances.at(i)->setChorusInstance(level, depth, frequency);
209 }
210 
setChorusInstance(int level,int depth,int frequency)211 void SoundEngine::setChorusInstance(int level, int depth, int frequency)
212 {
213     _mutexVoices.lock();
214     for (int i = 0; i < _listVoices.size(); i++)
215         if (_listVoices.at(i)->getKey() >= 0)
216             _listVoices.at(i)->setChorus(level, depth, frequency);
217     _mutexVoices.unlock();
218 }
219 
setPitchCorrection(qint16 correction,bool repercute)220 void SoundEngine::setPitchCorrection(qint16 correction, bool repercute)
221 {
222     for (int i = 0; i < _listInstances.size(); i++)
223         _listInstances.at(i)->setPitchCorrectionInstance(correction, repercute);
224 }
225 
setPitchCorrectionInstance(qint16 correction,bool repercute)226 void SoundEngine::setPitchCorrectionInstance(qint16 correction, bool repercute)
227 {
228     _mutexVoices.lock();
229     for (int i = 0; i < _listVoices.size(); i++)
230         if (_listVoices.at(i)->getKey() == -1 ||
231                 (_listVoices.at(i)->getKey() == -2 && repercute))
232             _listVoices[i]->setFineTune(correction);
233     _mutexVoices.unlock();
234 }
235 
setStartLoop(quint32 startLoop,bool repercute)236 void SoundEngine::setStartLoop(quint32 startLoop, bool repercute)
237 {
238     for (int i = 0; i < _listInstances.size(); i++)
239         _listInstances.at(i)->setStartLoopInstance(startLoop, repercute);
240 }
241 
setStartLoopInstance(quint32 startLoop,bool repercute)242 void SoundEngine::setStartLoopInstance(quint32 startLoop, bool repercute)
243 {
244     _mutexVoices.lock();
245     for (int i = 0; i < _listVoices.size(); i++)
246         if (_listVoices.at(i)->getKey() == -1 ||
247                 (_listVoices.at(i)->getKey() == -2 && repercute))
248             _listVoices[i]->setLoopStart(startLoop);
249     _mutexVoices.unlock();
250 }
251 
setEndLoop(quint32 endLoop,bool repercute)252 void SoundEngine::setEndLoop(quint32 endLoop, bool repercute)
253 {
254     for (int i = 0; i < _listInstances.size(); i++)
255         _listInstances.at(i)->setEndLoopInstance(endLoop, repercute);
256 }
257 
setEndLoopInstance(quint32 endLoop,bool repercute)258 void SoundEngine::setEndLoopInstance(quint32 endLoop, bool repercute)
259 {
260     _mutexVoices.lock();
261     for (int i = 0; i < _listVoices.size(); i++)
262         if (_listVoices.at(i)->getKey() == -1 ||
263                 (_listVoices.at(i)->getKey() == -2 && repercute))
264             _listVoices[i]->setLoopEnd(endLoop);
265     _mutexVoices.unlock();
266 }
267 
setLoopEnabled(bool isEnabled)268 void SoundEngine::setLoopEnabled(bool isEnabled)
269 {
270     _isLoopEnabled = isEnabled;
271     for (int i = 0; i < _listInstances.size(); i++)
272         _listInstances.at(i)->setLoopEnabledInstance(isEnabled);
273 }
274 
setLoopEnabledInstance(bool isEnabled)275 void SoundEngine::setLoopEnabledInstance(bool isEnabled)
276 {
277     // Update voices -1 and -2
278     _mutexVoices.lock();
279     for (int i = 0; i < _listVoices.size(); i++)
280         if (_listVoices.at(i)->getKey() < 0)
281             _listVoices.at(i)->setLoopMode(isEnabled);
282     _mutexVoices.unlock();
283 }
284 
setStereo(bool isStereo)285 void SoundEngine::setStereo(bool isStereo)
286 {
287     _isStereo = isStereo;
288     for (int i = 0; i < _listInstances.size(); i++)
289         _listInstances.at(i)->setStereoInstance(isStereo);
290 }
291 
setStereoInstance(bool isStereo)292 void SoundEngine::setStereoInstance(bool isStereo)
293 {
294     // Update voices -1 and -2
295     _mutexVoices.lock();
296     Voice * voice1 = nullptr;
297     Voice * voice2 = nullptr;
298     for (int i = 0; i < _listVoices.size(); i++)
299     {
300         if (_listVoices.at(i)->getKey() == -1)
301             voice1 = _listVoices.at(i);
302         else if (_listVoices.at(i)->getKey() == -2)
303             voice2 = _listVoices.at(i);
304     }
305     if (isStereo)
306     {
307         if (voice1)
308         {
309             double pan = voice1->getPan();
310             if (pan < 0)
311                 voice1->setPan(-50);
312             else if (pan > 0)
313                 voice1->setPan(50);
314             voice1->setGain(_gainSmpl - 3);
315         }
316         if (voice2)
317             voice2->setGain(_gainSmpl - 3);
318     }
319     else
320     {
321         if (voice1)
322         {
323             double pan = voice1->getPan();
324             if (pan < 0)
325                 voice1->setPan(-1);
326             else if (pan > 0)
327                 voice1->setPan(1);
328             voice1->setGain(_gainSmpl);
329         }
330         if (voice2)
331             voice2->setGain(-1000);
332     }
333     _mutexVoices.unlock();
334 }
335 
setGainSample(int gain)336 void SoundEngine::setGainSample(int gain)
337 {
338     _gainSmpl = gain;
339     for (int i = 0; i < _listInstances.size(); i++)
340         _listInstances.at(i)->setGainSampleInstance(gain);
341 }
342 
setGainSampleInstance(int gain)343 void SoundEngine::setGainSampleInstance(int gain)
344 {
345     // Update voices -1 and -2
346     _mutexVoices.lock();
347     for (int i = 0; i < _listVoices.size(); i++)
348     {
349         if (_listVoices.at(i)->getKey() == -1)
350         {
351             if (_isStereo)
352                 _listVoices.at(i)->setGain(gain - 12);
353             else
354                 _listVoices.at(i)->setGain(gain);
355         }
356         else if (_listVoices.at(i)->getKey() == -2 && _isStereo)
357             _listVoices.at(i)->setGain(gain - 12);
358     }
359     _mutexVoices.unlock();
360 }
361 
closeAll(int exclusiveClass,int numPreset,QList<Voice * > friends)362 void SoundEngine::closeAll(int exclusiveClass, int numPreset, QList<Voice*> friends)
363 {
364     for (int i = 0; i < _listInstances.size(); i++)
365         _listInstances.at(i)->closeAllInstance(exclusiveClass, numPreset, friends);
366 }
367 
closeAllInstance(int exclusiveClass,int numPreset,QList<Voice * > friends)368 void SoundEngine::closeAllInstance(int exclusiveClass, int numPreset, QList<Voice*> friends)
369 {
370     _mutexVoices.lock();
371     for (int i = 0; i < _listVoices.size(); i++)
372     {
373         if (_listVoices.at(i)->getExclusiveClass() == exclusiveClass &&
374                 _listVoices.at(i)->getPresetNumber() == numPreset &&
375                 !friends.contains(_listVoices.at(i)))
376             _listVoices.at(i)->release(true);
377     }
378     _mutexVoices.unlock();
379 }
380