/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * TX81Z routines for Performance parameters
 */

#define OVERLAY1

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

char *visnum(), *vis1num(), *viseffect(), *visass(), *viskey();
char *vischan(), *visnote(), *vistdetune(), *vistout(), *vislfo();
char *visponoff(), *vispvoice(), *vispshift();

static char Pbuff[17];

#define PMEMSIZE 76
#define PCEDSIZE 110

/* This array contains arbitrary screen labels */
struct labelinfo Ltx81p[] = {
1,17," 1      2      3      4      5      6      7      8",
2,17,"---    ---    ---    ---    ---    ---    ---    ---",
3,2,"Voice",
7,2,"Max Notes",
8,2,"Receive Ch.",
9,2,"Limit Low",
10,2,"Limit High",
11,2,"Detune",
12,2,"Note Shift",
13,2,"Volume",
14,2,"Out Assign",
15,2,"LFO Select",
16,2,"Micro Tune",
21,0,"-------------------------+",
22,0,"Auto-Note:               |",
23,0,"                         |",
-1,-1,NULL
};

/* This array defines all the editable parameters. */
struct paraminfo Ptx81p[] = {
"autopitch",    "Pitch",22, 11, 22, 17, visnum, 0, 127, 60, 0,
"autovol",      "Vol",  23, 0, 23, 4, visnum, 0, 127, 63, 0,
"autodur",      "Dur",  23, 8, 23, 12, visnum, 1, 20, 5, 0,
"autochan",     "Chan", 23, 16, 23, 21, visnum, 1, 16, 1, 0,

"op1max",       NULL, -1, -1, 7, 18, visnum, 0, 8, 0, 0,
"op1voice",     NULL, -1, -1, 3, 17, vispvoice, 0, 159, 0, 0,
"op1rec",       NULL, -1, -1, 8, 18, vischan, 0, 16, 0, 0,
"op1liml",      NULL, -1, -1, 9, 18, visnote, 0, 127, 0, 0,
"op1limh",      NULL, -1, -1, 10, 18, visnote, 0, 127, 0, 0,
"op1detune",    NULL, -1, -1, 11, 18, vistdetune, 0, 14, 0, 0,
"op1shift",     NULL, -1, -1, 12, 18, vispshift, 0, 48, 0, 0,
"op1vol",       NULL, -1, -1, 13, 18, visnum, 0, 99, 0, 0,
"op1out",       NULL, -1, -1, 14, 18, vistout, 0, 3, 0, 0,
"op1lfo",       NULL, -1, -1, 15, 18, vislfo, 0, 3, 0, 0,
"op1micro",     NULL, -1, -1, 16, 18, visponoff, 0, 1, 0, 0,

"op2max",       NULL, -1, -1, 7, 25, visnum, 0, 8, 0, 0,
"op2voice",     NULL, -1, -1, 3, 24, vispvoice, 0, 159, 0, 0,
"op2rec",       NULL, -1, -1, 8, 25, vischan, 0, 16, 0, 0,
"op2liml",      NULL, -1, -1, 9, 25, visnote, 0, 127, 0, 0,
"op2limh",      NULL, -1, -1, 10, 25, visnote, 0, 127, 0, 0,
"op2detune",    NULL, -1, -1, 11, 25, vistdetune, 0, 14, 0, 0,
"op2shift",     NULL, -1, -1, 12, 25, vispshift, 0, 48, 0, 0,
"op2vol",       NULL, -1, -1, 13, 25, visnum, 0, 99, 0, 0,
"op2out",       NULL, -1, -1, 14, 25, vistout, 0, 3, 0, 0,
"op2lfo",       NULL, -1, -1, 15, 25, vislfo, 0, 3, 0, 0,
"op2micro",     NULL, -1, -1, 16, 25, visponoff, 0, 1, 0, 0,

"op3max",       NULL, -1, -1, 7, 32, visnum, 0, 8, 0, 0,
"op3voice",     NULL, -1, -1, 3, 31, vispvoice, 0, 159, 0, 0,
"op3rec",       NULL, -1, -1, 8, 32, vischan, 0, 16, 0, 0,
"op3liml",      NULL, -1, -1, 9, 32, visnote, 0, 127, 0, 0,
"op3limh",      NULL, -1, -1, 10, 32, visnote, 0, 127, 0, 0,
"op3detune",    NULL, -1, -1, 11, 32, vistdetune, 0, 14, 0, 0,
"op3shift",     NULL, -1, -1, 12, 32, vispshift, 0, 48, 0, 0,
"op3vol",       NULL, -1, -1, 13, 32, visnum, 0, 99, 0, 0,
"op3out",       NULL, -1, -1, 14, 32, vistout, 0, 3, 0, 0,
"op3lfo",       NULL, -1, -1, 15, 32, vislfo, 0, 3, 0, 0,
"op3micro",     NULL, -1, -1, 16, 32, visponoff, 0, 1, 0, 0,

"op4max",       NULL, -1, -1, 7, 39, visnum, 0, 8, 0, 0,
"op4voice",     NULL, -1, -1, 3, 38, vispvoice, 0, 159, 0, 0,
"op4rec",       NULL, -1, -1, 8, 39, vischan, 0, 16, 0, 0,
"op4liml",      NULL, -1, -1, 9, 39, visnote, 0, 127, 0, 0,
"op4limh",      NULL, -1, -1, 10, 39, visnote, 0, 127, 0, 0,
"op4detune",    NULL, -1, -1, 11, 39, vistdetune, 0, 14, 0, 0,
"op4shift",     NULL, -1, -1, 12, 39, vispshift, 0, 48, 0, 0,
"op4vol",       NULL, -1, -1, 13, 39, visnum, 0, 99, 0, 0,
"op4out",       NULL, -1, -1, 14, 39, vistout, 0, 3, 0, 0,
"op4lfo",       NULL, -1, -1, 15, 39, vislfo, 0, 3, 0, 0,
"op4micro",     NULL, -1, -1, 16, 39, visponoff, 0, 1, 0, 0,

"op5max",       NULL, -1, -1, 7, 46, visnum, 0, 8, 0, 0,
"op5voice",     NULL, -1, -1, 3, 45, vispvoice, 0, 159, 0, 0,
"op5rec",       NULL, -1, -1, 8, 46, vischan, 0, 16, 0, 0,
"op5liml",      NULL, -1, -1, 9, 46, visnote, 0, 127, 0, 0,
"op5limh",      NULL, -1, -1, 10, 46, visnote, 0, 127, 0, 0,
"op5detune",    NULL, -1, -1, 11, 46, vistdetune, 0, 14, 0, 0,
"op5shift",     NULL, -1, -1, 12, 46, vispshift, 0, 48, 0, 0,
"op5vol",       NULL, -1, -1, 13, 46, visnum, 0, 99, 0, 0,
"op5out",       NULL, -1, -1, 14, 46, vistout, 0, 3, 0, 0,
"op5lfo",       NULL, -1, -1, 15, 46, vislfo, 0, 3, 0, 0,
"op5micro",     NULL, -1, -1, 16, 46, visponoff, 0, 1, 0, 0,

"op6max",       NULL, -1, -1, 7, 53, visnum, 0, 8, 0, 0,
"op6voice",     NULL, -1, -1, 3, 52, vispvoice, 0, 159, 0, 0,
"op6rec",       NULL, -1, -1, 8, 53, vischan, 0, 16, 0, 0,
"op6liml",      NULL, -1, -1, 9, 53, visnote, 0, 127, 0, 0,
"op6limh",      NULL, -1, -1, 10, 53, visnote, 0, 127, 0, 0,
"op6detune",    NULL, -1, -1, 11, 53, vistdetune, 0, 14, 0, 0,
"op6shift",     NULL, -1, -1, 12, 53, vispshift, 0, 48, 0, 0,
"op6vol",       NULL, -1, -1, 13, 53, visnum, 0, 99, 0, 0,
"op6out",       NULL, -1, -1, 14, 53, vistout, 0, 3, 0, 0,
"op6lfo",       NULL, -1, -1, 15, 53, vislfo, 0, 3, 0, 0,
"op6micro",     NULL, -1, -1, 16, 53, visponoff, 0, 1, 0, 0,

"op7max",       NULL, -1, -1, 7, 60, visnum, 0, 8, 0, 0,
"op7voice",     NULL, -1, -1, 3, 59, vispvoice, 0, 159, 0, 0,
"op7rec",       NULL, -1, -1, 8, 60, vischan, 0, 16, 0, 0,
"op7liml",      NULL, -1, -1, 9, 60, visnote, 0, 127, 0, 0,
"op7limh",      NULL, -1, -1, 10, 60, visnote, 0, 127, 0, 0,
"op7detune",    NULL, -1, -1, 11, 60, vistdetune, 0, 14, 0, 0,
"op7shift",     NULL, -1, -1, 12, 60, vispshift, 0, 48, 0, 0,
"op7vol",       NULL, -1, -1, 13, 60, visnum, 0, 99, 0, 0,
"op7out",       NULL, -1, -1, 14, 60, vistout, 0, 3, 0, 0,
"op7lfo",       NULL, -1, -1, 15, 60, vislfo, 0, 3, 0, 0,
"op7micro",     NULL, -1, -1, 16, 60, visponoff, 0, 1, 0, 0,

"op8max",       NULL, -1, -1, 7, 67, visnum, 0, 8, 0, 0,
"op8voice",     NULL, -1, -1, 3, 66, vispvoice, 0, 159, 0, 0,
"op8rec",       NULL, -1, -1, 8, 67, vischan, 0, 16, 0, 0,
"op8liml",      NULL, -1, -1, 9, 67, visnote, 0, 127, 0, 0,
"op8limh",      NULL, -1, -1, 10, 67, visnote, 0, 127, 0, 0,
"op8detune",    NULL, -1, -1, 11, 67, vistdetune, 0, 14, 0, 0,
"op8shift",     NULL, -1, -1, 12, 67, vispshift, 0, 48, 0, 0,
"op8vol",       NULL, -1, -1, 13, 67, visnum, 0, 99, 0, 0,
"op8out",       NULL, -1, -1, 14, 67, vistout, 0, 3, 0, 0,
"op8lfo",       NULL, -1, -1, 15, 67, vislfo, 0, 3, 0, 0,
"op8micro",     NULL, -1, -1, 16, 67, visponoff, 0, 1, 0, 0,

"microtune",    "Micro Tune Table", 19, 32, 19, 53, visnum, 0, 12, 0, 0,
"microkey",     "Micro Tune Key", 20, 32, 20, 53, viskey, 0, 11, 0, 0,
"assmode",      "Assign Mode", 21, 32, 21, 53, visass, 0, 1, 0, 0,
"effect",       "Effect Select", 22, 32, 22, 53, viseffect, 0, 3, 0, 0,
NULL,   NULL, -1, -1, -1, -1, visnum, 0, 0, 0, 0
};

