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.
MicroDexed/addon/tx_edit.c

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;
}