1 /* Yamaha DX7 / TX7 Editor/Librarian
2  *
3  * Copyright (C) 1991, 1995, 1997, 1998, 2004, 2009, 2011,
4  * 2012, 2013 Sean Bolton.
5  *
6  * This is an ncurses-based patch editor for the Yamaha DX7 and
7  * TX7.  It is provided as-is, without any documentation, and
8  * is totally unsupported, but may be useful to you if you can't use
9  * JSynthLib or similar.  It started out life on my Apple ][+, then
10  * I ported it to my Amiga, then to my MS-DOS machine, then to
11  * Linux, so the code's a mess and nothing I'm proud of.  But, it
12  * does the job.
13  *
14  * Compile with:
15  *     gcc -o tx_edit tx_edit.c -lcurses -lasound
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License as
19  * published by the Free Software Foundation; either version 2 of
20  * the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be
23  * useful, but WITHOUT ANY WARRANTY; without even the implied
24  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
25  * PURPOSE.  See the GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public
28  * License along with this program; if not, write to the Free
29  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
30  * Boston, MA 02110-1301 USA.
31  *
32  * Revision History:
33  * 20040126 Sean Bolton - made help functions helpful, added ALSA support
34  * 20040205 Sean Bolton - clean up display with noecho, line drawing
35  * 20040207 Sean Bolton - add next/previous voice commands to edit mode
36  * 20090102 Sean Bolton - incorporated Martin Tarenskeen's patch loading
37  *                        enhancements
38  * 20110215 Sean Bolton - incorporated more patch loading enhancements
39  *                        from Martin Tarenskeen.
40  * 20121022 Sean Bolton - and yet more from Martin.
41  */
42 
43 /* Need to do:                              */
44 /*   need to provide color changing option  */
45 /*   bank and single receive                */
46 /*   auto buffer sizing?                    */
47 /*   a search option would be nice          */
48 /*   show channel/instrument on display     */
49 
50 #define VERSIONSTRING "0.94s"
51 
52 /* Undefine USE_ALSA_MIDI to just write to /dev/midi */
53 #define USE_ALSA_MIDI 1
54 
55 #define DEBUG 1
56 
57 #include <stdlib.h>
58 #include <errno.h>
59 #include <stdio.h>
60 #include <curses.h>
61 #include <stdarg.h>
62 #include <ctype.h>
63 #include <string.h>
64 #include <unistd.h>
65 #include <getopt.h>
66 
67 #ifdef USE_ALSA_MIDI
68 #include <alsa/asoundlib.h>
69 #endif
70 
71 #define RETURN_OK     0
72 #define RETURN_FAIL 255
73 
74 typedef unsigned char UBYTE;
75 
76 void cprintf(const char *fmt, ...);
77 
78 
79 /* ==== Files ==== */
80 
81 #define MAXPATH 80
82 
83 char FNameBuff[MAXPATH]="\0";
84 
85 /* ==== Buffers ==== */
86 
87 #define DEFAULTVOICES                8192
88 #define DX7_VOICE_SIZE_PACKED         128
89 #define DX7_VOICE_SIZE_UNPACKED       155
90 #define DX7_DUMP_SIZE_VOICE_SINGLE  155+8
91 #define DX7_DUMP_SIZE_VOICE_BULK   4096+8
92 
93 int Voices = DEFAULTVOICES;
94 
95 UBYTE *Buffer = NULL,
96       *VoiceData,
97       *SingleDump,
98       *SingleData,
99       *BulkDump;
100 int    BufferLength;
101 
102 /* ==== Console ==== */
103 
104 #define KEY_METAA       (0x200+'a')
105 #define KEY_METAB       (0x200+'b')
106 #define KEY_METAC       (0x200+'c')
107 #define KEY_METAD       (0x200+'d')
108 #define KEY_METAE       (0x200+'e')
109 #define KEY_METAG       (0x200+'g')
110 #define KEY_METAH       (0x200+'h')
111 #define KEY_METAL       (0x200+'l')
112 #define KEY_METAM       (0x200+'m')
113 #define KEY_METAO       (0x200+'o')
114 #define KEY_METAP       (0x200+'p')
115 #define KEY_METAQ       (0x200+'q')
116 #define KEY_METAR       (0x200+'r')
117 #define KEY_METAS       (0x200+'s')
118 #define KEY_METAT       (0x200+'t')
119 #undef KEY_ENTER
120 #define KEY_ENTER       (0x0a)
121 #define KEY_ESC         (0x1b)
122 #define KEY_METAEQ      (0x200+'=')  /* Alt-= */
123 #define KEY_METAPL      (0x200+'+')  /* Alt-+ */
124 #define KEY_METAEX      (0x200+'!')  /* Alt-! */
125 #define KEY_METANU      (0x200+'#')  /* Alt-# */
126 
127 enum textcolor {COLOR_MSG = 1, COLOR_LABEL, COLOR_DATA, COLOR_BLOCK,
128                 COLOR_CURSOR, COLOR_BCURSOR, COLOR_OPON, COLOR_OPOFF};
129 
130 #if 0
131 #define kc_Del       (0x5300)
132 #define kc_CtrlRight (0x7400)
133 #define kc_CtrlLeft  (0x7300)
134 #define kc_CtrlPgUp  (0x8400)
135 #define kc_CtrlPgDn  (0x7600)
136 #define kc_Home      (0x4700)
137 #define kc_End       (0x4f00)
138 #define kc_CtrlHome  (0x7700)
139 #define kc_CtrlEnd   (0x7500)
140 #endif
141 
142 /* ==== Midi ==== */
143 
144 #ifdef USE_ALSA_MIDI
145 snd_seq_t *MidiHandle = NULL;
146 int        MidiClient;
147 int        MidiPort = -1;
148 #endif
149 
150 char TXChannel = 0;  /* 0-15! */
151 
152 /* ==== VoiceEdit ==== */
153 
154 #define VOICEPARMS      146
155 #define VOICEPARMMAX    145
156 
157 #ifdef USE_CALCED_CURSOR_MOVES
158 #define VOICEPARMS_X_SPAN  57
159 #define VOICEPARMS_Y_SPAN  18
160 #endif
161 
162 int ve_Cursor = 0;
163 int ve_OpSelect = 63;
164 
165 #define vptName     1
166 #define vpt0_99     2
167 #define vpt0_7      3
168 #define vptMode     4   /* R,F */
169 #define vptFC       5   /* 0-31 */
170 #define vptFF       6   /* 0-99 */
171 #define vptDetune   7   /* 0-14, as -7-+7 */
172 #define vpt0_3      8
173 #define vptAlg      9   /* 0-31, as 1-32 */
174 #define vptCurve   10   /* 0-3, scaling curve */
175 #define vptBkPt    11   /* 0-99, breakpoint */
176 #define vptTrans   12   /* 0-48, transpose */
177 #define vptOnOff   13
178 #define vptWave    14
179 
180 unsigned char vtypemax[15] = {
181     0, 0, 99, 7, 1, 31, 99, 14, 3, 31, 3, 99, 48, 1, 5,
182 };
183 
184 struct _veParm {
185     UBYTE   Type;
186     UBYTE   Offset;
187     UBYTE   X;
188     UBYTE   Y;
189     UBYTE   Up;  /* -FIX- Up and Down are obsolete with calc'ed cursor moves */
190     UBYTE   Down;
191 } veParm[VOICEPARMS] = {
192 /*     T,  Off,  X,  Y,   U,   D */
193     {  1,  145, 31,  0, 145,   8, }, /* Name */
194     {  2,  105,  5,  4, 140,  17, }, /* O1 R1 */
195     {  2,  109,  8,  4, 141,  18, },
196     {  2,  106, 12,  4, 142,  19, },
197     {  2,  110, 15,  4, 142,  20, },
198     {  2,  107, 19,  4, 143,  21, },
199     {  2,  111, 22,  4, 144,  22, },
200     {  2,  108, 26,  4,   0,  23, },
201     {  2,  112, 29,  4,   0,  24, },
202     {  3,  118, 33,  4,   0,  25, }, /* O1 RS */
203     {  4,  122, 36,  4,   0,  26, },
204     {  5,  123, 38,  4, 145,  27, },
205     {  6,  124, 41,  4, 121,  28, },
206     {  7,  125, 44,  4, 121,  29, },
207     {  2,  121, 54,  4,  94,  30, },
208     {  3,  120, 58,  4,  95,  31, },
209     {  8,  119, 60,  4,  96,  32, }, /* O1 AMS */
210     {  2,   84,  5,  5,   1,  33, }, /* O2 R1 */
211     {  2,   88,  8,  5,   2,  34, },
212     {  2,   85, 12,  5,   3,  35, },
213     {  2,   89, 15,  5,   4,  36, },
214     {  2,   86, 19,  5,   5,  37, },
215     {  2,   90, 22,  5,   6,  38, },
216     {  2,   87, 26,  5,   7,  39, },
217     {  2,   91, 29,  5,   8,  40, },
218     {  3,   97, 33,  5,   9,  41, }, /* O2 RS */
219     {  4,  101, 36,  5,  10,  42, },
220     {  5,  102, 38,  5,  11,  43, },
221     {  6,  103, 41,  5,  12,  44, },
222     {  7,  104, 44,  5,  13,  45, },
223     {  2,  100, 54,  5,  14,  46, },
224     {  3,   99, 58,  5,  15,  47, },
225     {  8,   98, 60,  5,  16,  48, }, /* O2 AMS */
226     {  2,   63,  5,  6,  17,  49, }, /* O3 R1 */
227     {  2,   67,  8,  6,  18,  50, },
228     {  2,   64, 12,  6,  19,  51, },
229     {  2,   68, 15,  6,  20,  52, },
230     {  2,   65, 19,  6,  21,  53, },
231     {  2,   69, 22,  6,  22,  54, },
232     {  2,   66, 26,  6,  23,  55, },
233     {  2,   70, 29,  6,  24,  56, },
234     {  3,   76, 33,  6,  25,  57, }, /* O3 RS */
235     {  4,   80, 36,  6,  26,  58, },
236     {  5,   81, 38,  6,  27,  59, },
237     {  6,   82, 41,  6,  28,  60, },
238     {  7,   83, 44,  6,  29,  61, },
239     {  2,   79, 54,  6,  30,  62, },
240     {  3,   78, 58,  6,  31,  63, },
241     {  8,   77, 60,  6,  32,  64, }, /* O3 AMS */
242     {  2,   42,  5,  7,  33,  65, }, /* O4 R1 */
243     {  2,   46,  8,  7,  34,  66, },
244     {  2,   43, 12,  7,  35,  67, },
245     {  2,   47, 15,  7,  36,  68, },
246     {  2,   44, 19,  7,  37,  69, },
247     {  2,   48, 22,  7,  38,  70, },
248     {  2,   45, 26,  7,  39,  71, },
249     {  2,   49, 29,  7,  40,  72, },
250     {  3,   55, 33,  7,  41,  73, }, /* O4 RS */
251     {  4,   59, 36,  7,  42,  74, },
252     {  5,   60, 38,  7,  43,  75, },
253     {  6,   61, 41,  7,  44,  76, },
254     {  7,   62, 44,  7,  45,  77, },
255     {  2,   58, 54,  7,  46,  78, },
256     {  3,   57, 58,  7,  47,  79, },
257     {  8,   56, 60,  7,  48,  80, }, /* O4 AMS */
258     {  2,   21,  5,  8,  49,  81, }, /* O5 R1 */
259     {  2,   25,  8,  8,  50,  82, },
260     {  2,   22, 12,  8,  51,  83, },
261     {  2,   26, 15,  8,  52,  84, },
262     {  2,   23, 19,  8,  53,  85, },
263     {  2,   27, 22,  8,  54,  86, },
264     {  2,   24, 26,  8,  55,  87, },
265     {  2,   28, 29,  8,  56,  88, },
266     {  3,   34, 33,  8,  57,  89, }, /* O5 RS */
267     {  4,   38, 36,  8,  58,  90, },
268     {  5,   39, 38,  8,  59,  91, },
269     {  6,   40, 41,  8,  60,  92, },
270     {  7,   41, 44,  8,  61,  93, },
271     {  2,   37, 54,  8,  62,  94, },
272     {  3,   36, 58,  8,  63,  95, },
273     {  8,   35, 60,  8,  64,  96, }, /* O5 AMS */
274     {  2,    0,  5,  9,  65,  97, }, /* O6 R1 */
275     {  2,    4,  8,  9,  66,  98, },
276     {  2,    1, 12,  9,  67,  99, },
277     {  2,    5, 15,  9,  68, 100, },
278     {  2,    2, 19,  9,  69, 101, },
279     {  2,    6, 22,  9,  70, 102, },
280     {  2,    3, 26,  9,  71, 103, },
281     {  2,    7, 29,  9,  72, 104, },
282     {  3,   13, 33,  9,  73, 106, }, /* O6 RS */
283     {  4,   17, 36,  9,  74, 106, },
284     {  5,   18, 38,  9,  75, 106, },
285     {  6,   19, 41,  9,  76, 105, },
286     {  7,   20, 44,  9,  77, 105, },
287     {  2,   16, 54,  9,  78, 105, },
288     {  3,   15, 58,  9,  79, 105, },
289     {  8,   14, 60,  9,  80, 105, }, /* O6 AMS */
290     {  2,  126,  5, 10,  81, 108, }, /* P R1 */
291     {  2,  130,  8, 10,  82, 109, },
292     {  2,  127, 12, 10,  83, 110, },
293     {  2,  131, 15, 10,  84, 110, },
294     {  2,  128, 19, 10,  85, 111, },
295     {  2,  132, 22, 10,  86, 112, },
296     {  2,  129, 26, 10,  87, 112, },
297     {  2,  133, 29, 10,  88, 106, },
298     {  9,  134, 48, 11,  94, 107, }, /* Alg */
299     {  2,  137, 35, 12,  90, 113, },
300     {  3,  135, 49, 12, 105, 114, },
301     { 10,  116,  5, 13,  97, 115, }, /* O1 LC */
302     {  2,  114, 10, 13,  98, 116, },
303     { 11,  113, 13, 13,  99, 117, },
304     { 10,  117, 18, 13, 101, 118, },
305     {  2,  115, 23, 13, 102, 119, },
306     {  2,  138, 35, 13, 106, 120, },  /* Delay */
307     { 12,  144, 46, 13, 107, 121, },
308     { 10,   95,  5, 14, 108, 122, }, /* O2 LC */
309     {  2,   93, 10, 14, 109, 123, },
310     { 11,   92, 13, 14, 110, 124, },
311     { 10,   96, 18, 14, 111, 125, },
312     {  2,   94, 23, 14, 112, 126, },
313     {  2,  139, 35, 14, 113, 127, },  /* PMD */
314     { 13,  136, 47, 14, 114,  14, },
315     { 10,   74,  5, 15, 115, 128, }, /* O3 LC */
316     {  2,   72, 10, 15, 116, 129, },
317     { 11,   71, 13, 15, 117, 130, },
318     { 10,   75, 18, 15, 118, 131, },
319     {  2,   73, 23, 15, 119, 132, },
320     {  2,  140, 35, 15, 120, 133, },  /* AMD */
321     { 10,   53,  5, 16, 122, 134, }, /* O4 LC */
322     {  2,   51, 10, 16, 123, 135, },
323     { 11,   50, 13, 16, 124, 136, },
324     { 10,   54, 18, 16, 125, 137, },
325     {  2,   52, 23, 16, 126, 138, },
326     { 13,  141, 34, 16, 127, 139, },  /* Sync */
327     { 10,   32,  5, 17, 128, 140, }, /* O5 LC */
328     {  2,   30, 10, 17, 129, 141, },
329     { 11,   29, 13, 17, 130, 142, },
330     { 10,   33, 18, 17, 131, 143, },
331     {  2,   31, 23, 17, 132, 144, },
332     { 14,  142, 34, 17, 133, 145, },  /* Wave */
333     { 10,   11,  5, 18, 134,   1, }, /* O6 LC */
334     {  2,    9, 10, 18, 135,   2, },
335     { 11,    8, 13, 18, 136,   3, },
336     { 10,   12, 18, 18, 137,   5, },
337     {  2,   10, 23, 18, 138,   6, },
338     {  3,  143, 36, 18, 139,  10, }  /* PMS */
339 };
340 
341 unsigned short veFFF[100] = {
342     1000, 1023, 1047, 1072, 1096, 1122, 1148, 1175, 1202, 1230,
343     1259, 1288, 1318, 1349, 1380, 1413, 1445, 1479, 1514, 1549,
344     1585, 1622, 1660, 1698, 1738, 1778, 1820, 1862, 1905, 1950,
345     1995, 2042, 2089, 2138, 2188, 2239, 2291, 2344, 2399, 2455,
346     2512, 2570, 2630, 2692, 2754, 2818, 2884, 2951, 3020, 3090,
347     3162, 3236, 3311, 3388, 3467, 3548, 3631, 3715, 3802, 3890,
348     3981, 4074, 4169, 4266, 4365, 4467, 4571, 4677, 4786, 4898,
349     5012, 5129, 5248, 5370, 5495, 5623, 5754, 5888, 6026, 6166,
350     6310, 6457, 6607, 6761, 6918, 7079, 7244, 7413, 7586, 7762,
351     7943, 8128, 8318, 8511, 8710, 8913, 9120, 9333, 9550, 9772,
352 };
353 
354 /* ==== Algorithm ==== */
355 
356 char *veAlg[32] = {  /* 32 algs, max 9 high and 17 wide */
357     "   '`\n"           /* 1 */
358     "   6/\n"
359     "   |\n"
360     "   5\n"
361     "   |\n"
362     "2  4\n"
363     "|  |\n"
364     "1  3\n"
365     "L--/",
366     "\n"                /* 2 */
367     "   6\n"
368     "   |\n"
369     "   5\n"
370     "'` |\n"
371     "2/ 4\n"
372     "|  |\n"
373     "1  3\n"
374     "L--/",
375     "   '`\n"           /* 3 */
376     "3  6/\n"
377     "|  |\n"
378     "2  5\n"
379     "|  |\n"
380     "1  4\n"
381     "L--/",
382     "   '`\n"           /* 4 */
383     "3  6|\n"
384     "|  ||\n"
385     "2  5|\n"
386     "|  ||\n"
387     "1  4/\n"
388     "L--/",
389     "      '`\n"        /* 5 */
390     "2  4  6/\n"
391     "|  |  |\n"
392     "1  3  5\n"
393     "L--^--/",
394     "      '`\n"        /* 6 */
395     "2  4  6|\n"
396     "|  |  ||\n"
397     "1  3  5/\n"
398     "L--^--/",
399     "      '`\n"        /* 7 */
400     "      6/\n"
401     "      |\n"
402     "2  4  5\n"
403     "|  }--/\n"
404     "1  3\n"
405     "L--/",
406     "\n"                /* 8 */
407     "      6\n"
408     "   '` |\n"
409     "2  4/ 5\n"
410     "|  }--/\n"
411     "1  3\n"
412     "L--/",
413     "\n"                /* 9 */
414     "      6\n"
415     "'`    |\n"
416     "2/ 4  5\n"
417     "|  }--/\n"
418     "1  3\n"
419     "L--/",
420     "'`\n"              /* 10 */
421     "3/\n"
422     "|\n"
423     "2  5  6\n"
424     "|  }--/\n"
425     "1  4\n"
426     "L--/",
427     "\n"                /* 11 */
428     "3\n"
429     "|     '`\n"
430     "2  5  6/\n"
431     "|  }--/\n"
432     "1  4\n"
433     "L--/",
434     "'`\n"              /* 12 */
435     "2/ 4  5  6\n"
436     "|  L--+--/\n"
437     "1     3\n"
438     "L-----/",
439     "         '`\n"     /* 13 */
440     "2  4  5  6/\n" /* 13 */
441     "|  L--+--/\n"
442     "1     3\n"
443     "L-----/",
444     "      '`\n"        /* 14 */
445     "   5  6/\n"
446     "   }--/\n"
447     "2  4\n"
448     "|  |\n"
449     "1  3\n"
450     "L--/",
451     "\n"                /* 15 */
452     "   5  6\n"
453     "'` }--/\n"
454     "2/ 4\n"
455     "|  |\n"
456     "1  3\n"
457     "L--/",
458     "      '`\n"        /* 16 */
459     "   4  6/\n"
460     "   |  |\n"
461     "2  3  5\n"
462     "L--+--/\n"
463     "   1",
464     "\n"                /* 17 */
465     "   4  6\n"
466     "'` |  |\n"
467     "2/ 3  5\n"
468     "L--+--/\n"
469     "   1",
470     "      6\n"         /* 18 */
471     "      |\n"
472     "      5\n"
473     "   '` |\n"
474     "2  3/ 4\n"
475     "L--+--/\n"
476     "   1",
477     "3\n"               /* 19 */
478     "|  '`\n"
479     "2  6/\n"
480     "|  }--`\n"
481     "1  4  5\n"
482     "L--^--/",
483     "'`\n"              /* 20 */
484     "3/    5  6\n"
485     "}--`  }--/\n"
486     "1  2  4\n"
487     "L--^--/",
488     "'`\n"              /* 21 */
489     "3/    6\n"
490     "}--`  }--`\n"
491     "1  2  4  5\n"
492     "L--^--^--/",
493     "      '`\n"        /* 22 */
494     "2     6/\n"
495     "|  '--+--`\n"
496     "1  3  4  5\n"
497     "L--^--^--/",
498     "      '`\n"        /* 23 */
499     "   3  6/\n"
500     "   |  }--`\n"
501     "1  2  4  5\n"
502     "L--^--^--/",
503     "         '`\n"     /* 24 */
504     "         6/\n"
505     "      '--+--`\n"
506     "1  2  3  4  5\n"
507     "L--^--^--^--/",
508     "         '`\n"     /* 25 */
509     "         6/\n"
510     "         }--`\n"
511     "1  2  3  4  5\n"
512     "L--^--^--^--/",
513     "         '`\n"     /* 26 */
514     "   3  5  6/\n"
515     "   |  }--/\n"
516     "1  2  4\n"
517     "L--^--/",
518     "   '`\n"           /* 27 */
519     "   3/ 5  6\n"
520     "   |  }--/\n"
521     "1  2  4\n"
522     "L--^--/",
523     "   '`\n"           /* 28 */
524     "   5/\n"
525     "   |\n"
526     "2  4\n"
527     "|  |\n"
528     "1  3  6\n"
529     "L--^--/",
530     "         '`\n"     /* 29 */
531     "      4  6/\n"
532     "      |  |\n"
533     "1  2  3  5\n"
534     "L--^--^--/",
535     "      '`\n"        /* 30 */
536     "      5/\n"
537     "      |\n"
538     "      4\n"
539     "      |\n"
540     "1  2  3  6\n"
541     "L--^--^--/",
542     "            '`\n"
543     "            6/\n"  /* 31 */
544     "            |\n"
545     "1  2  3  4  5\n"
546     "L--^--^--^--/",
547     "               '`" /* 32 */
548     "1  2  3  4  5  6/"
549     "L--^--^--^--^--/",
550 };
551 
552 /* ==== Librarian ==== */
553 
noop(void)554 void noop(void){}
555 
556 void  (*LibBlockAction)(void) = noop;
557 
558 int   Voice_Cursor = 0, /* voice number under curser  */
559       Voice_TOS = 0,    /* " at top of screen         */
560       Voice_BMark,      /* " where block first marked */
561       Voice_BStart,     /* " of block start           */
562       Voice_BEnd;       /* " of block end             */
563 bool  blocking = FALSE,
564       blocked = FALSE;
565 /* -FIX- This should be dynamic! */
566 int   LibCols=5,        /* columns of names that fit on screen (15 char each) */
567       LibRows=16,       /* rows    of names that fit on screen */
568       LibNames=80;      /*            names that fit on screen */
569 
570 /* ==== Control ==== */
571 
572 int txmode=0,
573     newmode=0;
574 
575 #define MODELIB     1
576 #define MODEEDIT    2
577 #define MODEQUIT    3
578 
579 /* ==== Utility Stuff ==== */
580 
min(int a,int b)581 inline int min(int a, int b) { return (a < b ? a : b); }
max(int a,int b)582 inline int max(int a, int b) { return (a > b ? a : b); }
583 
584 char _NoteText[5]={'x','x','x','x','\0'};
585 
586 char *
NoteText(int note)587 NoteText(int note)
588 {
589     _NoteText[0]=(" C D  F G A ")[note%12];
590     _NoteText[1]=("C#D#EF#G#A#B")[note%12];
591     _NoteText[2]=("--012345678")[note/12];
592     _NoteText[3]=("21         ")[note/12];
593     return _NoteText;
594 }
595 
596 UBYTE *
voiceAddr(int voice)597 voiceAddr(int voice)
598 {
599  /* return voice*DX7_VOICE_SIZE_PACKED+VoiceData; */
600     return (voice << 7)     +VoiceData;
601 }
602 
603 void
PrintVName(int voice)604 PrintVName(int voice)  /* print name of voice - packed only! */
605 {
606     UBYTE ca[11];
607     int i;
608 
609     memcpy(ca, voiceAddr(voice)+118, 10);
610     for (i=0; i<10; i++) {
611         if (ca[i] < 32)
612             ca[i]=183;  /* centered dot */
613         else if (ca[i] >= 128)
614             ca[i]=174;  /* (R) symbol = out-of-range */
615         else {
616             switch (ca[i]) {
617                 case  92:  ca[i]=165;  break;  /* yen */
618                 case 126:  ca[i]=187;  break;  /* >> */
619                 case 127:  ca[i]=171;  break;  /* << */
620             }
621         }
622     }
623     ca[10]=0;
624     cprintf("%s", ca);
625 }
626 
627 /* ==== Init/Term Routines ==== */
628 
629 UBYTE InitVoice[] = {
630     0x62, 0x63, 0x63, 0x5A, 0x63, 0x63, 0x63, 0x00,
631     0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x02,
632     0x00, 0x62, 0x63, 0x63, 0x5A, 0x63, 0x63, 0x63,
633     0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00,
634     0x02, 0x00, 0x62, 0x63, 0x63, 0x5A, 0x63, 0x63,
635     0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
636     0x00, 0x02, 0x00, 0x62, 0x63, 0x63, 0x5A, 0x63,
637     0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
638     0x00, 0x00, 0x02, 0x00, 0x62, 0x63, 0x63, 0x5A,
639     0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
640     0x38, 0x00, 0x00, 0x02, 0x00, 0x62, 0x63, 0x63,
641     0x5A, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
642     0x00, 0x38, 0x00, 0x63, 0x02, 0x00, 0x63, 0x63,
643     0x63, 0x63, 0x32, 0x32, 0x32, 0x32, 0x00, 0x08,
644     0x23, 0x00, 0x00, 0x00, 0x31, 0x18, 0x20, 0x20,
645     0x20, 0x7F, 0x2D, 0x2D, 0x7E, 0x20, 0x20, 0x20 };
646 
647 UBYTE InitVoiceUnpacked[155] = {
648     0x62, 0x63, 0x63, 0x5a, 0x63, 0x63, 0x63, 0x00,
649     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650     0x00, 0x00, 0x01, 0x00, 0x07, 0x62, 0x63, 0x63,
651     0x5a, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
652     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
653     0x00, 0x07, 0x62, 0x63, 0x63, 0x5a, 0x63, 0x63,
654     0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655     0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x62,
656     0x63, 0x63, 0x5a, 0x63, 0x63, 0x63, 0x00, 0x00,
657     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658     0x00, 0x01, 0x00, 0x07, 0x62, 0x63, 0x63, 0x5a,
659     0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
660     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
661     0x07, 0x62, 0x63, 0x63, 0x5a, 0x63, 0x63, 0x63,
662     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663     0x00, 0x63, 0x00, 0x01, 0x00, 0x07, 0x63, 0x63,
664     0x63, 0x63, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00,
665     0x01, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
666     0x18, 0x20, 0x20, 0x20, 0x7f, 0x2d, 0x2d, 0x7e,
667     0x20, 0x20, 0x20
668 };
669 
670 void
EraseVoice(int voice)671 EraseVoice(int voice)
672 {
673     memcpy(voiceAddr(voice), InitVoice, DX7_VOICE_SIZE_PACKED);
674 }
675 
676 void
ConsoleTerm(void)677 ConsoleTerm(void)
678 {
679     endwin();
680 }
681 
682 bool
ConsoleInit(void)683 ConsoleInit(void)
684 {
685     initscr();
686     cbreak();
687     keypad(stdscr, TRUE);
688     curs_set(0);
689     start_color();
690 #if 1
691     init_pair(COLOR_MSG,     COLOR_WHITE, COLOR_YELLOW);  /* 0x1c */
692     init_pair(COLOR_LABEL,   COLOR_GREEN, COLOR_BLUE);    /* 0x1a */
693     init_pair(COLOR_DATA,    COLOR_WHITE, COLOR_BLUE);    /* 0x1f */
694     init_pair(COLOR_BLOCK,   COLOR_WHITE, COLOR_CYAN);    /* 0x3f */
695     init_pair(COLOR_CURSOR,  COLOR_BLACK, COLOR_GREEN);   /* 0x20 */
696     init_pair(COLOR_BCURSOR, COLOR_WHITE, COLOR_GREEN);   /* 0x2f */
697     init_pair(COLOR_OPON,    COLOR_GREEN, COLOR_BLUE);    /* 0x1a */
698     init_pair(COLOR_OPOFF,   COLOR_WHITE, COLOR_YELLOW);  /* 0x14 */
699 #else
700     init_pair(COLOR_MSG,     COLOR_WHITE, COLOR_YELLOW);  /* 0x1c */
701     init_pair(COLOR_LABEL,   COLOR_WHITE, COLOR_YELLOW);  /* 0x1a */
702     init_pair(COLOR_DATA,    COLOR_WHITE, COLOR_BLUE);    /* 0x1f */
703     init_pair(COLOR_BLOCK,   COLOR_BLACK, COLOR_YELLOW);  /* 0x3f */
704     init_pair(COLOR_CURSOR,  COLOR_WHITE, COLOR_YELLOW);  /* 0x20 */
705     init_pair(COLOR_BCURSOR, COLOR_BLACK, COLOR_YELLOW);  /* 0x2f */
706     init_pair(COLOR_OPON,    COLOR_WHITE, COLOR_YELLOW);  /* 0x1a */
707     init_pair(COLOR_OPOFF,   COLOR_WHITE, COLOR_YELLOW);  /* 0x14 */
708 #endif
709     bkgdset(COLOR_PAIR(COLOR_DATA));
710     attrset(COLOR_PAIR(COLOR_DATA)|A_BOLD);
711     noecho();
712     return TRUE;
713 }
714 
715 void
BuffTerm(void)716 BuffTerm(void)
717 {
718     if (Buffer) {
719         free(Buffer);
720         Buffer = NULL;
721     }
722 }
723 
724 bool
BuffInit(void)725 BuffInit(void)  /* returns TRUE if successful */
726 {
727     int i;
728 
729     BuffTerm();
730     /* calculate buffer size from number of voices * DX7_VOICE_SIZE_PACKED plus a bulk
731        dump buffer and a single dump buffer */
732     BufferLength = Voices * DX7_VOICE_SIZE_PACKED + DX7_DUMP_SIZE_VOICE_BULK + DX7_DUMP_SIZE_VOICE_SINGLE;
733     if (!(Buffer = malloc(BufferLength))) {
734         return FALSE;
735     }
736     VoiceData = Buffer;
737     BulkDump = VoiceData + Voices * DX7_VOICE_SIZE_PACKED;
738     SingleDump = BulkDump + DX7_DUMP_SIZE_VOICE_BULK;  /* must be last for alignment */
739     SingleData = SingleDump + 6;
740     /* Init the buffers */
741     for (i = 0; i < Voices; EraseVoice(i++));
742     return TRUE;
743 }
744 
745 bool
MidiInit(void)746 MidiInit(void)  /* returns TRUE if successful */
747 {
748 #ifdef USE_ALSA_MIDI
749 
750     const char *device = "hw";   /* could also be "default" */
751 
752  /* if (snd_seq_open(&MidiHandle, device, SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) { */
753     if (snd_seq_open(&MidiHandle, device, SND_SEQ_OPEN_OUTPUT, 0) < 0) {
754         fprintf(stderr, "MidiInit: could not open sequencer: %s\n", snd_strerror(errno));
755         return FALSE;
756     }
757 
758     snd_seq_set_client_name (MidiHandle, "TX/Edit");
759 
760     MidiClient = snd_seq_client_id(MidiHandle);
761 
762     if ((MidiPort = snd_seq_create_simple_port(MidiHandle, "TX/Edit",
763                                                SND_SEQ_PORT_CAP_READ |
764                                                SND_SEQ_PORT_CAP_SUBS_READ,
765                                                SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) {
766         fprintf(stderr, "MidiInit: error creating port: %s\n", snd_strerror(errno));
767         return FALSE;
768     }
769 
770     return TRUE;
771 
772 #else /* not USE_ALSA_MIDI */
773     return TRUE;
774 #endif /* USE_ALSA_MIDI */
775 }
776 
777 void
MidiTerm(void)778 MidiTerm(void)
779 {
780 #ifdef USE_ALSA_MIDI
781     if (MidiHandle) {
782         snd_seq_drain_output(MidiHandle);  /* do we need this? could use snd_seq_drop_output(handle) */
783     }
784     if (MidiPort >= 0) {
785         snd_seq_delete_simple_port (MidiHandle, MidiPort);
786         MidiPort = -1;
787     }
788     if (MidiHandle) {
789         snd_seq_close(MidiHandle);
790         MidiHandle = NULL;
791     }
792 #endif /* USE_ALSA_MIDI */
793 }
794 
795 void
TXTerm(int retcode)796 TXTerm(int retcode)
797 {
798     ConsoleTerm();
799     BuffTerm();
800     MidiTerm();
801     exit(retcode);
802 }
803 
804 void
TXInit(void)805 TXInit(void)  /* exit()s on failure */
806 {
807     if (!MidiInit()) {
808         fprintf(stderr, "MidiInit error!\n");
809         TXTerm(RETURN_FAIL);
810     }
811     if (!BuffInit()) {
812         fprintf(stderr, "Can't allocate memory for Voice Buffer!\n");
813         TXTerm(RETURN_FAIL);
814     }
815     if (!ConsoleInit()) {
816         fprintf(stderr, "ConsoleInit error!\n");
817         TXTerm(RETURN_FAIL);
818     }
819 }
820 
821 /* ==== Console Routines ==== */
822 
823 void
cprintf(const char * fmt,...)824 cprintf(const char *fmt, ...) {
825     va_list ap;
826     char tbuf[512];
827 
828     va_start(ap, fmt);
829     (void) vsnprintf(tbuf, 512, fmt, ap);
830     va_end(ap);
831     addstr(tbuf);
832 }
833 
834 int
cputch(int c)835 cputch(int c) {
836     return addch(c);
837 }
838 
839 int
cgetch(void)840 cgetch(void)
841 {
842     int c = getch();
843 
844     if(c == 27) {
845 	c = getch();
846 	if (isalpha(c)) c = tolower(c);
847         return 0x200 + c;
848     }
849     return c;
850 }
851 
852 void
textattr(enum textcolor c)853 textattr(enum textcolor c) {
854     bkgdset(COLOR_PAIR(c));
855     attrset(COLOR_PAIR(c)|A_BOLD);
856 }
857 
858 void
paktc(void)859 paktc(void)
860 {
861     textattr(COLOR_MSG);
862     cprintf(" Press Any Key to Continue... ");
863     textattr(COLOR_DATA);
864     cgetch();
865     cprintf("\r");
866     clrtoeol();
867 }
868 
869 void
gotomsg(void)870 gotomsg(void)
871 {
872     move(LibRows + 4, 2);
873 }
874 
875 /* ==== Midi Routines ==== */
876 
877 void
Unpack(int voice)878 Unpack(int voice)
879 {
880     UBYTE *a2, *a3;
881     UBYTE  d1,  d2;
882 
883         a2=SingleData;       /* a2 = &unpacked data */
884         a3=voiceAddr(voice); /* a3 = &packed data  */
885         for (d2=6; d2>0; d2--) {
886             for (d1=11; d1>0; d1--) { *a2++=*a3++; }  /* through rd */
887             *a2++=(*a3)&0x03;   /* lc */
888             *a2++=(*a3++)>>2;   /* rc */
889             *a2++=(*a3)&0x07;   /* rs */
890             *(a2+6)=(*a3++)>>3; /* pd */
891             *a2++=(*a3)&0x03;   /* ams */
892             *a2++=(*a3++)>>2;   /* kvs */
893             *a2++=*a3++;        /* ol */
894             *a2++=(*a3)&0x01;   /* m */
895             *a2++=(*a3++)>>1;   /* fc */
896             *a2=*a3++;          /* ff */
897             a2+=2;
898         }                       /* operator done */
899         for (d2=9; d2>0; d2--) {
900             *a2++=*a3++;
901         }                       /* through algorithm */
902         *a2++=(*a3)&0x07;       /* feedback */
903         *a2++=(*a3++)>>3;       /* oks */
904         for (d2=4; d2>0; d2--) {
905             *a2++=*a3++;
906         }                       /* through lamd */
907         *a2++=(*a3)&0x01;       /* lfo ks */
908         *a2++=((*a3)>>1)&0x07;  /* lfo wave */
909         *a2++=(*a3++)>>4;       /* lfo pms */
910         for (d2=11; d2>0; d2--) {
911             *a2++=*a3++;
912         }                       /* through name */
913 }
914 
915 void
_Pack(UBYTE * packed,UBYTE * unpacked)916 _Pack(UBYTE *packed, UBYTE *unpacked)
917 {
918     UBYTE *a2, *a3;
919     UBYTE  d1,  d2;
920 
921         a3=packed;    /* a3 = &packed data   */
922         a2=unpacked;  /* a2 = &unpacked data */
923         for (d2=6; d2>0; d2--) {
924             for (d1=11; d1>0; d1--) { *a3++=*a2++; }  /* through rd */
925             *a3++=((*a2)&0x03)|(((*(a2+1))&0x03)<<2);
926             a2+=2;              /* rc+lc */
927             *a3++=((*a2)&0x07)|(((*(a2+7))&0x0f)<<3);
928             a2++;               /* pd+rs */
929             *a3++=((*a2)&0x03)|(((*(a2+1))&0x07)<<2);
930             a2+=2;              /* kvs+ams */
931             *a3++=*a2++;        /* ol */
932             *a3++=((*a2)&0x01)|(((*(a2+1))&0x1f)<<1);
933             a2+=2;              /* fc+m */
934             *a3++=*a2;
935             a2+=2;              /* ff */
936         }                       /* operator done */
937         for (d2=9; d2>0; d2--) { *a3++=*a2++; }  /* through algorithm */
938         *a3++=((*a2)&0x07)|(((*(a2+1))&0x01)<<3);
939         a2+=2;                  /* oks+fb */
940         for (d2=4; d2>0; d2--) { *a3++=*a2++; }  /* through lamd */
941         *a3++=((*a2)&0x01)|(((*(a2+1))&0x07)<<1)|
942                            (((*(a2+2))&0x07)<<4);
943         a2+=3;                  /* lpms+lfw+lks */
944         for (d2=11; d2>0; d2--) { *a3++=*a2++; }  /* through name */
945 #ifdef GAK
946 d2=a3-voiceAddr(voice);
947 cprintf("128 %d\r\n",d2);
948 d2=a2-SingleData;
949 cprintf("155 %d\r\n",d2);
950 getch();
951 #endif
952 }
953 
954 void
Pack(int voice)955 Pack(int voice)
956 {
957     _Pack(voiceAddr(voice), SingleData);
958 }
959 
960 void
PutMidiMsg(UBYTE * buf,unsigned int size)961 PutMidiMsg(UBYTE *buf, unsigned int size)
962 {
963 #ifdef USE_ALSA_MIDI
964     snd_seq_event_t event;
965 
966     snd_seq_ev_clear(&event);
967     snd_seq_ev_set_source(&event, MidiPort);
968     snd_seq_ev_set_subs(&event);
969     snd_seq_ev_set_direct(&event);
970 
971     // set event type, data, so on:
972     event.type = SND_SEQ_EVENT_SYSEX;
973     snd_seq_ev_set_variable(&event, size, buf);
974 
975     if (snd_seq_event_output(MidiHandle, &event) < 0) {
976         gotomsg();
977         cprintf("PutMidiMsg: could not write output: %s\n", snd_strerror(errno));
978         return;
979     }
980     if (snd_seq_drain_output(MidiHandle) < 0) {
981         gotomsg();
982         cprintf("PutMidiMsg: error draining output: %s\n", snd_strerror(errno));
983     }
984 
985 #else /* not USE_ALSA_MIDI: */
986     FILE *fh;
987 
988     if ((fh = fopen("/dev/midi00", "wb"))) {  /* should fix this.... */
989 	fwrite(buf, 1, size, fh);
990 	fclose(fh);
991     }
992 #endif /* USE_ALSA_MIDI */
993 }
994 
995 void
ChecksumSingle(void)996 ChecksumSingle(void)
997 {
998     int sum = 0;
999     int i;
1000 
1001     for (i = 0; i < DX7_VOICE_SIZE_UNPACKED; sum -= SingleData[i++]);
1002     SingleData[DX7_VOICE_SIZE_UNPACKED] = sum & 0x7F;
1003 }
1004 
1005 void
PutUnpacked(void)1006 PutUnpacked(void)
1007 {
1008     UBYTE *sd;
1009 
1010     ChecksumSingle();
1011     sd = SingleDump;
1012     sd[0] = 0xF0;
1013     sd[1] = 0x43;
1014     sd[2] = TXChannel;
1015     sd[3] = 0;
1016     sd[4] = 0x01;
1017     sd[5] = 0x1B;
1018     sd[DX7_DUMP_SIZE_VOICE_SINGLE - 1] = 0xF7;
1019     PutMidiMsg(sd, DX7_DUMP_SIZE_VOICE_SINGLE);
1020 }
1021 
1022 void
PutPacked(int voice)1023 PutPacked(int voice)
1024 {
1025     Unpack(voice);
1026     PutUnpacked();
1027 }
1028 
1029 void
PutBank(int voice)1030 PutBank(int voice)
1031 {
1032     UBYTE *bd = BulkDump,
1033           *p1 = voiceAddr(voice),
1034           *p2,
1035           *pe,
1036           chksum = 0;
1037 
1038     if(voice <= Voices - 32) {
1039         bd[0] = 0xF0;
1040         bd[1] = 0x43;
1041         bd[2] = TXChannel;
1042         bd[3] = 9;
1043         bd[4] = 0x10;
1044         bd[5] = 0x00;
1045         for(p2 = bd + 6, pe = p2 + 4096; p2 < pe; chksum -= *p2++ = *p1++);
1046         bd[DX7_DUMP_SIZE_VOICE_BULK - 2] = chksum & 0x7f;
1047         bd[DX7_DUMP_SIZE_VOICE_BULK - 1] = 0xF7;
1048         PutMidiMsg(bd, DX7_DUMP_SIZE_VOICE_BULK);
1049     } else {
1050         beep();
1051     }
1052 }
1053 
1054 void
PutParm(int parm)1055 PutParm(int parm)
1056 {
1057     UBYTE offset = veParm[parm].Offset;
1058     UBYTE bd[7];
1059     bd[0] = 0xF0;
1060     bd[1] = 0x43;
1061     bd[2] = 0x10 | TXChannel;
1062     bd[3] = offset >> 7;
1063     bd[4] = offset & 0x7F;
1064     bd[5] = SingleData[offset];
1065     bd[6] = 0xF7;
1066     PutMidiMsg(bd, 7);
1067 }
1068 
1069 /* ==== Load/Save Routines ==== */
1070 
1071 bool
FileRequest(char * namebuf,char * title)1072 FileRequest(char *namebuf, char *title)
1073 {
1074     echo(); curs_set(1);
1075     cprintf(" %s\n\n Enter filename:\n > ",title);
1076     refresh();
1077     if (wgetnstr(stdscr, namebuf, 76) == ERR) {
1078 	namebuf[0] = 0;
1079     }
1080     noecho(); curs_set(0);
1081     cprintf("\n");
1082     return (strlen(namebuf)!=0);
1083 }
1084 
1085 void
LoadError(const char * filename,const char * error)1086 LoadError(const char *filename, const char *error)
1087 {
1088     cprintf(" Load - Error reading file '%s':\n", filename);
1089     cprintf(" '%s'!\n", error);
1090     paktc();
1091 }
1092 
1093 int
Load(char * filename)1094 Load(char *filename)
1095 {
1096     FILE *fp;
1097     char errbuf[256];
1098     long filelength;
1099     unsigned char *raw_patch_data = NULL;
1100     size_t filename_length;
1101     int count;
1102     int patchstart;
1103     int midshift;
1104     int datastart;
1105     int i;
1106     int op;
1107 
1108     /* this needs to 1) open and parse the file, 2a) if it's good, copy as
1109      * many patches as will fit into VoiceData beginning at Voice_Cursor,
1110      * 2b) if it's not good, print an appropriate error message and return. */
1111 
1112     if ((fp = fopen(filename, "rb")) == NULL) {
1113         snprintf(errbuf, 256, "could not open file for reading: %s", strerror(errno));
1114         LoadError(filename, errbuf);
1115         return 0;
1116     }
1117     if (fseek(fp, 0, SEEK_END) ||
1118         (filelength = ftell(fp)) == -1 ||
1119         fseek(fp, 0, SEEK_SET)) {
1120         snprintf(errbuf, 256, "couldn't get length of patch file: %s", strerror(errno));
1121         fclose(fp);
1122         LoadError(filename, errbuf);
1123         return 0;
1124     }
1125     if (filelength == 0) {
1126         fclose(fp);
1127         LoadError(filename, "patch file has zero length");
1128         return 0;
1129     } else if (filelength > 2097152) {
1130         fclose(fp);
1131         LoadError(filename, "patch file is too large");
1132         return 0;
1133     } else if (filelength < DX7_VOICE_SIZE_PACKED) {
1134         fclose (fp);
1135         LoadError(filename, "patch file is too small");
1136         return 0;
1137     }
1138 
1139     if (!(raw_patch_data = (unsigned char *)malloc(filelength))) {
1140         fclose(fp);
1141         LoadError(filename, "couldn't allocate memory for raw patch file");
1142         return 0;
1143     }
1144 
1145     if (fread(raw_patch_data, 1, filelength, fp) != (size_t)filelength) {
1146         snprintf(errbuf, 256, "short read on patch file: %s", strerror(errno));
1147         free(raw_patch_data);
1148         fclose(fp);
1149         LoadError(filename, errbuf);
1150         return 0;
1151     }
1152     fclose(fp);
1153     filename_length = strlen (filename);
1154 
1155     /* check if the file is a standard MIDI file */
1156     if (raw_patch_data[0] == 0x4d &&	/* "M" */
1157         raw_patch_data[1] == 0x54 &&	/* "T" */
1158         raw_patch_data[2] == 0x68 &&	/* "h" */
1159         raw_patch_data[3] == 0x64)	/* "d" */
1160         midshift = 2;
1161     else
1162         midshift = 0;
1163 
1164     /* scan SysEx or MIDI file for SysEx header(s) */
1165     count = 0;
1166     datastart = 0;
1167     for (patchstart = 0; patchstart + midshift + 5 < filelength; patchstart++) {
1168 
1169         if (raw_patch_data[patchstart] == 0xf0 &&
1170             raw_patch_data[patchstart + 1 + midshift] == 0x43 &&
1171             raw_patch_data[patchstart + 2 + midshift] <= 0x0f &&
1172             raw_patch_data[patchstart + 3 + midshift] == 0x09 &&
1173             raw_patch_data[patchstart + 5 + midshift] == 0x00 &&
1174             patchstart + 4103 + midshift < filelength &&
1175             raw_patch_data[patchstart + 4103 + midshift] == 0xf7) {  /* DX7 32 voice dump */
1176 
1177             memmove(raw_patch_data + count * DX7_VOICE_SIZE_PACKED,
1178                     raw_patch_data + patchstart + 6 + midshift, 4096);
1179             count += 32;
1180             patchstart += 4104;
1181 
1182         } else if (raw_patch_data[patchstart] == 0xf0 &&
1183                    raw_patch_data[patchstart + midshift + 1] == 0x43 &&
1184                    raw_patch_data[patchstart + midshift + 2] <= 0x0f &&
1185                    raw_patch_data[patchstart + midshift + 4] == 0x01 &&
1186                    raw_patch_data[patchstart + midshift + 5] == 0x1b &&
1187                    patchstart + midshift + 162 < filelength &&
1188                    raw_patch_data[patchstart + midshift + 162] == 0xf7) {  /* DX7 single voice (edit buffer) dump */
1189 
1190             _Pack ((UBYTE *)errbuf,  /* pack to errbuf to avoid a collision */
1191                    raw_patch_data + patchstart + midshift + 6);
1192             memcpy(raw_patch_data + count * DX7_VOICE_SIZE_PACKED,
1193                    errbuf, DX7_VOICE_SIZE_PACKED);
1194 
1195             count += 1;
1196             patchstart += DX7_DUMP_SIZE_VOICE_SINGLE;
1197         }
1198     }
1199 
1200     /* assume raw DX7/TX7 data if no SysEx header was found. */
1201     /* assume the user knows what she is doing ;-) */
1202 
1203     if (count == 0)
1204         count = filelength / DX7_VOICE_SIZE_PACKED;
1205 
1206     /* Dr.T and Steinberg TX7 file needs special treatment */
1207     if ((!strcmp(filename + filename_length - 4, ".TX7") ||
1208          !strcmp(filename + filename_length -4, ".SND") ||
1209          !strcmp(filename + filename_length -4, ".tx7") ||
1210          !strcmp(filename + filename_length - 4, ".snd")) && filelength == 8192) {
1211 
1212         count = 32;
1213         filelength = 4096;
1214     }
1215 
1216     /* Transform XSyn file also needs special treatment */
1217      if ((!strcmp(filename + filename_length - 4, ".BNK") ||
1218           !strcmp(filename + filename_length - 4, ".bnk")) && filelength == 8192) {
1219          for (i=0; i<32; i++)
1220          {
1221              memmove(raw_patch_data + 128*i, raw_patch_data + 256*i, 128);
1222          }
1223          count = 32;
1224          filelength = 4096;
1225      }
1226 
1227     /* Steinberg Synthworks DX7 SND */
1228     if ((!strcmp (filename + filename_length - 4, ".SND") ||
1229          !strcmp (filename + filename_length - 4, ".snd")) && filelength == 5216) {
1230 
1231         count = 32;
1232         filelength = 4096;
1233     }
1234 
1235     /* Voyetra SIDEMAN DX/TX
1236      * Voyetra Patchmaster DX7/TX7 */
1237     if ((filelength == 9816 || filelength == 5663) &&
1238         raw_patch_data[0] == 0xdf &&
1239         raw_patch_data[1] == 0x05 &&
1240         raw_patch_data[2] == 0x01 && raw_patch_data[3] == 0x00) {
1241 
1242         count = 32;
1243         datastart = 0x60f;
1244     }
1245 
1246     /* Yamaha DX200 editor .DX2 file */
1247     if ((!strcmp (filename + filename_length - 4, ".DX2") ||
1248          !strcmp (filename + filename_length - 4, ".dx2"))
1249         && filelength == 326454)
1250       {
1251           memmove (raw_patch_data + 16384, raw_patch_data + 34, 128 * 381);
1252           for (count = 0; count < 128; count++)
1253             {
1254                 for (op = 0; op < 6; op++)
1255                   {
1256                       for (i = 0; i < 8; i++)
1257                         {
1258                             raw_patch_data[17 * (5 - op) + i + 128 * count] =
1259                                 raw_patch_data[16384 + 35 * op + 76 + i + 381 * count];
1260                         }
1261                       raw_patch_data[17 * (5 - op) + 8 + 128 * count] =
1262                           raw_patch_data[16384 + 35 * op + 84 + 381 * count] - 21;
1263                       raw_patch_data[17 * (5 - op) + 9 + 128 * count] =
1264                           raw_patch_data[16384 + 35 * op + 87 + 381 * count];
1265                       raw_patch_data[17 * (5 - op) + 10 + 128 * count] =
1266                           raw_patch_data[16384 + 35 * op + 88 + 381 * count];
1267                       raw_patch_data[17 * (5 - op) + 11 + 128 * count] =
1268                           raw_patch_data[16384 + 35 * op + 85 + 381 * count] +
1269                           raw_patch_data[16384 + 35 * op + 86 + 381 * count] * 4;
1270                       raw_patch_data[17 * (5 - op) + 12 + 128 * count] =
1271                           raw_patch_data[16384 + 35 * op + 89 + 381 * count] +
1272                           raw_patch_data[16384 + 35 * op + 75 + 381 * count] * 8;
1273                       if (raw_patch_data[16384 + 35 * op + 71 + 381 * count] > 3)
1274                           raw_patch_data[16384 + 35 * op + 71 + 381 * count] = 3;
1275                       raw_patch_data[17 * (5 - op) + 13 + 128 * count] =
1276                           raw_patch_data[16384 + 35 * op + 71 + 381 * count] / 2 +
1277                           raw_patch_data[16384 + 35 * op + 91 + 381 * count] * 4;
1278                       raw_patch_data[17 * (5 - op) + 14 + 128 * count] =
1279                           raw_patch_data[16384 + 35 * op + 90 + 381 * count];
1280                       raw_patch_data[17 * (5 - op) + 15 + 128 * count] =
1281                           raw_patch_data[16384 + 35 * op + 72 + 381 * count] +
1282                           raw_patch_data[16384 + 35 * op + 73 + 381 * count] * 2;
1283                       raw_patch_data[17 * (5 - op) + 16 + 128 * count] =
1284                           raw_patch_data[16384 + 35 * op + 74 + 381 * count];
1285                   }
1286                 for (i = 0; i < 4; i++)
1287                   {
1288                       raw_patch_data[102 + i + 128 * count] =
1289                           raw_patch_data[16384 + 26 + i + 381 * count];
1290                   }
1291                 for (i = 0; i < 4; i++)
1292                   {
1293                       raw_patch_data[106 + i + 128 * count] =
1294                           raw_patch_data[16384 + 32 + i + 381 * count];
1295                   }
1296                 raw_patch_data[110 + 128 * count] =
1297                     raw_patch_data[16384 + 17 + 381 * count];
1298                 raw_patch_data[111 + 128 * count] =
1299                     raw_patch_data[16384 + 18 + 381 * count] +
1300                     raw_patch_data[16384 + 38 + 381 * count] * 8;
1301                 for (i = 0; i < 4; i++)
1302                   {
1303                       raw_patch_data[112 + i + 128 * count] =
1304                           raw_patch_data[16384 + 20 + i + 381 * count];
1305                   }
1306                 raw_patch_data[116 + 128 * count] =
1307                     raw_patch_data[16384 + 24 + 381 * count] +
1308                     raw_patch_data[16384 + 19 + 381 * count] * 2 +
1309                     raw_patch_data[16384 + 25 + 381 * count] * 16;
1310                 raw_patch_data[117 + 128 * count] =
1311                     raw_patch_data[16384 + 37 + 381 * count] - 36;
1312                 for (i = 0; i < 10; i++)
1313                   {
1314                       raw_patch_data[118 + i + 128 * count] =
1315                           raw_patch_data[16384 + i + 381 * count];
1316                   }
1317             }
1318 
1319           count = 128;
1320           filelength = 16384;
1321           datastart = 0;
1322 
1323       }
1324 
1325     /* finally, copy patchdata to the right location */
1326     if (count > Voices - Voice_Cursor) {  /* if ( voices-in-file > voices-to-end-of-buffer ) */
1327         cprintf(" Load - Patch file '%s' too big for remaining space:\n", filename);
1328         cprintf(" %d patches in file, only %d loaded!\n", count, Voices - Voice_Cursor);
1329         paktc();
1330         count = Voices - Voice_Cursor;
1331     }
1332 
1333     memcpy(voiceAddr(Voice_Cursor), raw_patch_data + datastart, DX7_VOICE_SIZE_PACKED * count);
1334     free (raw_patch_data);
1335     cprintf(" File '%s' loaded.\n", filename);
1336     return count;
1337 }
1338 
1339 void
Save(int vstart,int vend)1340 Save(int vstart, int vend)  /* range is inclusive, filename in FNameBuff */
1341 {
1342     FILE *fh;
1343     long flength;
1344 
1345     if ((fh = fopen(FNameBuff, "wb")) != 0) {
1346         flength = (vend - vstart + 1) * DX7_VOICE_SIZE_PACKED;
1347 	if (flength != fwrite(voiceAddr(vstart), 1, flength, fh)) {
1348             cprintf("Save - Error writing file '%s':\n", FNameBuff);
1349             cprintf(" '%s'!\n", strerror(errno));
1350             paktc();
1351         }
1352 	fclose(fh);
1353     } else {
1354         cprintf("Save - Error opening file '%s':\n", FNameBuff);
1355         cprintf(" '%s'!\n", strerror(errno));
1356         paktc();
1357     }
1358 }
1359 
1360 /* ==== VoiceEdit Stuff ==== */
1361 
1362 void
ve_ShowAlg(void)1363 ve_ShowAlg(void)
1364 {
1365     int alg = SingleData[134],
1366         x,
1367         y;
1368     char *s = veAlg[alg];
1369     bool t;
1370 
1371     textattr(COLOR_LABEL);
1372     for (y = 12; y <= 20; y++) {
1373         x = 56;
1374 	move(y, x);
1375         for (; x <= 72; x++) {
1376             switch (*s) {
1377                 case '1':   t = (!!(ve_OpSelect&32));  goto printop;
1378                 case '2':   t = (!!(ve_OpSelect&16));  goto printop;
1379                 case '3':   t = (!!(ve_OpSelect& 8));  goto printop;
1380                 case '4':   t = (!!(ve_OpSelect& 4));  goto printop;
1381                 case '5':   t = (!!(ve_OpSelect& 2));  goto printop;
1382                 case '6':   t = (!!(ve_OpSelect& 1));
1383                   printop:
1384                     textattr(t ? COLOR_OPON : COLOR_OPOFF);
1385                     cputch(*s++);
1386                     textattr(COLOR_LABEL);
1387                     break;
1388                 case 0:
1389                     cputch(' ');
1390                     break;
1391                 case '\n':
1392                     cputch(' ');
1393                     if (x == 72) s++;
1394                     break;
1395                 case '^':
1396                     cputch(ACS_BTEE); s++;
1397                     break;
1398                 case '-':
1399                     cputch(ACS_HLINE); s++;
1400                     break;
1401                 case 'L':
1402                     cputch(ACS_LLCORNER); s++;
1403                     break;
1404                 case '/':
1405                     cputch(ACS_LRCORNER); s++;
1406                     break;
1407                 case '}':
1408                     cputch(ACS_LTEE); s++;
1409                     break;
1410                 case '+':
1411                     cputch(ACS_PLUS); s++;
1412                     break;
1413 #if 0
1414                 case '?':  /* -FIX- */
1415                     cputch(ACS_RTEE); s++;
1416                     break;
1417                 case '?':  /* -FIX- */
1418                     cputch(ACS_TTEE); s++;
1419                     break;
1420 #endif
1421                 case '\'':
1422                     cputch(ACS_ULCORNER); s++;
1423                     break;
1424                 case '`':
1425                     cputch(ACS_URCORNER); s++;
1426                     break;
1427                 case '|':
1428                     cputch(ACS_VLINE); s++;
1429                     break;
1430                 default:
1431                     cputch(*s++);
1432                     break;
1433             }
1434         }
1435     }
1436     textattr(COLOR_DATA);
1437 }
1438 
1439 void
ve_FExtend(UBYTE fc,UBYTE ff,UBYTE mode,UBYTE y)1440 ve_FExtend(UBYTE fc, UBYTE ff, UBYTE mode, UBYTE y)
1441 {
1442     unsigned long f;
1443     char ca[10];
1444 
1445     textattr(COLOR_LABEL);
1446     move(y, 47);
1447     if (mode) { /* fixed */
1448         f = veFFF[ff];
1449         switch (fc & 3) {
1450             case 1: f *=   10;    break;
1451             case 2: f *=  100;    break;
1452             case 3: f *= 1000;    break;
1453         }
1454     } else {
1455         f = fc * 10;
1456         if (!f) f = 5;
1457         f = (100 + ff) * f;
1458     }
1459     f = sprintf(ca, "%ld", f);
1460     switch (f) {
1461         case 3: cprintf("0.%.3s", ca);              break;
1462         case 4: cprintf("%.1s.%.3s", ca, ca + 1);   break;
1463         case 5: cprintf("%.2s.%.2s", ca, ca + 2);   break;
1464         case 6: cprintf("%.3s.%.1s", ca, ca + 3);   break;
1465         case 7: cprintf("%.4s.", ca);               break;
1466     }
1467     textattr(COLOR_DATA);
1468 }
1469 
1470 void
ve_printParm(int parm)1471 ve_printParm(int parm)
1472 {
1473     unsigned char val = SingleData[veParm[parm].Offset],
1474                   c;
1475     char *t;
1476 
1477     move(veParm[parm].Y, veParm[parm].X);
1478     if (parm == ve_Cursor) textattr(COLOR_CURSOR);
1479     switch (veParm[parm].Type) {
1480         case vptName:
1481             {
1482                 UBYTE ca[11];
1483 
1484                 memcpy(ca, SingleData + 145, 10);
1485                 for (c = 0; c < 10; c++) {
1486                     if (ca[c] < 32)
1487                         ca[c]=183;  /* centered dot */
1488                     else if (ca[c] >= 128)
1489                         ca[c]=174;  /* (R) symbol = out-of-range */
1490                     else {
1491                         switch (ca[c]) {
1492                             case  92:  ca[c]=165;  break;  /* yen */
1493                             case 126:  ca[c]=187;  break;  /* >> */
1494                             case 127:  ca[c]=171;  break;  /* << */
1495                         }
1496                     }
1497                 }
1498                 ca[10] = 0;
1499                 cprintf("%s", ca);
1500             }
1501             break;
1502         case vpt0_99:
1503             if (val > 99)
1504                 cprintf("??");
1505             else
1506                 cprintf("%2.2d", val);
1507             break;
1508         case vpt0_7:
1509             if (val > 7)
1510                 cputch('?');
1511             else
1512                 cputch(val+'0');
1513             break;
1514         case vptMode:
1515             switch (val) {
1516                 case 0:  c = 'R'; break;
1517                 case 1:  c = 'F'; break;
1518                 default: c = '?'; break;
1519             }
1520             cputch(c);
1521             ve_FExtend(SingleData[veParm[parm+1].Offset],
1522                        SingleData[veParm[parm+2].Offset],
1523                        val,
1524                        veParm[parm].Y);
1525             break;
1526         case vptFC:
1527             if (val > 31)
1528                 cprintf("??");
1529             else
1530                 cprintf("%2d", val);
1531             ve_FExtend(val,
1532                        SingleData[veParm[parm+1].Offset],
1533                        SingleData[veParm[parm-1].Offset],
1534                        veParm[parm].Y);
1535             break;
1536         case vptFF:
1537             if (val > 99)
1538                 cprintf("??");
1539             else
1540                 cprintf("%2d", val);
1541             ve_FExtend(SingleData[veParm[parm-1].Offset],
1542                        val,
1543                        SingleData[veParm[parm-2].Offset],
1544                        veParm[parm].Y);
1545             break;
1546         case vptDetune:    /* 0-14, as -7-+7 */
1547             if (val > 14)
1548                 cprintf("??");
1549             else
1550                 cprintf("%+2d", val-7);
1551             break;
1552         case vpt0_3:
1553             if (val > 3)
1554                 cputch('?');
1555             else
1556                 cputch(val+'0');
1557             break;
1558         case vptAlg:   /* 0-31, as 1-32 */
1559             if (val > 31) {
1560                 cprintf("??");
1561                 break;
1562             }
1563             cprintf("%2d", val+1);
1564             ve_ShowAlg();
1565             return;
1566         case vptCurve:
1567             switch (val) {
1568                 case 0:   t = "-Lin"; break;
1569                 case 1:   t = "-Exp"; break;
1570                 case 2:   t = "+Exp"; break;
1571                 case 3:   t = "+Lin"; break;
1572                 default:  t = "????";
1573             }
1574             cprintf("%s", t);
1575             break;
1576         case vptBkPt:
1577             if (val > 99) {
1578                 cprintf("????");
1579                 break;
1580             }
1581             val += 21;
1582             goto printnote;
1583         case vptTrans:
1584             if (val > 48) {
1585                 cprintf("????");
1586                 break;
1587             }
1588             val += 36;
1589           printnote:
1590             cprintf("%s", NoteText(val));
1591             break;
1592         case vptOnOff:
1593             switch (val) {
1594                 case 0:  t = "Off";   break;
1595                 case 1:  t = " On";   break;
1596                 default: t = "???";
1597             }
1598             cprintf("%s", t);
1599             break;
1600         case vptWave:
1601             switch (val) {
1602                 case 0:   t = "TRI"; break;
1603                 case 1:   t = "SW-"; break;
1604                 case 2:   t = "SW+"; break;
1605                 case 3:   t = "SQU"; break;
1606                 case 4:   t = "SIN"; break;
1607                 case 5:   t = "S/H"; break;
1608                 default:  t = "???"; break;
1609             }
1610             cprintf("%s", t);
1611             break;
1612     }
1613     if (parm == ve_Cursor) textattr(COLOR_DATA);
1614 }
1615 
1616 void
ve_SetScreen(void)1617 ve_SetScreen(void)
1618 {
1619     textattr(COLOR_DATA);
1620     cprintf(" TX/Edit Voice Edit");
1621     textattr(COLOR_LABEL);
1622     cprintf("     Name\n"
1623             "                                                            A\n"
1624             "  O                              R                        V M\n"
1625             "  P  R1 L1  R2 L2  R3 L3  R4 L4  S  M FC FF  D Freq.  OL  S S\n");
1626     cprintf("  1\n"
1627             "  2\n"
1628             "  3\n"
1629             "  4\n"
1630             "  5\n"
1631             "  6\n"
1632             "  P\n");
1633     cprintf("                                          Alg.\n"
1634             "      Left   BkPt  Right     Speed        Fdbk\n");
1635     cprintf("  1                          Delay        C3=\n");
1636     cprintf("  2                          PMD          OKS\n");
1637     cprintf("  3                          AMD\n");
1638     cprintf("  4                          Sync\n");
1639     cprintf("  5                          Wave\n");
1640     cprintf("  6                          PMS\n");
1641     textattr(COLOR_DATA);
1642 }
1643 
1644 void
ve_DoScreen(void)1645 ve_DoScreen(void)
1646 {
1647     int i;
1648 
1649     for (i = 0; i < VOICEPARMS; ve_printParm(i++));
1650 }
1651 
1652 void
ve_Name(int c)1653 ve_Name(int c)
1654 {
1655     UBYTE i;
1656 
1657     for(i = 145; i < 154; i++) SingleData[i] = SingleData[i + 1];
1658     SingleData[154] = c;
1659     PutUnpacked();
1660     ve_printParm(0);
1661     ve_OpSelect = 63;
1662     ve_ShowAlg();
1663 }
1664 
1665 void
ve_Inc(int parm)1666 ve_Inc(int parm)
1667 {
1668     unsigned char val = SingleData[veParm[parm].Offset],
1669                   max;
1670 
1671     max = vtypemax[veParm[parm].Type];
1672     if (!max) return;
1673     if (++val > max) val = 0;
1674     SingleData[veParm[parm].Offset] = val;
1675     PutParm(parm);
1676     ve_printParm(parm);
1677 }
1678 
1679 void
ve_Dec(int parm)1680 ve_Dec(int parm)
1681 {
1682     unsigned char val = SingleData[veParm[parm].Offset],
1683                   max;
1684 
1685     max = vtypemax[veParm[parm].Type];
1686     if (!max) return;
1687     if (val)
1688         val--;
1689     else
1690         val = max;
1691     SingleData[veParm[parm].Offset] = val;
1692     PutParm(parm);
1693     ve_printParm(parm);
1694 }
1695 
1696 void
ve_Zero(void)1697 ve_Zero(void)
1698 {
1699     UBYTE offset = veParm[ve_Cursor].Offset;
1700 
1701     if(ve_Cursor == 0) { /* do name */
1702         for(offset = 154; offset > 145; offset--)
1703         SingleData[offset] = SingleData[offset - 1];
1704         SingleData[145] = ' ';
1705         PutUnpacked();
1706         ve_OpSelect = 63;
1707         ve_ShowAlg();
1708     } else {
1709         SingleData[offset] = InitVoiceUnpacked[offset];
1710         PutParm(ve_Cursor);
1711     }
1712     ve_printParm(ve_Cursor);
1713 }
1714 
1715 void
ve_CurUp(void)1716 ve_CurUp(void)
1717 {
1718     int oldcursor = ve_Cursor;
1719 #ifndef USE_CALCED_CURSOR_MOVES
1720     ve_Cursor = veParm[ve_Cursor].Up;
1721     ve_printParm(oldcursor);
1722     ve_printParm(ve_Cursor);
1723 #else /* USE_CALCED_CURSOR_MOVES */
1724     int i, dx, dy, distance,
1725         best = -1,
1726         bestdistance = 1000;
1727 
1728     /* try to find the closest parm in the 'up' direction */
1729     for (i = 0; i <= VOICEPARMMAX; i++) {
1730         dx = abs(veParm[ve_Cursor].X - veParm[i].X);
1731         dy = (veParm[ve_Cursor].Y - 1) - veParm[i].Y;
1732         if (dy < 0)
1733             dy += VOICEPARMS_Y_SPAN + 2; /* wrap */
1734         dy = dy * 5 / 2; /* prefer something <2.5 spaces away horizontally to 1 space vertically */
1735         distance = dx + dy;
1736         if (bestdistance > distance) {
1737             bestdistance = distance;
1738             best = i;
1739         }
1740     }
1741     if (best >= 0) {
1742         ve_Cursor = best;
1743         ve_printParm(oldcursor);
1744         ve_printParm(ve_Cursor);
1745     }
1746 #endif /* USE_CALCED_CURSOR_MOVES */
1747 }
1748 
1749 void
ve_CurDown(void)1750 ve_CurDown(void)
1751 {
1752     int oldcursor = ve_Cursor;
1753 #ifndef USE_CALCED_CURSOR_MOVES
1754     ve_Cursor = veParm[ve_Cursor].Down;
1755     ve_printParm(oldcursor);
1756     ve_printParm(ve_Cursor);
1757 #else /* USE_CALCED_CURSOR_MOVES */
1758     int i, dx, dy, distance,
1759         best = -1,
1760         bestdistance = 1000;
1761 
1762     /* try to find the closest parm in the 'down' direction */
1763     for (i = 0; i <= VOICEPARMMAX; i++) {
1764         dx = abs(veParm[i].X - veParm[ve_Cursor].X);
1765         dy = veParm[i].Y - (veParm[ve_Cursor].Y + 1);
1766         if (dy < 0)
1767             dy += VOICEPARMS_Y_SPAN + 2; /* wrap */
1768         dy = dy * 5 / 2; /* prefer something <2.5 spaces away horizontally to 1 space vertically */
1769         distance = dx + dy;
1770         if (bestdistance > distance) {
1771             bestdistance = distance;
1772             best = i;
1773         }
1774     }
1775     if (best >= 0) {
1776         ve_Cursor = best;
1777         ve_printParm(oldcursor);
1778         ve_printParm(ve_Cursor);
1779     }
1780 #endif /* USE_CALCED_CURSOR_MOVES */
1781 }
1782 
1783 void
ve_CurRight(void)1784 ve_CurRight(void)
1785 {
1786     int oldcursor = ve_Cursor;
1787 #ifndef USE_CALCED_CURSOR_MOVES
1788     if(++ve_Cursor > VOICEPARMMAX) ve_Cursor = 0;
1789     ve_printParm(oldcursor);
1790     ve_printParm(ve_Cursor);
1791 #else /* USE_CALCED_CURSOR_MOVES */
1792     int i, dx, dy, distance,
1793         best = -1,
1794         bestdistance = 1000;
1795 
1796     /* try to find the closest parm in the 'right' direction */
1797     for (i = 0; i <= VOICEPARMMAX; i++) {
1798         dx = veParm[i].X - (veParm[ve_Cursor].X + 2);
1799         if (dx < 0)
1800             dx += VOICEPARMS_X_SPAN + 4; /* wrap */
1801         dy = abs(veParm[i].Y - veParm[ve_Cursor].Y);
1802         dy = dy * 12; /* prefer something <8 spaces away horizontally to 1 space vertically */
1803         distance = dx + dy;
1804         if (bestdistance > distance) {
1805             bestdistance = distance;
1806             best = i;
1807         }
1808     }
1809     if (best >= 0) {
1810         ve_Cursor = best;
1811         ve_printParm(oldcursor);
1812         ve_printParm(ve_Cursor);
1813     }
1814 #endif /* USE_CALCED_CURSOR_MOVES */
1815 }
1816 
1817 void
ve_CurLeft(void)1818 ve_CurLeft(void)
1819 {
1820     int oldcursor = ve_Cursor;
1821 #ifndef USE_CALCED_CURSOR_MOVES
1822     if(ve_Cursor)
1823         ve_Cursor--;
1824     else
1825         ve_Cursor = VOICEPARMMAX;
1826     ve_printParm(oldcursor);
1827     ve_printParm(ve_Cursor);
1828 #else /* USE_CALCED_CURSOR_MOVES */
1829     int i, dx, dy, distance,
1830         best = -1,
1831         bestdistance = 1000;
1832 
1833     /* try to find the closest parm in the 'left' direction */
1834     for (i = 0; i <= VOICEPARMMAX; i++) {
1835         dx = (veParm[ve_Cursor].X - 2) - veParm[i].X;
1836         if (dx < 0)
1837             dx += VOICEPARMS_X_SPAN + 4; /* wrap */
1838         dy = abs(veParm[i].Y - veParm[ve_Cursor].Y);
1839         dy = dy * 12; /* prefer something <8 spaces away horizontally to 1 space vertically */
1840         distance = dx + dy;
1841         if (bestdistance > distance) {
1842             bestdistance = distance;
1843             best = i;
1844         }
1845     }
1846     if (best >= 0) {
1847         ve_Cursor = best;
1848         ve_printParm(oldcursor);
1849         ve_printParm(ve_Cursor);
1850     }
1851 #endif /* USE_CALCED_CURSOR_MOVES */
1852 }
1853 
1854 void
ve_Erase(void)1855 ve_Erase(void)
1856 {
1857     memcpy(SingleData, InitVoiceUnpacked, DX7_VOICE_SIZE_UNPACKED);
1858     // erase();
1859     // ve_SetScreen();
1860     ve_DoScreen();
1861     refresh();
1862     PutUnpacked();
1863 }
1864 
1865 void
ve_PgUp(void)1866 ve_PgUp(void)
1867 {
1868     if (Voice_Cursor) {
1869         Pack(Voice_Cursor);
1870         Unpack(--Voice_Cursor);
1871         ve_DoScreen();
1872         refresh();
1873         PutUnpacked();
1874     }
1875 }
1876 
1877 void
ve_PgDn(void)1878 ve_PgDn(void)
1879 {
1880     if (Voice_Cursor < Voices - 1) {
1881         Pack(Voice_Cursor);
1882         Unpack(++Voice_Cursor);
1883         ve_DoScreen();
1884         refresh();
1885         PutUnpacked();
1886     }
1887 }
1888 
1889 void
_ve_SetOps(void)1890 _ve_SetOps(void)
1891 {
1892     UBYTE bd[7];
1893 
1894     bd[0] = 0xF0;
1895     bd[1] = 0x43;
1896     bd[2] = 0x10 | TXChannel;
1897     bd[3] = 1;
1898     bd[4] = 27;
1899     bd[5] = ve_OpSelect;
1900     bd[6] = 0xF7;
1901     PutMidiMsg(bd, 7);
1902 }
1903 
1904 void
ve_SetOps(int o)1905 ve_SetOps(int o)
1906 {
1907     UBYTE i;
1908 
1909     ve_OpSelect ^= o;
1910     for (i = 1; i < 7; i++) {
1911         if (ve_OpSelect & (1 << (6 - i)))
1912             textattr(COLOR_OPON);
1913         else
1914             textattr(COLOR_OPOFF);
1915 	move(3 + i, 2);
1916         cprintf("%c", i + '0');
1917 	move(12 + i, 2);
1918         cprintf("%c", i + '0');
1919     }
1920     /* textattr(COLOR_DATA);  not needed with ve_ShowAlg() */
1921     ve_ShowAlg();
1922     _ve_SetOps();
1923 }
1924 
1925 void
ve_Number(int c)1926 ve_Number(int c)
1927 {
1928     unsigned char val = SingleData[veParm[ve_Cursor].Offset],
1929                   typ = veParm[ve_Cursor].Type,
1930                   max = vtypemax[typ];
1931 
1932     switch(typ) {
1933         case vpt0_99:
1934         case vptFF:
1935             val=(val * 10 + c - '0') % 100;
1936             break;
1937         case vptFC:
1938             val=(val * 10 + c - '0') % 100;
1939             for(; val > 31; val -= 10);
1940             break;
1941         case vpt0_7:
1942         case vpt0_3:
1943             val=c - '0';
1944             if(val > max) val = max;
1945             break;
1946         case vptAlg:
1947             val=((val + 1) * 10 + c - '0') % 100;
1948             if (!val) val = 1;
1949             for(; val > 32; val -= 10);
1950             val--;
1951             break;
1952         default:
1953             return;
1954     }
1955     SingleData[veParm[ve_Cursor].Offset] = val;
1956     PutParm(ve_Cursor);
1957     ve_printParm(ve_Cursor);
1958 }
1959 
1960 void
ve_Help(void)1961 ve_Help(void)
1962 {
1963     erase();
1964     cprintf(" TX/Edit v" VERSIONSTRING " Voice Edit Help\n\n");
1965 
1966     cprintf(" Up / Down /\n"
1967             " Right / Left  - Move cursor\n\n");
1968 
1969     cprintf(" +             - Increment field\n"
1970             " -             - Decrement field\n"
1971             " 0 through 9   - Enter data into field\n"
1972             " Backspace     - Zero/reset field\n\n");
1973 
1974     cprintf(" A through Z   - Rotate letters into name (name field only)\n\n"
1975 
1976             " F1 through F6 - Enable/disable operators 1 through 6\n\n");
1977 
1978     cprintf(" Meta-P        - Put edit buffer as single voice\n"
1979             " Meta-!        - Erase edit buffer to init voice\n"
1980             " PgUp / PgDn   - Move to previous / next voice\n"
1981 
1982             " Esc / Meta-L  - Return to librarian mode\n\n"
1983 
1984             " h / Meta-H    - Display this help screen\n\n");
1985 
1986     paktc();
1987     erase();
1988     ve_SetScreen();
1989     ve_DoScreen();
1990 }
1991 
1992 void
ve_CharIn(int c)1993 ve_CharIn(int c)
1994 {
1995     if(!ve_Cursor && c>=32 && c<=127) {
1996         ve_Name(c);
1997     } else {
1998         if(c >= 'A' && c <= 'Z')
1999             c = tolower(c);
2000         switch(c) {
2001             case '+':
2002             case '=':           ve_Inc(ve_Cursor);  break;
2003             case '-':           ve_Dec(ve_Cursor);  break;
2004 #if 0
2005             case kc_Del:
2006 #endif
2007             case KEY_BACKSPACE: ve_Zero();          break;
2008             case KEY_UP:        ve_CurUp();         break;
2009             case KEY_DOWN:      ve_CurDown();       break;
2010             case KEY_RIGHT:     ve_CurRight();      break;
2011             case KEY_LEFT:      ve_CurLeft();       break;
2012             case KEY_METAL:
2013             case KEY_ESC:       newmode=MODELIB;    break;
2014             case KEY_F(1):      ve_SetOps(32);      break;
2015             case KEY_F(2):      ve_SetOps(16);      break;
2016             case KEY_F(3):      ve_SetOps( 8);      break;
2017             case KEY_F(4):      ve_SetOps( 4);      break;
2018             case KEY_F(5):      ve_SetOps( 2);      break;
2019             case KEY_F(6):      ve_SetOps( 1);      break;
2020             case KEY_PPAGE:     ve_PgUp();          break;
2021             case KEY_NPAGE:     ve_PgDn();          break;
2022             case KEY_METAP:     PutUnpacked();      break;
2023             case KEY_METAEX:    ve_Erase();         break;
2024             case KEY_METAH:
2025             case 'h':           ve_Help();          break;
2026             default:
2027                 if(c>='0' && c<='9') {
2028                     ve_Number(c);
2029                 } else {
2030                     gotomsg();
2031                     cprintf(" Type <Alt-H> for help...");
2032                     beep();
2033 #ifdef DEBUG
2034                     cprintf("keycode=0x%04x", c);
2035 #endif
2036                 }
2037                 break;
2038         }
2039     }
2040 }
2041 
2042 /* ==== Librarian Stuff ==== */
2043 
2044 void
LibPrintVName(int voice)2045 LibPrintVName(int voice)  /* print name at correct cursor position */
2046 {
2047     if (Voice_TOS <= voice && voice < Voice_TOS + LibNames) {
2048         move((voice-Voice_TOS)%LibRows + 2,
2049              (voice-Voice_TOS)/LibRows * 15 + 1);
2050         if (voice<Voices) {
2051 	    textattr(COLOR_LABEL);
2052 	    if (voice < 10000) {
2053                 cprintf("%4d ", voice);
2054             } else {
2055 		cprintf("?%03d ", voice % 1000);
2056             }
2057             if (voice==Voice_Cursor) {
2058                 if(blocking)
2059                     textattr(COLOR_BCURSOR);
2060                 else
2061                     textattr(COLOR_CURSOR);
2062             } else {
2063                 if (blocking||blocked) {
2064                     if (Voice_BStart<=voice&&voice<=Voice_BEnd) {
2065                         textattr(COLOR_BLOCK);
2066                     } else
2067                         textattr(COLOR_DATA);
2068                 } else
2069                     textattr(COLOR_DATA);
2070             }
2071             PrintVName(voice);
2072             textattr(COLOR_DATA);
2073         } else {
2074             cprintf("               ");
2075 	}
2076     }
2077 }
2078 
2079 void
LibSetScreen(void)2080 LibSetScreen(void)  /* setup librarian screen */
2081 {
2082 #if USE_ALSA_MIDI
2083     char temp[80];
2084 
2085     snprintf(temp, 80, "TX/Edit v%s (%d:%d)", VERSIONSTRING, MidiClient, MidiPort);
2086     mvaddstr(0, 1, temp);
2087 #else
2088     mvaddstr(0, 1, "TX/Edit v" VERSIONSTRING);
2089 #endif
2090 }
2091 
2092 void
LibDoScreen(void)2093 LibDoScreen(void)  /* print voice names */
2094 {
2095     int i;
2096 
2097     for (i=Voice_TOS; i<Voice_TOS+LibNames; LibPrintVName(i++));
2098 }
2099 
2100 void
SetBlock(void)2101 SetBlock(void)  /* fake a block under cursor if no block marked */
2102 {
2103     if (!(blocking || blocked))
2104         Voice_BMark = Voice_BStart = Voice_BEnd = Voice_Cursor;
2105 }
2106 
2107 void
CancelBlock(void)2108 CancelBlock(void)
2109 {
2110     blocking = FALSE;
2111     blocked = FALSE;
2112     LibBlockAction = noop;
2113     LibDoScreen();
2114     gotomsg();
2115     clrtoeol();
2116 }
2117 
2118 void
StartBlock(void)2119 StartBlock(void)  /* or cancel block if one is marked */
2120 {
2121     if (!(blocking || blocked)) {
2122         blocking = TRUE;
2123         Voice_BMark = Voice_BStart = Voice_BEnd = Voice_Cursor;
2124         LibPrintVName(Voice_Cursor);
2125     } else
2126         CancelBlock();
2127 }
2128 
2129 void
EndBlock(void)2130 EndBlock(void)
2131 {
2132     blocking = FALSE;
2133     blocked = TRUE;
2134     LibPrintVName(Voice_Cursor);
2135 }
2136 
2137 void
EscBlock(void)2138 EscBlock(void)  /* cancel block if one is marked */
2139 {
2140     if(blocking || blocked)
2141         CancelBlock();
2142 }
2143 
2144 void
CheckBlock(void)2145 CheckBlock(void)
2146 {
2147     if (blocking) {
2148         if (Voice_Cursor < Voice_BMark) {
2149             Voice_BStart = Voice_Cursor;
2150             Voice_BEnd   = Voice_BMark;
2151         } else {
2152             Voice_BStart = Voice_BMark;
2153             Voice_BEnd   = Voice_Cursor;
2154         }
2155     }
2156 }
2157 
2158 void
LibCurUp(void)2159 LibCurUp(void)
2160 {
2161     if (Voice_Cursor) {
2162         int vc;
2163 
2164         vc = --Voice_Cursor;
2165         CheckBlock();
2166         if (vc >= Voice_TOS) {
2167             LibPrintVName(vc);
2168             LibPrintVName(++vc);
2169         } else {
2170             Voice_TOS = max(Voice_TOS - LibRows, 0);
2171             LibDoScreen();
2172         }
2173     }
2174 }
2175 
2176 void
LibCurDown(void)2177 LibCurDown(void)
2178 {
2179     if (Voice_Cursor < Voices - 1) {
2180         int vc;
2181 
2182         vc = ++Voice_Cursor;
2183         CheckBlock();
2184         if (vc < Voice_TOS + LibNames) {
2185             LibPrintVName(vc);
2186             LibPrintVName(--vc);
2187         } else {
2188             Voice_TOS += LibRows;
2189             LibDoScreen();
2190         }
2191     }
2192 }
2193 
2194 void
LibCurRight(void)2195 LibCurRight(void)
2196 {
2197     if (Voice_Cursor < Voices - 1) {
2198         int oldvc, newvc;
2199 
2200         oldvc = Voice_Cursor;
2201         Voice_Cursor = newvc = min(oldvc + LibRows, Voices - 1);
2202         CheckBlock();
2203         if (newvc < Voice_TOS + LibNames) {
2204             if (blocking) {
2205                 for (; oldvc <= newvc; LibPrintVName(oldvc++));
2206             } else {
2207                 LibPrintVName(oldvc);
2208                 LibPrintVName(newvc);
2209             }
2210         } else {
2211             Voice_TOS += LibRows;
2212             LibDoScreen();
2213         }
2214     }
2215 }
2216 
2217 void
LibCurLeft(void)2218 LibCurLeft(void)
2219 {
2220     if (Voice_Cursor) {
2221         int oldvc, newvc;
2222 
2223         oldvc = Voice_Cursor;
2224         Voice_Cursor = newvc = max(oldvc - LibRows, 0);
2225         CheckBlock();
2226         if (newvc >= Voice_TOS) {
2227             if (blocking) {
2228                 for (; oldvc >= newvc; LibPrintVName(oldvc--));
2229             } else {
2230                 LibPrintVName(oldvc);
2231                 LibPrintVName(newvc);
2232             }
2233         } else {
2234             Voice_TOS = max(Voice_TOS - LibRows, 0);
2235             LibDoScreen();
2236         }
2237     }
2238 }
2239 
2240 void
LibCtrlPgUp(void)2241 LibCtrlPgUp(void)
2242 {
2243     if (Voice_Cursor) {
2244         int oldvc, newvc;
2245 
2246         oldvc = Voice_Cursor;
2247         Voice_Cursor = newvc = max(Voice_Cursor - 1, 0) & 0xffe0;
2248         CheckBlock();
2249         if (newvc >= Voice_TOS) {
2250             if (blocking) {
2251                 for (; oldvc >= newvc; LibPrintVName(oldvc--));
2252             } else {
2253                 LibPrintVName(oldvc);
2254                 LibPrintVName(newvc);
2255             }
2256         } else {
2257             Voice_TOS=newvc;
2258             LibDoScreen();
2259         }
2260     }
2261 }
2262 
2263 void
LibCtrlPgDn(void)2264 LibCtrlPgDn(void)
2265 {
2266     if (Voice_Cursor < Voices-1) {
2267         int oldvc, newvc;
2268 
2269         oldvc = Voice_Cursor;
2270         Voice_Cursor = newvc = min(((Voice_Cursor + 33) & 0xffe0) - 1, Voices - 1);
2271         CheckBlock();
2272         if (newvc < Voice_TOS + LibNames) {
2273             if (blocking) {
2274                 for (; oldvc <= newvc; LibPrintVName(oldvc++));
2275             } else {
2276                 LibPrintVName(oldvc);
2277                 LibPrintVName(newvc);
2278             }
2279         } else {
2280             Voice_TOS=max(newvc - LibNames + 1, 0);
2281             LibDoScreen();
2282         }
2283     }
2284 }
2285 
2286 void
LibCurEnd(void)2287 LibCurEnd(void)
2288 {
2289     Voice_Cursor = Voices - 1;
2290     Voice_TOS = max(Voices - LibNames, 0);
2291     CheckBlock();
2292     LibDoScreen();
2293 }
2294 
2295 void
LibCurHome(void)2296 LibCurHome(void)
2297 {
2298     Voice_Cursor = 0;
2299     Voice_TOS = 0;
2300     CheckBlock();
2301     LibDoScreen();
2302 }
2303 
2304 void
LibPgUp(void)2305 LibPgUp(void)
2306 {
2307     if (Voice_Cursor) {
2308         int oldvc, newvc;
2309 
2310         oldvc = Voice_Cursor;
2311         Voice_Cursor = newvc = max(Voice_Cursor - 1, 0) & 0xfff0;
2312         CheckBlock();
2313         if (newvc >= Voice_TOS) {
2314             if (blocking) {
2315                 for (; oldvc >= newvc; LibPrintVName(oldvc--));
2316             } else {
2317                 LibPrintVName(oldvc);
2318                 LibPrintVName(newvc);
2319             }
2320         } else {
2321             Voice_TOS = newvc;
2322             LibDoScreen();
2323         }
2324     }
2325 }
2326 
2327 void
LibPgDn(void)2328 LibPgDn(void)
2329 {
2330     if (Voice_Cursor < Voices-1) {
2331         int oldvc, newvc;
2332 
2333         oldvc = Voice_Cursor;
2334         Voice_Cursor = newvc = min(((Voice_Cursor + 17) & 0xfff0) - 1, Voices - 1);
2335         CheckBlock();
2336         if (newvc < Voice_TOS + LibNames) {
2337             if (blocking) {
2338                 for (; oldvc <= newvc; LibPrintVName(oldvc++));
2339             } else {
2340                 LibPrintVName(oldvc);
2341                 LibPrintVName(newvc);
2342             }
2343         } else {
2344             Voice_TOS = max(newvc - LibNames + 1, 0);
2345             LibDoScreen();
2346         }
2347     }
2348 }
2349 
2350 void
LibCtrlRight(void)2351 LibCtrlRight(void)
2352 {
2353 
2354     Voice_Cursor = min(Voice_Cursor + LibNames, Voices - 1);
2355     Voice_TOS    = min(Voice_TOS    + LibNames, max(Voices - LibNames, 0));
2356     CheckBlock();
2357     LibDoScreen();
2358 }
2359 
2360 void
LibCtrlLeft(void)2361 LibCtrlLeft(void)
2362 {
2363     if (Voice_Cursor) {
2364         Voice_Cursor = max(Voice_Cursor - LibNames, 0);
2365         Voice_TOS    = max(Voice_TOS    - LibNames, 0);
2366         CheckBlock();
2367         LibDoScreen();
2368     }
2369 }
2370 
2371 void
LBA_Copy(void)2372 LBA_Copy(void)
2373 {
2374 #ifdef DEBUG
2375     if (!blocked) { cprintf("LBA_Copy - not Blocked?!"); return; }
2376 #endif
2377     memmove(voiceAddr(Voice_Cursor),
2378 	    voiceAddr(Voice_BStart),
2379            min(Voice_BEnd - Voice_BStart + 1, Voices - Voice_Cursor) * DX7_VOICE_SIZE_PACKED);
2380     CancelBlock();
2381 }
2382 
2383 void
LibCopy(void)2384 LibCopy(void)
2385 {
2386     SetBlock();
2387     EndBlock();
2388     LibBlockAction = LBA_Copy;
2389     gotomsg();
2390     cprintf("Move Cursor to Copy destination and press return...");
2391 }
2392 
2393 void
LibDelete(void)2394 LibDelete(void)
2395 {
2396     int i;
2397 
2398     SetBlock();
2399     if (Voices > Voice_BEnd + 1)
2400         memmove(voiceAddr(Voice_BStart),
2401 		voiceAddr(Voice_BEnd + 1),
2402                (Voices - Voice_BEnd - 1) * DX7_VOICE_SIZE_PACKED);
2403     for (i = Voices - Voice_BEnd + Voice_BStart - 1; i < Voices; EraseVoice(i++));
2404     CancelBlock();
2405 }
2406 
2407 void
LibErase(void)2408 LibErase(void)
2409 {
2410     int i;
2411 
2412     SetBlock();
2413     for (i = Voice_BStart; i <= Voice_BEnd; EraseVoice(i++));
2414     CancelBlock();
2415 }
2416 
2417 void
LibLoad(void)2418 LibLoad(void)
2419 {
2420     erase();
2421     LibSetScreen();
2422     cprintf("\n\n");
2423     if (FileRequest(FNameBuff, "TX/Edit Load Voices")) {
2424         Load(FNameBuff);
2425     }
2426     erase();
2427     LibSetScreen();
2428     LibDoScreen();
2429 }
2430 
2431 void
LBA_Move(void)2432 LBA_Move(void)  /* swap patches, overlapping ranges CF! */
2433 {
2434     int i;
2435     UBYTE *v1, *v2;
2436 
2437 #ifdef DEBUG
2438     if (!blocked) { cprintf("LBA_Move - not Blocked?!"); return; }
2439 #endif
2440     for (i = Voice_BStart;
2441             (i <= Voice_BEnd) && (Voice_Cursor + i - Voice_BStart < Voices); i++) {
2442         v1=voiceAddr(i);
2443         v2=voiceAddr(Voice_Cursor + i - Voice_BStart);
2444         memmove(SingleData, v1, DX7_VOICE_SIZE_PACKED);
2445         memmove(v1, v2,         DX7_VOICE_SIZE_PACKED);
2446         memmove(v2, SingleData, DX7_VOICE_SIZE_PACKED);
2447     }
2448     CancelBlock();
2449 }
2450 
2451 void
LibMove(void)2452 LibMove(void)
2453 {
2454     SetBlock();
2455     EndBlock();
2456     LibBlockAction = LBA_Move;
2457     gotomsg();
2458     cprintf("Move Cursor to Move destination and press return...");
2459 }
2460 
2461 void
LibSave(void)2462 LibSave(void)
2463 {
2464     if (blocking) {
2465         erase();
2466         LibSetScreen();
2467         cprintf("\n\n");
2468         Save(Voice_BStart, Voice_BEnd);
2469         erase();
2470         LibSetScreen();
2471         CancelBlock();
2472     } else {
2473         gotomsg();
2474         textattr(COLOR_MSG);
2475         cprintf(" Save - Must mark block first! - ");
2476         paktc();
2477     }
2478 }
2479 
2480 void
LibSaveAs(void)2481 LibSaveAs(void)
2482 {
2483     if (blocking) {
2484         erase();
2485         LibSetScreen();
2486         cprintf("\n\n");
2487         if (FileRequest(FNameBuff, "TX/Edit Save Voices")) {
2488             Save(Voice_BStart, Voice_BEnd);
2489         }
2490         erase();
2491         LibSetScreen();
2492         CancelBlock();
2493     } else {
2494         gotomsg();
2495         textattr(COLOR_MSG);
2496         cprintf("Save As - Must mark block first! - ");
2497         paktc();
2498     }
2499 }
2500 
2501 UBYTE
lstol(UBYTE c)2502 lstol(UBYTE c)
2503 {
2504     if (c >= 'A' && c <= 'Z')
2505         return c + 32;
2506     else
2507         return c;
2508 }
2509 
2510 int
_LibSortCmp(const UBYTE * v1,const UBYTE * v2)2511 _LibSortCmp(const UBYTE *v1, const UBYTE *v2)
2512 {
2513     int i;
2514     for (i = 118; i < 128; i++) {
2515         if (lstol(v1[i]) != lstol(v2[i]))
2516             return lstol(v1[i]) - lstol(v2[i]);
2517     }
2518     return 0;
2519 }
2520 
2521 void
LibSort(void)2522 LibSort(void)
2523 {
2524     SetBlock();
2525     if (Voice_BStart != Voice_BEnd) {
2526         qsort(voiceAddr(Voice_BStart), Voice_BEnd - Voice_BStart + 1,
2527               DX7_VOICE_SIZE_PACKED, (int (*)())_LibSortCmp);
2528     }
2529     CancelBlock();
2530 }
2531 
2532 int
_LibSortCmpPatch(const UBYTE * v1,const UBYTE * v2)2533 _LibSortCmpPatch(const UBYTE *v1, const UBYTE *v2)
2534 {
2535     int i;
2536 #define SORT_BY_ALGORITHM_FIRST
2537 #ifdef  SORT_BY_ALGORITHM_FIRST
2538     if (v1[110] != v2[110]) return v1[110] - v2[110];
2539 #endif
2540     for (i = 0; i < 118; i++) {
2541         if (v1[i] != v2[i])
2542             return v1[i] - v2[i];
2543     }
2544     return 0;
2545 }
2546 
2547 void
LibSortPatch(void)2548 LibSortPatch(void)
2549 {
2550     SetBlock();
2551     if (Voice_BStart != Voice_BEnd) {
2552         qsort(voiceAddr(Voice_BStart), Voice_BEnd - Voice_BStart + 1,
2553               DX7_VOICE_SIZE_PACKED, (int (*)())_LibSortCmpPatch);
2554     }
2555 /* #define SORT_PATCH_ERASE_DUPLICATES */
2556 #ifdef SORT_PATCH_ERASE_DUPLICATES
2557     {
2558         int i;
2559         for (i = Voice_BEnd - 1; i >= Voice_BStart; i--) {
2560             if (memcmp(voiceAddr(i), voiceAddr(i + 1), 118) == 0)
2561                 EraseVoice(i + 1);
2562         }
2563     }
2564 #endif
2565     CancelBlock();
2566 }
2567 
2568 void
LibHelp(void)2569 LibHelp(void)
2570 {
2571     erase();
2572     cprintf(" TX/Edit v" VERSIONSTRING " Help\n\n");
2573 
2574     cprintf(" a / Meta-A  - Save block As\n"
2575             " b / Meta-B  - Start block\n"
2576             " c / Meta-C  - Copy\n"
2577             "     Meta-D  - Delete\n"
2578             " e / Meta-E  - Enter Edit mode\n");
2579 
2580 #if 0
2581             " g / Meta-G  - Get (voice or 32 voices?)\n"
2582 #endif
2583 
2584     cprintf(" h / Meta-H  - Display this help screen\n\n"
2585             " m / Meta-M  - Move\n"
2586             " o / Meta-O  - Load\n"
2587             " p / Meta-P  - Put single voice (use space to step-send)\n");
2588 
2589 #if 0
2590             " r / Meta-R  - Receive (voice or 32 voices?)\n"
2591 #endif
2592 
2593     cprintf("     Meta-S  - Save block\n"
2594             "     Meta-T  - Put bank (32 voices starting at cursor)\n"
2595             "     Meta-=  - Sort block by patch names\n"
2596             "     Meta-+  - Sort block by patch data\n"
2597             "     Meta-!  - Erase voice\n");
2598 
2599 #if 0
2600             "     Meta-#  - Change MIDI channel\n"
2601 #endif
2602 
2603     cprintf(" Escape      - Cancel block\n"
2604             " Enter       - Perform pending block action\n"
2605             " Up / Down /\n"
2606             " Right / Left /\n"
2607             " PgUp / PgDn - Move cursor\n");
2608 
2609 #if 0
2610     /* Ctrl-Right, Ctrl-Left, Ctrl-PgUp, Ctrl-PgDn, End, Ctrl-End, Home, Ctrl-Home could have functions */
2611 #endif
2612 
2613     paktc();
2614     erase();
2615     LibSetScreen();
2616     LibDoScreen();
2617 }
2618 
2619 void
vl_CharIn(int c)2620 vl_CharIn(int c)
2621 {
2622     if(c >= 'A' && c <= 'Z')
2623         c = tolower(c);
2624     switch (c) {
2625         case KEY_METAA:
2626         case 'a':       LibSaveAs();            break;
2627         case KEY_METAB:
2628         case 'b':       StartBlock();           break;
2629         case KEY_METAC:
2630         case 'c':       LibCopy();              break;
2631         case KEY_METAD: LibDelete();            break;
2632         case KEY_METAE:
2633         case 'e':       newmode=MODEEDIT;       break;
2634 #if 0
2635         case KEY_METAG:
2636         case 'g':       cprintf("Get!!!!");     break;
2637 #endif
2638         case KEY_METAH:
2639         case 'h':       LibHelp();              break;
2640         case KEY_METAM:
2641         case 'm':       LibMove();              break;
2642         case KEY_METAO:
2643         case 'o':       LibLoad();              break;
2644         /* Space for Step-Send */
2645         case ' ':       LibCurDown();  /* and fall through to: */
2646         case KEY_METAP:
2647         case 'p':       PutPacked(Voice_Cursor); break;
2648 #if 0
2649         case KEY_METAR:
2650         case 'r':       cprintf("Receive!!!!"); break;
2651 #endif
2652         case KEY_METAS:   LibSave();              break;
2653         case KEY_METAT:   PutBank(Voice_Cursor);  break;
2654         case KEY_METAEQ:  LibSort();              break;
2655         case KEY_METAPL:  LibSortPatch();         break;
2656         case KEY_METAEX:  LibErase();             break;
2657 #if 0
2658         case KEY_METANU:
2659         case '#':       cprintf("Channel!!!!"); break;
2660 #endif
2661         case KEY_ESC:       EscBlock();         break;
2662         case KEY_ENTER:     LibBlockAction();   break;
2663         case KEY_UP:        LibCurUp();         break;
2664         case KEY_DOWN:      LibCurDown();       break;
2665         case KEY_RIGHT:     LibCurRight();      break;
2666         case KEY_LEFT:      LibCurLeft();       break;
2667 #if 0
2668         case kc_CtrlRight:  LibCtrlRight();     break;
2669         case kc_CtrlLeft:   LibCtrlLeft();      break;
2670 #endif
2671         case KEY_PPAGE:     LibPgUp();          break;
2672         case KEY_NPAGE:     LibPgDn();          break;
2673 #if 0
2674         case kc_CtrlPgUp:   LibCtrlPgUp();      break;
2675         case kc_CtrlPgDn:   LibCtrlPgDn();      break;
2676         case kc_End:
2677         case kc_CtrlEnd:    LibCurEnd();        break;
2678         case kc_Home:
2679         case kc_CtrlHome:   LibCurHome();       break;
2680 #endif
2681         default:
2682             gotomsg();
2683             cprintf(" Type <Alt-H> for help...");
2684             beep();
2685 #ifdef DEBUG
2686             cprintf("keycode=0x%04x, 0%o", c, c);
2687 #endif
2688     }
2689 }
2690 
2691 /* ==== Control ==== */
2692 
2693 void
TXsetmode(void)2694 TXsetmode(void)
2695 {
2696     /* cleanup from old mode */
2697     switch(txmode) {
2698         case MODELIB:
2699             blocking = FALSE;
2700             blocked = FALSE;
2701             LibBlockAction = noop;
2702             break;
2703         case MODEEDIT:
2704             if(ve_OpSelect != 63) {
2705                 ve_OpSelect = 63;
2706                 _ve_SetOps();
2707             }
2708             Pack(Voice_Cursor);
2709             break;
2710     }
2711     txmode=newmode;
2712     /* set up for new mode */
2713     switch(txmode) {
2714         case MODELIB:
2715             if (Voice_Cursor < Voice_TOS || Voice_Cursor >= Voice_TOS + LibNames) {
2716                 Voice_TOS = min(Voice_Cursor & 0xfff0, max(Voices - LibNames, 0));
2717             }
2718             erase();
2719             LibSetScreen();
2720             LibDoScreen();
2721             refresh();
2722             break;
2723         case MODEEDIT:
2724             erase();
2725             Unpack(Voice_Cursor);
2726             ve_SetScreen();
2727             ve_DoScreen();
2728             refresh();
2729             PutUnpacked();
2730             break;
2731     }
2732 }
2733 
2734 int
main(int argc,char ** argv)2735 main(int argc, char ** argv)
2736 {
2737     int c;
2738 
2739     static struct option long_options[] = {
2740         {"help", 0, 0, 'h'},
2741         {"voices", 1, 0, 'v'},
2742         {0, 0, 0, 0}
2743     };
2744 
2745     while ((c = getopt_long(argc, argv, "hv:", long_options, NULL)) != EOF) {
2746         switch (c) {
2747           case 'v':
2748             Voices = atoi(optarg);
2749             if (Voices < 32) Voices = 32;
2750             break;
2751           case 'h':
2752           default:
2753             fprintf(stderr, "TX/Edit v" VERSIONSTRING " (c)2004 Sean Bolton\n"
2754                             "options:\n"
2755                             "-vnnn --voices=nnn   allocate nnn voice slots\n"
2756                             "-h    --help         print this message and exit\n");
2757             exit(c == 'h' ? 0 : 1);
2758         }
2759     }
2760 
2761     TXInit();
2762     if (optind < argc) { /* load command line arguments */
2763         scrollok(stdscr, TRUE);
2764         erase();
2765         LibSetScreen();
2766         cprintf("\n\n");
2767         for (c = optind; c < argc; c++) {
2768             Voice_Cursor += Load(argv[c]);
2769         }
2770         paktc();
2771         Voice_Cursor = 0;
2772         scrollok(stdscr, FALSE);
2773     }
2774     newmode=MODELIB;
2775     TXsetmode();
2776     do {
2777 refresh(); /* -FIX- */
2778         c = cgetch();
2779         switch (c) {
2780             case KEY_METAQ:     newmode=MODEQUIT;  break;
2781             default:
2782                 switch(txmode) {
2783                     case MODELIB:   vl_CharIn(c);  break;
2784                     case MODEEDIT:  ve_CharIn(c);  break;
2785                 }
2786                 break;
2787         }
2788         if (txmode != newmode) TXsetmode();
2789     } while (txmode != MODEQUIT);
2790     TXTerm(RETURN_OK);  /* never returns */
2791     return 0;
2792 }
2793