char *tx81voices[] = {
        "GrandPiano", "Uprt piano", "Deep Grd", "HonkeyTonk", "Elec Grand",
        "Fuzz Piano", "SkoolPiano", "Thump Pno", "LoTine81Z", "HiTine81Z",
        "ElectroPno", "NewElectro", "DynomiteEP", "DynoWurlie", "Wood Piano",
        "Reed Piano", "PercOrgan", "16 8 4 2 F", "PumpOrgan", "<6 Tease>",
        "Farcheeza", "Small Pipe", "Big Church", "AnalogOrgn", "Thin Clav",
        "EZ Clav", "Fuzz Clavi", "LiteHarpsi", "RichHarpsi", "Celeste",
        "BriteCelst", "Squeezebox",

        "Trumpet81Z", "Full Brass", "Flugelhorn", "ChorusBras", "FrenchHorn",
        "AtackBrass", "SpitBoneBC", "Horns BC", "MelloTenor", "RaspAlto",
        "Flute", "Pan Floot", "Bassoon", "Oboe", "Clarinet",
        "Harmonica", "DoubleBass", "BowCello", "BoxCello", "SoloViolin",
        "HiString 1", "LowString", "Pizzicato", "Harp", "ReverbStrg",
        "SynString", "Voices", "HarmoPad", "FanfarTpts", "HiString 2",
        "PercFlute", "BreathOrgn",

        "NylonGuit", "Guitar #1", "TwelveStrg", "Funky Pick", "AllThatJaz",
        "HeavyMetal", "Old Banjo", "Zither", "ElecBass 1", "SqncrBass",
        "SynFunkBas", "ElecBass 2", "AnalogBass", "Jaco Bass", "LatelyBass",
        "MonophBass", "StadiumSol", "TrumptSolo", "BCSexyPhon", "Lyrisyn",
        "WarmSquare", "Sync Lead", "MellowSqar", "Jazz Flute", "HeavyLead",
        "Java Jive", "Xylophone", "GreatVibes   ", "Sitar", "Bell Pad",
        "PlasticHit", "DigiAnnie",

        "BaadBreath", "VocalNuts", "KrstlChoir", "Metalimba", "WaterGlass",
        "BowedBell", ">>WOW<<", "Fuzzy Koto", "Spc Midiot", "Gurgle",
        "Hole in 1", "Birds", "MalibuNite", "Helicopter", "Flight Sim",
        "Brthbells", "Storm Wind", "Alarm Call", "Racing Car", "Whistling",
        "Space Talk", "Space Vibe", "Timpani", "FM Hi-Hats", "Bass Drum",
        "Tube Bells", "Noise Shot", "Snare 1", "Snare 2", "Hand Drum",
        "Synballs", "Efem Toms"
};

