/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * DX-7s routines
 *
 * Scott Snyder - ssnyder@citromeo.bitnet, ssnyder@romeo.caltech.edu
 */

#define ARYLEN(a) (sizeof((a))/sizeof((a)[0]))

#define BITS(x, start, len) (((x) >> (start)) & ((1<<(len))-1))

#define OVERLAY1

#define VCED_SIZE 155
#define ADVCED_SIZE 49

#define VMEM_SIZE 128
#define ADVMEM_SIZE 35
#define NVOICES 32

#include "glib.h"
#include <ctype.h>

char *visnum(), *visonoff(), *vism3num(), *viswave(), *vismono();
char *visfreq(), *visdx1a(), *visr2num();

char *visdx7fq(), *visdx7fx(), *vism7num(), *visdx7note(), *visdx7crv();
char *visdx7a(), *visdx7wave(), *visdx7brkpt();

char *visdx7fq1(), *visdx7fq2(), *visdx7fq3();
char *visdx7fq4(), *visdx7fq5(), *visdx7fq6();
char *visdx7fx1(), *visdx7fx2(), *visdx7fx3();
char *visdx7fx4(), *visdx7fx5(), *visdx7fx6();

char *visdx7sport(),  *visdx7spbmode(), *visdx7spegrng(), *visdx7ssngl();
char *visdx7smono(),  *visdx7sedmode(), *visdx7sdumpm(),  *visdx7sdumam();
char *visdx7sdumeg(), *visdx7sdum4(),   *visdx7ssclm(),   *visdx7crv();

char *visdx7sfx1(), *visdx7sfx2(), *visdx7sfx3();
char *visdx7sfx4(), *visdx7sfx5(), *visdx7sfx6();

#define RESERVESIZE VMEM_SIZE

/* This array contains arbitrary screen labels */
struct labelinfo Ldx7S[] = {
#MENU
                      N: set name; q: quit; K: incr; J: decr; >: max; <: min  k
                  space: play autonote Pitch  %   Vol  %   Dur  %   Chan  %  h l
                                                                              j
    Atk  Sust1 Sust2  Rls          Scal Out De  Rat  Sens  Brk  Depth  Curve
OP Rt Lv Rt Lv Rt Lv Rt Lv  Freq   Mode Lvl tun Scl Key AM Pt   L  R   L    R
-- -- -- -- -- -- -- -- -- ------- ---- --- --- --- --- -- ---- -- -- ---- ----
 1 %  %  %  %  %  %  %  %  %    %  %     %   %   %   %   % %    %  %  %    %
 2 %  %  %  %  %  %  %  %  %    %  %     %   %   %   %   % %    %  %  %    %
 3 %  %  %  %  %  %  %  %  %    %  %     %   %   %   %   % %    %  %  %    %
 4 %  %  %  %  %  %  %  %  %    %  %     %   %   %   %   % %    %  %  %    %
 5 %  %  %  %  %  %  %  %  %    %  %     %   %   %   %   % %    %  %  %    %
 6 %  %  %  %  %  %  %  %  %    %  %     %   %   %   %   % %    %  %  %    %
PE %  %  %  %  %  %  %  %
                                      Osc. Sync     %      Rnd Pitch      @
Algorithm   %  LFO trigger   %        Feedback      %      Port. mode     @
============== LFO Speed     %        Middle C      %      Port. step     @
               LFO Delay     %        PEG Range     %      Port. time     @
               LFO AM Depth  %        PEG by vel    %
               LFO PM Depth  %        PEG Rate Scl  %                     @
               LFO Wave      %        PB Range      %      PM range       @
               LFO Sync      %        PB Step       %      AM range       @
               LFO PM Sense  %        PB Mode       %      EG bias        @
               Unison detune %        Poly/Mono     %                     @
               FC1 is CS1    %        Unison mode   %
#END
-1,-1,NULL
};

