1 /*
2 Copyright (C) 2003-2008 Fons Adriaensen <fons@kokkinizita.net>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifdef Q_OS_MAC
20 #include <locale.h>
21 #endif
22
23 #include "aeolus.h"
24 #include "model.h"
25
26 namespace Ms {
27 extern QString dataPath;
28 extern QString mscoreGlobalShare;
29 };
30
31 #include "synthesizer/event.h"
32 #include "libmscore/xml.h"
33 #include "sparm_p.h"
34
35 const std::vector<ParDescr> Aeolus::pd = {
36 { A_VOLUME, "volume", true, 0.32f, 0.00f, 1.00f },
37 { A_REVSIZE, "revsize", true, 0.075f, 0.025f, 0.15f },
38 { A_REVTIME, "revtime", true, 4.0f, 2.0f, 7.00f },
39 { A_STPOSIT, "stposit", true, 0.5f, -1.00f, 1.0f },
40 };
41
42 //---------------------------------------------------------
43 // createAeolus
44 //---------------------------------------------------------
45
createAeolus()46 Synthesizer* createAeolus()
47 {
48 return new Aeolus();
49 }
50
51 //---------------------------------------------------------
52 // Aeolus
53 //---------------------------------------------------------
54
Aeolus()55 Aeolus::Aeolus() : Synthesizer()
56 {
57 model = nullptr;
58 patchList.append(new MidiPatch { false, "Aeolus", 0, 0, 0, "Aeolus" });
59
60 _sc_cmode = 0;
61 _sc_group = 0;
62 _running = false;
63 _hold = 0;
64 _nplay = 0;
65 _nasect = 0;
66 _ndivis = 0;
67 _revsize = 0.0f;
68 _revtime = 0.0f;
69 nout = 0;
70 _fsamp = 0.0f;
71 _fsize = 0;
72 _ifc_init = nullptr;
73 _midimap = { 0 };
74 _asectp = { nullptr };
75 _divisp = { nullptr };
76 _keymap = { 0 };
77 _audiopar = { 0.0f };
78 routb = { 0.0f };
79 loutb = { 0.0f };
80 _asectpar = { nullptr };
81 _ifelms = { 0 };
82 _tempstr = { 0 };
83 }
84
~Aeolus()85 Aeolus::~Aeolus()
86 {
87 delete model;
88 for (int i = 0; i < _nasect; i++)
89 delete _asectp [i];
90 for (int i = 0; i < _ndivis; i++)
91 delete _divisp [i];
92 }
93
94 //---------------------------------------------------------
95 // init
96 //---------------------------------------------------------
97
init(float samplerate)98 void Aeolus::init(float samplerate)
99 {
100 setlocale(LC_ALL, "C"); // scanf of floats does not work otherwise
101
102 QString stops = mscoreGlobalShare + "/sound/aeolus/stops";
103 int n = strlen(qPrintable(stops));
104 char* stopsPath = new char[n+1];
105 strcpy(stopsPath, qPrintable(stops));
106
107 QDir dir;
108 QString waves = dataPath + QString("/aeolus/waves%1").arg(int(samplerate));
109 dir.mkpath(waves);
110 n = strlen(qPrintable(waves));
111 char* wavesPath = new char[n+1];
112 strcpy(wavesPath, qPrintable(waves));
113
114 audio_init(int(samplerate));
115 model = new Model (this, _midimap, stopsPath, "Aeolus", wavesPath);
116
117 audio_start();
118 model->init();
119 }
120
121 //---------------------------------------------------------
122 // setMasterTuning
123 //---------------------------------------------------------
124
setMasterTuning(double)125 void Aeolus::setMasterTuning(double)
126 {
127 }
128
129 //---------------------------------------------------------
130 // masterTuning
131 //---------------------------------------------------------
132
masterTuning() const133 double Aeolus::masterTuning() const
134 {
135 return 440.0;
136 }
137
138 //---------------------------------------------------------
139 // play
140 //---------------------------------------------------------
141
play(const PlayEvent & event)142 void Aeolus::play(const PlayEvent& event)
143 {
144 int ch = event.channel();
145 int type = event.type();
146 int m = _midimap [ch] & 0x7f; // Keyboard and hold bits
147
148 if (type == ME_NOTEON) {
149 int n = event.dataA();
150 int v = event.dataB();
151 if ((n >= 36) && (n <= 96)) {
152 n -= 36;
153 if (v == 0)
154 key_off(n, m);
155 else
156 key_on(n, m);
157 }
158 }
159 else if (type == ME_NOTEOFF) {
160 int n = event.dataA();
161 if ((n >= 36) && (n <= 96)) {
162 n -= 36;
163 key_off(n, m);
164 }
165 }
166 else if (type == ME_CONTROLLER) {
167 int p = event.dataA();
168 int v = event.dataB();
169 switch(p) {
170 case MIDICTL_IFELM:
171 if (v & 0x40) {
172 // Set mode or clear group.
173 _sc_cmode = (v >> 4) & 3;
174 _sc_group = v & 7;
175 if (_sc_cmode == 0)
176 model->clr_group(_sc_group);
177 }
178 else if (_sc_cmode) {
179 // Set, reset or toggle stop.
180 model->set_ifelm (_sc_group, v & 0x1f, _sc_cmode - 1);
181 }
182 break;
183 case CTRL_ALL_NOTES_OFF:
184 allNotesOff(ch);
185 break;
186 }
187 }
188 }
189
190 //---------------------------------------------------------
191 // allNotesOff
192 //---------------------------------------------------------
193
allNotesOff(int)194 void Aeolus::allNotesOff(int)
195 {
196 for (int i = 0; i < NNOTES; ++i)
197 _keymap[i] = 0x80;
198 }
199
200 //---------------------------------------------------------
201 // getPatchInfo
202 //---------------------------------------------------------
203
getPatchInfo() const204 const QList<MidiPatch*>& Aeolus::getPatchInfo() const
205 {
206 return patchList;
207 }
208
209 //---------------------------------------------------------
210 // setValue
211 //---------------------------------------------------------
212
setValue(int id,double value)213 void Aeolus::setValue(int id, double value)
214 {
215 const ParDescr* p = parameter(id);
216 if (p == 0)
217 return;
218 double v;
219 if (p->log)
220 v = exp(p->min + value * (p->max - p->min));
221 else
222 v = p->min + value * (p->max - p->min);
223
224 switch (id) {
225 case A_VOLUME: _audiopar[VOLUME] = v; break;
226 case A_REVSIZE: _audiopar[REVSIZE] = v; break;
227 case A_REVTIME: _audiopar[REVTIME] = v; break;
228 case A_STPOSIT: _audiopar[STPOSIT] = v; break;
229 }
230 }
231
232 //---------------------------------------------------------
233 // value
234 //---------------------------------------------------------
235
value(int idx) const236 double Aeolus::value(int idx) const
237 {
238 double v = 0.0;
239 switch (idx) {
240 case A_VOLUME: v = _audiopar[VOLUME]; break;
241 case A_REVSIZE: v = _audiopar[REVSIZE]; break;
242 case A_REVTIME: v = _audiopar[REVTIME]; break;
243 case A_STPOSIT: v = _audiopar[STPOSIT]; break;
244 }
245 const ParDescr* p = parameter(idx);
246 if (p->log)
247 v = (log(v) - p->min)/(p->max - p->min);
248 else
249 v = (v - p->min)/(p->max - p->min);
250 return v;
251 }
252
253 //---------------------------------------------------------
254 // state
255 //---------------------------------------------------------
256
state() const257 SynthesizerGroup Aeolus::state() const
258 {
259 SynthesizerGroup g;
260 g.setName(name());
261
262 for (const ParDescr& d : pd)
263 g.push_back(IdValue(d.id, QString("%1").arg(value(d.id))));
264 return g;
265 }
266
267 //---------------------------------------------------------
268 // setState
269 //---------------------------------------------------------
270
setState(const SynthesizerGroup & g)271 bool Aeolus::setState(const SynthesizerGroup& g)
272 {
273 for (const IdValue& v : g)
274 setValue(v.id, v.data.toDouble());
275 return true;
276 }
277
278 //---------------------------------------------------------
279 // parameter
280 //---------------------------------------------------------
281
parameter(int idx) const282 const ParDescr* Aeolus::parameter(int idx) const
283 {
284 return &pd[idx];
285 }
286
287