/*
 * tx8pdin
 *
 * Take info from 'data' and stuff values in the P array, by using
 * the setval (and setopval) functions.  The data is in PMEM format.
 */

tx8pdin(data)
char *data;
{
        int dop, n, msb;

        for ( n=1; n<=8; n++ ) {
                dop = (n-1)*8;
                setopval(n,"max",data[0+dop] & 017);
                msb = (data[0+dop]>>4)&01;
                setopval(n,"voice",128*msb + (data[1+dop]&0177));
                setopval(n,"rec",data[2+dop] & 037);
                setopval(n,"liml",data[3+dop] & 0177);
                setopval(n,"limh",data[4+dop] & 0177);
                setopval(n,"detune",data[5+dop] & 017);
                setopval(n,"shift",data[6+dop] & 077);
                setopval(n,"vol",data[7+dop] & 0177);
                setopval(n,"out",(data[0+dop]>>5) & 03);
                setopval(n,"lfo",(data[2+dop]>>5) & 03);
                setopval(n,"micro",(data[6+dop]>>6) & 01);
        }
        setval("microtune",data[64] & 017);
        setval("assmode",data[65] & 01);
        setval("effect",(data[65]>>1) & 03);
        setval("microkey",(data[65]>>3) & 017);

        setval("autochan",Channel);
}