/* This array defines all the editable parameters. */
struct paraminfo Pdx7S[] = {
"autopitch",	NULL, -1, -1,  %%, visnum, 0, 127, 60, 0,
"autovol",	NULL, -1, -1,  %%, visnum, 0, 127, 63, 0,
"autodur",	NULL, -1, -1,  %%, visnum, 1,  20,  5, 0,
"autochan",	NULL, -1, -1,  %%, visnum, 1,  16,  1, 0,

"op1atkrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1atklv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1sust1rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1sust1lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1sust2rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1sust2lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1rlsrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1rlslv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1freq",	NULL, -1, -1,   %%, visdx7fq1,  0, 4067, 0, 0,
"op1fx",	NULL, -1, -1,   %%, visdx7sfx1, 0,    1, 0, 0,
#O op1scalmode	dx7ssclm	%%	1	0	0x20	5
"op1outlevel",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1detune",	NULL, -1, -1,   %%, vism7num,   0,   14, 0, 0,
"op1ratscl",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
"op1tchsens",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
#O op1amsens	num		%%	7	3	0x38	3
"op1brkpt",	NULL, -1, -1,   %%, visdx7brkpt,0,   99, 0, 0,
"op1ldepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1rdepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op1lcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op1rcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op1modsens",	NULL, -1, -1,-1,-1, visnum,     0,    3, 0, 0,

"op2atkrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2atklv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2sust1rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2sust1lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2sust2rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2sust2lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2rlsrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2rlslv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2freq",	NULL, -1, -1,   %%, visdx7fq2,  0, 4067, 0, 0,
"op2fx",	NULL, -1, -1,   %%, visdx7sfx2, 0,    1, 0, 0,
#O op2scalmode	dx7ssclm	%%	1	0	0x10	4
"op2outlevel",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2detune",	NULL, -1, -1,   %%, vism7num,   0,   14, 0, 0,
"op2ratscl",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
"op2tchsens",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
#O op2amsens	num		%%	7	3	0x07
"op2brkpt",	NULL, -1, -1,   %%, visdx7brkpt,0,   99, 0, 0,
"op2ldepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2rdepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op2lcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op2rcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op2modsens",	NULL, -1, -1,-1,-1, visnum,     0,    3, 0, 0,

"op3atkrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3atklv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3sust1rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3sust1lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3sust2rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3sust2lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3rlsrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3rlslv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3freq",	NULL, -1, -1,   %%, visdx7fq3,  0, 4067, 0, 0,
"op3fx",	NULL, -1, -1,   %%, visdx7sfx3, 0,    1, 0, 0,
#O op3scalmode	dx7ssclm	%%	1	0	0x08	3
"op3outlevel",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3detune",	NULL, -1, -1,   %%, vism7num,   0,   14, 0, 0,
"op3ratscl",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
"op3tchsens",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
#O op3amsens	num		%%	7	2	0x38	3
"op3brkpt",	NULL, -1, -1,   %%, visdx7brkpt,0,   99, 0, 0,
"op3ldepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3rdepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op3lcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op3rcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op3modsens",	NULL, -1, -1,-1,-1, visnum,     0,    3, 0, 0,

"op4atkrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4atklv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4sust1rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4sust1lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4sust2rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4sust2lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4rlsrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4rlslv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4freq",	NULL, -1, -1,   %%, visdx7fq4,  0, 4067, 0, 0,
"op4fx",	NULL, -1, -1,   %%, visdx7sfx4, 0,    1, 0, 0,
#O op4scalmode	dx7ssclm	%%	1	0	0x04	2
"op4outlevel",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4detune",	NULL, -1, -1,   %%, vism7num,   0,   14, 0, 0,
"op4ratscl",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
"op4tchsens",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
#O op4amsens	num		%%	7	2	0x07
"op4brkpt",	NULL, -1, -1,   %%, visdx7brkpt,0,   99, 0, 0,
"op4ldepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4rdepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op4lcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op4rcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op4modsens",	NULL, -1, -1,-1,-1, visnum,     0,    3, 0, 0,

"op5atkrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5atklv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5sust1rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5sust1lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5sust2rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5sust2lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5rlsrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5rlslv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5freq",	NULL, -1, -1,   %%, visdx7fq5,  0, 4067, 0, 0,
"op5fx",	NULL, -1, -1,   %%, visdx7sfx5, 0,    1, 0, 0,
#O op5scalmode	dx7ssclm	%%	1	0	0x02	1
"op5outlevel",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5detune",	NULL, -1, -1,   %%, vism7num,   0,   14, 0, 0,
"op5ratscl",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
"op5tchsens",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
#O op5amsens	num		%%	7	1	0x38	3
"op5brkpt",	NULL, -1, -1,   %%, visdx7brkpt,0,   99, 0, 0,
"op5ldepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5rdepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op5lcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op5rcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op5modsens",	NULL, -1, -1,-1,-1, visnum,     0,    3, 0, 0,

"op6atkrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6atklv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6sust1rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6sust1lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6sust2rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6sust2lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6rlsrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6rlslv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6freq",	NULL, -1, -1,   %%, visdx7fq6,  0, 4067, 0, 0,
"op6fx",	NULL, -1, -1,   %%, visdx7sfx6, 0,    1, 0, 0,
#O op6scalmode	dx7ssclm	%%	1	0	0x01
"op6outlevel",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6detune",	NULL, -1, -1,   %%, vism7num,   0,   14, 0, 0,
"op6ratscl",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
"op6tchsens",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
#O op6amsens	num		%%	7	1	0x07
"op6brkpt",	NULL, -1, -1,   %%, visdx7brkpt,0,   99, 0, 0,
"op6ldepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6rdepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"op6lcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op6rcurve",	NULL, -1, -1,   %%, visdx7crv,  0,    3, 0, 0,
"op6modsens",	NULL, -1, -1,-1,-1, visnum,     0,    3, 0, 0,

"pegatkrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"pegatklv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"pegsust1rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"pegsust1lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"pegsust2rt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"pegsust2lv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"pegrlsrt",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"pegrlslv",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,

"oscsync",	NULL, -1, -1,   %%, visonoff,   0,    1, 0, 0,
"algorithm",	NULL, -1, -1,   %%, visdx7a,    0,   31, 0, 0,
#O lfotrig	dx7ssngl	%%	1	4	0x04	2
"feedback",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
"lfospeed",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
"transpose",	NULL, -1, -1,   %%, visdx7note, 0,   48, 0, 0,
"lfodelay",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
#O pegrange	dx7spegrng	%%	3	4	0x03
"lfoamdepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
#O pegvel	onoff		%%	1	4	0x08	3
"lfopmdepth",	NULL, -1, -1,   %%, visnum,     0,   99, 0, 0,
#O pegratscl	num		%%	7	24	0x07
"lfowave",	NULL, -1, -1,   %%, visdx7wave, 0,    5, 0, 0,
#O pbrange	num		%%	12	5	0x3C	2
"lfosync",	NULL, -1, -1,   %%, visonoff,   0,    1, 0, 0,
#O pbstep	num		%%	12	6	0x0F
"lfopmsens",	NULL, -1, -1,   %%, visnum,     0,    7, 0, 0,
#O pbmode	dx7spbmode	%%	3	6	0x30	4
#O unidetune	num		%%	7	34	0x07
#O polymono	dx7smono	%%	1	5	0x01
#O fc1_cs1	onoff		%%	1	34	0x08	3
#O unison	onoff		%%	1	5	0x02	1

#O rndpitch	num		@@	7	4	0x70	4
#O portmode	dx7sport	@@	1	7	0x01
#O portstep	num		@@	12	7	0x1E	1
#O porttime	num		@@	99	8

/*
 * note: for proper operation of this hack, the 'edit mode' parm must be
 *  displayed before any of the dummy parms when the screen is first being
 *  drawn. making it alphabetically less will accomplish this.
 */

"_aeditmode",	NULL, -1, -1,   @@, visdx7sedmode, 0,  5, 0, 0,
"_dummy_pm",	NULL, -1, -1,   @@, visdx7sdumpm,  0, 99, 0, 0,
"_dummy_am",	NULL, -1, -1,   @@, visdx7sdumam,  0, 99, 0, 0,
"_dummy_eg",	NULL, -1, -1,   @@, visdx7sdumeg,  0, 99, 0, 0,
"_dummy4",	NULL, -1, -1,   @@, visdx7sdum4,   0, 99, 0, 1,

#O mw_pm	num		--	99	9
#O mw_am	num		--	99	10
#O mw_eg	num		--	99	11
#O mw_vol	num		--	99	-1

#O fc1_pm	num		--	99	12
#O fc1_am	num		--	99	13
#O fc1_eg	num		--	99	14
#O fc1_vol	num		--	99	15

#O fc2_pm	num		--	99	26
#O fc2_am	num		--	99	27
#O fc2_eg	num		--	99	28
#O fc2_vol	num		--	99	29

#O midi_pm	num		--	99	30
#O midi_am	num		--	99	31
#O midi_eg	num		--	99	32
#O midi_vol	num		--	99	33

#O bc_pm	num		--	99	16
#O bc_am	num		--	99	17
#O bc_eg	num		--	99	18
#O bc_pitchb	num		--	100	19

#O at_pm	num		--	99	20
#O at_am	num		--	99	21
#O at_eg	num		--	99	22
#O at_pitchb	num		--	100	23

NULL,	NULL, -1, -1, -1, -1, visnum, 0, 0, 0, 0
};

