From 98e7d87678ce6a1405eae20b300c6f4fc8203e25 Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Mon, 28 May 2018 15:33:48 +0200 Subject: [PATCH] Fixes, tests, extensions and some docs. --- addon/tx_edit.c | 2794 ++++++++++++++++++++++++++++++++++++++++++ doc/sysex-format.txt | 289 +++++ doc/voice_data.txt | 72 ++ 3 files changed, 3155 insertions(+) create mode 100644 addon/tx_edit.c create mode 100644 doc/sysex-format.txt create mode 100644 doc/voice_data.txt diff --git a/addon/tx_edit.c b/addon/tx_edit.c new file mode 100644 index 0000000..98e7529 --- /dev/null +++ b/addon/tx_edit.c @@ -0,0 +1,2794 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_ALSA_MIDI +#include +#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 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= 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 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; +} diff --git a/doc/sysex-format.txt b/doc/sysex-format.txt new file mode 100644 index 0000000..15d65f6 --- /dev/null +++ b/doc/sysex-format.txt @@ -0,0 +1,289 @@ +(Message GUS:472) +Received: from mailhub.iastate.edu by po-3.iastate.edu + id AA06806; Sat, 25 Sep 93 16:13:53 -0500 +Received: from Waisman.Wisc.EDU (don.waisman.wisc.edu) by mailhub.iastate.edu + id AA23002; Sat, 25 Sep 1993 16:14:09 -0500 +Received: from Waisman.Wisc.EDU by Waisman.Wisc.EDU (PMDF V4.2-10 #2484) id + <01H3DDLUXLDSBMA3H1@Waisman.Wisc.EDU>; Sat, 25 Sep 1993 16:13:40 CDT +Date: Sat, 25 Sep 1993 16:13:40 -0500 (CDT) +From: "Ewan A. Macpherson" +Subject: DX7 Data Format +To: xeno@iastate.edu +Message-Id: <01H3DDLUY4O2BMA3H1@Waisman.Wisc.EDU> +Organization: Waisman Center, University of Wisconsin-Madison +X-Vms-To: IN::"xeno@iastate.edu" +Mime-Version: 1.0 +Content-Type: TEXT/PLAIN; CHARSET=US-ASCII +Content-Transfer-Encoding: 7BIT + +Gary: + +I don't know anything about the differences between the DX7 and DX7s, but this +DX7 info may be useful. I posted this to r.m.s. before xmas. + +I've seen many requests for public domain / shareware DX editors, but I've +never seen a definitive reply. They're usually along the lines of "I was +roaching around on CompuServe last month, and I think I remember seeing one..." + +Anyway, hope this helps ... + +========================================================================= + +For those interested in unpacking the uscd.edu DX7 patch data, here is +DX7 data format information. + + compiled from - the DX7 MIDI Data Format Sheet + - article by Steve DeFuria (Keyboard Jan 87) + - looking at what my DX7 spits out + +I have kept the kinda weird notation used in the DX7 Data Sheet to reduce +typing errors. Where it doesn't quite make sense to me I've added comments. +(And I will not be liable for errors etc ....) + +Contents: A: SYSEX Message: Bulk Data for 1 Voice + B: SYSEX Message: Bulk Data for 32 Voices + C: SYSEX Message: Parameter Change + D: Data Structure: Single Voice Dump & Voice Parameter #'s + E: Function Parameter #'s + F: Data Structure: Bulk Dump Packed Format + +//////////////////////////////////////////////////////////// +A: +SYSEX Message: Bulk Data for 1 Voice +------------------------------------ + bits hex description + + 11110000 F0 Status byte - start sysex + 0iiiiiii 43 ID # (i=67; Yamaha) + 0sssnnnn 00 Sub-status (s=0) & channel number (n=0; ch 1) + 0fffffff 00 format number (f=0; 1 voice) + 0bbbbbbb 01 byte count MS byte + 0bbbbbbb 1B byte count LS byte (b=155; 1 voice) + 0ddddddd ** data byte 1 + + | | | + + 0ddddddd ** data byte 155 + 0eeeeeee ** checksum (masked 2's complement of sum of 155 bytes) + 11110111 F7 Status - end sysex + + + +/////////////////////////////////////////////////////////// +B: +SYSEX Message: Bulk Data for 32 Voices +-------------------------------------- + bits hex description + + 11110000 F0 Status byte - start sysex + 0iiiiiii 43 ID # (i=67; Yamaha) + 0sssnnnn 00 Sub-status (s=0) & channel number (n=0; ch 1) + 0fffffff 09 format number (f=9; 32 voices) + 0bbbbbbb 20 byte count MS byte + 0bbbbbbb 00 byte count LS byte (b=4096; 32 voices) + 0ddddddd ** data byte 1 + + | | | + + 0ddddddd ** data byte 4096 (there are 128 bytes / voice) + 0eeeeeee ** checksum (masked 2's comp. of sum of 4096 bytes) + 11110111 F7 Status - end sysex + + +///////////////////////////////////////////////////////////// +C: +SYSEX MESSAGE: Parameter Change +------------------------------- + bits hex description + + 11110000 F0 Status byte - start sysex + 0iiiiiii 43 ID # (i=67; Yamaha) + 0sssnnnn 10 Sub-status (s=1) & channel number (n=0; ch 1) + 0gggggpp ** parameter group # (g=0; voice, g=2; function) + 0ppppppp ** parameter # (these are listed in next section) + Note that voice parameter #'s can go over 128 so + the pp bits in the group byte are either 00 for + par# 0-127 or 01 for par# 128-155. In the latter case + you add 128 to the 0ppppppp byte to compute par#. + 0ddddddd ** data byte + 11110111 F7 Status - end sysex + + +////////////////////////////////////////////////////////////// + +D: +Data Structure: Single Voice Dump & Parameter #'s (single voice format, g=0) +------------------------------------------------------------------------- + +Parameter + Number Parameter Value Range +--------- --------- ----------- + 0 OP6 EG rate 1 0-99 + 1 " " rate 2 " + 2 " " rate 3 " + 3 " " rate 4 " + 4 " " level 1 " + 5 " " level 2 " + 6 " " level 3 " + 7 " " level 4 " + 8 OP6 KBD LEV SCL BRK PT " C3= $27 + 9 " " " " LFT DEPTH " + 10 " " " " RHT DEPTH " + 11 " " " " LFT CURVE 0-3 0=-LIN, -EXP, +EXP, +LIN + 12 " " " " RHT CURVE " " " " " + 13 OP6 KBD RATE SCALING 0-7 + 14 OP6 AMP MOD SENSITIVITY 0-3 + 15 OP6 KEY VEL SENSITIVITY 0-7 + 16 OP6 OPERATOR OUTPUT LEVEL 0-99 + 17 OP6 OSC MODE (fixed/ratio) 0-1 0=ratio + 18 OP6 OSC FREQ COARSE 0-31 + 19 OP6 OSC FREQ FINE 0-99 + 20 OP6 OSC DETUNE 0-14 0: det=-7 + 21 \ + | > repeat above for OSC 5, OSC 4, ... OSC 1 +125 / +126 PITCH EG RATE 1 0-99 +127 " " RATE 2 " +128 " " RATE 3 " +129 " " RATE 4 " +130 " " LEVEL 1 " +131 " " LEVEL 2 " +132 " " LEVEL 3 " +133 " " LEVEL 4 " +134 ALGORITHM # 0-31 +135 FEEDBACK 0-7 +136 OSCILLATOR SYNC 0-1 +137 LFO SPEED 0-99 +138 " DELAY " +139 " PITCH MOD DEPTH " +140 " AMP MOD DEPTH " +141 LFO SYNC 0-1 +142 " WAVEFORM 0-5, (data sheet claims 9-4 ?!?) + 0:TR, 1:SD, 2:SU, 3:SQ, 4:SI, 5:SH +143 PITCH MOD SENSITIVITY 0-7 +144 TRANSPOSE 0-48 12 = C2 +145 VOICE NAME CHAR 1 ASCII +146 VOICE NAME CHAR 2 ASCII +147 VOICE NAME CHAR 3 ASCII +148 VOICE NAME CHAR 4 ASCII +149 VOICE NAME CHAR 5 ASCII +150 VOICE NAME CHAR 6 ASCII +151 VOICE NAME CHAR 7 ASCII +152 VOICE NAME CHAR 8 ASCII +153 VOICE NAME CHAR 9 ASCII +154 VOICE NAME CHAR 10 ASCII +155 OPERATOR ON/OFF + bit6 = 0 / bit 5: OP1 / ... / bit 0: OP6 + +Note that there are actually 156 parameters listed here, one more than in +a single voice dump. The OPERATOR ON/OFF parameter is not stored with the +voice, and is only transmitted or received while editing a voice. So it +only shows up in parameter change SYS-EX's. + + +//////////////////////////////////////////////////////// + +E: +Function Parameters: (g=2) +------------------------- + +Parameter +Number Parameter Range +--------- ---------- ------ +64 MONO/POLY MODE CHANGE 0-1 O=POLY +65 PITCH BEND RANGE 0-12 +66 " " STEP 0-12 +67 PORTAMENTO MODE 0-1 0=RETAIN 1=FOLLOW +68 " GLISS 0-1 +69 " TIME 0-99 +70 MOD WHEEL RANGE 0-99 +71 " " ASSIGN 0-7 b0: pitch, b1:amp, b2: EG bias +72 FOOT CONTROL RANGE 0-99 +73 " " ASSIGN 0-7 " +74 BREATH CONT RANGE 0-99 +75 " " ASSIGN 0-7 " +76 AFTERTOUCH RANGE 0-99 +77 " ASSIGN 0-7 " + +/////////////////////////////////////////////////////////////// + +F: +Data Structure: Bulk Dump Packed Format +--------------------------------------- + +OK, now the tricky bit. For a bulk dump the 155 voice parameters for each + voice are packed into 32 consecutive 128 byte chunks as follows ... + +byte bit # + # 6 5 4 3 2 1 0 param A range param B range +---- --- --- --- --- --- --- --- ------------ ----- ------------ ----- + 0 R1 OP6 EG R1 0-99 + 1 R2 OP6 EG R2 0-99 + 2 R3 OP6 EG R3 0-99 + 3 R4 OP6 EG R4 0-99 + 4 L1 OP6 EG L1 0-99 + 5 L2 OP6 EG L2 0-99 + 6 L3 OP6 EG L3 0-99 + 7 L4 OP6 EG L4 0-99 + 8 BP LEV SCL BRK PT 0-99 + 9 LD SCL LEFT DEPTH 0-99 + 10 RD SCL RGHT DEPTH 0-99 + 11 0 0 0 | RC | LC | SCL LEFT CURVE 0-3 SCL RGHT CURVE 0-3 + 12 | DET | RS | OSC DETUNE 0-14 OSC RATE SCALE 0-7 + 13 0 0 | KVS | AMS | KEY VEL SENS 0-7 AMP MOD SENS 0-3 + 14 OL OP6 OUTPUT LEV 0-99 + 15 0 | FC | M | FREQ COARSE 0-31 OSC MODE 0-1 + 16 FF FREQ FINE 0-99 + 17 \ + | > these 17 bytes for OSC 5 + 33 / + 34 \ + | > these 17 bytes for OSC 4 + 50 / + 51 \ + | > these 17 bytes for OSC 3 + 67 / + 68 \ + | > these 17 bytes for OSC 2 + 84 / + 85 \ + | > these 17 bytes for OSC 1 +101 / + +byte bit # + # 6 5 4 3 2 1 0 param A range param B range +---- --- --- --- --- --- --- --- ------------ ----- ------------ ----- +102 PR1 PITCH EG R1 0-99 +103 PR2 PITCH EG R2 0-99 +104 PR3 PITCH EG R3 0-99 +105 PR4 PITCH EG R4 0-99 +106 PL1 PITCH EG L1 0-99 +107 PL2 PITCH EG L2 0-99 +108 PL3 PITCH EG L3 0-99 +109 PL4 PITCH EG L4 0-99 +110 0 0 | ALG | ALGORITHM 0-31 +111 0 0 0 |OKS| FB | OSC KEY SYNC 0-1 FEEDBACK 0-7 +112 LFS LFO SPEED 0-99 +113 LFD LFO DELAY 0-99 +114 LPMD LF PT MOD DEP 0-99 +115 LAMD LF AM MOD DEP 0-99 +116 | LPMS | LFW |LKS| LF PT MOD SNS 0-7 WAVE 0-5, SYNC 0-1 +117 TRNSP TRANSPOSE 0-48 +118 NAME CHAR 1 VOICE NAME 1 ASCII +119 NAME CHAR 2 VOICE NAME 2 ASCII +120 NAME CHAR 3 VOICE NAME 3 ASCII +121 NAME CHAR 4 VOICE NAME 4 ASCII +122 NAME CHAR 5 VOICE NAME 5 ASCII +123 NAME CHAR 6 VOICE NAME 6 ASCII +124 NAME CHAR 7 VOICE NAME 7 ASCII +125 NAME CHAR 8 VOICE NAME 8 ASCII +126 NAME CHAR 9 VOICE NAME 9 ASCII +127 NAME CHAR 10 VOICE NAME 10 ASCII + +///////////////////////////////////////////////////////////////////// + +And that's it. + +Hope this is useful. + +ewan. diff --git a/doc/voice_data.txt b/doc/voice_data.txt new file mode 100644 index 0000000..a279e5d --- /dev/null +++ b/doc/voice_data.txt @@ -0,0 +1,72 @@ +F: +Data Structure: Bulk Dump Packed Format +--------------------------------------- + +OK, now the tricky bit. For a bulk dump the 155 voice parameters for each + voice are packed into 32 consecutive 128 byte chunks as follows ... + +byte bit # + # 6 5 4 3 2 1 0 param A range param B range +---- --- --- --- --- --- --- --- ------------ ----- ------------ ----- + 0 R1 OP6 EG R1 0-99 + 1 R2 OP6 EG R2 0-99 + 2 R3 OP6 EG R3 0-99 + 3 R4 OP6 EG R4 0-99 + 4 L1 OP6 EG L1 0-99 + 5 L2 OP6 EG L2 0-99 + 6 L3 OP6 EG L3 0-99 + 7 L4 OP6 EG L4 0-99 + 8 BP LEV SCL BRK PT 0-99 + 9 LD SCL LEFT DEPTH 0-99 + 10 RD SCL RGHT DEPTH 0-99 + 11 0 0 0 | RC | LC | SCL LEFT CURVE 0-3 SCL RGHT CURVE 0-3 + 12 | DET | RS | OSC DETUNE 0-14 OSC RATE SCALE 0-7 + 13 0 0 | KVS | AMS | KEY VEL SENS 0-7 AMP MOD SENS 0-3 + 14 OL OP6 OUTPUT LEV 0-99 + 15 0 | FC | M | FREQ COARSE 0-31 OSC MODE 0-1 + 16 FF FREQ FINE 0-99 + 17 \ + | > these 17 bytes for OSC 5 + 33 / + 34 \ + | > these 17 bytes for OSC 4 + 50 / + 51 \ + | > these 17 bytes for OSC 3 + 67 / + 68 \ + | > these 17 bytes for OSC 2 + 84 / + 85 \ + | > these 17 bytes for OSC 1 +101 / + +byte bit # + # 6 5 4 3 2 1 0 param A range param B range +---- --- --- --- --- --- --- --- ------------ ----- ------------ ----- +102 PR1 PITCH EG R1 0-99 +103 PR2 PITCH EG R2 0-99 +104 PR3 PITCH EG R3 0-99 +105 PR4 PITCH EG R4 0-99 +106 PL1 PITCH EG L1 0-99 +107 PL2 PITCH EG L2 0-99 +108 PL3 PITCH EG L3 0-99 +109 PL4 PITCH EG L4 0-99 +110 0 0 | ALG | ALGORITHM 0-31 +111 0 0 0 |OKS| FB | OSC KEY SYNC 0-1 FEEDBACK 0-7 +112 LFS LFO SPEED 0-99 +113 LFD LFO DELAY 0-99 +114 LPMD LF PT MOD DEP 0-99 +115 LAMD LF AM MOD DEP 0-99 +116 | LPMS | LFW |LKS| LF PT MOD SNS 0-7 WAVE 0-5, SYNC 0-1 +117 TRNSP TRANSPOSE 0-48 +118 NAME CHAR 1 VOICE NAME 1 ASCII +119 NAME CHAR 2 VOICE NAME 2 ASCII +120 NAME CHAR 3 VOICE NAME 3 ASCII +121 NAME CHAR 4 VOICE NAME 4 ASCII +122 NAME CHAR 5 VOICE NAME 5 ASCII +123 NAME CHAR 6 VOICE NAME 6 ASCII +124 NAME CHAR 7 VOICE NAME 7 ASCII +125 NAME CHAR 8 VOICE NAME 8 ASCII +126 NAME CHAR 9 VOICE NAME 9 ASCII +127 NAME CHAR 10 VOICE NAME 10 ASCII