/*
 * tx8pdout
 *
 * Take (possibly changed) parameters values out of the P array and
 * put them back into 'data'.
 */

tx8pdout(data)
char *data;
{
        int dop, n, voicenum, msb;

        for ( n=1; n<=8; n++ ) {
                dop = (n-1)*8;
                voicenum = getopval(n,"voice");
                msb = (voicenum>>7)&01;
                data[0+dop] = getopval(n,"max") | (msb<<4)
                                | getopval(n,"out")<<5;
                data[1+dop] = voicenum & 0177;
                data[2+dop] = getopval(n,"lfo")<<5 | getopval(n,"rec");
                data[3+dop] = getopval(n,"liml");
                data[4+dop] = getopval(n,"limh");
                data[5+dop] = getopval(n,"detune");
                data[6+dop] = getopval(n,"micro")<<6 | getopval(n,"shift");
                data[7+dop] = getopval(n,"vol");
        }
        data[64] = getval("microtune");
        data[65] = getval("microkey")<<3 | getval("effect")<<1
                        | getval("assmode");
        Channel = getval("autochan");
}

tx8psedit(data)
char *data;
{
        char pdata[PCEDSIZE];
        int n, cksum, c;
        char *p;

        clrdata(pdata,PCEDSIZE);
        pmemtopced(data,pdata);
        sendmidi(0xf0);
        sendmidi(0x43);
        sendmidi(Channel-1);    /* channel # */
        sendmidi(0x7e);         /* format type */
        sendmidi(0x00);         /* byte count */
        sendmidi(0x78);         /* byte count */
        p = "LM  8976PE";
        cksum = 0;
        while ( (c=(int)(*p++)) != '\0' ) {
                sendmidi(c);
                cksum += c;
        }
        for ( n=0; n<PCEDSIZE; n++ ) {
                c = (int)(pdata[n]);
                sendmidi(c);
                cksum += c;
        }
        sendmidi((-cksum) & 0x7f);
        sendmidi(EOX);
}