char *visdx7smono(v)
int v;
{
  showparam(parmindex("portmode"), 0);
  return vismono(v);
}

char *visdx7ssngl(v)
int v;
{
  if (v == 0)
    return "Single";
  else
    return "Multi";
}

char *visdx7spegrng(v)
int v;
{
  switch (v) {
    case 0: return "8oct";
    case 1: return "2oct";
    case 2: return "1oct";
    case 3: return "1/2oct";
    default: return "???";
  }
}

char *visdx7spbmode(v)
int v;
{
  switch (v) {
    case 0: return "Norm";
    case 1: return "Low";
    case 2: return "High";
    case 3: return "Key On";
    default: return "???";
  }
}

char *visdx7sport(v)
int v;
{
  if (getval("polymono") == 0)
    if (v == 0)
      return "Retain";
    else
      return "Follow";
  else
    if (v == 0)
      return "Fingrd";
    else
      return "Fulltm";
}

char *edmodes[] = {
  "Modulation Wheel",
  "Aftertouch",
  "Breath Control",
  "Foot Control 1",
  "Foot Control 2",
  "MIDI Control",
};

char *edmode_prefixes[] = {"mw", "at", "bc", "fc1", "fc2", "midi",};

char *mk_mode_parm(v, suffix)
unsigned v;
char *suffix;
{
  static char buf[20];

  if (v < ARYLEN(edmode_prefixes)) {
    sprintf(buf, "%s_%s", edmode_prefixes[v], suffix);
    return buf;
  }
  else return "???";
}

