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 #include <time.h>
20 #include "model.h"
21 #include "scales.h"
22 #include "global.h"
23 #include "aeolus.h"
24 
25 #define VERSION "0.0.0"
26 
27 //---------------------------------------------------------
28 //   Divis
29 //---------------------------------------------------------
30 
Divis()31 Divis::Divis() : _flags(0), _dmask(0), _nrank(0)
32       {
33       *_label = 0;
34       _param[SWELL].set("swell", SWELL_DEF, SWELL_MIN, SWELL_MAX);
35       _param[TFREQ].set("tfreq", TFREQ_DEF, TFREQ_MIN, TFREQ_MAX);
36       _param[TMODD].set("tmodd", TMODD_DEF, TMODD_MIN, TMODD_MAX);
37       }
38 
Keybd()39 Keybd::Keybd() : _flags(0)
40       {
41       *_label = 0;
42       }
43 
Ifelm()44 Ifelm::Ifelm() : _state(0)
45       {
46       _label[0] = 0;
47       _mnemo[0] = 0;
48       }
49 
Group()50 Group::Group() : _nifelm(0)
51       {
52       _label[0] = 0;
53       }
54 
55 //---------------------------------------------------------
56 //   Model
57 //---------------------------------------------------------
58 
Model(Aeolus * a,uint16_t * midimap,const char * stops,const char * instr,const char * waves)59 Model::Model (Aeolus* a,
60    uint16_t* midimap,
61    const char* stops,
62    const char* instr,
63    const char* waves)
64    :
65    _aeolus(a),
66    _midimap (midimap),
67    _stops (stops),
68    _ready (false),
69    _nasect (0),
70    _ndivis (0),
71    _nkeybd (0),
72    _ngroup (0),
73    _count (0),
74    _bank (0),
75    _pres (0),
76    _sc_cmode (0),
77    _sc_group (0)
78       {
79       sprintf (_instr, "%s/%s", stops, instr);
80       _waves = waves;
81       memset (_midimap, 0, 16 * sizeof (uint16_t));
82       memset (_preset, 0, NBANK * NPRES * sizeof (Preset *));
83       }
84 
85 //---------------------------------------------------------
86 //   init
87 //---------------------------------------------------------
88 
init()89 void Model::init()
90       {
91       read_instr ();
92       read_presets ();
93 
94       // init audio
95       Divis* D = _divis;
96       for (int d = 0; d < _ndivis; d++, D++) {
97             M_new_divis M;
98             M._flags = D->_flags;
99             M._dmask = D->_dmask;
100             M._asect = D->_asect;
101             M._swell = D->_param [Divis::SWELL].fval();
102             M._tfreq = D->_param [Divis::TFREQ].fval();
103             M._tmodd = D->_param [Divis::TMODD].fval();
104             _aeolus->newDivis(&M);
105             }
106 
107       init_iface();
108       init_ranks(MT_LOAD_RANK);
109       init_ranks(MT_SAVE_RANK);
110       }
111 
112 //---------------------------------------------------------
113 //   init_iface
114 //---------------------------------------------------------
115 
init_iface()116 void Model::init_iface()
117       {
118       M_ifc_init* M = new M_ifc_init;
119       _aeolus->_ifc_init = M;
120       M->_stops  = _stops;
121       M->_waves  = _waves;
122       M->_instr  = _instr;
123       M->_client = 0;     // _midi->_client;
124       M->_ipport = 0;     // _midi->_ipport;
125       M->_nasect = _nasect;
126       M->_nkeybd = _nkeybd;
127       M->_ndivis = _ndivis;
128       M->_ngroup = _ngroup;
129       M->_ntempe = NSCALES;
130       for (int i = 0; i < NKEYBD; i++) {
131             Keybd* K = _keybd + i;
132             M->_keybdd [i]._label = K->_label;
133             M->_keybdd [i]._flags = K->_flags;
134             }
135       for (int i = 0; i < NDIVIS; i++) {
136             Divis* D = _divis + i;
137             M->_divisd [i]._label = D->_label;
138             M->_divisd [i]._flags = D->_flags;
139             M->_divisd [i]._asect = D->_asect;
140             }
141       for (int i = 0; i < NGROUP; i++) {
142             Group* G = _group + i;
143             M->_groupd [i]._label  = G->_label;
144             M->_groupd [i]._nifelm = G->_nifelm;
145             for (int j = 0; j < G->_nifelm; j++) {
146                   M->_groupd [i]._ifelmd [j]._label = G->_ifelms [j]._label;
147                   M->_groupd [i]._ifelmd [j]._mnemo = G->_ifelms [j]._mnemo;
148                   M->_groupd [i]._ifelmd [j]._type  = G->_ifelms [j]._type;
149                   }
150             }
151       for (int i = 0; i < NSCALES; i++) {
152             M->_temped [i]._label = scales [i]._label;
153             M->_temped [i]._mnemo = scales [i]._mnemo;
154             }
155 
156       set_mconf (0, _chconf[0]._bits);
157       }
158 
init_ranks(int comm)159 void Model::init_ranks (int comm)
160       {
161       _count++;
162       _ready = false;
163 //WS      send_event (TO_IFACE, new M_ifc_retune (_fbase, _itemp));
164 
165       for (int g = 0; g < _ngroup; g++) {
166             Group* G = _group + g;
167             for (int i = 0; i < G->_nifelm; i++)
168                   proc_rank (g, i, comm);
169             }
170       _ready = true;
171       }
172 
173 
proc_rank(int g,int i,int comm)174 void Model::proc_rank (int g, int i, int comm)
175       {
176       Ifelm* I = _group [g]._ifelms + i;
177       if ((I->_type == Ifelm::DIVRANK) || (I->_type == Ifelm::KBDRANK)) {
178             int d = (I->_action0 >> 16) & 255;
179             int r = (I->_action0 >>  8) & 255;
180             Rank* R = _divis [d]._ranks + r;
181             if (comm == MT_SAVE_RANK) {
182                   if (R->_wave->modif ()) {
183                         R->_wave->save(_waves, R->_sdef, _aeolus->_fsamp,
184                            _fbase, scales[_itemp]._data);
185                         }
186                   }
187             else if (R->_count != _count) {
188                   R->_count = _count;
189                   M_def_rank M(comm);
190                   M._divis = d;
191                   M._rank  = r;
192                   M._group = g;
193                   M._ifelm = i;
194                   M._fsamp = _aeolus->_fsamp;
195                   M._fbase = _fbase;
196                   M._scale = scales [_itemp]._data;
197                   M._sdef  = R->_sdef;
198                   M._wave  = R->_wave;
199                   M._path  = _waves;
200 
201 //WS                  send_event(TO_IFACE, new M_ifc_ifelm (MT_IFC_ELATT, M._group, M._ifelm));
202 
203                   M._wave = new Rankwave (M._sdef->_n0, M._sdef->_n1);
204                   if (M._wave->load (M._path, M._sdef, M._fsamp, M._fbase, M._scale))
205                         M._wave->gen_waves (M._sdef, M._fsamp, M._fbase, M._scale);
206 
207                   _aeolus->_divisp [M._divis]->set_rank (M._rank, M._wave,  M._sdef->_pan, M._sdef->_del);
208                   _divis [M._divis]._ranks [M._rank]._wave = M._wave;
209                   }
210             }
211       }
212 
213 //---------------------------------------------------------
214 //   set_ifelm
215 //    Set, reset or toggle a stop.
216 //          m - 0 reset
217 //              1 set
218 //              2 toggle
219 //---------------------------------------------------------
220 
set_ifelm(int g,int i,int m)221 void Model::set_ifelm (int g, int i, int m)
222       {
223       Group* G = _group + g;
224 
225       if (!_ready || (g >= _ngroup) || (i >= G->_nifelm)) {
226             printf("Aeolus::Model::set_ifelm failed, ready %d %d>=%d %d>=%d\n", _ready, g, _ngroup, i, G->_nifelm);
227             return;
228             }
229       Ifelm* I = G->_ifelms + i;
230       int s = (m == 2) ? I->_state ^ 1 : m;
231       if (I->_state != s) {
232             I->_state = s;
233             _aeolus->proc_queue(s ? I->_action1 : I->_action0);
234             M_ifc_ifelm*  e = new M_ifc_ifelm (MT_IFC_ELCLR + s, g, i);
235             if (m == 0)
236                   _aeolus->_ifelms [e->_group] &= ~(1 << e->_ifelm);
237             else if (m == 1)
238                   _aeolus->_ifelms [e->_group] |= (1 << e->_ifelm);
239             else if (m == 2)
240                   _aeolus->_ifelms [e->_group] = 0;
241             }
242       }
243 
clr_group(int g)244 void Model::clr_group (int g)
245       {
246       Group* G = _group + g;
247 
248       if ((! _ready) || (g >= _ngroup))
249             return;
250 
251       for (int i = 0; i < G->_nifelm; i++) {
252             Ifelm* I = G->_ifelms + i;
253             if (I->_state) {
254                   I->_state = 0;
255                   _aeolus->proc_queue(I->_action0);
256                   }
257             }
258       _aeolus->_ifelms[g] = 0;
259       }
260 
261 
262 //---------------------------------------------------------
263 //   get_state
264 //---------------------------------------------------------
265 
get_state(uint32_t * d)266 void Model::get_state(uint32_t* d)
267       {
268       for (int g = 0; g < _ngroup; g++) {
269             Group* G = _group + g;
270             uint32_t s = 0;
271             for (int i = 0; i < G->_nifelm; i++) {
272                   Ifelm* I = G->_ifelms + i;
273                   if (I->_state & 1)
274                         s |= 1 << i;
275                   }
276             *d++ = s;
277             }
278       }
279 
280 
281 //---------------------------------------------------------
282 //   set_state
283 //---------------------------------------------------------
284 
set_state(int bank,int pres)285 void Model::set_state(int bank, int pres)
286       {
287       uint32_t d[NGROUP];
288 
289       _bank = bank;
290       _pres = pres;
291       if (get_preset(bank, pres, d)) {
292             for (int g = 0; g < _ngroup; g++) {
293                   uint32_t s = d [g];
294                   Group* G = _group + g;
295                   for (int i = 0; i < G->_nifelm; i++) {
296                         set_ifelm (g, i, s & 1);
297                         s >>= 1;
298                         }
299                   }
300             }
301       }
302 
303 
set_mconf(int,uint16_t * d)304 void Model::set_mconf (int /*i*/, uint16_t *d)
305       {
306       midi_off(127);
307       for (int j = 0; j < 16; j++) {
308             int a = d [j];
309             int b =  (a & 0x1000) ? (_keybd [a & 7]._flags & 127) : 0;
310             b |= a & 0x7700;
311             _midimap [j] = b;
312             }
313       }
314 
315 
midi_off(int mask)316 void Model::midi_off (int mask)
317       {
318       mask &= 127;
319       _aeolus->proc_queue((2 << 24) | (mask << 16) | mask);
320       }
321 
322 
retune(float freq,int temp)323 void Model::retune (float freq, int temp)
324 {
325     if (_ready)
326     {
327         _fbase = freq;
328         _itemp = temp;
329         init_ranks (MT_CALC_RANK);
330     }
331     else  {
332 //WS            send_event (TO_IFACE, new M_ifc_retune (_fbase, _itemp));
333             }
334 }
335 
recalc(int g,int i)336 void Model::recalc (int g, int i)
337       {
338       _count++;
339       _ready = false;
340       proc_rank (g, i, MT_CALC_RANK);
341       }
342 
343 #if 0
344 void Model::save ()
345       {
346       write_instr ();
347       writePresets();
348       _ready = false;
349       for (int g = 0; g < _ngroup; g++) {
350             Group* G = _group + g;
351             for (int i = 0; i < G->_nifelm; i++)
352                   proc_rank (g, i, MT_SAVE_RANK);
353             }
354       }
355 #endif
356 
find_rank(int g,int i)357 Rank *Model::find_rank (int g, int i)
358       {
359       Ifelm* I = _group [g]._ifelms + i;
360       if ((I->_type == Ifelm::DIVRANK) || (I->_type == Ifelm::KBDRANK)) {
361             int d = (I->_action0 >> 16) & 255;
362             int r = (I->_action0 >>  8) & 255;
363             return _divis [d]._ranks + r;
364             }
365       return 0;
366       }
367 
368 
read_instr()369 int Model::read_instr ()
370       {
371       int           line, stat, n;
372       bool          instr;
373       int           d, k, r, s;
374       char          c, *p, *q;
375       char          t1 [256];
376       char          t2 [256];
377       Keybd         *K;
378       Divis         *D;
379       Rank          *R;
380       Group         *G;
381       Ifelm         *I;
382       Addsynth      *A;
383 
384       #undef ERROR
385       enum { CONT, DONE, ERROR, COMM, ARGS, MORE, NO_INSTR, IN_INSTR,
386            BAD_SCOPE, BAD_ASECT, BAD_RANK, BAD_DIVIS, BAD_KEYBD, BAD_IFACE,
387            BAD_STR1, BAD_STR2 };
388 
389       QFile f(QString("%1/definition").arg(_instr));
390       if (!f.open(QIODevice::ReadOnly))  {
391             fprintf (stderr, "Can't open '%s' for reading\n", qPrintable(f.fileName()));
392             return 1;
393             }
394 
395       stat = 0;
396       line = 0;
397       instr = false;
398       D = 0;
399       G = 0;
400       d = k = r = s = 0;
401 #ifdef WIN32
402       QByteArray bb;
403       while (!stat) {
404             line++;
405             bb = f.readLine(1024);
406             if(bb.isEmpty())
407                   break;
408             p = bb.data();
409 #else
410       char buff [1024];
411       while (!stat && f.readLine(buff, 1024)) {
412             line++;
413             p = buff;
414 #endif
415             if (*p != '/') {
416                   while (isspace (*p))
417                         p++;
418                   if ((*p > ' ') && (*p != '#')) {
419                         fprintf (stderr, "Syntax error in line %d\n", line);
420                         stat = COMM;
421                         }
422                   continue;
423                   }
424 
425             q = p;
426             while ((*q >= ' ') && !isspace (*q))
427                   q++;
428             *q++ = 0;
429             while ((*q >= ' ') && isspace (*q))
430                   q++;
431 
432             if (! strcmp (p, "/instr/new")) {
433                   if (instr)
434                         stat = IN_INSTR;
435                   else
436                         instr = true;
437                   }
438             else if (! instr) {
439                   stat = NO_INSTR;
440                   }
441             else if (! strcmp (p, "/instr/end")) {
442                   instr = false;
443                   stat = DONE;
444                   }
445             else if (! strcmp (p, "/manual/new") || ! strcmp (p, "/pedal/new")) {
446                   if (D || G)
447                         stat = BAD_SCOPE;
448                   else if (sscanf (q, "%s%n", t1, &n) != 1)
449                         stat = ARGS;
450                   else {
451                         q += n;
452                         if (_nkeybd == NKEYBD) {
453                               fprintf (stderr, "Line %d: can't create more than %d keyboards\n", line, NKEYBD);
454                               stat = ERROR;
455                               }
456                         else if (strlen (t1) > 15)
457                               stat = BAD_STR1;
458                         else {
459                               k = _nkeybd++;
460                               K = _keybd + k;
461                               strcpy (K->_label, t1);
462                               K->_flags = 1 << k;
463                               if (p [1] == 'p')
464                                     K->_flags |= HOLD_MASK | Keybd::IS_PEDAL;
465                               }
466                         }
467                   }
468             else if (! strcmp (p, "/divis/new")) {
469                   if (D || G)
470                         stat = BAD_SCOPE;
471                   else if (sscanf (q, "%s%d%d%n", t1, &k, &s, &n) != 3)
472                         stat = ARGS;
473                   else
474           {
475             q += n;
476             if (_ndivis == NDIVIS)
477             {
478                 fprintf (stderr, "Line %d: can't create more than %d divisions\n", line, NDIVIS);
479                 stat = ERROR;
480             }
481             else if (strlen (t1) > 15) stat = BAD_STR1;
482             else if ((k < 0) || (k > _nkeybd)) stat = BAD_KEYBD;
483             else if ((s < 1) || (s > NASECT))  stat = BAD_ASECT;
484             else
485             {
486                 D = _divis + _ndivis++;
487                 strcpy (D->_label, t1);
488                     if (_nasect < s) _nasect = s;
489                 D->_asect = s - 1;
490                     D->_keybd = k - 1;
491                 if (k--) D->_dmask = _keybd [k]._flags & 127;
492             }
493           }
494       }
495         else if (! strcmp (p, "/divis/end"))
496         {
497           if (!D || G) stat = BAD_SCOPE;
498             else D = 0;
499       }
500         else if (! strcmp (p, "/group/new"))
501         {
502           if (D || G) stat = BAD_SCOPE;
503             else if (sscanf (q, "%s%n", t1, &n) != 1) stat = ARGS;
504             else
505           {
506             q += n;
507             if (_ngroup == NGROUP)
508             {
509                 fprintf (stderr, "Line %d: can't create more than %d groups\n", line, NGROUP);
510                 stat = ERROR;
511             }
512             else if (strlen (t1) > 15) stat = BAD_STR1;
513             else
514             {
515                 G = _group + _ngroup++;
516                 strcpy (G->_label, t1);
517             }
518           }
519       }
520         else if (! strcmp (p, "/group/end"))
521         {
522           if (D || !G) stat = BAD_SCOPE;
523             else G = 0;
524       }
525 
526             else if (! strcmp (p, "/tuning")) {
527                   if (D || G)
528                         stat = BAD_SCOPE;
529                   else {
530                         int nargs = sscanf (q, "%f %d%n", &_fbase, &_itemp, &n);
531                         if (nargs != 2)
532                               stat = ARGS;
533                         else
534                               q += n;
535                         }
536                   }
537 
538         else if (! strcmp (p, "/rank"))
539         {
540           if (!D && G) stat = BAD_SCOPE;
541             else if (sscanf (q, "%c%d%s%n", &c, &d, t1, &n) != 3) stat = ARGS;
542             else
543           {
544               q += n;
545                 if (D->_nrank == Divis::NRANK)
546             {
547                 fprintf (stderr, "Line %d: can't create more than %d ranks per division\n", line, Divis::NRANK);
548                 stat = ERROR;
549             }
550                 else if (strlen (t1) > 63) stat = BAD_STR1;
551                 else
552             {
553                     A = new Addsynth;
554                 strcpy (A->_filename, t1);
555                     if (A->load (_stops))
556                 {
557                   stat = ERROR;
558                   delete A;
559                 }
560                     else
561                 {
562                         A->_pan = c;
563                         A->_del = d;
564                   R = D->_ranks + D->_nrank++;
565                         R->_count = 0;
566                         R->_sdef = A;
567                         R->_wave = 0;
568                 }
569             }
570           }
571       }
572         else if (! strcmp (p, "/tremul"))
573         {
574           if (D)
575           {
576             float val1;
577             float val2;
578             if (sscanf (q, "%f%f%n", &val1, &val2, &n) != 2)
579                stat = ARGS;
580             else {
581                 D->_param[Divis::TFREQ].set(val1);
582                 D->_param[Divis::TMODD].set(val2);
583                 q += n;
584                 D->_flags |= Divis::HAS_TREM;
585             }
586           }
587           else if (G)
588           {
589             if (sscanf (q, "%d%s%s%n", &d, t1, t2, &n) != 3) stat = ARGS;
590                 else
591             {
592                 q += n;
593                     if (G->_nifelm == Group::NIFELM) stat = BAD_IFACE;
594                     else if ((d < 1) || (d > _ndivis)) stat = BAD_DIVIS;
595                 else if (strlen (t1) >  7) stat = BAD_STR1;
596                 else if (strlen (t2) > 31) stat = BAD_STR2;
597                     else
598                 {
599                         d--;
600                   I = G->_ifelms + G->_nifelm++;
601                   strcpy (I->_mnemo, t1);
602                   strcpy (I->_label, t2);
603                   I->_type = Ifelm::TREMUL;
604                   I->_action0 = (16 << 24) | (d << 16) | 0;
605                   I->_action1 = (16 << 24) | (d << 16) | 1;
606                 }
607             }
608           }
609             else stat = BAD_SCOPE;
610       }
611         else if (! strcmp (p, "/swell"))
612         {
613           if (!D || G) stat = BAD_SCOPE;
614             else D->_flags |= Divis::HAS_SWELL;
615       }
616         else if (! strcmp (p, "/stop"))
617         {
618           if (D || !G) stat = BAD_SCOPE;
619             else if (sscanf (q, "%d%d%d%n", &k, &d, &r, &n) != 3) stat = ARGS;
620             else
621           {
622               q += n;
623                 if (G->_nifelm == Group::NIFELM) stat = BAD_IFACE;
624                 else if ((k < 0) || (k > _nkeybd)) stat = BAD_KEYBD;
625                 else if ((d < 1) || (d > _ndivis)) stat = BAD_DIVIS;
626                 else if ((r < 1) || (r > _divis [d - 1]._nrank)) stat = BAD_RANK;
627                 else
628             {
629                     k--;
630                     d--;
631                     r--;
632                 I = G->_ifelms + G->_nifelm++;
633                     R = _divis [d]._ranks + r;
634                     strcpy (I->_label, R->_sdef->_stopname);
635                     strcpy (I->_mnemo, R->_sdef->_mnemonic);
636                     I->_keybd = k;
637                     if (k >= 0)
638                 {
639                         I->_type = Ifelm::KBDRANK;
640                   k = _keybd [k]._flags & 127;
641                 }
642                 else
643                 {
644                         I->_type = Ifelm::DIVRANK;
645                   k = 128;
646                 }
647                     I->_action0 = (6 << 24) | (d << 16) | (r << 8) | k;
648                     I->_action1 = (7 << 24) | (d << 16) | (r << 8) | k;
649             }
650           }
651       }
652         else if (! strcmp (p, "/coupler"))
653         {
654           if (D || !G) stat = BAD_SCOPE;
655             else if (sscanf (q, "%d%d%s%s%n", &k, &d, t1, t2, &n) != 4) stat = ARGS;
656             else
657           {
658             q += n;
659                 if (G->_nifelm == Group::NIFELM) stat = BAD_IFACE;
660                 else if ((k < 1) || (k > _nkeybd)) stat = BAD_KEYBD;
661                 else if ((d < 1) || (d > _ndivis)) stat = BAD_DIVIS;
662             else if (strlen (t1) >  7) stat = BAD_STR1;
663             else if (strlen (t2) > 31) stat = BAD_STR2;
664                 else
665             {
666                     k--;
667                     d--;
668                 I = G->_ifelms + G->_nifelm++;
669                     strcpy (I->_mnemo, t1);
670                     strcpy (I->_label, t2);
671                     I->_type = Ifelm::COUPLER;
672                   I->_keybd = k;
673                     k = _keybd [k]._flags & 127;
674                     I->_action0 = (4 << 24) | (d << 16) | k;
675                     I->_action1 = (5 << 24) | (d << 16) | k;
676             }
677           }
678       }
679         else stat = COMM;
680 
681         if (stat <= DONE)
682       {
683             while (isspace (*q)) q++;
684             if (*q > ' ') stat = MORE;
685       }
686 
687         switch (stat)
688       {
689         case COMM:
690           fprintf (stderr, "Line %d: unknown command '%s'\n", line, p);
691             break;
692         case ARGS:
693           fprintf (stderr, "Line %d: missing arguments in '%s' command\n", line, p);
694             break;
695         case MORE:
696           fprintf (stderr, "Line %d: extra arguments in '%s' command\n", line, p);
697             break;
698         case NO_INSTR:
699           fprintf (stderr, "Line %d: command '%s' outside instrument scope\n", line, p);
700             break;
701         case IN_INSTR:
702           fprintf (stderr, "Line %d: command '%s' inside instrument scope\n", line, p);
703             break;
704         case BAD_SCOPE:
705           fprintf (stderr, "Line %d: command '%s' in wrong scope\n", line, p);
706             break;
707         case BAD_ASECT:
708           fprintf (stderr, "Line %d: no section '%d'\n", line, s);
709             break;
710         case BAD_RANK:
711           fprintf (stderr, "Line %d: no rank '%d' in division '%d'\n", line, r, d);
712             break;
713         case BAD_KEYBD:
714           fprintf (stderr, "Line %d: no keyboard '%d'\n", line, k);
715             break;
716         case BAD_DIVIS:
717           fprintf (stderr, "Line %d: no division '%d'\n", line, d);
718             break;
719         case BAD_IFACE:
720           fprintf (stderr, "Line %d: can't create more than '%d' elements per group\n", line, Group::NIFELM);
721             break;
722         case BAD_STR1:
723           fprintf (stderr, "Line %d: string '%s' is too long\n", line, t1);
724             break;
725         case BAD_STR2:
726           fprintf (stderr, "Line %d: string '%s' is too long\n", line, t1);
727             break;
728       }
729     }
730 
731       f.close();
732       return (stat <= DONE) ? 0 : 2;
733       }
734 
735 
736 int Model::write_instr()
737       {
738       FILE          *F;
739       int           d, g, i, k, r;
740       char          buff [1024];
741       time_t        t;
742       Divis         *D;
743       Rank          *R;
744       Group         *G;
745       Ifelm         *I;
746       Addsynth      *A;
747 
748     snprintf (buff, sizeof(buff), "%s/definition", _instr);
749     if (! (F = fopen (buff, "w")))
750     {
751       fprintf (stderr, "Can't open '%s' for writing\n", buff);
752         return 1;
753     }
754     printf ("Writing '%s'\n", buff);
755     t = time (0);
756 
757     fprintf (F, "# Aeolus instrument definition file\n");
758     fprintf (F, "# Created by Aeolus-%s at %s\n", VERSION, ctime (&t));
759 
760     fprintf (F, "\n/instr/new\n");
761     fprintf (F, "/tuning %5.1f %d\n", _fbase, _itemp);
762 
763     fprintf (F, "\n# Keyboards\n#\n");
764     for (k = 0; k < _nkeybd; k++)
765     {
766       if (_keybd [k]._flags & Keybd::IS_PEDAL) fprintf (F, "/pedal/new    %s\n", _keybd [k]._label);
767         else                                     fprintf (F, "/manual/new   %s\n", _keybd [k]._label);
768     }
769 
770     fprintf (F, "\n# Divisions\n#\n");
771     for (d = 0; d < _ndivis; d++)
772     {
773       D = _divis + d;
774         fprintf (F, "/divis/new    %-7s  %d  %d\n", D->_label, D->_keybd + 1, D->_asect + 1);
775         for (r = 0; r < D->_nrank; r++)
776       {
777             R = D->_ranks + r;
778           A = R->_sdef;
779             fprintf (F, "/rank         %c %3d  %s\n", A->_pan, A->_del, A->_filename);
780       }
781         if (D->_flags & Divis::HAS_SWELL) fprintf (F, "/swell\n");
782         if (D->_flags & Divis::HAS_TREM) fprintf (F, "/tremul       %3.1f  %3.1f\n",
783                                                   D->_param [Divis::TFREQ].fval(), D->_param [Divis::TMODD].fval());
784         fprintf (F, "/divis/end\n\n");
785     }
786 
787     fprintf (F, "# Interface groups\n#\n");
788     for (g = 0; g < _ngroup; g++)
789     {
790       G = _group + g;
791         fprintf (F, "/group/new    %-7s\n", G->_label);
792         for (i = 0; i < G->_nifelm; i++)
793       {
794           I = G->_ifelms + i;
795             switch (I->_type)
796           {
797           case Ifelm::DIVRANK:
798           case Ifelm::KBDRANK:
799                 k = I->_keybd;
800                 d = (I->_action0 >> 16) & 255;
801                 r = (I->_action0 >>  8) & 255;
802                 fprintf (F, "/stop         %d   %d  %2d\n", k + 1, d + 1, r + 1);
803             break;
804 
805           case Ifelm::COUPLER:
806                 k = I->_keybd;
807                 d = (I->_action0 >> 16) & 255;
808                 fprintf (F, "/coupler      %d   %d   %-7s  %s\n", k + 1, d + 1, I->_mnemo, I->_label);
809             break;
810 
811           case Ifelm::TREMUL:
812                 d = (I->_action0 >> 16) & 255;
813                 D = _divis + d;
814                 fprintf (F, "/tremul       %d       %-7s  %s\n", d + 1, I->_mnemo, I->_label);
815             break;
816           }
817       }
818         fprintf (F, "/group/end\n\n");
819     }
820 
821     fprintf (F, "\n/instr/end\n");
822     fclose (F);
823 
824     return 0;
825 }
826 
827 //---------------------------------------------------------
828 //   get_preset
829 //---------------------------------------------------------
830 
831 int Model::get_preset (int bank, int pres, uint32_t *bits)
832       {
833       if ((bank < 0) | (pres < 0) || (bank >= NBANK) || (pres >= NPRES))
834             return 0;
835       Preset* P = _preset [bank][pres];
836       if (P) {
837             for (int k = 0; k < _ngroup; k++)
838                   *bits++ = P->_bits [k];
839             return _ngroup;
840             }
841       return 0;
842       }
843 
844 //---------------------------------------------------------
845 //   set_preset
846 //---------------------------------------------------------
847 
848 void Model::set_preset (int bank, int pres, uint32_t *bits)
849       {
850       if ((bank  < 0) | (pres < 0) || (bank >= NBANK) || (pres >= NPRES))
851             return;
852       Preset* P = _preset [bank][pres];
853       if (!P) {
854             P = new Preset;
855             _preset [bank][pres] = P;
856             }
857       for (int k = 0; k < _ngroup; k++)
858             P->_bits [k] = *bits++;
859       }
860 
861 //---------------------------------------------------------
862 //   ins_preset
863 //---------------------------------------------------------
864 
865 void Model::ins_preset (int bank, int pres, uint32_t *bits)
866       {
867       if ((bank < 0) | (pres < 0) || (bank >= NBANK) || (pres >= NPRES))
868             return;
869       Preset* P = _preset [bank][NPRES - 1];
870       for (int j = NPRES - 1; j > pres; j--)
871             _preset [bank][j] = _preset [bank][j - 1];
872       if (!P) {
873             P = new Preset;
874             _preset [bank][pres] = P;
875             }
876       for (int k = 0; k < _ngroup; k++)
877             P->_bits [k] = *bits++;
878       }
879 
880 //---------------------------------------------------------
881 //   del_preset
882 //---------------------------------------------------------
883 
884 void Model::del_preset (int bank, int pres)
885       {
886       if ((bank < 0) | (pres < 0) || (bank >= NBANK) || (pres >= NPRES))
887             return;
888       delete _preset [bank][pres];
889       for (int j = pres; j < NPRES - 1; j++)
890             _preset [bank][j] = _preset [bank][j + 1];
891       _preset [bank][NPRES - 1] = 0;
892       }
893 
894 //---------------------------------------------------------
895 //   read_presets
896 //---------------------------------------------------------
897 
898 int Model::read_presets()
899       {
900       char name [1024];
901       uchar data [256];
902 
903       QFile f(QString("%1/presets").arg(_instr));
904       if (!f.open(QIODevice::ReadOnly)) {
905             fprintf (stderr, "Can't open '%s' for reading\n", qPrintable(f.fileName()));
906             return 1;
907             }
908 
909       f.read((char*)data, 16);
910       if (strcmp ((char *) data, "PRESET") || data [7]) {
911             fprintf (stderr, "File '%s' is not a valid preset file\n", name);
912             f.close();
913             return 1;
914             }
915       int n = RD2 (data + 14);
916 
917       if (f.read ((char*)data, 256) != 256) {
918             fprintf (stderr, "No valid data in file '%s'\n", name);
919             f.close();
920             return 1;
921             }
922 // printf("==read_presets: chconf\n");
923       uchar* p = data;
924       for (int i = 0; i < 8; i++) {
925             for (int j = 0; j < 16; j++) {
926                   int val = RD2(p);
927 //                  printf("   %d %d = %d\n", i, j, val);
928                   _chconf [i]._bits [j] = val;
929                   p += 2;
930                   }
931             }
932       if (n != _ngroup) {
933             fprintf (stderr, "Presets in file '%s' are not compatible\n", name);
934             f.close();
935             return 1;
936             }
937       while (f.read ((char*)data, 4 + 4 * _ngroup) == 4 + 4 * _ngroup) {
938             p = data;
939             int i = *p++;
940             int j = *p++;
941             p++;
942             p++;
943             if ((i < NBANK) && (j < NPRES)) {
944                   Preset* P = new Preset;
945                   for (int k = 0; k < _ngroup; k++) {
946                         P->_bits [k] = RD4 (p);
947                         p += 4;
948                         }
949                   _preset [i][j] = P;
950                   }
951             }
952       f.close();
953       return 0;
954       }
955 
956 //---------------------------------------------------------
957 //   write_presets
958 //---------------------------------------------------------
959 
960 bool Model::writePresets()
961       {
962       char   name [1024];
963       uchar  data [256];
964       FILE   *F;
965 
966       snprintf (name, sizeof(name), "%s/presets", _instr);
967       if (! (F = fopen (name, "w"))) {
968             fprintf (stderr, "Can't open '%s' for writing\n", name);
969             return 1;
970             }
971 
972       strcpy ((char *) data, "PRESET");
973       data [7] = 0;
974       WR2 (data +  8, 0);
975       WR2 (data + 10, 0);
976       WR2 (data + 12, 0);
977       WR2 (data + 14, _ngroup);
978       fwrite (data, 16, 1, F);
979 
980       uchar* p = data;
981       for (int i = 0; i < 8; i++) {
982             for (int j = 0; j < 16; j++) {
983                   int v = _chconf [i]._bits [j];
984                   WR2 (p, v);
985                   p += 2;
986                   }
987             }
988       fwrite (data, 256, 1, F);
989 
990       for (int i = 0; i < NBANK; i++) {
991             for (int j = 0; j < NPRES; j++) {
992                   Preset* P = _preset [i][j];
993                   if (P) {
994                         p = data;
995                         *p++ = i;
996                         *p++ = j;
997                         *p++ = 0;
998                         *p++ = 0;
999                         for (int k = 0; k < _ngroup; k++) {
1000                               int v = P->_bits [k];
1001                               WR4 (p, v);
1002                               p += 4;
1003                               }
1004                         fwrite (data, 4 + 4 * _ngroup, 1, F);
1005                         }
1006                   }
1007             }
1008       fclose (F);
1009       return 0;
1010       }
1011 
1012