/* Convert PMEM to PCED format */
pmemtopced(indata,outdata)
char *indata, *outdata;
{
        int n, inop, outop;

        for ( n=1; n<=8; n++ ) {
                inop = (n-1)*8;
                outop = (n-1)*12;

                outdata[0+outop] = indata[0+inop] & 017;

                outdata[1+outop] = (indata[0+inop]>>4)&01;
                outdata[2+outop] = indata[1+inop] & 0177;
                outdata[3+outop] = indata[2+inop] & 037;
                outdata[4+outop] = indata[3+inop] & 0177;
                outdata[5+outop] = indata[4+inop] & 0177;
                outdata[6+outop] = indata[5+inop] & 017;
                outdata[7+outop] = indata[6+inop] & 077;
                outdata[8+outop] = indata[7+inop] & 0177;
                outdata[9+outop] = (indata[0+inop]>>5) & 03;
                outdata[10+outop] = (indata[2+inop]>>5) & 03;
                outdata[11+outop] = (indata[6+inop]>>6) & 01;
        }
        outdata[96] = indata[64] & 017;
        outdata[97] = indata[65] & 01;
        outdata[98] = (indata[65]>>1) & 03;
        outdata[99] = (indata[65]>>3) & 017;
        for ( n=0; n<10; n++ )
                outdata[100+n] = indata[66+n];
}

/* send a bulk performance dump to the tx81z */
tx8psbulk(data)
char *data;
{
        int c, v, n, cksum;
        char *p;

        sendmidi(0xf0);
        sendmidi(0x43);
        sendmidi(Channel-1);    /* Channel # */
        sendmidi(0x7e);
        sendmidi(0x13);
        sendmidi(0x0a);
        p = "LM  8976PM";
        cksum = 0;
        while ( (c=(int)(*p++)) != '\0' ) {
                sendmidi(c);
                cksum += c;
        }
        /* send 32 PMEM's worth of data */
        for ( v=0; v<32; v++ ) {
                for ( n=0; n<PMEMSIZE; n++ ) {
                        /* 24 PMEM's are editable, but the bulk dump has 32 */
                        if ( v >= 24 )
                                c = 0;
                        else
                                c = VOICEBYTE(data,v,n);
                        sendmidi(c & 0xff);
                        cksum += c;
                }
        }
        sendmidi((-cksum) & 0x7f);
        sendmidi(0xf7);
}

/* Request and read a bulk performance dump from the TX81Z */
tx8pgbulk(data)
char *data;
{
        int c, n, v, b1, b2, cksum, ret = 1;
        long begin, toolong;
        char *p;

        flushmidi();

        sendmidi(0xf0);
        sendmidi(0x43);
        sendmidi(0x20 | (Channel-1));   /* Channel # */
        sendmidi(0x7e);
        p = "LM  8976PM";
        while ( (c=(int)(*p++)) != '\0' )
                sendmidi(c);
        sendmidi(EOX);

        begin = milliclock();
        toolong = begin + 1000 * TIMEOUT;

        /* wait for the x43 byte starting the dump */
        while ( milliclock() < toolong ) {
                if ( STATMIDI && (c=(getmidi() & 0xff)) == 0x43 )
                        break;
        }
        if ( c != 0x43 ) {
                Reason = "Timeout waiting for 0x43";
                goto getout;
        }
        /* get the 14 bytes preceeding the data */
        for ( cksum=n=0; n<14; n++ ) {
                /* twiddle your thumbs, but not forever */
                while ( ! STATMIDI ) {
                        if ( milliclock() > toolong )
                                goto timeout;   /* the end of an era */
                }
                c = getmidi();
                if(n >= 4)
                        cksum += c; /* start of LM... keyword */
        }
        /* 32 memories are dumped */
        for ( v=0; v<32; v++ ) {
                for ( n=0; n<PMEMSIZE; n++ ) {
                        /* twiddle your thumbs, but not forever */
                        while ( ! STATMIDI ) {
                                if ( milliclock() > toolong )
                                        goto timeout;   /* the end of an era */
                        }
                        c = (getmidi() & 0xff);
                        /* Ignore non-data bytes ? */
                        if ( c & 0x80 )
                                continue;
                        /* compute checksum */
                        cksum += c;
                        /* Only 24 memories are used */
                        if ( v < 24 )
                                VOICEBYTE(data,v,n) = c;
                }
        }
timeout:
        if ( v < 32 ) {
                Reason = "Timeout while reading!";
                goto getout;
        }
        b1 = (getmidi() & 0xff);        /* Checksum */
        b2 = (getmidi() & 0xff);        /* EOX */
        cksum = (-cksum) & 0x7f;        /* convert to what we must match */
        if ( b2 != EOX )
                Reason = "EOX not received";
        else if ( b1 != cksum ) {
                static char ckbuff[80];
                sprintf(ckbuff,"Checksum doesn't match (got %d expected %d)",b1,cksum);
                /* Reason = "Checksum doesn't match"; */
                Reason = ckbuff;
        }
        else {
                Reason = "";
                ret = 0;        /* all's well */
        }
getout:
        return(ret);
}