char *visdx7sedmode(v, eras)
unsigned v, eras;
{
  int j;
  static char buf[30];

  if (eras) {
    showparam(parmindex("_dummy_pm"), 1);
    showparam(parmindex("_dummy_am"), 1);
    showparam(parmindex("_dummy_eg"), 1);
    showparam(parmindex("_dummy4"), 1);
  }
  else {
    setval("_dummy_pm", getval(mk_mode_parm(v, "pm")));
    setval("_dummy_am", getval(mk_mode_parm(v, "am")));
    setval("_dummy_eg", getval(mk_mode_parm(v, "eg")));

    showparam(parmindex("_dummy_pm"), 0);
    showparam(parmindex("_dummy_am"), 0);
    showparam(parmindex("_dummy_eg"), 0);

    j = parmindex("_dummy4");
    if (v == 0)	/* MW */
      disableparm(j);
    else {
      enableparm(j);
      if (v == 1 || v == 2) {  /* BC, AT */
        P[j].p_max = 100;
        setval("_dummy4", getval(mk_mode_parm(v, "pitchb")));
      }
      else {
        P[j].p_max = 99;
        setval("_dummy4", getval(mk_mode_parm(v, "vol")));
      }
      showparam(j, 0);
    }
  }

  sprintf(buf, "~15l%s", v < ARYLEN(edmodes) ? edmodes[v] : "???");
  return buf;
}

char *visdx7sdumpm(v)
int v;
{
  setval(mk_mode_parm(getval("_aeditmode"), "pm"), v);
  return visnum(v);
}

