1 //=============================================================================
2 // Zerberus
3 // Zample player
4 //
5 // Copyright (C) 2013 Werner Schweer
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 version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include <stdio.h>
14
15 #include "zerberus.h"
16 #include "zerberusgui.h"
17 #include "voice.h"
18 #include "channel.h"
19 #include "instrument.h"
20 #include "zone.h"
21
22 #include "midi/event.h"
23 #include "midi/midipatch.h"
24
25 #include "mscore/preferences.h"
26
27 bool Zerberus::initialized = false;
28 // instruments can be shared between several zerberus instances
29 std::list<ZInstrument*> Zerberus::globalInstruments;
30
31 //---------------------------------------------------------
32 // createZerberus
33 //---------------------------------------------------------
34
createZerberus()35 Ms::Synthesizer* createZerberus()
36 {
37 return new Zerberus();
38 }
39
40 //---------------------------------------------------------
41 // Zerberus
42 //---------------------------------------------------------
43
Zerberus()44 Zerberus::Zerberus()
45 : Synthesizer()
46 {
47 if (!initialized) {
48 initialized = true;
49 Voice::init();
50 }
51
52 freeVoices.init(this);
53 for (int i = 0; i < MAX_CHANNELS; ++i)
54 _channel[i] = new Channel(this, i);
55 busy = true; // no sf loaded yet
56 }
57
58 //---------------------------------------------------------
59 // ~Zerberus
60 //---------------------------------------------------------
61
~Zerberus()62 Zerberus::~Zerberus()
63 {
64 busy = true;
65 while (!instruments.empty()) {
66 auto i = instruments.front();
67 auto it = instruments.begin();
68 instruments.erase(it);
69
70 i->setRefCount(i->refCount() - 1);
71 if (i->refCount() <= 0) {
72 delete i;
73 auto it1 = find(globalInstruments.begin(), globalInstruments.end(), i);
74 if (it1 != globalInstruments.end())
75 globalInstruments.erase(it1);
76 }
77 }
78 for (Channel* c : _channel)
79 delete c;
80
81 qDeleteAll(patches);
82 }
83
84 //---------------------------------------------------------
85 // programChange
86 //---------------------------------------------------------
87
programChange(int channel,int program)88 void Zerberus::programChange(int channel, int program)
89 {
90 qDebug("Zerberus programChange %d %d", channel, program);
91 }
92
93 //---------------------------------------------------------
94 // trigger
95 // gui
96 //---------------------------------------------------------
97
trigger(Channel * channel,int key,int velo,Trigger trigger,int cc,int ccVal,double durSinceNoteOn)98 void Zerberus::trigger(Channel* channel, int key, int velo, Trigger trigger, int cc, int ccVal, double durSinceNoteOn)
99 {
100 ZInstrument* i = channel->instrument();
101 double random = (double) rand() / (double) RAND_MAX;
102 for (Zone* z : i->zones()) {
103 if (z->match(channel, key, velo, trigger, random, cc, ccVal)) {
104 //
105 // handle offBy voices
106 //
107 if (z->group) {
108 for (Voice* v = activeVoices; v; v = v->next()) {
109 if (v->offBy() == z->group) {
110 if (v->offMode() == OffMode::FAST)
111 v->stop(1);
112 else
113 v->stop();
114 }
115 }
116 }
117
118 if (freeVoices.empty()) {
119 qDebug("Zerberus: out of voices...");
120 return;
121 }
122
123 Voice* voice = freeVoices.pop();
124 Q_ASSERT(voice->isOff());
125 voice->start(channel, key, velo, z, durSinceNoteOn);
126 voice->setNext(activeVoices);
127 activeVoices = voice;
128 }
129 }
130 }
131
132 //---------------------------------------------------------
133 // processNoteOff
134 //---------------------------------------------------------
135
processNoteOff(Channel * cp,int key)136 void Zerberus::processNoteOff(Channel* cp, int key)
137 {
138 for (Voice* v = activeVoices; v; v = v->next()) {
139 if ((v->channel() == cp)
140 && (v->key() == key)
141 && (v->loopMode() != LoopMode::ONE_SHOT)
142 ) {
143 if (cp->sustain() < 0x40 && !v->isStopped()) {
144 v->stop();
145 double durSinceNoteOn = v->getSamplesSinceStart() / sampleRate();
146 trigger(cp, key, v->velocity(), Trigger::RELEASE, -1, -1, durSinceNoteOn);
147 }
148 else {
149 if (v->isPlaying())
150 v->sustained();
151 }
152 }
153 }
154 }
155
156 //---------------------------------------------------------
157 // processNoteOn
158 //---------------------------------------------------------
159
processNoteOn(Channel * cp,int key,int velo)160 void Zerberus::processNoteOn(Channel* cp, int key, int velo)
161 {
162 for (Voice* v = activeVoices; v; v = v->next()) {
163 if (v->channel() == cp && v->key() == key) {
164 if (v->isSustained()) {
165 //if (v->isPlaying())
166 //printf("retrigger (stop) %p\n", v);
167 v->stop(100); // fast stop
168 }
169 }
170 }
171 trigger(cp, key, velo, Trigger::ATTACK, -1, -1, 0);
172 }
173
174 //---------------------------------------------------------
175 // process
176 //---------------------------------------------------------
177
play(const Ms::PlayEvent & event)178 void Zerberus::play(const Ms::PlayEvent& event)
179 {
180 if (busy)
181 return;
182 static_assert(MAX_CHANNELS - 1 >= std::numeric_limits<decltype(event.channel())>::max(), "need to add a check for a channel number range");
183 //if (event.channel() >= MAX_CHANNELS)
184 // return;
185 Channel* cp = _channel[event.channel()];
186 if (cp->instrument() == 0) {
187 // qDebug("Zerberus::play(): no instrument for channel %d", event.channel());
188 return;
189 }
190
191 switch(event.type()) {
192 case Ms::ME_NOTEOFF:
193 processNoteOff(cp, event.dataA());
194 break;
195
196 case Ms::ME_NOTEON: {
197 int key = event.dataA();
198 int vel = event.dataB();
199 if (vel)
200 processNoteOn(cp, key, vel);
201 else
202 processNoteOff(cp, key);
203 }
204 break;
205
206 case Ms::ME_CONTROLLER:
207 cp->controller(event.dataA(), event.dataB());
208 trigger(cp, -1, -1, Trigger::CC, event.dataA(), event.dataB(), 0);
209 break;
210
211 default:
212 qDebug("Zerberus: event type 0x%02x", event.type());
213 break;
214 }
215 }
216
217 //---------------------------------------------------------
218 // process
219 // realtime
220 //---------------------------------------------------------
221
process(unsigned frames,float * p,float *,float *)222 void Zerberus::process(unsigned frames, float* p, float*, float*)
223 {
224 if (busy)
225 return;
226 Voice* v = activeVoices;
227 Voice* pv = 0;
228 while (v) {
229 v->process(frames, p);
230 if (v->isOff()) {
231 if (pv)
232 pv->setNext(v->next());
233 else
234 activeVoices = v->next();
235 freeVoices.push(v);
236 }
237 else
238 pv = v;
239 v = v->next();
240 }
241 }
242
243 //---------------------------------------------------------
244 // name
245 //---------------------------------------------------------
246
name() const247 const char* Zerberus::name() const
248 {
249 return "Zerberus";
250 }
251
252 //---------------------------------------------------------
253 // getPatchInfo
254 //---------------------------------------------------------
255
updatePatchList()256 void Zerberus::updatePatchList()
257 {
258 qDeleteAll(patches);
259 patches.clear();
260 int idx = 0;
261 for (ZInstrument* i : instruments) {
262 Ms::MidiPatch* p = new Ms::MidiPatch { false, name(), 0, idx, 0, i->name() };
263 patches.append(p);
264 ++idx;
265 }
266 }
267
268 //---------------------------------------------------------
269 // allSoundsOff
270 //---------------------------------------------------------
271
allSoundsOff(int channel)272 void Zerberus::allSoundsOff(int channel)
273 {
274 allNotesOff(channel);
275 }
276
277 //---------------------------------------------------------
278 // allNotesOff
279 //---------------------------------------------------------
280
allNotesOff(int channel)281 void Zerberus::allNotesOff(int channel)
282 {
283 busy = true;
284 for (Voice* v = activeVoices; v; v = v->next()) {
285 if (channel == -1 || (v->channel()->idx() == channel))
286 v->stop();
287 }
288 busy = false;
289 }
290
291 //---------------------------------------------------------
292 // loadSoundFonts
293 //---------------------------------------------------------
294
loadSoundFonts(const QStringList & sl)295 bool Zerberus::loadSoundFonts(const QStringList& sl)
296 {
297 for (const QString& s : sl) {
298 if (!loadInstrument(s))
299 return false;
300 }
301 updatePatchList();
302 return true;
303 }
304
305 //---------------------------------------------------------
306 // removeSoundFonts
307 //---------------------------------------------------------
308
removeSoundFonts(const QStringList & fileNames)309 bool Zerberus::removeSoundFonts(const QStringList& fileNames)
310 {
311 for (auto fileName : fileNames) {
312 if (!removeSoundFont(QFileInfo(fileName).absoluteFilePath()))
313 return false;
314 }
315 updatePatchList();
316 return true;
317 }
318
319 //---------------------------------------------------------
320 // soundFonts
321 //---------------------------------------------------------
322
soundFonts() const323 QStringList Zerberus::soundFonts() const
324 {
325 QStringList sl;
326 for (ZInstrument* i : instruments)
327 sl.append(i->path());
328 return sl;
329 }
330
331 //---------------------------------------------------------
332 // soundFontsInfo
333 //---------------------------------------------------------
334
soundFontsInfo() const335 std::vector<Ms::SoundFontInfo> Zerberus::soundFontsInfo() const
336 {
337 std::vector<Ms::SoundFontInfo> sl;
338 sl.reserve(instruments.size());
339 for (ZInstrument* i : instruments)
340 sl.emplace_back(i->path());
341 return sl;
342 }
343
344 //---------------------------------------------------------
345 // addSoundFont
346 //---------------------------------------------------------
347
addSoundFont(const QString & s)348 bool Zerberus::addSoundFont(const QString& s)
349 {
350 QMutexLocker locker(&mutex);
351 bool res = loadInstrument(s);
352 updatePatchList();
353 return res;
354 }
355
356 //---------------------------------------------------------
357 // removeSoundFont
358 //---------------------------------------------------------
359
removeSoundFont(const QString & s)360 bool Zerberus::removeSoundFont(const QString& s)
361 {
362 for (ZInstrument* i : instruments) {
363 if (i->path() == s) {
364 auto it = find(instruments.begin(), instruments.end(), i);
365 if (it == instruments.end())
366 return false;
367 instruments.erase(it);
368 for (int k = 0; k < MAX_CHANNELS; ++k) {
369 if (_channel[k]->instrument() == i)
370 _channel[k]->setInstrument(0);
371 }
372 if (!instruments.empty()) {
373 for (int ii = 0; ii < MAX_CHANNELS; ++ii) {
374 if (_channel[ii]->instrument() == 0)
375 _channel[ii]->setInstrument(instruments.front());
376 }
377 }
378 i->setRefCount(i->refCount() - 1);
379 if (i->refCount() <= 0) {
380 auto it1 = find(globalInstruments.begin(), globalInstruments.end(), i);
381 if (it1 == globalInstruments.end())
382 return false;
383 globalInstruments.erase(it1);
384 delete i;
385 }
386
387 updatePatchList();
388 return true;
389 }
390 }
391
392 updatePatchList();
393 return false;
394 }
395
396 //---------------------------------------------------------
397 // state
398 //---------------------------------------------------------
399
state() const400 Ms::SynthesizerGroup Zerberus::state() const
401 {
402 Ms::SynthesizerGroup g;
403 g.setName(name());
404
405 QStringList sfl = soundFonts();
406 foreach(QString sf, sfl)
407 g.push_back(Ms::IdValue(0, sf));
408 return g;
409 }
410
411 //---------------------------------------------------------
412 // setState
413 //---------------------------------------------------------
414
setState(const Ms::SynthesizerGroup & sp)415 bool Zerberus::setState(const Ms::SynthesizerGroup& sp)
416 {
417 QStringList sfs;
418 for (const Ms::IdValue& v : sp)
419 sfs.append(v.data);
420 return loadSoundFonts(sfs);
421 }
422
423 //---------------------------------------------------------
424 // instrument
425 //---------------------------------------------------------
426
instrument(int n) const427 ZInstrument* Zerberus::instrument(int n) const
428 {
429 int idx = 0;
430 for (auto i = instruments.begin(); i != instruments.end(); ++i) {
431 if (idx == n)
432 return *i;
433 ++idx;
434 }
435 return 0;
436 }
437
438 //---------------------------------------------------------
439 // loadInstrument
440 // return true on success
441 //---------------------------------------------------------
442
loadInstrument(const QString & s)443 bool Zerberus::loadInstrument(const QString& s)
444 {
445 if (s.isEmpty())
446 return false;
447 QFileInfo fis(s);
448 QString fileName = fis.fileName();
449 for (ZInstrument* instr : instruments) {
450 if (QFileInfo(instr->path()).fileName() == fileName) { // already loaded?
451 return true;
452 }
453 }
454 for (ZInstrument* instr : globalInstruments) {
455 if (QFileInfo(instr->path()).fileName() == fileName) {
456 instruments.push_back(instr);
457 instr->setRefCount(instr->refCount() + 1);
458 if (instruments.size() == 1) {
459 for (int i = 0; i < MAX_CHANNELS; ++i)
460 _channel[i]->setInstrument(instr);
461 }
462 busy = false;
463 return true;
464 }
465 }
466
467 QFileInfoList l = Zerberus::sfzFiles();
468 QString path;
469 foreach (const QFileInfo& fi, l) {
470 if (fi.fileName() == fileName) {
471 path = fi.absoluteFilePath();
472 break;
473 }
474 }
475 busy = true;
476 ZInstrument* instr = new ZInstrument(this);
477
478 try {
479 if (instr->load(path)) {
480 globalInstruments.push_back(instr);
481 instruments.push_back(instr);
482 instr->setRefCount(1);
483 //
484 // set default instrument for all channels:
485 //
486 if (instruments.size() == 1) {
487 for (int i = 0; i < MAX_CHANNELS; ++i)
488 _channel[i]->setInstrument(instr);
489 }
490 busy = false;
491 return true;
492 }
493 }
494 catch (std::bad_alloc& a) {
495 qDebug("Unable to allocate memory when loading Zerberus soundfont %s", qPrintable(s));
496
497 // Prevent "Unreferenced local variable" warning for a
498 Q_UNUSED(a);
499 }
500 catch (...) {
501 }
502 qDebug("Zerberus::loadInstrument failed");
503 busy = false;
504 delete instr;
505 return false;
506 }
507
508