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