char *visdx7sdumam(v)
int v;
{
  setval(mk_mode_parm(getval("_aeditmode"), "am"), v);
  return visnum(v);
}

char *visdx7sdumeg(v)
int v;
{
  setval(mk_mode_parm(getval("_aeditmode"), "eg"), v);
  return visnum(v);
}

char *visdx7sdum4(v)
int v;
{
  int mode = getval("_aeditmode");
  static char buf[40];

  if (mode == 1 || mode == 2) { /* BC, AT */
    setval(mk_mode_parm(mode, "pitchb"), v);
    sprintf(buf, "~15lPitch Bias~5 %s", visnum(v-50));
    return buf;
  }
  else {
    setval(mk_mode_parm(mode, "vol"), v);
    sprintf(buf, "~15lVolume Range~3 %s", visnum(v));
    return buf;
  }
}

char *visdx7ssclm(v)
int v;
{
  if (v == 0)
    return "Norm";
  else
    return "Frac";
}

char *visdx7sfx1(v) { return visdx7fx(v, 1, 1); }
char *visdx7sfx2(v) { return visdx7fx(v, 2, 1); }
char *visdx7sfx3(v) { return visdx7fx(v, 3, 1); }
char *visdx7sfx4(v) { return visdx7fx(v, 4, 1); }
char *visdx7sfx5(v) { return visdx7fx(v, 5, 1); }
char *visdx7sfx6(v) { return visdx7fx(v, 6, 1); }

dx7Sdin(data)
char *data;
{
  int op;

#SETVAL

  dx7din(data);

  for (op=1; op <= 6; op++)
    setopval(op, "modsens", 0);
}

dx7Sdout(data)
char *data;
{
#GETVAL
  dx7dout(data);
}

dx7Sadvmemtoadvced(in, out)
char *in, *out;
{
  int op;

  for (op=1; op <= 6; op++)
    out[6-op] = BITS(in[0], (6-op), 1);		/* scaling mode */
  out[ 6] = BITS(in[1], 0, 3);			/* op6 am sens */
  out[ 7] = BITS(in[1], 3, 3);			/* op5 am sens */
  out[ 8] = BITS(in[2], 0, 3);			/* op4 am sens */
  out[ 9] = BITS(in[2], 3, 3);			/* op3 am sens */
  out[10] = BITS(in[3], 0, 3);			/* op2 am sens */
  out[11] = BITS(in[3], 3, 3);			/* op1 am sens */

  out[12] = BITS(in[4], 0, 2);			/* pegrange		*/
  out[13] = BITS(in[4], 2, 1);			/* lfotrig		*/
  out[14] = BITS(in[4], 3, 1);			/* pegvel		*/
  out[15] = BITS(in[5], 0, 2);			/* polymono/unison	*/
  out[16] = BITS(in[5], 2, 4);			/* pbrange		*/
  out[17] = BITS(in[6], 0, 4);			/* pbstep		*/
  out[18] = BITS(in[6], 4, 2);			/* pbmode		*/
  out[19] = BITS(in[4], 4, 3);			/* rndpitch		*/
  out[20] = BITS(in[7], 0, 1);			/* portmode		*/
  out[21] = BITS(in[7], 1, 4);			/* portstep		*/
  out[22] = in[8];				/* porttime		*/

  out[23] = in[9];				/* mw_pm		*/
  out[24] = in[10];				/* mw_am		*/
  out[25] = in[11];				/* mw_eg		*/

  out[26] = in[12];				/* fc1_pm		*/
  out[27] = in[13];				/* fc1_am		*/
  out[28] = in[14];				/* fc1_eg		*/
  out[29] = in[15];				/* fc1_vol		*/

  out[30] = in[16];				/* bc_pm		*/
  out[31] = in[17];				/* bc_am		*/
  out[32] = in[18];				/* bc_eg		*/
  out[33] = in[19];				/* bc_pitchb		*/

  out[34] = in[20];				/* at_pm		*/
  out[35] = in[21];				/* at_am		*/
  out[36] = in[22];				/* at_eg		*/
  out[37] = in[23];				/* at_pitchb		*/

  out[38] = BITS(in[24], 0, 3);			/* pegratscl		*/

  out[39] = in[26];				/* fc2_pm		*/
  out[40] = in[27];				/* fc2_am		*/
  out[41] = in[28];				/* fc2_eg		*/
  out[42] = in[29];				/* fc2_vol		*/

  out[43] = in[30];				/* midi_pm		*/
  out[44] = in[31];				/* midi_am		*/
  out[45] = in[32];				/* midi_eg		*/
  out[46] = in[33];				/* midi_vol		*/

  out[47] = BITS(in[34], 0, 3);			/* unidetune		*/
  out[48] = BITS(in[34], 3, 1);			/* fc1_cs1		*/
}  

