You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2794 lines
76 KiB
2794 lines
76 KiB
/* Yamaha DX7 / TX7 Editor/Librarian
|
|
*
|
|
* Copyright (C) 1991, 1995, 1997, 1998, 2004, 2009, 2011,
|
|
* 2012, 2013 Sean Bolton.
|
|
*
|
|
* This is an ncurses-based patch editor for the Yamaha DX7 and
|
|
* TX7. It is provided as-is, without any documentation, and
|
|
* is totally unsupported, but may be useful to you if you can't use
|
|
* JSynthLib or similar. It started out life on my Apple ][+, then
|
|
* I ported it to my Amiga, then to my MS-DOS machine, then to
|
|
* Linux, so the code's a mess and nothing I'm proud of. But, it
|
|
* does the job.
|
|
*
|
|
* Compile with:
|
|
* gcc -o tx_edit tx_edit.c -lcurses -lasound
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be
|
|
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; if not, write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA.
|
|
*
|
|
* Revision History:
|
|
* 20040126 Sean Bolton - made help functions helpful, added ALSA support
|
|
* 20040205 Sean Bolton - clean up display with noecho, line drawing
|
|
* 20040207 Sean Bolton - add next/previous voice commands to edit mode
|
|
* 20090102 Sean Bolton - incorporated Martin Tarenskeen's patch loading
|
|
* enhancements
|
|
* 20110215 Sean Bolton - incorporated more patch loading enhancements
|
|
* from Martin Tarenskeen.
|
|
* 20121022 Sean Bolton - and yet more from Martin.
|
|
*/
|
|
|
|
/* Need to do: */
|
|
/* need to provide color changing option */
|
|
/* bank and single receive */
|
|
/* auto buffer sizing? */
|
|
/* a search option would be nice */
|
|
/* show channel/instrument on display */
|
|
|
|
#define VERSIONSTRING "0.94s"
|
|
|
|
/* Undefine USE_ALSA_MIDI to just write to /dev/midi */
|
|
#define USE_ALSA_MIDI 1
|
|
|
|
#define DEBUG 1
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <curses.h>
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
|
|
#ifdef USE_ALSA_MIDI
|
|
#include <alsa/asoundlib.h>
|
|
#endif
|
|
|
|
#define RETURN_OK 0
|
|
#define RETURN_FAIL 255
|
|
|
|
typedef unsigned char UBYTE;
|
|
|
|
void cprintf(const char *fmt, ...);
|
|
|
|
|
|
/* ==== Files ==== */
|
|
|
|
#define MAXPATH 80
|
|
|
|
char FNameBuff[MAXPATH]="\0";
|
|
|
|
/* ==== Buffers ==== */
|
|
|
|
#define DEFAULTVOICES 8192
|
|
#define DX7_VOICE_SIZE_PACKED 128
|
|
#define DX7_VOICE_SIZE_UNPACKED 155
|
|
#define DX7_DUMP_SIZE_VOICE_SINGLE 155+8
|
|
#define DX7_DUMP_SIZE_VOICE_BULK 4096+8
|
|
|
|
int Voices = DEFAULTVOICES;
|
|
|
|
UBYTE *Buffer = NULL,
|
|
*VoiceData,
|
|
*SingleDump,
|
|
*SingleData,
|
|
*BulkDump;
|
|
int BufferLength;
|
|
|
|
/* ==== Console ==== */
|
|
|
|
#define KEY_METAA (0x200+'a')
|
|
#define KEY_METAB (0x200+'b')
|
|
#define KEY_METAC (0x200+'c')
|
|
#define KEY_METAD (0x200+'d')
|
|
#define KEY_METAE (0x200+'e')
|
|
#define KEY_METAG (0x200+'g')
|
|
#define KEY_METAH (0x200+'h')
|
|
#define KEY_METAL (0x200+'l')
|
|
#define KEY_METAM (0x200+'m')
|
|
#define KEY_METAO (0x200+'o')
|
|
#define KEY_METAP (0x200+'p')
|
|
#define KEY_METAQ (0x200+'q')
|
|
#define KEY_METAR (0x200+'r')
|
|
#define KEY_METAS (0x200+'s')
|
|
#define KEY_METAT (0x200+'t')
|
|
#undef KEY_ENTER
|
|
#define KEY_ENTER (0x0a)
|
|
#define KEY_ESC (0x1b)
|
|
#define KEY_METAEQ (0x200+'=') /* Alt-= */
|
|
#define KEY_METAPL (0x200+'+') /* Alt-+ */
|
|
#define KEY_METAEX (0x200+'!') /* Alt-! */
|
|
#define KEY_METANU (0x200+'#') /* Alt-# */
|
|
|
|
enum textcolor {COLOR_MSG = 1, COLOR_LABEL, COLOR_DATA, COLOR_BLOCK,
|
|
COLOR_CURSOR, COLOR_BCURSOR, COLOR_OPON, COLOR_OPOFF};
|
|
|
|
#if 0
|
|
#define kc_Del (0x5300)
|
|
#define kc_CtrlRight (0x7400)
|
|
#define kc_CtrlLeft (0x7300)
|
|
#define kc_CtrlPgUp (0x8400)
|
|
#define kc_CtrlPgDn (0x7600)
|
|
#define kc_Home (0x4700)
|
|
#define kc_End (0x4f00)
|
|
#define kc_CtrlHome (0x7700)
|
|
#define kc_CtrlEnd (0x7500)
|
|
#endif
|
|
|
|
/* ==== Midi ==== */
|
|
|
|
#ifdef USE_ALSA_MIDI
|
|
snd_seq_t *MidiHandle = NULL;
|
|
int MidiClient;
|
|
int MidiPort = -1;
|
|
#endif
|
|
|
|
char TXChannel = 0; /* 0-15! */
|
|
|
|
/* ==== VoiceEdit ==== */
|
|
|
|
#define VOICEPARMS 146
|
|
#define VOICEPARMMAX 145
|
|
|
|
#ifdef USE_CALCED_CURSOR_MOVES
|
|
#define VOICEPARMS_X_SPAN 57
|
|
#define VOICEPARMS_Y_SPAN 18
|
|
#endif
|
|
|
|
int ve_Cursor = 0;
|
|
int ve_OpSelect = 63;
|
|
|
|
#define vptName 1
|
|
#define vpt0_99 2
|
|
#define vpt0_7 3
|
|
#define vptMode 4 /* R,F */
|
|
#define vptFC 5 /* 0-31 */
|
|
#define vptFF 6 /* 0-99 */
|
|
#define vptDetune 7 /* 0-14, as -7-+7 */
|
|
#define vpt0_3 8
|
|
#define vptAlg 9 /* 0-31, as 1-32 */
|
|
#define vptCurve 10 /* 0-3, scaling curve */
|
|
#define vptBkPt 11 /* 0-99, breakpoint */
|
|
#define vptTrans 12 /* 0-48, transpose */
|
|
#define vptOnOff 13
|
|
#define vptWave 14
|
|
|
|
unsigned char vtypemax[15] = {
|
|
0, 0, 99, 7, 1, 31, 99, 14, 3, 31, 3, 99, 48, 1, 5,
|
|
};
|
|
|
|
struct _veParm {
|
|
UBYTE Type;
|
|
UBYTE Offset;
|
|
UBYTE X;
|
|
UBYTE Y;
|
|
UBYTE Up; /* -FIX- Up and Down are obsolete with calc'ed cursor moves */
|
|
UBYTE Down;
|
|
} veParm[VOICEPARMS] = {
|
|
/* T, Off, X, Y, U, D */
|
|
{ 1, 145, 31, 0, 145, 8, }, /* Name */
|
|
{ 2, 105, 5, 4, 140, 17, }, /* O1 R1 */
|
|
{ 2, 109, 8, 4, 141, 18, },
|
|
{ 2, 106, 12, 4, 142, 19, },
|
|
{ 2, 110, 15, 4, 142, 20, },
|
|
{ 2, 107, 19, 4, 143, 21, },
|
|
{ 2, 111, 22, 4, 144, 22, },
|
|
{ 2, 108, 26, 4, 0, 23, },
|
|
{ 2, 112, 29, 4, 0, 24, },
|
|
{ 3, 118, 33, 4, 0, 25, }, /* O1 RS */
|
|
{ 4, 122, 36, 4, 0, 26, },
|
|
{ 5, 123, 38, 4, 145, 27, },
|
|
{ 6, 124, 41, 4, 121, 28, },
|
|
{ 7, 125, 44, 4, 121, 29, },
|
|
{ 2, 121, 54, 4, 94, 30, },
|
|
{ 3, 120, 58, 4, 95, 31, },
|
|
{ 8, 119, 60, 4, 96, 32, }, /* O1 AMS */
|
|
{ 2, 84, 5, 5, 1, 33, }, /* O2 R1 */
|
|
{ 2, 88, 8, 5, 2, 34, },
|
|
{ 2, 85, 12, 5, 3, 35, },
|
|
{ 2, 89, 15, 5, 4, 36, },
|
|
{ 2, 86, 19, 5, 5, 37, },
|
|
{ 2, 90, 22, 5, 6, 38, },
|
|
{ 2, 87, 26, 5, 7, 39, },
|
|
{ 2, 91, 29, 5, 8, 40, },
|
|
{ 3, 97, 33, 5, 9, 41, }, /* O2 RS */
|
|
{ 4, 101, 36, 5, 10, 42, },
|
|
{ 5, 102, 38, 5, 11, 43, },
|
|
{ 6, 103, 41, 5, 12, 44, },
|
|
{ 7, 104, 44, 5, 13, 45, },
|
|
{ 2, 100, 54, 5, 14, 46, },
|
|
{ 3, 99, 58, 5, 15, 47, },
|
|
{ 8, 98, 60, 5, 16, 48, }, /* O2 AMS */
|
|
{ 2, 63, 5, 6, 17, 49, }, /* O3 R1 */
|
|
{ 2, 67, 8, 6, 18, 50, },
|
|
{ 2, 64, 12, 6, 19, 51, },
|
|
{ 2, 68, 15, 6, 20, 52, },
|
|
{ 2, 65, 19, 6, 21, 53, },
|
|
{ 2, 69, 22, 6, 22, 54, },
|
|
{ 2, 66, 26, 6, 23, 55, },
|
|
{ 2, 70, 29, 6, 24, 56, },
|
|
{ 3, 76, 33, 6, 25, 57, }, /* O3 RS */
|
|
{ 4, 80, 36, 6, 26, 58, },
|
|
{ 5, 81, 38, 6, 27, 59, },
|
|
{ 6, 82, 41, 6, 28, 60, },
|
|
{ 7, 83, 44, 6, 29, 61, },
|
|
{ 2, 79, 54, 6, 30, 62, },
|
|
{ 3, 78, 58, 6, 31, 63, },
|
|
{ 8, 77, 60, 6, 32, 64, }, /* O3 AMS */
|
|
{ 2, 42, 5, 7, 33, 65, }, /* O4 R1 */
|
|
{ 2, 46, 8, 7, 34, 66, },
|
|
{ 2, 43, 12, 7, 35, 67, },
|
|
{ 2, 47, 15, 7, 36, 68, },
|
|
{ 2, 44, 19, 7, 37, 69, },
|
|
{ 2, 48, 22, 7, 38, 70, },
|
|
{ 2, 45, 26, 7, 39, 71, },
|
|
{ 2, 49, 29, 7, 40, 72, },
|
|
{ 3, 55, 33, 7, 41, 73, }, /* O4 RS */
|
|
{ 4, 59, 36, 7, 42, 74, },
|
|
{ 5, 60, 38, 7, 43, 75, },
|
|
{ 6, 61, 41, 7, 44, 76, },
|
|
{ 7, 62, 44, 7, 45, 77, },
|
|
{ 2, 58, 54, 7, 46, 78, },
|
|
{ 3, 57, 58, 7, 47, 79, },
|
|
{ 8, 56, 60, 7, 48, 80, }, /* O4 AMS */
|
|
{ 2, 21, 5, 8, 49, 81, }, /* O5 R1 */
|
|
{ 2, 25, 8, 8, 50, 82, },
|
|
{ 2, 22, 12, 8, 51, 83, },
|
|
{ 2, 26, 15, 8, 52, 84, },
|
|
{ 2, 23, 19, 8, 53, 85, },
|
|
{ 2, 27, 22, 8, 54, 86, },
|
|
{ 2, 24, 26, 8, 55, 87, },
|
|
{ 2, 28, 29, 8, 56, 88, },
|
|
{ 3, 34, 33, 8, 57, 89, }, /* O5 RS */
|
|
{ 4, 38, 36, 8, 58, 90, },
|
|
{ 5, 39, 38, 8, 59, 91, },
|
|
{ 6, 40, 41, 8, 60, 92, },
|
|
{ 7, 41, 44, 8, 61, 93, },
|
|
{ 2, 37, 54, 8, 62, 94, },
|
|
{ 3, 36, 58, 8, 63, 95, },
|
|
{ 8, 35, 60, 8, 64, 96, }, /* O5 AMS */
|
|
{ 2, 0, 5, 9, 65, 97, }, /* O6 R1 */
|
|
{ 2, 4, 8, 9, 66, 98, },
|
|
{ 2, 1, 12, 9, 67, 99, },
|
|
{ 2, 5, 15, 9, 68, 100, },
|
|
{ 2, 2, 19, 9, 69, 101, },
|
|
{ 2, 6, 22, 9, 70, 102, },
|
|
{ 2, 3, 26, 9, 71, 103, },
|
|
{ 2, 7, 29, 9, 72, 104, },
|
|
{ 3, 13, 33, 9, 73, 106, }, /* O6 RS */
|
|
{ 4, 17, 36, 9, 74, 106, },
|
|
{ 5, 18, 38, 9, 75, 106, },
|
|
{ 6, 19, 41, 9, 76, 105, },
|
|
{ 7, 20, 44, 9, 77, 105, },
|
|
{ 2, 16, 54, 9, 78, 105, },
|
|
{ 3, 15, 58, 9, 79, 105, },
|
|
{ 8, 14, 60, 9, 80, 105, }, /* O6 AMS */
|
|
{ 2, 126, 5, 10, 81, 108, }, /* P R1 */
|
|
{ 2, 130, 8, 10, 82, 109, },
|
|
{ 2, 127, 12, 10, 83, 110, },
|
|
{ 2, 131, 15, 10, 84, 110, },
|
|
{ 2, 128, 19, 10, 85, 111, },
|
|
{ 2, 132, 22, 10, 86, 112, },
|
|
{ 2, 129, 26, 10, 87, 112, },
|
|
{ 2, 133, 29, 10, 88, 106, },
|
|
{ 9, 134, 48, 11, 94, 107, }, /* Alg */
|
|
{ 2, 137, 35, 12, 90, 113, },
|
|
{ 3, 135, 49, 12, 105, 114, },
|
|
{ 10, 116, 5, 13, 97, 115, }, /* O1 LC */
|
|
{ 2, 114, 10, 13, 98, 116, },
|
|
{ 11, 113, 13, 13, 99, 117, },
|
|
{ 10, 117, 18, 13, 101, 118, },
|
|
{ 2, 115, 23, 13, 102, 119, },
|
|
{ 2, 138, 35, 13, 106, 120, }, /* Delay */
|
|
{ 12, 144, 46, 13, 107, 121, },
|
|
{ 10, 95, 5, 14, 108, 122, }, /* O2 LC */
|
|
{ 2, 93, 10, 14, 109, 123, },
|
|
{ 11, 92, 13, 14, 110, 124, },
|
|
{ 10, 96, 18, 14, 111, 125, },
|
|
{ 2, 94, 23, 14, 112, 126, },
|
|
{ 2, 139, 35, 14, 113, 127, }, /* PMD */
|
|
{ 13, 136, 47, 14, 114, 14, },
|
|
{ 10, 74, 5, 15, 115, 128, }, /* O3 LC */
|
|
{ 2, 72, 10, 15, 116, 129, },
|
|
{ 11, 71, 13, 15, 117, 130, },
|
|
{ 10, 75, 18, 15, 118, 131, },
|
|
{ 2, 73, 23, 15, 119, 132, },
|
|
{ 2, 140, 35, 15, 120, 133, }, /* AMD */
|
|
{ 10, 53, 5, 16, 122, 134, }, /* O4 LC */
|
|
{ 2, 51, 10, 16, 123, 135, },
|
|
{ 11, 50, 13, 16, 124, 136, },
|
|
{ 10, 54, 18, 16, 125, 137, },
|
|
{ 2, 52, 23, 16, 126, 138, },
|
|
{ 13, 141, 34, 16, 127, 139, }, /* Sync */
|
|
{ 10, 32, 5, 17, 128, 140, }, /* O5 LC */
|
|
{ 2, 30, 10, 17, 129, 141, },
|
|
{ 11, 29, 13, 17, 130, 142, },
|
|
{ 10, 33, 18, 17, 131, 143, },
|
|
{ 2, 31, 23, 17, 132, 144, },
|
|
{ 14, 142, 34, 17, 133, 145, }, /* Wave */
|
|
{ 10, 11, 5, 18, 134, 1, }, /* O6 LC */
|
|
{ 2, 9, 10, 18, 135, 2, },
|
|
{ 11, 8, 13, 18, 136, 3, },
|
|
{ 10, 12, 18, 18, 137, 5, },
|
|
{ 2, 10, 23, 18, 138, 6, },
|
|
{ 3, 143, 36, 18, 139, 10, } /* PMS */
|
|
};
|
|
|
|
unsigned short veFFF[100] = {
|
|
1000, 1023, 1047, 1072, 1096, 1122, 1148, 1175, 1202, 1230,
|
|
1259, 1288, 1318, 1349, 1380, 1413, 1445, 1479, 1514, 1549,
|
|
1585, 1622, 1660, 1698, 1738, 1778, 1820, 1862, 1905, 1950,
|
|
1995, 2042, 2089, 2138, 2188, 2239, 2291, 2344, 2399, 2455,
|
|
2512, 2570, 2630, 2692, 2754, 2818, 2884, 2951, 3020, 3090,
|
|
3162, 3236, 3311, 3388, 3467, 3548, 3631, 3715, 3802, 3890,
|
|
3981, 4074, 4169, 4266, 4365, 4467, 4571, 4677, 4786, 4898,
|
|
5012, 5129, 5248, 5370, 5495, 5623, 5754, 5888, 6026, 6166,
|
|
6310, 6457, 6607, 6761, 6918, 7079, 7244, 7413, 7586, 7762,
|
|
7943, 8128, 8318, 8511, 8710, 8913, 9120, 9333, 9550, 9772,
|
|
};
|
|
|
|
/* ==== Algorithm ==== */
|
|
|
|
char *veAlg[32] = { /* 32 algs, max 9 high and 17 wide */
|
|
" '`\n" /* 1 */
|
|
" 6/\n"
|
|
" |\n"
|
|
" 5\n"
|
|
" |\n"
|
|
"2 4\n"
|
|
"| |\n"
|
|
"1 3\n"
|
|
"L--/",
|
|
"\n" /* 2 */
|
|
" 6\n"
|
|
" |\n"
|
|
" 5\n"
|
|
"'` |\n"
|
|
"2/ 4\n"
|
|
"| |\n"
|
|
"1 3\n"
|
|
"L--/",
|
|
" '`\n" /* 3 */
|
|
"3 6/\n"
|
|
"| |\n"
|
|
"2 5\n"
|
|
"| |\n"
|
|
"1 4\n"
|
|
"L--/",
|
|
" '`\n" /* 4 */
|
|
"3 6|\n"
|
|
"| ||\n"
|
|
"2 5|\n"
|
|
"| ||\n"
|
|
"1 4/\n"
|
|
"L--/",
|
|
" '`\n" /* 5 */
|
|
"2 4 6/\n"
|
|
"| | |\n"
|
|
"1 3 5\n"
|
|
"L--^--/",
|
|
" '`\n" /* 6 */
|
|
"2 4 6|\n"
|
|
"| | ||\n"
|
|
"1 3 5/\n"
|
|
"L--^--/",
|
|
" '`\n" /* 7 */
|
|
" 6/\n"
|
|
" |\n"
|
|
"2 4 5\n"
|
|
"| }--/\n"
|
|
"1 3\n"
|
|
"L--/",
|
|
"\n" /* 8 */
|
|
" 6\n"
|
|
" '` |\n"
|
|
"2 4/ 5\n"
|
|
"| }--/\n"
|
|
"1 3\n"
|
|
"L--/",
|
|
"\n" /* 9 */
|
|
" 6\n"
|
|
"'` |\n"
|
|
"2/ 4 5\n"
|
|
"| }--/\n"
|
|
"1 3\n"
|
|
"L--/",
|
|
"'`\n" /* 10 */
|
|
"3/\n"
|
|
"|\n"
|
|
"2 5 6\n"
|
|
"| }--/\n"
|
|
"1 4\n"
|
|
"L--/",
|
|
"\n" /* 11 */
|
|
"3\n"
|
|
"| '`\n"
|
|
"2 5 6/\n"
|
|
"| }--/\n"
|
|
"1 4\n"
|
|
"L--/",
|
|
"'`\n" /* 12 */
|
|
"2/ 4 5 6\n"
|
|
"| L--+--/\n"
|
|
"1 3\n"
|
|
"L-----/",
|
|
" '`\n" /* 13 */
|
|
"2 4 5 6/\n" /* 13 */
|
|
"| L--+--/\n"
|
|
"1 3\n"
|
|
"L-----/",
|
|
" '`\n" /* 14 */
|
|
" 5 6/\n"
|
|
" }--/\n"
|
|
"2 4\n"
|
|
"| |\n"
|
|
"1 3\n"
|
|
"L--/",
|
|
"\n" /* 15 */
|
|
" 5 6\n"
|
|
"'` }--/\n"
|
|
"2/ 4\n"
|
|
"| |\n"
|
|
"1 3\n"
|
|
"L--/",
|
|
" '`\n" /* 16 */
|
|
" 4 6/\n"
|
|
" | |\n"
|
|
"2 3 5\n"
|
|
"L--+--/\n"
|
|
" 1",
|
|
"\n" /* 17 */
|
|
" 4 6\n"
|
|
"'` | |\n"
|
|
"2/ 3 5\n"
|
|
"L--+--/\n"
|
|
" 1",
|
|
" 6\n" /* 18 */
|
|
" |\n"
|
|
" 5\n"
|
|
" '` |\n"
|
|
"2 3/ 4\n"
|
|
"L--+--/\n"
|
|
" 1",
|
|
"3\n" /* 19 */
|
|
"| '`\n"
|
|
"2 6/\n"
|
|
"| }--`\n"
|
|
"1 4 5\n"
|
|
"L--^--/",
|
|
"'`\n" /* 20 */
|
|
"3/ 5 6\n"
|
|
"}--` }--/\n"
|
|
"1 2 4\n"
|
|
"L--^--/",
|
|
"'`\n" /* 21 */
|
|
"3/ 6\n"
|
|
"}--` }--`\n"
|
|
"1 2 4 5\n"
|
|
"L--^--^--/",
|
|
" '`\n" /* 22 */
|
|
"2 6/\n"
|
|
"| '--+--`\n"
|
|
"1 3 4 5\n"
|
|
"L--^--^--/",
|
|
" '`\n" /* 23 */
|
|
" 3 6/\n"
|
|
" | }--`\n"
|
|
"1 2 4 5\n"
|
|
"L--^--^--/",
|
|
" '`\n" /* 24 */
|
|
" 6/\n"
|
|
" '--+--`\n"
|
|
"1 2 3 4 5\n"
|
|
"L--^--^--^--/",
|
|
" '`\n" /* 25 */
|
|
" 6/\n"
|
|
" }--`\n"
|
|
"1 2 3 4 5\n"
|
|
"L--^--^--^--/",
|
|
" '`\n" /* 26 */
|
|
" 3 5 6/\n"
|
|
" | }--/\n"
|
|
"1 2 4\n"
|
|
"L--^--/",
|
|
" '`\n" /* 27 */
|
|
" 3/ 5 6\n"
|
|
" | }--/\n"
|
|
"1 2 4\n"
|
|
"L--^--/",
|
|
" '`\n" /* 28 */
|
|
" 5/\n"
|
|
" |\n"
|
|
"2 4\n"
|
|
"| |\n"
|
|
"1 3 6\n"
|
|
"L--^--/",
|
|
" '`\n" /* 29 */
|
|
" 4 6/\n"
|
|
" | |\n"
|
|
"1 2 3 5\n"
|
|
"L--^--^--/",
|
|
" '`\n" /* 30 */
|
|
" 5/\n"
|
|
" |\n"
|
|
" 4\n"
|
|
" |\n"
|
|
"1 2 3 6\n"
|
|
"L--^--^--/",
|
|
" '`\n"
|
|
" 6/\n" /* 31 */
|
|
" |\n"
|
|
"1 2 3 4 5\n"
|
|
"L--^--^--^--/",
|
|
" '`" /* 32 */
|
|
"1 2 3 4 5 6/"
|
|
"L--^--^--^--^--/",
|
|
};
|
|
|
|
/* ==== Librarian ==== */
|
|
|
|
void noop(void){}
|
|
|
|
void (*LibBlockAction)(void) = noop;
|
|
|
|
int Voice_Cursor = 0, /* voice number under curser */
|
|
Voice_TOS = 0, /* " at top of screen */
|
|
Voice_BMark, /* " where block first marked */
|
|
Voice_BStart, /* " of block start */
|
|
Voice_BEnd; /* " of block end */
|
|
bool blocking = FALSE,
|
|
blocked = FALSE;
|
|
/* -FIX- This should be dynamic! */
|
|
int LibCols=5, /* columns of names that fit on screen (15 char each) */
|
|
LibRows=16, /* rows of names that fit on screen */
|
|
LibNames=80; /* names that fit on screen */
|
|
|
|
/* ==== Control ==== */
|
|
|
|
int txmode=0,
|
|
newmode=0;
|
|
|
|
#define MODELIB 1
|
|
#define MODEEDIT 2
|
|
#define MODEQUIT 3
|
|
|
|
/* ==== Utility Stuff ==== */
|
|
|
|
//inline int min(int a, int b) { return (a < b ? a : b); }
|
|
//inline int max(int a, int b) { return (a > b ? a : b); }
|
|
int min(int a, int b) { return (a < b ? a : b); }
|
|
int max(int a, int b) { return (a > b ? a : b); }
|
|
|
|
char _NoteText[5]={'x','x','x','x','\0'};
|
|
|
|
char *
|
|
NoteText(int note)
|
|
{
|
|
_NoteText[0]=(" C D F G A ")[note%12];
|
|
_NoteText[1]=("C#D#EF#G#A#B")[note%12];
|
|
_NoteText[2]=("--012345678")[note/12];
|
|
_NoteText[3]=("21 ")[note/12];
|
|
return _NoteText;
|
|
}
|
|
|
|
UBYTE *
|
|
voiceAddr(int voice)
|
|
{
|
|
/* return voice*DX7_VOICE_SIZE_PACKED+VoiceData; */
|
|
return (voice << 7) +VoiceData;
|
|
}
|
|
|
|
void
|
|
PrintVName(int voice) /* print name of voice - packed only! */
|
|
{
|
|
UBYTE ca[11];
|
|
int i;
|
|
|
|
memcpy(ca, voiceAddr(voice)+118, 10);
|
|
for (i=0; i<10; i++) {
|
|
if (ca[i] < 32)
|
|
ca[i]=183; /* centered dot */
|
|
else if (ca[i] >= 128)
|
|
ca[i]=174; /* (R) symbol = out-of-range */
|
|
else {
|
|
switch (ca[i]) {
|
|
case 92: ca[i]=165; break; /* yen */
|
|
case 126: ca[i]=187; break; /* >> */
|
|
case 127: ca[i]=171; break; /* << */
|
|
}
|
|
}
|
|
}
|
|
ca[10]=0;
|
|
cprintf("%s", ca);
|
|
}
|
|
|
|
/* ==== Init/Term Routines ==== */
|
|
|
|
UBYTE InitVoice[] = {
|
|
0x62, 0x63, 0x63, 0x5A, 0x63, 0x63, 0x63, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x02,
|
|
0x00, 0x62, 0x63, 0x63, 0x5A, 0x63, 0x63, 0x63,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00,
|
|
0x02, 0x00, 0x62, 0x63, 0x63, 0x5A, 0x63, 0x63,
|
|
0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00,
|
|
0x00, 0x02, 0x00, 0x62, 0x63, 0x63, 0x5A, 0x63,
|
|
0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
|
|
0x00, 0x00, 0x02, 0x00, 0x62, 0x63, 0x63, 0x5A,
|
|
0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x38, 0x00, 0x00, 0x02, 0x00, 0x62, 0x63, 0x63,
|
|
0x5A, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x38, 0x00, 0x63, 0x02, 0x00, 0x63, 0x63,
|
|
0x63, 0x63, 0x32, 0x32, 0x32, 0x32, 0x00, 0x08,
|
|
0x23, 0x00, 0x00, 0x00, 0x31, 0x18, 0x20, 0x20,
|
|
0x20, 0x7F, 0x2D, 0x2D, 0x7E, 0x20, 0x20, 0x20 };
|
|
|
|
UBYTE InitVoiceUnpacked[155] = {
|
|
0x62, 0x63, 0x63, 0x5a, 0x63, 0x63, 0x63, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x07, 0x62, 0x63, 0x63,
|
|
0x5a, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x00, 0x07, 0x62, 0x63, 0x63, 0x5a, 0x63, 0x63,
|
|
0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x07, 0x62,
|
|
0x63, 0x63, 0x5a, 0x63, 0x63, 0x63, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x01, 0x00, 0x07, 0x62, 0x63, 0x63, 0x5a,
|
|
0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
0x07, 0x62, 0x63, 0x63, 0x5a, 0x63, 0x63, 0x63,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x63, 0x00, 0x01, 0x00, 0x07, 0x63, 0x63,
|
|
0x63, 0x63, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00,
|
|
0x01, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03,
|
|
0x18, 0x20, 0x20, 0x20, 0x7f, 0x2d, 0x2d, 0x7e,
|
|
0x20, 0x20, 0x20
|
|
};
|
|
|
|
void
|
|
EraseVoice(int voice)
|
|
{
|
|
memcpy(voiceAddr(voice), InitVoice, DX7_VOICE_SIZE_PACKED);
|
|
}
|
|
|
|
void
|
|
ConsoleTerm(void)
|
|
{
|
|
endwin();
|
|
}
|
|
|
|
bool
|
|
ConsoleInit(void)
|
|
{
|
|
initscr();
|
|
cbreak();
|
|
keypad(stdscr, TRUE);
|
|
curs_set(0);
|
|
start_color();
|
|
#if 1
|
|
init_pair(COLOR_MSG, COLOR_WHITE, COLOR_YELLOW); /* 0x1c */
|
|
init_pair(COLOR_LABEL, COLOR_GREEN, COLOR_BLUE); /* 0x1a */
|
|
init_pair(COLOR_DATA, COLOR_WHITE, COLOR_BLUE); /* 0x1f */
|
|
init_pair(COLOR_BLOCK, COLOR_WHITE, COLOR_CYAN); /* 0x3f */
|
|
init_pair(COLOR_CURSOR, COLOR_BLACK, COLOR_GREEN); /* 0x20 */
|
|
init_pair(COLOR_BCURSOR, COLOR_WHITE, COLOR_GREEN); /* 0x2f */
|
|
init_pair(COLOR_OPON, COLOR_GREEN, COLOR_BLUE); /* 0x1a */
|
|
init_pair(COLOR_OPOFF, COLOR_WHITE, COLOR_YELLOW); /* 0x14 */
|
|
#else
|
|
init_pair(COLOR_MSG, COLOR_WHITE, COLOR_YELLOW); /* 0x1c */
|
|
init_pair(COLOR_LABEL, COLOR_WHITE, COLOR_YELLOW); /* 0x1a */
|
|
init_pair(COLOR_DATA, COLOR_WHITE, COLOR_BLUE); /* 0x1f */
|
|
init_pair(COLOR_BLOCK, COLOR_BLACK, COLOR_YELLOW); /* 0x3f */
|
|
init_pair(COLOR_CURSOR, COLOR_WHITE, COLOR_YELLOW); /* 0x20 */
|
|
init_pair(COLOR_BCURSOR, COLOR_BLACK, COLOR_YELLOW); /* 0x2f */
|
|
init_pair(COLOR_OPON, COLOR_WHITE, COLOR_YELLOW); /* 0x1a */
|
|
init_pair(COLOR_OPOFF, COLOR_WHITE, COLOR_YELLOW); /* 0x14 */
|
|
#endif
|
|
bkgdset(COLOR_PAIR(COLOR_DATA));
|
|
attrset(COLOR_PAIR(COLOR_DATA)|A_BOLD);
|
|
noecho();
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
BuffTerm(void)
|
|
{
|
|
if (Buffer) {
|
|
free(Buffer);
|
|
Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
bool
|
|
BuffInit(void) /* returns TRUE if successful */
|
|
{
|
|
int i;
|
|
|
|
BuffTerm();
|
|
/* calculate buffer size from number of voices * DX7_VOICE_SIZE_PACKED plus a bulk
|
|
dump buffer and a single dump buffer */
|
|
BufferLength = Voices * DX7_VOICE_SIZE_PACKED + DX7_DUMP_SIZE_VOICE_BULK + DX7_DUMP_SIZE_VOICE_SINGLE;
|
|
if (!(Buffer = malloc(BufferLength))) {
|
|
return FALSE;
|
|
}
|
|
VoiceData = Buffer;
|
|
BulkDump = VoiceData + Voices * DX7_VOICE_SIZE_PACKED;
|
|
SingleDump = BulkDump + DX7_DUMP_SIZE_VOICE_BULK; /* must be last for alignment */
|
|
SingleData = SingleDump + 6;
|
|
/* Init the buffers */
|
|
for (i = 0; i < Voices; EraseVoice(i++));
|
|
return TRUE;
|
|
}
|
|
|
|
bool
|
|
MidiInit(void) /* returns TRUE if successful */
|
|
{
|
|
#ifdef USE_ALSA_MIDI
|
|
|
|
const char *device = "hw"; /* could also be "default" */
|
|
|
|
/* if (snd_seq_open(&MidiHandle, device, SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK) < 0) { */
|
|
if (snd_seq_open(&MidiHandle, device, SND_SEQ_OPEN_OUTPUT, 0) < 0) {
|
|
fprintf(stderr, "MidiInit: could not open sequencer: %s\n", snd_strerror(errno));
|
|
return FALSE;
|
|
}
|
|
|
|
snd_seq_set_client_name (MidiHandle, "TX/Edit");
|
|
|
|
MidiClient = snd_seq_client_id(MidiHandle);
|
|
|
|
if ((MidiPort = snd_seq_create_simple_port(MidiHandle, "TX/Edit",
|
|
SND_SEQ_PORT_CAP_READ |
|
|
SND_SEQ_PORT_CAP_SUBS_READ,
|
|
SND_SEQ_PORT_TYPE_MIDI_GENERIC)) < 0) {
|
|
fprintf(stderr, "MidiInit: error creating port: %s\n", snd_strerror(errno));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
#else /* not USE_ALSA_MIDI */
|
|
return TRUE;
|
|
#endif /* USE_ALSA_MIDI */
|
|
}
|
|
|
|
void
|
|
MidiTerm(void)
|
|
{
|
|
#ifdef USE_ALSA_MIDI
|
|
if (MidiHandle) {
|
|
snd_seq_drain_output(MidiHandle); /* do we need this? could use snd_seq_drop_output(handle) */
|
|
}
|
|
if (MidiPort >= 0) {
|
|
snd_seq_delete_simple_port (MidiHandle, MidiPort);
|
|
MidiPort = -1;
|
|
}
|
|
if (MidiHandle) {
|
|
snd_seq_close(MidiHandle);
|
|
MidiHandle = NULL;
|
|
}
|
|
#endif /* USE_ALSA_MIDI */
|
|
}
|
|
|
|
void
|
|
TXTerm(int retcode)
|
|
{
|
|
ConsoleTerm();
|
|
BuffTerm();
|
|
MidiTerm();
|
|
exit(retcode);
|
|
}
|
|
|
|
void
|
|
TXInit(void) /* exit()s on failure */
|
|
{
|
|
if (!MidiInit()) {
|
|
fprintf(stderr, "MidiInit error!\n");
|
|
TXTerm(RETURN_FAIL);
|
|
}
|
|
if (!BuffInit()) {
|
|
fprintf(stderr, "Can't allocate memory for Voice Buffer!\n");
|
|
TXTerm(RETURN_FAIL);
|
|
}
|
|
if (!ConsoleInit()) {
|
|
fprintf(stderr, "ConsoleInit error!\n");
|
|
TXTerm(RETURN_FAIL);
|
|
}
|
|
}
|
|
|
|
/* ==== Console Routines ==== */
|
|
|
|
void
|
|
cprintf(const char *fmt, ...) {
|
|
va_list ap;
|
|
char tbuf[512];
|
|
|
|
va_start(ap, fmt);
|
|
(void) vsnprintf(tbuf, 512, fmt, ap);
|
|
va_end(ap);
|
|
addstr(tbuf);
|
|
}
|
|
|
|
int
|
|
cputch(int c) {
|
|
return addch(c);
|
|
}
|
|
|
|
int
|
|
cgetch(void)
|
|
{
|
|
int c = getch();
|
|
|
|
if(c == 27) {
|
|
c = getch();
|
|
if (isalpha(c)) c = tolower(c);
|
|
return 0x200 + c;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
void
|
|
textattr(enum textcolor c) {
|
|
bkgdset(COLOR_PAIR(c));
|
|
attrset(COLOR_PAIR(c)|A_BOLD);
|
|
}
|
|
|
|
void
|
|
paktc(void)
|
|
{
|
|
textattr(COLOR_MSG);
|
|
cprintf(" Press Any Key to Continue... ");
|
|
textattr(COLOR_DATA);
|
|
cgetch();
|
|
cprintf("\r");
|
|
clrtoeol();
|
|
}
|
|
|
|
void
|
|
gotomsg(void)
|
|
{
|
|
move(LibRows + 4, 2);
|
|
}
|
|
|
|
/* ==== Midi Routines ==== */
|
|
|
|
void
|
|
Unpack(int voice)
|
|
{
|
|
UBYTE *a2, *a3;
|
|
UBYTE d1, d2;
|
|
|
|
a2=SingleData; /* a2 = &unpacked data */
|
|
a3=voiceAddr(voice); /* a3 = &packed data */
|
|
for (d2=6; d2>0; d2--) {
|
|
for (d1=11; d1>0; d1--) { *a2++=*a3++; } /* through rd */
|
|
*a2++=(*a3)&0x03; /* lc */
|
|
*a2++=(*a3++)>>2; /* rc */
|
|
*a2++=(*a3)&0x07; /* rs */
|
|
*(a2+6)=(*a3++)>>3; /* pd */
|
|
*a2++=(*a3)&0x03; /* ams */
|
|
*a2++=(*a3++)>>2; /* kvs */
|
|
*a2++=*a3++; /* ol */
|
|
*a2++=(*a3)&0x01; /* m */
|
|
*a2++=(*a3++)>>1; /* fc */
|
|
*a2=*a3++; /* ff */
|
|
a2+=2;
|
|
} /* operator done */
|
|
for (d2=9; d2>0; d2--) {
|
|
*a2++=*a3++;
|
|
} /* through algorithm */
|
|
*a2++=(*a3)&0x07; /* feedback */
|
|
*a2++=(*a3++)>>3; /* oks */
|
|
for (d2=4; d2>0; d2--) {
|
|
*a2++=*a3++;
|
|
} /* through lamd */
|
|
*a2++=(*a3)&0x01; /* lfo ks */
|
|
*a2++=((*a3)>>1)&0x07; /* lfo wave */
|
|
*a2++=(*a3++)>>4; /* lfo pms */
|
|
for (d2=11; d2>0; d2--) {
|
|
*a2++=*a3++;
|
|
} /* through name */
|
|
}
|
|
|
|
void
|
|
_Pack(UBYTE *packed, UBYTE *unpacked)
|
|
{
|
|
UBYTE *a2, *a3;
|
|
UBYTE d1, d2;
|
|
|
|
a3=packed; /* a3 = &packed data */
|
|
a2=unpacked; /* a2 = &unpacked data */
|
|
for (d2=6; d2>0; d2--) {
|
|
for (d1=11; d1>0; d1--) { *a3++=*a2++; } /* through rd */
|
|
*a3++=((*a2)&0x03)|(((*(a2+1))&0x03)<<2);
|
|
a2+=2; /* rc+lc */
|
|
*a3++=((*a2)&0x07)|(((*(a2+7))&0x0f)<<3);
|
|
a2++; /* pd+rs */
|
|
*a3++=((*a2)&0x03)|(((*(a2+1))&0x07)<<2);
|
|
a2+=2; /* kvs+ams */
|
|
*a3++=*a2++; /* ol */
|
|
*a3++=((*a2)&0x01)|(((*(a2+1))&0x1f)<<1);
|
|
a2+=2; /* fc+m */
|
|
*a3++=*a2;
|
|
a2+=2; /* ff */
|
|
} /* operator done */
|
|
for (d2=9; d2>0; d2--) { *a3++=*a2++; } /* through algorithm */
|
|
*a3++=((*a2)&0x07)|(((*(a2+1))&0x01)<<3);
|
|
a2+=2; /* oks+fb */
|
|
for (d2=4; d2>0; d2--) { *a3++=*a2++; } /* through lamd */
|
|
*a3++=((*a2)&0x01)|(((*(a2+1))&0x07)<<1)|
|
|
(((*(a2+2))&0x07)<<4);
|
|
a2+=3; /* lpms+lfw+lks */
|
|
for (d2=11; d2>0; d2--) { *a3++=*a2++; } /* through name */
|
|
#ifdef GAK
|
|
d2=a3-voiceAddr(voice);
|
|
cprintf("128 %d\r\n",d2);
|
|
d2=a2-SingleData;
|
|
cprintf("155 %d\r\n",d2);
|
|
getch();
|
|
#endif
|
|
}
|
|
|
|
void
|
|
Pack(int voice)
|
|
{
|
|
_Pack(voiceAddr(voice), SingleData);
|
|
}
|
|
|
|
void
|
|
PutMidiMsg(UBYTE *buf, unsigned int size)
|
|
{
|
|
#ifdef USE_ALSA_MIDI
|
|
snd_seq_event_t event;
|
|
|
|
snd_seq_ev_clear(&event);
|
|
snd_seq_ev_set_source(&event, MidiPort);
|
|
snd_seq_ev_set_subs(&event);
|
|
snd_seq_ev_set_direct(&event);
|
|
|
|
// set event type, data, so on:
|
|
event.type = SND_SEQ_EVENT_SYSEX;
|
|
snd_seq_ev_set_variable(&event, size, buf);
|
|
|
|
if (snd_seq_event_output(MidiHandle, &event) < 0) {
|
|
gotomsg();
|
|
cprintf("PutMidiMsg: could not write output: %s\n", snd_strerror(errno));
|
|
return;
|
|
}
|
|
if (snd_seq_drain_output(MidiHandle) < 0) {
|
|
gotomsg();
|
|
cprintf("PutMidiMsg: error draining output: %s\n", snd_strerror(errno));
|
|
}
|
|
|
|
#else /* not USE_ALSA_MIDI: */
|
|
FILE *fh;
|
|
|
|
if ((fh = fopen("/dev/midi00", "wb"))) { /* should fix this.... */
|
|
fwrite(buf, 1, size, fh);
|
|
fclose(fh);
|
|
}
|
|
#endif /* USE_ALSA_MIDI */
|
|
}
|
|
|
|
void
|
|
ChecksumSingle(void)
|
|
{
|
|
int sum = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < DX7_VOICE_SIZE_UNPACKED; sum -= SingleData[i++]);
|
|
SingleData[DX7_VOICE_SIZE_UNPACKED] = sum & 0x7F;
|
|
}
|
|
|
|
void
|
|
PutUnpacked(void)
|
|
{
|
|
UBYTE *sd;
|
|
|
|
ChecksumSingle();
|
|
sd = SingleDump;
|
|
sd[0] = 0xF0;
|
|
sd[1] = 0x43;
|
|
sd[2] = TXChannel;
|
|
sd[3] = 0;
|
|
sd[4] = 0x01;
|
|
sd[5] = 0x1B;
|
|
sd[DX7_DUMP_SIZE_VOICE_SINGLE - 1] = 0xF7;
|
|
PutMidiMsg(sd, DX7_DUMP_SIZE_VOICE_SINGLE);
|
|
}
|
|
|
|
void
|
|
PutPacked(int voice)
|
|
{
|
|
Unpack(voice);
|
|
PutUnpacked();
|
|
}
|
|
|
|
void
|
|
PutBank(int voice)
|
|
{
|
|
UBYTE *bd = BulkDump,
|
|
*p1 = voiceAddr(voice),
|
|
*p2,
|
|
*pe,
|
|
chksum = 0;
|
|
|
|
if(voice <= Voices - 32) {
|
|
bd[0] = 0xF0;
|
|
bd[1] = 0x43;
|
|
bd[2] = TXChannel;
|
|
bd[3] = 9;
|
|
bd[4] = 0x10;
|
|
bd[5] = 0x00;
|
|
for(p2 = bd + 6, pe = p2 + 4096; p2 < pe; chksum -= *p2++ = *p1++);
|
|
bd[DX7_DUMP_SIZE_VOICE_BULK - 2] = chksum & 0x7f;
|
|
bd[DX7_DUMP_SIZE_VOICE_BULK - 1] = 0xF7;
|
|
PutMidiMsg(bd, DX7_DUMP_SIZE_VOICE_BULK);
|
|
} else {
|
|
beep();
|
|
}
|
|
}
|
|
|
|
void
|
|
PutParm(int parm)
|
|
{
|
|
UBYTE offset = veParm[parm].Offset;
|
|
UBYTE bd[7];
|
|
bd[0] = 0xF0;
|
|
bd[1] = 0x43;
|
|
bd[2] = 0x10 | TXChannel;
|
|
bd[3] = offset >> 7;
|
|
bd[4] = offset & 0x7F;
|
|
bd[5] = SingleData[offset];
|
|
bd[6] = 0xF7;
|
|
PutMidiMsg(bd, 7);
|
|
}
|
|
|
|
/* ==== Load/Save Routines ==== */
|
|
|
|
bool
|
|
FileRequest(char *namebuf, char *title)
|
|
{
|
|
echo(); curs_set(1);
|
|
cprintf(" %s\n\n Enter filename:\n > ",title);
|
|
refresh();
|
|
if (wgetnstr(stdscr, namebuf, 76) == ERR) {
|
|
namebuf[0] = 0;
|
|
}
|
|
noecho(); curs_set(0);
|
|
cprintf("\n");
|
|
return (strlen(namebuf)!=0);
|
|
}
|
|
|
|
void
|
|
LoadError(const char *filename, const char *error)
|
|
{
|
|
cprintf(" Load - Error reading file '%s':\n", filename);
|
|
cprintf(" '%s'!\n", error);
|
|
paktc();
|
|
}
|
|
|
|
int
|
|
Load(char *filename)
|
|
{
|
|
FILE *fp;
|
|
char errbuf[256];
|
|
long filelength;
|
|
unsigned char *raw_patch_data = NULL;
|
|
size_t filename_length;
|
|
int count;
|
|
int patchstart;
|
|
int midshift;
|
|
int datastart;
|
|
int i;
|
|
int op;
|
|
|
|
/* this needs to 1) open and parse the file, 2a) if it's good, copy as
|
|
* many patches as will fit into VoiceData beginning at Voice_Cursor,
|
|
* 2b) if it's not good, print an appropriate error message and return. */
|
|
|
|
if ((fp = fopen(filename, "rb")) == NULL) {
|
|
snprintf(errbuf, 256, "could not open file for reading: %s", strerror(errno));
|
|
LoadError(filename, errbuf);
|
|
return 0;
|
|
}
|
|
if (fseek(fp, 0, SEEK_END) ||
|
|
(filelength = ftell(fp)) == -1 ||
|
|
fseek(fp, 0, SEEK_SET)) {
|
|
snprintf(errbuf, 256, "couldn't get length of patch file: %s", strerror(errno));
|
|
fclose(fp);
|
|
LoadError(filename, errbuf);
|
|
return 0;
|
|
}
|
|
if (filelength == 0) {
|
|
fclose(fp);
|
|
LoadError(filename, "patch file has zero length");
|
|
return 0;
|
|
} else if (filelength > 2097152) {
|
|
fclose(fp);
|
|
LoadError(filename, "patch file is too large");
|
|
return 0;
|
|
} else if (filelength < DX7_VOICE_SIZE_PACKED) {
|
|
fclose (fp);
|
|
LoadError(filename, "patch file is too small");
|
|
return 0;
|
|
}
|
|
|
|
if (!(raw_patch_data = (unsigned char *)malloc(filelength))) {
|
|
fclose(fp);
|
|
LoadError(filename, "couldn't allocate memory for raw patch file");
|
|
return 0;
|
|
}
|
|
|
|
if (fread(raw_patch_data, 1, filelength, fp) != (size_t)filelength) {
|
|
snprintf(errbuf, 256, "short read on patch file: %s", strerror(errno));
|
|
free(raw_patch_data);
|
|
fclose(fp);
|
|
LoadError(filename, errbuf);
|
|
return 0;
|
|
}
|
|
fclose(fp);
|
|
filename_length = strlen (filename);
|
|
|
|
/* check if the file is a standard MIDI file */
|
|
if (raw_patch_data[0] == 0x4d && /* "M" */
|
|
raw_patch_data[1] == 0x54 && /* "T" */
|
|
raw_patch_data[2] == 0x68 && /* "h" */
|
|
raw_patch_data[3] == 0x64) /* "d" */
|
|
midshift = 2;
|
|
else
|
|
midshift = 0;
|
|
|
|
/* scan SysEx or MIDI file for SysEx header(s) */
|
|
count = 0;
|
|
datastart = 0;
|
|
for (patchstart = 0; patchstart + midshift + 5 < filelength; patchstart++) {
|
|
|
|
if (raw_patch_data[patchstart] == 0xf0 &&
|
|
raw_patch_data[patchstart + 1 + midshift] == 0x43 &&
|
|
raw_patch_data[patchstart + 2 + midshift] <= 0x0f &&
|
|
raw_patch_data[patchstart + 3 + midshift] == 0x09 &&
|
|
raw_patch_data[patchstart + 5 + midshift] == 0x00 &&
|
|
patchstart + 4103 + midshift < filelength &&
|
|
raw_patch_data[patchstart + 4103 + midshift] == 0xf7) { /* DX7 32 voice dump */
|
|
|
|
memmove(raw_patch_data + count * DX7_VOICE_SIZE_PACKED,
|
|
raw_patch_data + patchstart + 6 + midshift, 4096);
|
|
count += 32;
|
|
patchstart += 4104;
|
|
|
|
} else if (raw_patch_data[patchstart] == 0xf0 &&
|
|
raw_patch_data[patchstart + midshift + 1] == 0x43 &&
|
|
raw_patch_data[patchstart + midshift + 2] <= 0x0f &&
|
|
raw_patch_data[patchstart + midshift + 4] == 0x01 &&
|
|
raw_patch_data[patchstart + midshift + 5] == 0x1b &&
|
|
patchstart + midshift + 162 < filelength &&
|
|
raw_patch_data[patchstart + midshift + 162] == 0xf7) { /* DX7 single voice (edit buffer) dump */
|
|
|
|
_Pack ((UBYTE *)errbuf, /* pack to errbuf to avoid a collision */
|
|
raw_patch_data + patchstart + midshift + 6);
|
|
memcpy(raw_patch_data + count * DX7_VOICE_SIZE_PACKED,
|
|
errbuf, DX7_VOICE_SIZE_PACKED);
|
|
|
|
count += 1;
|
|
patchstart += DX7_DUMP_SIZE_VOICE_SINGLE;
|
|
}
|
|
}
|
|
|
|
/* assume raw DX7/TX7 data if no SysEx header was found. */
|
|
/* assume the user knows what she is doing ;-) */
|
|
|
|
if (count == 0)
|
|
count = filelength / DX7_VOICE_SIZE_PACKED;
|
|
|
|
/* Dr.T and Steinberg TX7 file needs special treatment */
|
|
if ((!strcmp(filename + filename_length - 4, ".TX7") ||
|
|
!strcmp(filename + filename_length -4, ".SND") ||
|
|
!strcmp(filename + filename_length -4, ".tx7") ||
|
|
!strcmp(filename + filename_length - 4, ".snd")) && filelength == 8192) {
|
|
|
|
count = 32;
|
|
filelength = 4096;
|
|
}
|
|
|
|
/* Transform XSyn file also needs special treatment */
|
|
if ((!strcmp(filename + filename_length - 4, ".BNK") ||
|
|
!strcmp(filename + filename_length - 4, ".bnk")) && filelength == 8192) {
|
|
for (i=0; i<32; i++)
|
|
{
|
|
memmove(raw_patch_data + 128*i, raw_patch_data + 256*i, 128);
|
|
}
|
|
count = 32;
|
|
filelength = 4096;
|
|
}
|
|
|
|
/* Steinberg Synthworks DX7 SND */
|
|
if ((!strcmp (filename + filename_length - 4, ".SND") ||
|
|
!strcmp (filename + filename_length - 4, ".snd")) && filelength == 5216) {
|
|
|
|
count = 32;
|
|
filelength = 4096;
|
|
}
|
|
|
|
/* Voyetra SIDEMAN DX/TX
|
|
* Voyetra Patchmaster DX7/TX7 */
|
|
if ((filelength == 9816 || filelength == 5663) &&
|
|
raw_patch_data[0] == 0xdf &&
|
|
raw_patch_data[1] == 0x05 &&
|
|
raw_patch_data[2] == 0x01 && raw_patch_data[3] == 0x00) {
|
|
|
|
count = 32;
|
|
datastart = 0x60f;
|
|
}
|
|
|
|
/* Yamaha DX200 editor .DX2 file */
|
|
if ((!strcmp (filename + filename_length - 4, ".DX2") ||
|
|
!strcmp (filename + filename_length - 4, ".dx2"))
|
|
&& filelength == 326454)
|
|
{
|
|
memmove (raw_patch_data + 16384, raw_patch_data + 34, 128 * 381);
|
|
for (count = 0; count < 128; count++)
|
|
{
|
|
for (op = 0; op < 6; op++)
|
|
{
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
raw_patch_data[17 * (5 - op) + i + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 76 + i + 381 * count];
|
|
}
|
|
raw_patch_data[17 * (5 - op) + 8 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 84 + 381 * count] - 21;
|
|
raw_patch_data[17 * (5 - op) + 9 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 87 + 381 * count];
|
|
raw_patch_data[17 * (5 - op) + 10 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 88 + 381 * count];
|
|
raw_patch_data[17 * (5 - op) + 11 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 85 + 381 * count] +
|
|
raw_patch_data[16384 + 35 * op + 86 + 381 * count] * 4;
|
|
raw_patch_data[17 * (5 - op) + 12 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 89 + 381 * count] +
|
|
raw_patch_data[16384 + 35 * op + 75 + 381 * count] * 8;
|
|
if (raw_patch_data[16384 + 35 * op + 71 + 381 * count] > 3)
|
|
raw_patch_data[16384 + 35 * op + 71 + 381 * count] = 3;
|
|
raw_patch_data[17 * (5 - op) + 13 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 71 + 381 * count] / 2 +
|
|
raw_patch_data[16384 + 35 * op + 91 + 381 * count] * 4;
|
|
raw_patch_data[17 * (5 - op) + 14 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 90 + 381 * count];
|
|
raw_patch_data[17 * (5 - op) + 15 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 72 + 381 * count] +
|
|
raw_patch_data[16384 + 35 * op + 73 + 381 * count] * 2;
|
|
raw_patch_data[17 * (5 - op) + 16 + 128 * count] =
|
|
raw_patch_data[16384 + 35 * op + 74 + 381 * count];
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
raw_patch_data[102 + i + 128 * count] =
|
|
raw_patch_data[16384 + 26 + i + 381 * count];
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
raw_patch_data[106 + i + 128 * count] =
|
|
raw_patch_data[16384 + 32 + i + 381 * count];
|
|
}
|
|
raw_patch_data[110 + 128 * count] =
|
|
raw_patch_data[16384 + 17 + 381 * count];
|
|
raw_patch_data[111 + 128 * count] =
|
|
raw_patch_data[16384 + 18 + 381 * count] +
|
|
raw_patch_data[16384 + 38 + 381 * count] * 8;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
raw_patch_data[112 + i + 128 * count] =
|
|
raw_patch_data[16384 + 20 + i + 381 * count];
|
|
}
|
|
raw_patch_data[116 + 128 * count] =
|
|
raw_patch_data[16384 + 24 + 381 * count] +
|
|
raw_patch_data[16384 + 19 + 381 * count] * 2 +
|
|
raw_patch_data[16384 + 25 + 381 * count] * 16;
|
|
raw_patch_data[117 + 128 * count] =
|
|
raw_patch_data[16384 + 37 + 381 * count] - 36;
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
raw_patch_data[118 + i + 128 * count] =
|
|
raw_patch_data[16384 + i + 381 * count];
|
|
}
|
|
}
|
|
|
|
count = 128;
|
|
filelength = 16384;
|
|
datastart = 0;
|
|
|
|
}
|
|
|
|
/* finally, copy patchdata to the right location */
|
|
if (count > Voices - Voice_Cursor) { /* if ( voices-in-file > voices-to-end-of-buffer ) */
|
|
cprintf(" Load - Patch file '%s' too big for remaining space:\n", filename);
|
|
cprintf(" %d patches in file, only %d loaded!\n", count, Voices - Voice_Cursor);
|
|
paktc();
|
|
count = Voices - Voice_Cursor;
|
|
}
|
|
|
|
memcpy(voiceAddr(Voice_Cursor), raw_patch_data + datastart, DX7_VOICE_SIZE_PACKED * count);
|
|
free (raw_patch_data);
|
|
cprintf(" File '%s' loaded.\n", filename);
|
|
return count;
|
|
}
|
|
|
|
void
|
|
Save(int vstart, int vend) /* range is inclusive, filename in FNameBuff */
|
|
{
|
|
FILE *fh;
|
|
long flength;
|
|
|
|
if ((fh = fopen(FNameBuff, "wb")) != 0) {
|
|
flength = (vend - vstart + 1) * DX7_VOICE_SIZE_PACKED;
|
|
if (flength != fwrite(voiceAddr(vstart), 1, flength, fh)) {
|
|
cprintf("Save - Error writing file '%s':\n", FNameBuff);
|
|
cprintf(" '%s'!\n", strerror(errno));
|
|
paktc();
|
|
}
|
|
fclose(fh);
|
|
} else {
|
|
cprintf("Save - Error opening file '%s':\n", FNameBuff);
|
|
cprintf(" '%s'!\n", strerror(errno));
|
|
paktc();
|
|
}
|
|
}
|
|
|
|
/* ==== VoiceEdit Stuff ==== */
|
|
|
|
void
|
|
ve_ShowAlg(void)
|
|
{
|
|
int alg = SingleData[134],
|
|
x,
|
|
y;
|
|
char *s = veAlg[alg];
|
|
bool t;
|
|
|
|
textattr(COLOR_LABEL);
|
|
for (y = 12; y <= 20; y++) {
|
|
x = 56;
|
|
move(y, x);
|
|
for (; x <= 72; x++) {
|
|
switch (*s) {
|
|
case '1': t = (!!(ve_OpSelect&32)); goto printop;
|
|
case '2': t = (!!(ve_OpSelect&16)); goto printop;
|
|
case '3': t = (!!(ve_OpSelect& 8)); goto printop;
|
|
case '4': t = (!!(ve_OpSelect& 4)); goto printop;
|
|
case '5': t = (!!(ve_OpSelect& 2)); goto printop;
|
|
case '6': t = (!!(ve_OpSelect& 1));
|
|
printop:
|
|
textattr(t ? COLOR_OPON : COLOR_OPOFF);
|
|
cputch(*s++);
|
|
textattr(COLOR_LABEL);
|
|
break;
|
|
case 0:
|
|
cputch(' ');
|
|
break;
|
|
case '\n':
|
|
cputch(' ');
|
|
if (x == 72) s++;
|
|
break;
|
|
case '^':
|
|
cputch(ACS_BTEE); s++;
|
|
break;
|
|
case '-':
|
|
cputch(ACS_HLINE); s++;
|
|
break;
|
|
case 'L':
|
|
cputch(ACS_LLCORNER); s++;
|
|
break;
|
|
case '/':
|
|
cputch(ACS_LRCORNER); s++;
|
|
break;
|
|
case '}':
|
|
cputch(ACS_LTEE); s++;
|
|
break;
|
|
case '+':
|
|
cputch(ACS_PLUS); s++;
|
|
break;
|
|
#if 0
|
|
case '?': /* -FIX- */
|
|
cputch(ACS_RTEE); s++;
|
|
break;
|
|
case '?': /* -FIX- */
|
|
cputch(ACS_TTEE); s++;
|
|
break;
|
|
#endif
|
|
case '\'':
|
|
cputch(ACS_ULCORNER); s++;
|
|
break;
|
|
case '`':
|
|
cputch(ACS_URCORNER); s++;
|
|
break;
|
|
case '|':
|
|
cputch(ACS_VLINE); s++;
|
|
break;
|
|
default:
|
|
cputch(*s++);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
textattr(COLOR_DATA);
|
|
}
|
|
|
|
void
|
|
ve_FExtend(UBYTE fc, UBYTE ff, UBYTE mode, UBYTE y)
|
|
{
|
|
unsigned long f;
|
|
char ca[10];
|
|
|
|
textattr(COLOR_LABEL);
|
|
move(y, 47);
|
|
if (mode) { /* fixed */
|
|
f = veFFF[ff];
|
|
switch (fc & 3) {
|
|
case 1: f *= 10; break;
|
|
case 2: f *= 100; break;
|
|
case 3: f *= 1000; break;
|
|
}
|
|
} else {
|
|
f = fc * 10;
|
|
if (!f) f = 5;
|
|
f = (100 + ff) * f;
|
|
}
|
|
f = sprintf(ca, "%ld", f);
|
|
switch (f) {
|
|
case 3: cprintf("0.%.3s", ca); break;
|
|
case 4: cprintf("%.1s.%.3s", ca, ca + 1); break;
|
|
case 5: cprintf("%.2s.%.2s", ca, ca + 2); break;
|
|
case 6: cprintf("%.3s.%.1s", ca, ca + 3); break;
|
|
case 7: cprintf("%.4s.", ca); break;
|
|
}
|
|
textattr(COLOR_DATA);
|
|
}
|
|
|
|
void
|
|
ve_printParm(int parm)
|
|
{
|
|
unsigned char val = SingleData[veParm[parm].Offset],
|
|
c;
|
|
char *t;
|
|
|
|
move(veParm[parm].Y, veParm[parm].X);
|
|
if (parm == ve_Cursor) textattr(COLOR_CURSOR);
|
|
switch (veParm[parm].Type) {
|
|
case vptName:
|
|
{
|
|
UBYTE ca[11];
|
|
|
|
memcpy(ca, SingleData + 145, 10);
|
|
for (c = 0; c < 10; c++) {
|
|
if (ca[c] < 32)
|
|
ca[c]=183; /* centered dot */
|
|
else if (ca[c] >= 128)
|
|
ca[c]=174; /* (R) symbol = out-of-range */
|
|
else {
|
|
switch (ca[c]) {
|
|
case 92: ca[c]=165; break; /* yen */
|
|
case 126: ca[c]=187; break; /* >> */
|
|
case 127: ca[c]=171; break; /* << */
|
|
}
|
|
}
|
|
}
|
|
ca[10] = 0;
|
|
cprintf("%s", ca);
|
|
}
|
|
break;
|
|
case vpt0_99:
|
|
if (val > 99)
|
|
cprintf("??");
|
|
else
|
|
cprintf("%2.2d", val);
|
|
break;
|
|
case vpt0_7:
|
|
if (val > 7)
|
|
cputch('?');
|
|
else
|
|
cputch(val+'0');
|
|
break;
|
|
case vptMode:
|
|
switch (val) {
|
|
case 0: c = 'R'; break;
|
|
case 1: c = 'F'; break;
|
|
default: c = '?'; break;
|
|
}
|
|
cputch(c);
|
|
ve_FExtend(SingleData[veParm[parm+1].Offset],
|
|
SingleData[veParm[parm+2].Offset],
|
|
val,
|
|
veParm[parm].Y);
|
|
break;
|
|
case vptFC:
|
|
if (val > 31)
|
|
cprintf("??");
|
|
else
|
|
cprintf("%2d", val);
|
|
ve_FExtend(val,
|
|
SingleData[veParm[parm+1].Offset],
|
|
SingleData[veParm[parm-1].Offset],
|
|
veParm[parm].Y);
|
|
break;
|
|
case vptFF:
|
|
if (val > 99)
|
|
cprintf("??");
|
|
else
|
|
cprintf("%2d", val);
|
|
ve_FExtend(SingleData[veParm[parm-1].Offset],
|
|
val,
|
|
SingleData[veParm[parm-2].Offset],
|
|
veParm[parm].Y);
|
|
break;
|
|
case vptDetune: /* 0-14, as -7-+7 */
|
|
if (val > 14)
|
|
cprintf("??");
|
|
else
|
|
cprintf("%+2d", val-7);
|
|
break;
|
|
case vpt0_3:
|
|
if (val > 3)
|
|
cputch('?');
|
|
else
|
|
cputch(val+'0');
|
|
break;
|
|
case vptAlg: /* 0-31, as 1-32 */
|
|
if (val > 31) {
|
|
cprintf("??");
|
|
break;
|
|
}
|
|
cprintf("%2d", val+1);
|
|
ve_ShowAlg();
|
|
return;
|
|
case vptCurve:
|
|
switch (val) {
|
|
case 0: t = "-Lin"; break;
|
|
case 1: t = "-Exp"; break;
|
|
case 2: t = "+Exp"; break;
|
|
case 3: t = "+Lin"; break;
|
|
default: t = "????";
|
|
}
|
|
cprintf("%s", t);
|
|
break;
|
|
case vptBkPt:
|
|
if (val > 99) {
|
|
cprintf("????");
|
|
break;
|
|
}
|
|
val += 21;
|
|
goto printnote;
|
|
case vptTrans:
|
|
if (val > 48) {
|
|
cprintf("????");
|
|
break;
|
|
}
|
|
val += 36;
|
|
printnote:
|
|
cprintf("%s", NoteText(val));
|
|
break;
|
|
case vptOnOff:
|
|
switch (val) {
|
|
case 0: t = "Off"; break;
|
|
case 1: t = " On"; break;
|
|
default: t = "???";
|
|
}
|
|
cprintf("%s", t);
|
|
break;
|
|
case vptWave:
|
|
switch (val) {
|
|
case 0: t = "TRI"; break;
|
|
case 1: t = "SW-"; break;
|
|
case 2: t = "SW+"; break;
|
|
case 3: t = "SQU"; break;
|
|
case 4: t = "SIN"; break;
|
|
case 5: t = "S/H"; break;
|
|
default: t = "???"; break;
|
|
}
|
|
cprintf("%s", t);
|
|
break;
|
|
}
|
|
if (parm == ve_Cursor) textattr(COLOR_DATA);
|
|
}
|
|
|
|
void
|
|
ve_SetScreen(void)
|
|
{
|
|
textattr(COLOR_DATA);
|
|
cprintf(" TX/Edit Voice Edit");
|
|
textattr(COLOR_LABEL);
|
|
cprintf(" Name\n"
|
|
" A\n"
|
|
" O R V M\n"
|
|
" P R1 L1 R2 L2 R3 L3 R4 L4 S M FC FF D Freq. OL S S\n");
|
|
cprintf(" 1\n"
|
|
" 2\n"
|
|
" 3\n"
|
|
" 4\n"
|
|
" 5\n"
|
|
" 6\n"
|
|
" P\n");
|
|
cprintf(" Alg.\n"
|
|
" Left BkPt Right Speed Fdbk\n");
|
|
cprintf(" 1 Delay C3=\n");
|
|
cprintf(" 2 PMD OKS\n");
|
|
cprintf(" 3 AMD\n");
|
|
cprintf(" 4 Sync\n");
|
|
cprintf(" 5 Wave\n");
|
|
cprintf(" 6 PMS\n");
|
|
textattr(COLOR_DATA);
|
|
}
|
|
|
|
void
|
|
ve_DoScreen(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < VOICEPARMS; ve_printParm(i++));
|
|
}
|
|
|
|
void
|
|
ve_Name(int c)
|
|
{
|
|
UBYTE i;
|
|
|
|
for(i = 145; i < 154; i++) SingleData[i] = SingleData[i + 1];
|
|
SingleData[154] = c;
|
|
PutUnpacked();
|
|
ve_printParm(0);
|
|
ve_OpSelect = 63;
|
|
ve_ShowAlg();
|
|
}
|
|
|
|
void
|
|
ve_Inc(int parm)
|
|
{
|
|
unsigned char val = SingleData[veParm[parm].Offset],
|
|
max;
|
|
|
|
max = vtypemax[veParm[parm].Type];
|
|
if (!max) return;
|
|
if (++val > max) val = 0;
|
|
SingleData[veParm[parm].Offset] = val;
|
|
PutParm(parm);
|
|
ve_printParm(parm);
|
|
}
|
|
|
|
void
|
|
ve_Dec(int parm)
|
|
{
|
|
unsigned char val = SingleData[veParm[parm].Offset],
|
|
max;
|
|
|
|
max = vtypemax[veParm[parm].Type];
|
|
if (!max) return;
|
|
if (val)
|
|
val--;
|
|
else
|
|
val = max;
|
|
SingleData[veParm[parm].Offset] = val;
|
|
PutParm(parm);
|
|
ve_printParm(parm);
|
|
}
|
|
|
|
void
|
|
ve_Zero(void)
|
|
{
|
|
UBYTE offset = veParm[ve_Cursor].Offset;
|
|
|
|
if(ve_Cursor == 0) { /* do name */
|
|
for(offset = 154; offset > 145; offset--)
|
|
SingleData[offset] = SingleData[offset - 1];
|
|
SingleData[145] = ' ';
|
|
PutUnpacked();
|
|
ve_OpSelect = 63;
|
|
ve_ShowAlg();
|
|
} else {
|
|
SingleData[offset] = InitVoiceUnpacked[offset];
|
|
PutParm(ve_Cursor);
|
|
}
|
|
ve_printParm(ve_Cursor);
|
|
}
|
|
|
|
void
|
|
ve_CurUp(void)
|
|
{
|
|
int oldcursor = ve_Cursor;
|
|
#ifndef USE_CALCED_CURSOR_MOVES
|
|
ve_Cursor = veParm[ve_Cursor].Up;
|
|
ve_printParm(oldcursor);
|
|
ve_printParm(ve_Cursor);
|
|
#else /* USE_CALCED_CURSOR_MOVES */
|
|
int i, dx, dy, distance,
|
|
best = -1,
|
|
bestdistance = 1000;
|
|
|
|
/* try to find the closest parm in the 'up' direction */
|
|
for (i = 0; i <= VOICEPARMMAX; i++) {
|
|
dx = abs(veParm[ve_Cursor].X - veParm[i].X);
|
|
dy = (veParm[ve_Cursor].Y - 1) - veParm[i].Y;
|
|
if (dy < 0)
|
|
dy += VOICEPARMS_Y_SPAN + 2; /* wrap */
|
|
dy = dy * 5 / 2; /* prefer something <2.5 spaces away horizontally to 1 space vertically */
|
|
distance = dx + dy;
|
|
if (bestdistance > distance) {
|
|
bestdistance = distance;
|
|
best = i;
|
|
}
|
|
}
|
|
if (best >= 0) {
|
|
ve_Cursor = best;
|
|
ve_printParm(oldcursor);
|
|
ve_printParm(ve_Cursor);
|
|
}
|
|
#endif /* USE_CALCED_CURSOR_MOVES */
|
|
}
|
|
|
|
void
|
|
ve_CurDown(void)
|
|
{
|
|
int oldcursor = ve_Cursor;
|
|
#ifndef USE_CALCED_CURSOR_MOVES
|
|
ve_Cursor = veParm[ve_Cursor].Down;
|
|
ve_printParm(oldcursor);
|
|
ve_printParm(ve_Cursor);
|
|
#else /* USE_CALCED_CURSOR_MOVES */
|
|
int i, dx, dy, distance,
|
|
best = -1,
|
|
bestdistance = 1000;
|
|
|
|
/* try to find the closest parm in the 'down' direction */
|
|
for (i = 0; i <= VOICEPARMMAX; i++) {
|
|
dx = abs(veParm[i].X - veParm[ve_Cursor].X);
|
|
dy = veParm[i].Y - (veParm[ve_Cursor].Y + 1);
|
|
if (dy < 0)
|
|
dy += VOICEPARMS_Y_SPAN + 2; /* wrap */
|
|
dy = dy * 5 / 2; /* prefer something <2.5 spaces away horizontally to 1 space vertically */
|
|
distance = dx + dy;
|
|
if (bestdistance > distance) {
|
|
bestdistance = distance;
|
|
best = i;
|
|
}
|
|
}
|
|
if (best >= 0) {
|
|
ve_Cursor = best;
|
|
ve_printParm(oldcursor);
|
|
ve_printParm(ve_Cursor);
|
|
}
|
|
#endif /* USE_CALCED_CURSOR_MOVES */
|
|
}
|
|
|
|
void
|
|
ve_CurRight(void)
|
|
{
|
|
int oldcursor = ve_Cursor;
|
|
#ifndef USE_CALCED_CURSOR_MOVES
|
|
if(++ve_Cursor > VOICEPARMMAX) ve_Cursor = 0;
|
|
ve_printParm(oldcursor);
|
|
ve_printParm(ve_Cursor);
|
|
#else /* USE_CALCED_CURSOR_MOVES */
|
|
int i, dx, dy, distance,
|
|
best = -1,
|
|
bestdistance = 1000;
|
|
|
|
/* try to find the closest parm in the 'right' direction */
|
|
for (i = 0; i <= VOICEPARMMAX; i++) {
|
|
dx = veParm[i].X - (veParm[ve_Cursor].X + 2);
|
|
if (dx < 0)
|
|
dx += VOICEPARMS_X_SPAN + 4; /* wrap */
|
|
dy = abs(veParm[i].Y - veParm[ve_Cursor].Y);
|
|
dy = dy * 12; /* prefer something <8 spaces away horizontally to 1 space vertically */
|
|
distance = dx + dy;
|
|
if (bestdistance > distance) {
|
|
bestdistance = distance;
|
|
best = i;
|
|
}
|
|
}
|
|
if (best >= 0) {
|
|
ve_Cursor = best;
|
|
ve_printParm(oldcursor);
|
|
ve_printParm(ve_Cursor);
|
|
}
|
|
#endif /* USE_CALCED_CURSOR_MOVES */
|
|
}
|
|
|
|
void
|
|
ve_CurLeft(void)
|
|
{
|
|
int oldcursor = ve_Cursor;
|
|
#ifndef USE_CALCED_CURSOR_MOVES
|
|
if(ve_Cursor)
|
|
ve_Cursor--;
|
|
else
|
|
ve_Cursor = VOICEPARMMAX;
|
|
ve_printParm(oldcursor);
|
|
ve_printParm(ve_Cursor);
|
|
#else /* USE_CALCED_CURSOR_MOVES */
|
|
int i, dx, dy, distance,
|
|
best = -1,
|
|
bestdistance = 1000;
|
|
|
|
/* try to find the closest parm in the 'left' direction */
|
|
for (i = 0; i <= VOICEPARMMAX; i++) {
|
|
dx = (veParm[ve_Cursor].X - 2) - veParm[i].X;
|
|
if (dx < 0)
|
|
dx += VOICEPARMS_X_SPAN + 4; /* wrap */
|
|
dy = abs(veParm[i].Y - veParm[ve_Cursor].Y);
|
|
dy = dy * 12; /* prefer something <8 spaces away horizontally to 1 space vertically */
|
|
distance = dx + dy;
|
|
if (bestdistance > distance) {
|
|
bestdistance = distance;
|
|
best = i;
|
|
}
|
|
}
|
|
if (best >= 0) {
|
|
ve_Cursor = best;
|
|
ve_printParm(oldcursor);
|
|
ve_printParm(ve_Cursor);
|
|
}
|
|
#endif /* USE_CALCED_CURSOR_MOVES */
|
|
}
|
|
|
|
void
|
|
ve_Erase(void)
|
|
{
|
|
memcpy(SingleData, InitVoiceUnpacked, DX7_VOICE_SIZE_UNPACKED);
|
|
// erase();
|
|
// ve_SetScreen();
|
|
ve_DoScreen();
|
|
refresh();
|
|
PutUnpacked();
|
|
}
|
|
|
|
void
|
|
ve_PgUp(void)
|
|
{
|
|
if (Voice_Cursor) {
|
|
Pack(Voice_Cursor);
|
|
Unpack(--Voice_Cursor);
|
|
ve_DoScreen();
|
|
refresh();
|
|
PutUnpacked();
|
|
}
|
|
}
|
|
|
|
void
|
|
ve_PgDn(void)
|
|
{
|
|
if (Voice_Cursor < Voices - 1) {
|
|
Pack(Voice_Cursor);
|
|
Unpack(++Voice_Cursor);
|
|
ve_DoScreen();
|
|
refresh();
|
|
PutUnpacked();
|
|
}
|
|
}
|
|
|
|
void
|
|
_ve_SetOps(void)
|
|
{
|
|
UBYTE bd[7];
|
|
|
|
bd[0] = 0xF0;
|
|
bd[1] = 0x43;
|
|
bd[2] = 0x10 | TXChannel;
|
|
bd[3] = 1;
|
|
bd[4] = 27;
|
|
bd[5] = ve_OpSelect;
|
|
bd[6] = 0xF7;
|
|
PutMidiMsg(bd, 7);
|
|
}
|
|
|
|
void
|
|
ve_SetOps(int o)
|
|
{
|
|
UBYTE i;
|
|
|
|
ve_OpSelect ^= o;
|
|
for (i = 1; i < 7; i++) {
|
|
if (ve_OpSelect & (1 << (6 - i)))
|
|
textattr(COLOR_OPON);
|
|
else
|
|
textattr(COLOR_OPOFF);
|
|
move(3 + i, 2);
|
|
cprintf("%c", i + '0');
|
|
move(12 + i, 2);
|
|
cprintf("%c", i + '0');
|
|
}
|
|
/* textattr(COLOR_DATA); not needed with ve_ShowAlg() */
|
|
ve_ShowAlg();
|
|
_ve_SetOps();
|
|
}
|
|
|
|
void
|
|
ve_Number(int c)
|
|
{
|
|
unsigned char val = SingleData[veParm[ve_Cursor].Offset],
|
|
typ = veParm[ve_Cursor].Type,
|
|
max = vtypemax[typ];
|
|
|
|
switch(typ) {
|
|
case vpt0_99:
|
|
case vptFF:
|
|
val=(val * 10 + c - '0') % 100;
|
|
break;
|
|
case vptFC:
|
|
val=(val * 10 + c - '0') % 100;
|
|
for(; val > 31; val -= 10);
|
|
break;
|
|
case vpt0_7:
|
|
case vpt0_3:
|
|
val=c - '0';
|
|
if(val > max) val = max;
|
|
break;
|
|
case vptAlg:
|
|
val=((val + 1) * 10 + c - '0') % 100;
|
|
if (!val) val = 1;
|
|
for(; val > 32; val -= 10);
|
|
val--;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
SingleData[veParm[ve_Cursor].Offset] = val;
|
|
PutParm(ve_Cursor);
|
|
ve_printParm(ve_Cursor);
|
|
}
|
|
|
|
void
|
|
ve_Help(void)
|
|
{
|
|
erase();
|
|
cprintf(" TX/Edit v" VERSIONSTRING " Voice Edit Help\n\n");
|
|
|
|
cprintf(" Up / Down /\n"
|
|
" Right / Left - Move cursor\n\n");
|
|
|
|
cprintf(" + - Increment field\n"
|
|
" - - Decrement field\n"
|
|
" 0 through 9 - Enter data into field\n"
|
|
" Backspace - Zero/reset field\n\n");
|
|
|
|
cprintf(" A through Z - Rotate letters into name (name field only)\n\n"
|
|
|
|
" F1 through F6 - Enable/disable operators 1 through 6\n\n");
|
|
|
|
cprintf(" Meta-P - Put edit buffer as single voice\n"
|
|
" Meta-! - Erase edit buffer to init voice\n"
|
|
" PgUp / PgDn - Move to previous / next voice\n"
|
|
|
|
" Esc / Meta-L - Return to librarian mode\n\n"
|
|
|
|
" h / Meta-H - Display this help screen\n\n");
|
|
|
|
paktc();
|
|
erase();
|
|
ve_SetScreen();
|
|
ve_DoScreen();
|
|
}
|
|
|
|
void
|
|
ve_CharIn(int c)
|
|
{
|
|
if(!ve_Cursor && c>=32 && c<=127) {
|
|
ve_Name(c);
|
|
} else {
|
|
if(c >= 'A' && c <= 'Z')
|
|
c = tolower(c);
|
|
switch(c) {
|
|
case '+':
|
|
case '=': ve_Inc(ve_Cursor); break;
|
|
case '-': ve_Dec(ve_Cursor); break;
|
|
#if 0
|
|
case kc_Del:
|
|
#endif
|
|
case KEY_BACKSPACE: ve_Zero(); break;
|
|
case KEY_UP: ve_CurUp(); break;
|
|
case KEY_DOWN: ve_CurDown(); break;
|
|
case KEY_RIGHT: ve_CurRight(); break;
|
|
case KEY_LEFT: ve_CurLeft(); break;
|
|
case KEY_METAL:
|
|
case KEY_ESC: newmode=MODELIB; break;
|
|
case KEY_F(1): ve_SetOps(32); break;
|
|
case KEY_F(2): ve_SetOps(16); break;
|
|
case KEY_F(3): ve_SetOps( 8); break;
|
|
case KEY_F(4): ve_SetOps( 4); break;
|
|
case KEY_F(5): ve_SetOps( 2); break;
|
|
case KEY_F(6): ve_SetOps( 1); break;
|
|
case KEY_PPAGE: ve_PgUp(); break;
|
|
case KEY_NPAGE: ve_PgDn(); break;
|
|
case KEY_METAP: PutUnpacked(); break;
|
|
case KEY_METAEX: ve_Erase(); break;
|
|
case KEY_METAH:
|
|
case 'h': ve_Help(); break;
|
|
default:
|
|
if(c>='0' && c<='9') {
|
|
ve_Number(c);
|
|
} else {
|
|
gotomsg();
|
|
cprintf(" Type <Alt-H> for help...");
|
|
beep();
|
|
#ifdef DEBUG
|
|
cprintf("keycode=0x%04x", c);
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ==== Librarian Stuff ==== */
|
|
|
|
void
|
|
LibPrintVName(int voice) /* print name at correct cursor position */
|
|
{
|
|
if (Voice_TOS <= voice && voice < Voice_TOS + LibNames) {
|
|
move((voice-Voice_TOS)%LibRows + 2,
|
|
(voice-Voice_TOS)/LibRows * 15 + 1);
|
|
if (voice<Voices) {
|
|
textattr(COLOR_LABEL);
|
|
if (voice < 10000) {
|
|
cprintf("%4d ", voice);
|
|
} else {
|
|
cprintf("?%03d ", voice % 1000);
|
|
}
|
|
if (voice==Voice_Cursor) {
|
|
if(blocking)
|
|
textattr(COLOR_BCURSOR);
|
|
else
|
|
textattr(COLOR_CURSOR);
|
|
} else {
|
|
if (blocking||blocked) {
|
|
if (Voice_BStart<=voice&&voice<=Voice_BEnd) {
|
|
textattr(COLOR_BLOCK);
|
|
} else
|
|
textattr(COLOR_DATA);
|
|
} else
|
|
textattr(COLOR_DATA);
|
|
}
|
|
PrintVName(voice);
|
|
textattr(COLOR_DATA);
|
|
} else {
|
|
cprintf(" ");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibSetScreen(void) /* setup librarian screen */
|
|
{
|
|
#if USE_ALSA_MIDI
|
|
char temp[80];
|
|
|
|
snprintf(temp, 80, "TX/Edit v%s (%d:%d)", VERSIONSTRING, MidiClient, MidiPort);
|
|
mvaddstr(0, 1, temp);
|
|
#else
|
|
mvaddstr(0, 1, "TX/Edit v" VERSIONSTRING);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
LibDoScreen(void) /* print voice names */
|
|
{
|
|
int i;
|
|
|
|
for (i=Voice_TOS; i<Voice_TOS+LibNames; LibPrintVName(i++));
|
|
}
|
|
|
|
void
|
|
SetBlock(void) /* fake a block under cursor if no block marked */
|
|
{
|
|
if (!(blocking || blocked))
|
|
Voice_BMark = Voice_BStart = Voice_BEnd = Voice_Cursor;
|
|
}
|
|
|
|
void
|
|
CancelBlock(void)
|
|
{
|
|
blocking = FALSE;
|
|
blocked = FALSE;
|
|
LibBlockAction = noop;
|
|
LibDoScreen();
|
|
gotomsg();
|
|
clrtoeol();
|
|
}
|
|
|
|
void
|
|
StartBlock(void) /* or cancel block if one is marked */
|
|
{
|
|
if (!(blocking || blocked)) {
|
|
blocking = TRUE;
|
|
Voice_BMark = Voice_BStart = Voice_BEnd = Voice_Cursor;
|
|
LibPrintVName(Voice_Cursor);
|
|
} else
|
|
CancelBlock();
|
|
}
|
|
|
|
void
|
|
EndBlock(void)
|
|
{
|
|
blocking = FALSE;
|
|
blocked = TRUE;
|
|
LibPrintVName(Voice_Cursor);
|
|
}
|
|
|
|
void
|
|
EscBlock(void) /* cancel block if one is marked */
|
|
{
|
|
if(blocking || blocked)
|
|
CancelBlock();
|
|
}
|
|
|
|
void
|
|
CheckBlock(void)
|
|
{
|
|
if (blocking) {
|
|
if (Voice_Cursor < Voice_BMark) {
|
|
Voice_BStart = Voice_Cursor;
|
|
Voice_BEnd = Voice_BMark;
|
|
} else {
|
|
Voice_BStart = Voice_BMark;
|
|
Voice_BEnd = Voice_Cursor;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibCurUp(void)
|
|
{
|
|
if (Voice_Cursor) {
|
|
int vc;
|
|
|
|
vc = --Voice_Cursor;
|
|
CheckBlock();
|
|
if (vc >= Voice_TOS) {
|
|
LibPrintVName(vc);
|
|
LibPrintVName(++vc);
|
|
} else {
|
|
Voice_TOS = max(Voice_TOS - LibRows, 0);
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibCurDown(void)
|
|
{
|
|
if (Voice_Cursor < Voices - 1) {
|
|
int vc;
|
|
|
|
vc = ++Voice_Cursor;
|
|
CheckBlock();
|
|
if (vc < Voice_TOS + LibNames) {
|
|
LibPrintVName(vc);
|
|
LibPrintVName(--vc);
|
|
} else {
|
|
Voice_TOS += LibRows;
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibCurRight(void)
|
|
{
|
|
if (Voice_Cursor < Voices - 1) {
|
|
int oldvc, newvc;
|
|
|
|
oldvc = Voice_Cursor;
|
|
Voice_Cursor = newvc = min(oldvc + LibRows, Voices - 1);
|
|
CheckBlock();
|
|
if (newvc < Voice_TOS + LibNames) {
|
|
if (blocking) {
|
|
for (; oldvc <= newvc; LibPrintVName(oldvc++));
|
|
} else {
|
|
LibPrintVName(oldvc);
|
|
LibPrintVName(newvc);
|
|
}
|
|
} else {
|
|
Voice_TOS += LibRows;
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibCurLeft(void)
|
|
{
|
|
if (Voice_Cursor) {
|
|
int oldvc, newvc;
|
|
|
|
oldvc = Voice_Cursor;
|
|
Voice_Cursor = newvc = max(oldvc - LibRows, 0);
|
|
CheckBlock();
|
|
if (newvc >= Voice_TOS) {
|
|
if (blocking) {
|
|
for (; oldvc >= newvc; LibPrintVName(oldvc--));
|
|
} else {
|
|
LibPrintVName(oldvc);
|
|
LibPrintVName(newvc);
|
|
}
|
|
} else {
|
|
Voice_TOS = max(Voice_TOS - LibRows, 0);
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibCtrlPgUp(void)
|
|
{
|
|
if (Voice_Cursor) {
|
|
int oldvc, newvc;
|
|
|
|
oldvc = Voice_Cursor;
|
|
Voice_Cursor = newvc = max(Voice_Cursor - 1, 0) & 0xffe0;
|
|
CheckBlock();
|
|
if (newvc >= Voice_TOS) {
|
|
if (blocking) {
|
|
for (; oldvc >= newvc; LibPrintVName(oldvc--));
|
|
} else {
|
|
LibPrintVName(oldvc);
|
|
LibPrintVName(newvc);
|
|
}
|
|
} else {
|
|
Voice_TOS=newvc;
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibCtrlPgDn(void)
|
|
{
|
|
if (Voice_Cursor < Voices-1) {
|
|
int oldvc, newvc;
|
|
|
|
oldvc = Voice_Cursor;
|
|
Voice_Cursor = newvc = min(((Voice_Cursor + 33) & 0xffe0) - 1, Voices - 1);
|
|
CheckBlock();
|
|
if (newvc < Voice_TOS + LibNames) {
|
|
if (blocking) {
|
|
for (; oldvc <= newvc; LibPrintVName(oldvc++));
|
|
} else {
|
|
LibPrintVName(oldvc);
|
|
LibPrintVName(newvc);
|
|
}
|
|
} else {
|
|
Voice_TOS=max(newvc - LibNames + 1, 0);
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibCurEnd(void)
|
|
{
|
|
Voice_Cursor = Voices - 1;
|
|
Voice_TOS = max(Voices - LibNames, 0);
|
|
CheckBlock();
|
|
LibDoScreen();
|
|
}
|
|
|
|
void
|
|
LibCurHome(void)
|
|
{
|
|
Voice_Cursor = 0;
|
|
Voice_TOS = 0;
|
|
CheckBlock();
|
|
LibDoScreen();
|
|
}
|
|
|
|
void
|
|
LibPgUp(void)
|
|
{
|
|
if (Voice_Cursor) {
|
|
int oldvc, newvc;
|
|
|
|
oldvc = Voice_Cursor;
|
|
Voice_Cursor = newvc = max(Voice_Cursor - 1, 0) & 0xfff0;
|
|
CheckBlock();
|
|
if (newvc >= Voice_TOS) {
|
|
if (blocking) {
|
|
for (; oldvc >= newvc; LibPrintVName(oldvc--));
|
|
} else {
|
|
LibPrintVName(oldvc);
|
|
LibPrintVName(newvc);
|
|
}
|
|
} else {
|
|
Voice_TOS = newvc;
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibPgDn(void)
|
|
{
|
|
if (Voice_Cursor < Voices-1) {
|
|
int oldvc, newvc;
|
|
|
|
oldvc = Voice_Cursor;
|
|
Voice_Cursor = newvc = min(((Voice_Cursor + 17) & 0xfff0) - 1, Voices - 1);
|
|
CheckBlock();
|
|
if (newvc < Voice_TOS + LibNames) {
|
|
if (blocking) {
|
|
for (; oldvc <= newvc; LibPrintVName(oldvc++));
|
|
} else {
|
|
LibPrintVName(oldvc);
|
|
LibPrintVName(newvc);
|
|
}
|
|
} else {
|
|
Voice_TOS = max(newvc - LibNames + 1, 0);
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
LibCtrlRight(void)
|
|
{
|
|
|
|
Voice_Cursor = min(Voice_Cursor + LibNames, Voices - 1);
|
|
Voice_TOS = min(Voice_TOS + LibNames, max(Voices - LibNames, 0));
|
|
CheckBlock();
|
|
LibDoScreen();
|
|
}
|
|
|
|
void
|
|
LibCtrlLeft(void)
|
|
{
|
|
if (Voice_Cursor) {
|
|
Voice_Cursor = max(Voice_Cursor - LibNames, 0);
|
|
Voice_TOS = max(Voice_TOS - LibNames, 0);
|
|
CheckBlock();
|
|
LibDoScreen();
|
|
}
|
|
}
|
|
|
|
void
|
|
LBA_Copy(void)
|
|
{
|
|
#ifdef DEBUG
|
|
if (!blocked) { cprintf("LBA_Copy - not Blocked?!"); return; }
|
|
#endif
|
|
memmove(voiceAddr(Voice_Cursor),
|
|
voiceAddr(Voice_BStart),
|
|
min(Voice_BEnd - Voice_BStart + 1, Voices - Voice_Cursor) * DX7_VOICE_SIZE_PACKED);
|
|
CancelBlock();
|
|
}
|
|
|
|
void
|
|
LibCopy(void)
|
|
{
|
|
SetBlock();
|
|
EndBlock();
|
|
LibBlockAction = LBA_Copy;
|
|
gotomsg();
|
|
cprintf("Move Cursor to Copy destination and press return...");
|
|
}
|
|
|
|
void
|
|
LibDelete(void)
|
|
{
|
|
int i;
|
|
|
|
SetBlock();
|
|
if (Voices > Voice_BEnd + 1)
|
|
memmove(voiceAddr(Voice_BStart),
|
|
voiceAddr(Voice_BEnd + 1),
|
|
(Voices - Voice_BEnd - 1) * DX7_VOICE_SIZE_PACKED);
|
|
for (i = Voices - Voice_BEnd + Voice_BStart - 1; i < Voices; EraseVoice(i++));
|
|
CancelBlock();
|
|
}
|
|
|
|
void
|
|
LibErase(void)
|
|
{
|
|
int i;
|
|
|
|
SetBlock();
|
|
for (i = Voice_BStart; i <= Voice_BEnd; EraseVoice(i++));
|
|
CancelBlock();
|
|
}
|
|
|
|
void
|
|
LibLoad(void)
|
|
{
|
|
erase();
|
|
LibSetScreen();
|
|
cprintf("\n\n");
|
|
if (FileRequest(FNameBuff, "TX/Edit Load Voices")) {
|
|
Load(FNameBuff);
|
|
}
|
|
erase();
|
|
LibSetScreen();
|
|
LibDoScreen();
|
|
}
|
|
|
|
void
|
|
LBA_Move(void) /* swap patches, overlapping ranges CF! */
|
|
{
|
|
int i;
|
|
UBYTE *v1, *v2;
|
|
|
|
#ifdef DEBUG
|
|
if (!blocked) { cprintf("LBA_Move - not Blocked?!"); return; }
|
|
#endif
|
|
for (i = Voice_BStart;
|
|
(i <= Voice_BEnd) && (Voice_Cursor + i - Voice_BStart < Voices); i++) {
|
|
v1=voiceAddr(i);
|
|
v2=voiceAddr(Voice_Cursor + i - Voice_BStart);
|
|
memmove(SingleData, v1, DX7_VOICE_SIZE_PACKED);
|
|
memmove(v1, v2, DX7_VOICE_SIZE_PACKED);
|
|
memmove(v2, SingleData, DX7_VOICE_SIZE_PACKED);
|
|
}
|
|
CancelBlock();
|
|
}
|
|
|
|
void
|
|
LibMove(void)
|
|
{
|
|
SetBlock();
|
|
EndBlock();
|
|
LibBlockAction = LBA_Move;
|
|
gotomsg();
|
|
cprintf("Move Cursor to Move destination and press return...");
|
|
}
|
|
|
|
void
|
|
LibSave(void)
|
|
{
|
|
if (blocking) {
|
|
erase();
|
|
LibSetScreen();
|
|
cprintf("\n\n");
|
|
Save(Voice_BStart, Voice_BEnd);
|
|
erase();
|
|
LibSetScreen();
|
|
CancelBlock();
|
|
} else {
|
|
gotomsg();
|
|
textattr(COLOR_MSG);
|
|
cprintf(" Save - Must mark block first! - ");
|
|
paktc();
|
|
}
|
|
}
|
|
|
|
void
|
|
LibSaveAs(void)
|
|
{
|
|
if (blocking) {
|
|
erase();
|
|
LibSetScreen();
|
|
cprintf("\n\n");
|
|
if (FileRequest(FNameBuff, "TX/Edit Save Voices")) {
|
|
Save(Voice_BStart, Voice_BEnd);
|
|
}
|
|
erase();
|
|
LibSetScreen();
|
|
CancelBlock();
|
|
} else {
|
|
gotomsg();
|
|
textattr(COLOR_MSG);
|
|
cprintf("Save As - Must mark block first! - ");
|
|
paktc();
|
|
}
|
|
}
|
|
|
|
UBYTE
|
|
lstol(UBYTE c)
|
|
{
|
|
if (c >= 'A' && c <= 'Z')
|
|
return c + 32;
|
|
else
|
|
return c;
|
|
}
|
|
|
|
int
|
|
_LibSortCmp(const UBYTE *v1, const UBYTE *v2)
|
|
{
|
|
int i;
|
|
for (i = 118; i < 128; i++) {
|
|
if (lstol(v1[i]) != lstol(v2[i]))
|
|
return lstol(v1[i]) - lstol(v2[i]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
LibSort(void)
|
|
{
|
|
SetBlock();
|
|
if (Voice_BStart != Voice_BEnd) {
|
|
qsort(voiceAddr(Voice_BStart), Voice_BEnd - Voice_BStart + 1,
|
|
DX7_VOICE_SIZE_PACKED, (int (*)())_LibSortCmp);
|
|
}
|
|
CancelBlock();
|
|
}
|
|
|
|
int
|
|
_LibSortCmpPatch(const UBYTE *v1, const UBYTE *v2)
|
|
{
|
|
int i;
|
|
#define SORT_BY_ALGORITHM_FIRST
|
|
#ifdef SORT_BY_ALGORITHM_FIRST
|
|
if (v1[110] != v2[110]) return v1[110] - v2[110];
|
|
#endif
|
|
for (i = 0; i < 118; i++) {
|
|
if (v1[i] != v2[i])
|
|
return v1[i] - v2[i];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
LibSortPatch(void)
|
|
{
|
|
SetBlock();
|
|
if (Voice_BStart != Voice_BEnd) {
|
|
qsort(voiceAddr(Voice_BStart), Voice_BEnd - Voice_BStart + 1,
|
|
DX7_VOICE_SIZE_PACKED, (int (*)())_LibSortCmpPatch);
|
|
}
|
|
/* #define SORT_PATCH_ERASE_DUPLICATES */
|
|
#ifdef SORT_PATCH_ERASE_DUPLICATES
|
|
{
|
|
int i;
|
|
for (i = Voice_BEnd - 1; i >= Voice_BStart; i--) {
|
|
if (memcmp(voiceAddr(i), voiceAddr(i + 1), 118) == 0)
|
|
EraseVoice(i + 1);
|
|
}
|
|
}
|
|
#endif
|
|
CancelBlock();
|
|
}
|
|
|
|
void
|
|
LibHelp(void)
|
|
{
|
|
erase();
|
|
cprintf(" TX/Edit v" VERSIONSTRING " Help\n\n");
|
|
|
|
cprintf(" a / Meta-A - Save block As\n"
|
|
" b / Meta-B - Start block\n"
|
|
" c / Meta-C - Copy\n"
|
|
" Meta-D - Delete\n"
|
|
" e / Meta-E - Enter Edit mode\n");
|
|
|
|
#if 0
|
|
" g / Meta-G - Get (voice or 32 voices?)\n"
|
|
#endif
|
|
|
|
cprintf(" h / Meta-H - Display this help screen\n\n"
|
|
" m / Meta-M - Move\n"
|
|
" o / Meta-O - Load\n"
|
|
" p / Meta-P - Put single voice (use space to step-send)\n");
|
|
|
|
#if 0
|
|
" r / Meta-R - Receive (voice or 32 voices?)\n"
|
|
#endif
|
|
|
|
cprintf(" Meta-S - Save block\n"
|
|
" Meta-T - Put bank (32 voices starting at cursor)\n"
|
|
" Meta-= - Sort block by patch names\n"
|
|
" Meta-+ - Sort block by patch data\n"
|
|
" Meta-! - Erase voice\n");
|
|
|
|
#if 0
|
|
" Meta-# - Change MIDI channel\n"
|
|
#endif
|
|
|
|
cprintf(" Escape - Cancel block\n"
|
|
" Enter - Perform pending block action\n"
|
|
" Up / Down /\n"
|
|
" Right / Left /\n"
|
|
" PgUp / PgDn - Move cursor\n");
|
|
|
|
#if 0
|
|
/* Ctrl-Right, Ctrl-Left, Ctrl-PgUp, Ctrl-PgDn, End, Ctrl-End, Home, Ctrl-Home could have functions */
|
|
#endif
|
|
|
|
paktc();
|
|
erase();
|
|
LibSetScreen();
|
|
LibDoScreen();
|
|
}
|
|
|
|
void
|
|
vl_CharIn(int c)
|
|
{
|
|
if(c >= 'A' && c <= 'Z')
|
|
c = tolower(c);
|
|
switch (c) {
|
|
case KEY_METAA:
|
|
case 'a': LibSaveAs(); break;
|
|
case KEY_METAB:
|
|
case 'b': StartBlock(); break;
|
|
case KEY_METAC:
|
|
case 'c': LibCopy(); break;
|
|
case KEY_METAD: LibDelete(); break;
|
|
case KEY_METAE:
|
|
case 'e': newmode=MODEEDIT; break;
|
|
#if 0
|
|
case KEY_METAG:
|
|
case 'g': cprintf("Get!!!!"); break;
|
|
#endif
|
|
case KEY_METAH:
|
|
case 'h': LibHelp(); break;
|
|
case KEY_METAM:
|
|
case 'm': LibMove(); break;
|
|
case KEY_METAO:
|
|
case 'o': LibLoad(); break;
|
|
/* Space for Step-Send */
|
|
case ' ': LibCurDown(); /* and fall through to: */
|
|
case KEY_METAP:
|
|
case 'p': PutPacked(Voice_Cursor); break;
|
|
#if 0
|
|
case KEY_METAR:
|
|
case 'r': cprintf("Receive!!!!"); break;
|
|
#endif
|
|
case KEY_METAS: LibSave(); break;
|
|
case KEY_METAT: PutBank(Voice_Cursor); break;
|
|
case KEY_METAEQ: LibSort(); break;
|
|
case KEY_METAPL: LibSortPatch(); break;
|
|
case KEY_METAEX: LibErase(); break;
|
|
#if 0
|
|
case KEY_METANU:
|
|
case '#': cprintf("Channel!!!!"); break;
|
|
#endif
|
|
case KEY_ESC: EscBlock(); break;
|
|
case KEY_ENTER: LibBlockAction(); break;
|
|
case KEY_UP: LibCurUp(); break;
|
|
case KEY_DOWN: LibCurDown(); break;
|
|
case KEY_RIGHT: LibCurRight(); break;
|
|
case KEY_LEFT: LibCurLeft(); break;
|
|
#if 0
|
|
case kc_CtrlRight: LibCtrlRight(); break;
|
|
case kc_CtrlLeft: LibCtrlLeft(); break;
|
|
#endif
|
|
case KEY_PPAGE: LibPgUp(); break;
|
|
case KEY_NPAGE: LibPgDn(); break;
|
|
#if 0
|
|
case kc_CtrlPgUp: LibCtrlPgUp(); break;
|
|
case kc_CtrlPgDn: LibCtrlPgDn(); break;
|
|
case kc_End:
|
|
case kc_CtrlEnd: LibCurEnd(); break;
|
|
case kc_Home:
|
|
case kc_CtrlHome: LibCurHome(); break;
|
|
#endif
|
|
default:
|
|
gotomsg();
|
|
cprintf(" Type <Alt-H> for help...");
|
|
beep();
|
|
#ifdef DEBUG
|
|
cprintf("keycode=0x%04x, 0%o", c, c);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* ==== Control ==== */
|
|
|
|
void
|
|
TXsetmode(void)
|
|
{
|
|
/* cleanup from old mode */
|
|
switch(txmode) {
|
|
case MODELIB:
|
|
blocking = FALSE;
|
|
blocked = FALSE;
|
|
LibBlockAction = noop;
|
|
break;
|
|
case MODEEDIT:
|
|
if(ve_OpSelect != 63) {
|
|
ve_OpSelect = 63;
|
|
_ve_SetOps();
|
|
}
|
|
Pack(Voice_Cursor);
|
|
break;
|
|
}
|
|
txmode=newmode;
|
|
/* set up for new mode */
|
|
switch(txmode) {
|
|
case MODELIB:
|
|
if (Voice_Cursor < Voice_TOS || Voice_Cursor >= Voice_TOS + LibNames) {
|
|
Voice_TOS = min(Voice_Cursor & 0xfff0, max(Voices - LibNames, 0));
|
|
}
|
|
erase();
|
|
LibSetScreen();
|
|
LibDoScreen();
|
|
refresh();
|
|
break;
|
|
case MODEEDIT:
|
|
erase();
|
|
Unpack(Voice_Cursor);
|
|
ve_SetScreen();
|
|
ve_DoScreen();
|
|
refresh();
|
|
PutUnpacked();
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
main(int argc, char ** argv)
|
|
{
|
|
int c;
|
|
|
|
static struct option long_options[] = {
|
|
{"help", 0, 0, 'h'},
|
|
{"voices", 1, 0, 'v'},
|
|
{0, 0, 0, 0}
|
|
};
|
|
|
|
while ((c = getopt_long(argc, argv, "hv:", long_options, NULL)) != EOF) {
|
|
switch (c) {
|
|
case 'v':
|
|
Voices = atoi(optarg);
|
|
if (Voices < 32) Voices = 32;
|
|
break;
|
|
case 'h':
|
|
default:
|
|
fprintf(stderr, "TX/Edit v" VERSIONSTRING " (c)2004 Sean Bolton\n"
|
|
"options:\n"
|
|
"-vnnn --voices=nnn allocate nnn voice slots\n"
|
|
"-h --help print this message and exit\n");
|
|
exit(c == 'h' ? 0 : 1);
|
|
}
|
|
}
|
|
|
|
TXInit();
|
|
if (optind < argc) { /* load command line arguments */
|
|
scrollok(stdscr, TRUE);
|
|
erase();
|
|
LibSetScreen();
|
|
cprintf("\n\n");
|
|
for (c = optind; c < argc; c++) {
|
|
Voice_Cursor += Load(argv[c]);
|
|
}
|
|
paktc();
|
|
Voice_Cursor = 0;
|
|
scrollok(stdscr, FALSE);
|
|
}
|
|
newmode=MODELIB;
|
|
TXsetmode();
|
|
do {
|
|
refresh(); /* -FIX- */
|
|
c = cgetch();
|
|
switch (c) {
|
|
case KEY_METAQ: newmode=MODEQUIT; break;
|
|
default:
|
|
switch(txmode) {
|
|
case MODELIB: vl_CharIn(c); break;
|
|
case MODEEDIT: ve_CharIn(c); break;
|
|
}
|
|
break;
|
|
}
|
|
if (txmode != newmode) TXsetmode();
|
|
} while (txmode != MODEQUIT);
|
|
TXTerm(RETURN_OK); /* never returns */
|
|
return 0;
|
|
}
|
|
|