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 
20 #include "messages.h"
21 #include "aeolus.h"
22 
23 //---------------------------------------------------------
24 //   start
25 //---------------------------------------------------------
26 
audio_start()27 void Aeolus::audio_start ()
28       {
29       _fsize  = 0;
30       for (int i = 0; i < _nasect; i++)
31             _asectpar [i] = _asectp [i]->get_apar ();
32       }
33 
34 //---------------------------------------------------------
35 //   init
36 //---------------------------------------------------------
37 
audio_init(int sampleRate)38 void Aeolus::audio_init(int sampleRate)
39       {
40       _nplay   = 2;
41       _fsamp   = sampleRate;
42       _audiopar[VOLUME] = 0.32f;
43       _audiopar[REVSIZE] = 0.075f;
44       _revtime = 4.0f;
45       _audiopar[REVTIME] = _revtime;
46       _audiopar[STPOSIT] = 0.5f;
47       _revsize = 0.075;
48 
49       _nasect = NASECT;
50       for (int i = 0; i < NASECT; i++) {
51             _asectp [i] = new Asection ((float) _fsamp);
52             _asectp [i]->set_size (_revsize);
53             }
54       _hold = KEYS_MASK;
55       }
56 
57 //---------------------------------------------------------
58 //   proc_queue
59 //    Execute command from the model
60 //---------------------------------------------------------
61 
proc_queue(uint32_t k)62 void Aeolus::proc_queue (uint32_t k)
63       {
64       int c = k >> 24;
65       int j = (k >> 16) & 255;
66       int i = (k >>  8) & 255;
67       int b = k & 255;
68 
69       switch (c) {
70             case 0:     // Single key off.
71                   key_off (i, b);
72                   break;
73 
74             case 1:     // Single key on.
75                   key_on (i, b);
76                   break;
77 
78             case 2:     // Conditional key off.
79                   cond_key_off (j, b);
80                   break;
81 
82             case 3:     // Conditional key on.
83                   cond_key_on (j, b);
84                   break;
85 
86             case 4:     // Clear bits in division mask.
87                   _divisp [j]->clr_div_mask (b);
88                   break;
89 
90             case 5:     // Set bits in division mask.
91                   _divisp [j]->set_div_mask (b);
92                   break;
93 
94             case 6:     // Clear bits in rank mask.
95                   _divisp [j]->clr_rank_mask (i, b);
96                   break;
97 
98             case 7:     // Set bits in rank mask.
99                   _divisp [j]->set_rank_mask (i, b);
100                   break;
101 
102             case 8:     // Hold off.
103                   _hold = KEYS_MASK;
104                   cond_key_off (HOLD_MASK, HOLD_MASK);
105                   break;
106 
107             case 9:     // Hold on.
108                   _hold = KEYS_MASK | HOLD_MASK;
109                   cond_key_on (j, HOLD_MASK);
110                   break;
111 
112             case 16:    // Tremulant on/off.
113                   if (b)
114                         _divisp [j]->trem_on ();
115                   else
116                         _divisp [j]->trem_off ();
117                   break;
118 
119             case 17:    // Per-division performance controllers.
120                   qDebug("Aeolus: not impl.");
121 #if 0
122                   if (n < 2)
123                         return;
124 //TODO                  u.i = Q->read (1);
125 //TODO                  Q->read_commit (2);
126                   switch (i) {
127                         case 0: _divisp [j]->set_swell (u.f); break;
128                         case 1: _divisp [j]->set_tfreq (u.f); break;
129                         case 2: _divisp [j]->set_tmodd (u.f); break;
130                         break;
131                         }
132 #endif
133                   break;
134             }
135       }
136 
137 //---------------------------------------------------------
138 //   process
139 //---------------------------------------------------------
140 
process(unsigned nframes,float * out,float *,float *)141 void Aeolus::process(unsigned nframes, float* out, float*, float*)
142       {
143       float gain = 1.0;
144 
145       for (int n = 0; n < NNOTES; n++) {
146             int m = _keymap[n];
147             if (m & 128) {
148                   m &= 127;
149                   _keymap [n] = m;
150                   for (int d = 0; d < _ndivis; d++)
151                         _divisp[d]->update (n, m);
152                   }
153             }
154 
155       for (int d = 0; d < _ndivis; d++)
156             _divisp[d]->update(_keymap);
157 
158       if (fabsf(_revsize - _audiopar [REVSIZE]) > 0.001f) {
159             _revsize = _audiopar[REVSIZE];
160             for (int j = 0; j < _nasect; j++)
161                   _asectp[j]->set_size(_revsize);
162             }
163       int k = nout;
164       while (nframes > 0) {
165             if (nout == 0) {
166                   float W [PERIOD];
167                   float X [PERIOD];
168                   float Y [PERIOD];
169                   float R [PERIOD];
170                   memset(W, 0, PERIOD * sizeof (float));
171                   memset(X, 0, PERIOD * sizeof (float));
172                   memset(Y, 0, PERIOD * sizeof (float));
173                   memset(R, 0, PERIOD * sizeof (float));
174 
175                   for (int j = 0; j < _ndivis; j++)
176                         _divisp[j]->process();
177                   for (int j = 0; j < _nasect; j++)
178                         _asectp[j]->process(gain, W, X, Y, R);
179 
180                   float stposit = _audiopar[STPOSIT];
181                   for (int j = 0; j < PERIOD; j++) {
182                         loutb[j] = W[j] + stposit * X[j] + Y[j];
183                         routb[j] = W[j] + stposit * X[j] - Y[j];
184                         }
185                   nout = PERIOD;
186                   k   += PERIOD;
187                   }
188             *out++ += gain * loutb[PERIOD - nout];
189             *out++ += gain * routb[PERIOD - nout];
190             --nout;
191             --nframes;
192             }
193       }
194 
195 //---------------------------------------------------------
196 //   newDivis
197 //---------------------------------------------------------
198 
newDivis(M_new_divis * X)199 void Aeolus::newDivis(M_new_divis* X)
200       {
201       Division     *D = new Division (_asectp [X->_asect], (float) _fsamp);
202       D->set_div_mask (X->_dmask);
203       D->set_swell (X->_swell);
204       D->set_tfreq (X->_tfreq);
205       D->set_tmodd (X->_tmodd);
206       _divisp [_ndivis] = D;
207       _ndivis++;
208       }
209 
cond_key_off(int m,int b)210 void Aeolus::cond_key_off (int m, int b)
211       {
212       unsigned char* p = _keymap;
213 
214       for (int i = 0; i < NNOTES; i++, p++) {
215             if (*p & m) {
216                   *p &= ~b;
217                   *p |= 0x80;
218                   }
219             }
220       }
221 
cond_key_on(int m,int b)222 void Aeolus::cond_key_on (int m, int b)
223       {
224       unsigned char* p = _keymap;
225 
226       for (int i = 0; i < NNOTES; i++, p++) {
227             if (*p & m)
228                   *p |= b | 0x80;
229             }
230       }
231 
key_off(int n,int b)232 void Aeolus::key_off (int n, int b)
233       {
234       _keymap[n] &= ~b;
235       _keymap[n] |= 0x80;
236       }
237 
key_on(int n,int b)238 void Aeolus::key_on (int n, int b)
239       {
240       _keymap[n] |= b | 0x80;
241       }
242 
243 
244