char *
tx8pnof(data)
char *data;
{
        int n;

        for ( n=0; n<10; n++ )
                Pbuff[n] = data[66+n];
        Pbuff[10] = '\0';
        return(Pbuff);
} 

tx8psnof(data,name)
char *data, *name;
{
        int n;

        for ( n=0; name[n]!='\0' && n<10; n++ )
                data[66+n] = name[n];
        for ( ; n<10; n++ )
                data[66+n] = ' ';
} 

char *
visass(v)
{
        switch(v){
        case 0: return("normal");
        case 1: return("alternate");
        }
        return("");
}

char *
viskey(v)
{
        switch(v){
        case 0: return("C");
        case 1: return("C#");
        case 2: return("D");
        case 3: return("D#");
        case 4: return("E");
        case 5: return("F");
        case 6: return("F#");
        case 7: return("G");
        case 8: return("G#");
        case 9: return("A");
        case 10: return("A#");
        case 11: return("B");
        }
        return("");
}

char *
viseffect(v)
{
        switch(v){
        case 0: return("none");
        case 1: return("delay");
        case 2: return("pan");
        case 3: return("chord");
        }
        return("");
}

char *
vischan(v)
{
        if ( v >= 0 && v <= 15 ) {
                sprintf(Pbuff,"%d",v+1);
                return(Pbuff);
        }
        if ( v == 16 )
                return("omni");
        return("");
}

char *
visnote(v)
{
        int octave;

        octave = (v/12) - 2;
        sprintf(Pbuff,"%s%d",viskey(v%12),octave);
        return(Pbuff);
}

char *
vispshift(v)
{
        sprintf(Pbuff,"%d",v-24);
        return(Pbuff);
}

char *
vistdetune(v)
{
        sprintf(Pbuff,"%d",v-7);
        return(Pbuff);
}

char *
vistout(v)
{
        switch (v) {
        case 0: return("off");
        case 1: return("I");
        case 2: return("II");
        case 3: return("I+II");
        }
        return("");
}

char *
vislfo(v)
{
        switch (v) {
        case 0: return("off");
        case 1: return("inst1");
        case 2: return("inst2");
        case 3: return("vib");
        }
        return("");
}

char *
visponoff(v)
{
        switch(v){
        case 0: return("off");
        case 1: return("on");
        }
        return("");
}

char *
vispvoice(v)
{
        char *p, *prefixes = "IABCD";
        int bank, vnum, vindex;

        bank = v/32;
        vnum = (v%32) + 1;
        sprintf(Pbuff,vnum<10?"%c0%d":"%c%d",prefixes[bank],vnum);
        if ( bank > 0 ) {
                vindex = (bank-1)*32+vnum-1;
                if ( vindex >= 0 && vindex < 128 ) {
                        strcat(Pbuff,"~d~l~l~l");
                        p = tx81voices[vindex];
                        if ( strlen(p) <= 5 )
                                strcat(Pbuff,p);
                        else {
                                char buff[11];
                                strcpy(buff,p);
                                buff[5] = '\0';
                                strcat(Pbuff,buff);
                                strcat(Pbuff,"~d~l~l~l~l~l");
                                strcat(Pbuff,&p[5]);
                        }
                }
        }
        return(Pbuff);
}