dx7Ssadvced(data)
char *data;
{
  return dx7send_bulk(5, ADVCED_SIZE, data);
}

dx7Ssedit(data)
char *data;
{
  char edmem[ADVCED_SIZE];

  dx7Sadvmemtoadvced(data+128, edmem);
  return dx7sedit(data) || dx7Ssadvced(edmem);
}

static int alloc_bufs(vmem, advmem)
char **vmem, **advmem;
{
  if ((*vmem = (char *)malloc(NVOICES * VMEM_SIZE)) != NULL) {
    if ((*advmem = (char *)malloc(NVOICES * ADVMEM_SIZE)) != NULL)
      return 0;
    free(*vmem);
  }

  Reason = "Couldn't allocate enough buffer space";
  return 1;
}

static split_data(data, vmem, advmem)
char *data, *vmem, *advmem;
{
  int i;

  for (i=0; i<NVOICES; i++) {
    memcpy(vmem, data, VMEM_SIZE);
    memcpy(advmem, data+VMEM_SIZE, ADVMEM_SIZE);
    data += VMEM_SIZE + ADVMEM_SIZE;
    vmem += VMEM_SIZE;
    advmem += ADVMEM_SIZE;
  }
}

static combine_data(data, vmem, advmem)
char *data, *vmem, *advmem;
{
  int i;

  for (i=0; i<NVOICES; i++) {
    memcpy(data, vmem, VMEM_SIZE);
    memcpy(data+VMEM_SIZE, advmem, ADVMEM_SIZE);
    data += VMEM_SIZE + ADVMEM_SIZE;
    vmem += VMEM_SIZE;
    advmem += ADVMEM_SIZE;
  }
}

dx7Ssbulk(data)
char *data;
{
  char *vmem, *advmem;
  int retstat;

  if (alloc_bufs(&vmem, &advmem)) return 1;
  split_data(data, vmem, advmem);

  retstat = dx7sbulk(vmem) || dx7send_bulk(6, NVOICES * ADVMEM_SIZE, advmem);

  free(vmem);
  free(advmem);

  return retstat;
}

dx7Sgbulk(data)
char *data;
{
  char *vmem, *advmem;
  int retstat;

  if (alloc_bufs(&vmem, &advmem)) return 1;

  retstat = dx7gbulk(vmem) || dx7get_bulk(6, NVOICES * ADVMEM_SIZE, advmem);

  if (!retstat) combine_data(data, vmem, advmem);

  free(vmem);
  free(advmem);

  return retstat;
}

static char deflt_advmem[] = {
 0, 0, 0, 0, 3, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 
 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };

/* read a DX7 file as a DX7S file */

dx7Sread_dx7(f, data)
FILE *f;
char *data;
{
  int v;

  message("Reading DX7 bank");

  for (v=0; v<NVOICES; v++) {
    fread(data, VMEM_SIZE, 1, f);
    memcpy(data+VMEM_SIZE, deflt_advmem, ADVMEM_SIZE);
    data += VMEM_SIZE + ADVMEM_SIZE;
  }
}

/* read a DX7s file as a DX7 file */

dx7read_dx7S(f, data)
FILE *f;
char *data;
{
  int v;

  message("Reading DX7s bank");

  for (v=0; v<NVOICES; v++) {
    fread(data, VMEM_SIZE, 1, f);
    fseek(f, (long)ADVMEM_SIZE, SEEK_CUR);
    data += VMEM_SIZE;
  }
}
