/*
 * GLIB - a Generic LIBrarian and editor for synths
 *
 * DW8000 Librarian
 *
 * Code completed 8/24/87 --  Steven A. Falco  moss!saf
 */

#define OVERLAY2

#include "glib.h"

#define DW8VSIZE 51

char *visnum(), *visd8wave(), *visd8oct(), *visd8trk();
char *visd8ival(), *visd8detu(), *visd8asel(), *dw8vnum(), *visd8amod();
char *visd8mgw(), *visd8mode(), *visd8pol(),*visd8sem(), *visonoff();

/* This array contains arbitrary screen labels */
struct labelinfo Ldw800[] = {
 2,0,"+----------------------------------+----------------+------------------+------+",
 3,0,"|         Osc 1     Osc 2     Noise|          ModGen|          AutoBend| Mode |",
 4,0,"|Octave",4,35,"|Waveform",4,52,"|Select",4,71,"|      |",
 5,0,"|Waveform",5,35,"|Frequency",5,52,"|Mode",5,71,"|      |",
 6,0,"|Level",6,35,"|Delay",6,52,"|Time",6,71,"|      |",
 7,0,"|Interval",7,35,"|Osc",7,52,"|Intensity",7,71,"|      |",
 8,0,"|Detune",8,35,"|VCF",8,52,"|",8,71,"|      |",
 9,0,"+------------------+---------------+----------------+------------------+------+",
10,0,"|",10,11,"VCF  VCA|",10,30,"Delay|    Joystick    |     Portamento   |Key   |",
11,0,"|Attack",11,19,"|Time",11,35,"|Osc",11,52,"|Time",11,71,"|Param |",
12,0,"|Decay",12,19,"|Factor",12,35,"|VCF",12,52,"|",12,71,"|      |",
13,0,"|Break Pt.",13,19,"|Feedback",13,35,"+----------------+------------------+------+",
14,0,"|Slope",14,19,"|Frequency      |",
15,0,"|Sustain",15,19,"|Intensity      | +-------------------------+--------------+",
16,0,"|Release",16,19,"|Eff.Level      | |Space = Play Note",16,63,"| Auto-Note    |",
17,0,"|V.Sensitv",17,19,"+---------------+ |",17,63,"|",17,78,"|",
18,0,"|Cutoff",18,19,"|       AftTouch| |h = left   q = quit      |Pitch",18,78,"|",
19,0,"|Resonance",19,19,"|Osc.MG",19,35,"| |j = down   N = Set Name  |Duration      |",
20,0,"|Tracking",20,19,"|VCF",20,35,"| |k = up     J = Decrement |Volume",20,78,"|",
21,0,"|Polarity",21,19,"|VCA",21,35,"| |l = right  K = Increment |Channel       |",
22,0,"|EG.Intens",22,19,"|",22,35,"| |",22,63,"|",22,78,"|",
23,0,"+------------------+---------------+ +-------------------------+--------------+",
-1,-1,NULL
};

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

"o1oct",        NULL,   -1,-1,  4, 10, visd8oct,        0,   3, 0, 0,
"o1wave",       NULL,   -1,-1,  5, 10, visd8wave,       0,  15, 0, 0,
"o1lev",        NULL,   -1,-1,  6, 10, visnum,          0,  31, 0, 0,
"o2oct",        NULL,   -1,-1,  4, 20, visd8oct,        0,   3, 0, 0,
"o2wave",       NULL,   -1,-1,  5, 20, visd8wave,       0,  15, 0, 0,
"o2lev",        NULL,   -1,-1,  6, 20, visnum,          0,  31, 0, 0,
"o2ival",       NULL,   -1,-1,  7, 20, visd8ival,       0,   7, 0, 0,
"o2detu",       NULL,   -1,-1,  8, 20, visd8detu,       0,   7, 0, 0,
"noise",        NULL,   -1,-1,  6, 30, visnum,          0,  31, 0, 0,

"mgwave",       NULL,   -1,-1,  4, 46, visd8mgw,        0,   3, 0, 0,
"mgfrew",       NULL,   -1,-1,  5, 46, visnum,          0,  31, 0, 0,
"mgdela",       NULL,   -1,-1,  6, 46, visnum,          0,  31, 0, 0,
"mgosc",        NULL,   -1,-1,  7, 46, visnum,          0,  31, 0, 0,
"mgvcf",        NULL,   -1,-1,  8, 46, visnum,          0,  31, 0, 0,

"abndsel",      NULL,   -1,-1,  4, 63, visd8asel,       0,   3, 0, 0,
"abndmod",      NULL,   -1,-1,  5, 63, visd8amod,       0,   1, 0, 0,
"abndtim",      NULL,   -1,-1,  6, 63, visnum,          0,  31, 0, 0,
"abndins",      NULL,   -1,-1,  7, 63, visnum,          0,  31, 0, 0,

"mode",         NULL,   -1,-1,  4, 72, visd8mode,       0,   3, 0, 0,

"fatt",         NULL,   -1,-1, 11, 11, visnum,          0,  31, 0, 0,
"fdec",         NULL,   -1,-1, 12, 11, visnum,          0,  31, 0, 0,
"fbrk",         NULL,   -1,-1, 13, 11, visnum,          0,  31, 0, 0,
"fslp",         NULL,   -1,-1, 14, 11, visnum,          0,  31, 0, 0,
"fsus",         NULL,   -1,-1, 15, 11, visnum,          0,  31, 0, 0,
"frel",         NULL,   -1,-1, 16, 11, visnum,          0,  31, 0, 0,
"fsens",        NULL,   -1,-1, 17, 11, visnum,          0,   7, 0, 0,
"fcut",         NULL,   -1,-1, 18, 11, visnum,          0,  63, 0, 0,
"fres",         NULL,   -1,-1, 19, 11, visnum,          0,  31, 0, 0,
"ftrk",         NULL,   -1,-1, 20, 11, visd8trk,        0,   3, 0, 0,
"fpol",         NULL,   -1,-1, 21, 11, visd8pol,        0,   1, 0, 0,
"fegi",         NULL,   -1,-1, 22, 11, visnum,          0,  31, 0, 0,
"aatt",         NULL,   -1,-1, 11, 16, visnum,          0,  31, 0, 0,
"adec",         NULL,   -1,-1, 12, 16, visnum,          0,  31, 0, 0,
"abrk",         NULL,   -1,-1, 13, 16, visnum,          0,  31, 0, 0,
"aslp",         NULL,   -1,-1, 14, 16, visnum,          0,  31, 0, 0,
"asus",         NULL,   -1,-1, 15, 16, visnum,          0,  31, 0, 0,
"arel",         NULL,   -1,-1, 16, 16, visnum,          0,  31, 0, 0,
"asens",        NULL,   -1,-1, 17, 16, visnum,          0,   7, 0, 0,

"dtim",         NULL,   -1,-1, 11, 30, visnum,          0,   7, 0, 0,
"dfact",        NULL,   -1,-1, 12, 30, visnum,          0,  15, 0, 0,
"dfeed",        NULL,   -1,-1, 13, 30, visnum,          0,  15, 0, 0,
"dfreq",        NULL,   -1,-1, 14, 30, visnum,          0,  31, 0, 0,
"dintns",       NULL,   -1,-1, 15, 30, visnum,          0,  31, 0, 0,
"deff",         NULL,   -1,-1, 16, 30, visnum,          0,  15, 0, 0,

"atosc",        NULL,   -1,-1, 19, 27, visnum,          0,   3, 0, 0,
"atvcf",        NULL,   -1,-1, 20, 27, visnum,          0,   3, 0, 0,
"atvca",        NULL,   -1,-1, 21, 27, visnum,          0,   3, 0, 0,

"joyosc",       NULL,   -1,-1, 11, 40, visd8sem,        0,  15, 0, 0,
"joyvcf",       NULL,   -1,-1, 12, 40, visonoff,        0,   1, 0, 0,

"portam",       NULL,   -1,-1, 11, 58, visnum,          0,  31, 0, 0,

"vnumb",        NULL,   -1,-1, 12, 72, dw8vnum,         0,  63, 0, 0,

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

/*
 * dw8vnum
 *
 * Convert a voice number (0 to 63) to the string displayed in the
 * librarian (ie. 11 to 88).
 */

char *
dw8vnum(n)
{
        static char v[3];

        if ( n < 0 || n > 63 )
                return("??");

        v[0] = n/8 + '1';
        v[1] = n%8 + '1';
        v[2] = '\0';
        return(v);
}

/*
 * dw8numv
 *
 * Convert a display-style voice number (11 to 88) to internal
 * format (0 - 63).
 */

dw8numv(n)
int n;
{
        int ld, rd;
        
        /* crack out the digits as octal codes */
        ld = (n / 10) - 1; /* left digit */
        rd = (n % 10) - 1; /* right digit */
        
        if(ld < 0 || ld > 7 || rd < 0 || rd > 7) {
                return(-1);
        } else {
                return(ld * 8 + rd); /* combine as octal */
        }
}

/*
 * dw8din
 *
 * Take library bank 'data' and stuff values in the P array, by using
 * the setval function.
 */

dw8din(data)
char *data;
{
        /* The first 20 bytes are reserved (arbitrarily) for the voice name */
        setval("o1oct",data[20]);
        setval("o1wave",data[21]);
        setval("o1lev",data[22]);
        setval("abndsel",data[23]);
        setval("abndmod",data[24]);
        setval("abndtim",data[25]);
        setval("abndins",data[26]);     
        setval("o2oct",data[27]);
        setval("o2wave",data[28]);
        setval("o2lev",data[29]);
        setval("o2ival",data[30]);
        setval("o2detu",data[31]);
        setval("noise",data[32]);
        setval("mode",data[33]);
        setval("vnumb",data[34]);
        setval("fcut",data[35]);
        setval("fres",data[36]);
        setval("ftrk",data[37]);
        setval("fpol",data[38]);
        setval("fegi",data[39]);
        setval("fatt",data[40]);
        setval("fdec",data[41]);
        setval("fbrk",data[42]);
        setval("fslp",data[43]);
        setval("fsus",data[44]);
        setval("frel",data[45]);
        setval("fsens",data[46]);
        setval("aatt",data[47]);
        setval("adec",data[48]);
        setval("abrk",data[49]);
        setval("aslp",data[50]);
        setval("asus",data[51]);
        setval("arel",data[52]);
        setval("asens",data[53]);
        setval("mgwave",data[54]);
        setval("mgfrew",data[55]);
        setval("mgdela",data[56]);
        setval("mgosc",data[57]);
        setval("mgvcf",data[58]);
        setval("joyosc",data[59]);
        setval("joyvcf",data[60]);
        setval("dtim",data[61]);
        setval("dfact",data[62]);
        setval("dfeed",data[63]);
        setval("dfreq",data[64]);
        setval("dintns",data[65]);
        setval("deff",data[66]);
        setval("portam",data[67]);
        setval("atosc",data[68]);
        setval("atvcf",data[69]);
        setval("atvca",data[70]);

        /* We set the 'auto-note' channel upon entry */
        setval("autochan",Channel);
}

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

dw8dout(data)
char *data;
{
        data[20] = getval("o1oct");
        data[21] = getval("o1wave");
        data[22] = getval("o1lev");
        data[23] = getval("abndsel");
        data[24] = getval("abndmod");
        data[25] = getval("abndtim");
        data[26] = getval("abndins");
        data[27] = getval("o2oct");
        data[28] = getval("o2wave");
        data[29] = getval("o2lev");
        data[30] = getval("o2ival");
        data[31] = getval("o2detu");
        data[32] = getval("noise");
        data[33] = getval("mode");
        data[34] = getval("vnumb");
        data[35] = getval("fcut");
        data[36] = getval("fres");
        data[37] = getval("ftrk");
        data[38] = getval("fpol");
        data[39] = getval("fegi");
        data[40] = getval("fatt");
        data[41] = getval("fdec");
        data[42] = getval("fbrk");
        data[43] = getval("fslp");
        data[44] = getval("fsus");
        data[45] = getval("frel");
        data[46] = getval("fsens");
        data[47] = getval("aatt");
        data[48] = getval("adec");
        data[49] = getval("abrk");
        data[50] = getval("aslp");
        data[51] = getval("asus");
        data[52] = getval("arel");
        data[53] = getval("asens");
        data[54] = getval("mgwave");
        data[55] = getval("mgfrew");
        data[56] = getval("mgdela");
        data[57] = getval("mgosc");
        data[58] = getval("mgvcf");
        data[59] = getval("joyosc");
        data[60] = getval("joyvcf");
        data[61] = getval("dtim");
        data[62] = getval("dfact");
        data[63] = getval("dfeed");
        data[64] = getval("dfreq");
        data[65] = getval("dintns");
        data[66] = getval("deff");
        data[67] = getval("portam");
        data[68] = getval("atosc");
        data[69] = getval("atvcf");
        data[70] = getval("atvca");

        /* If the autochan parameter has changed, update Channel */
        Channel = getval("autochan");
}

/*
 * dw8sedit
 *
 * Send a single voice to the edit buffer of the DW8000.  This will be whatever
 * voice is currently selected.
 */

dw8sedit(data)
char *data;
{
        int n;
        
        sendmidi(0xf0);
        sendmidi(0x42);
        sendmidi(0x30 | (Channel - 1));
        sendmidi(0x03);
        sendmidi(0x40);
        for(n = 0; n < DW8VSIZE; n++) {
                sendmidi(data[n + 20] & 0x7f);
        }
        sendmidi(EOX);
}

/*
 * dw8nof
 *
 * Return a pointer to the voice name buried in library bank data.
 */
char *
dw8nof(data)
char *data;
{
        static char currbuff[17];
        char *p;
        int m;

        p = currbuff;
        for ( m=0; m<16; m++ )
                *p++ = data[m];
        *p = '\0';
        return(currbuff);
}

/*
 * dw8snof
 *
 * Set the voice name buried in data to name.
 */
dw8snof(data,name)
char *data;
char *name;
{
        char *p;
        int m;

        for ( p=name,m=0; *p!='\0' && m<16; p++,m++ )
                data[m] = *p;
        for ( ; m<16; m++ )
                data[m] = ' ';
}

/* dw8sone - send a single voice to the DW8000 */
dw8sone(iv, data)
int iv;
char *data;
{
        int c, b2, ret = 1;
        long begin, toolong;

        /* select voice n */
        sendmidi(0xc0 | (Channel - 1));
        sendmidi(iv);
        
        /* send data */
        dw8sedit(data);
        
        /* request write */
        sendmidi(0xf0);
        sendmidi(0x42);
        sendmidi(0x30 | (Channel - 1));
        sendmidi(0x03);
        sendmidi(0x11); /* write request */
        sendmidi(iv);   /* the now-current voice */
        sendmidi(EOX);
        
        /* read the ack/nack - set up for timeout */
        begin = milliclock();
        toolong = begin + 1000 * TIMEOUT;

        /* wait for the 0x03 byte (dw8000 ID byte) */
        while ( milliclock() < toolong ) {
                if ( STATMIDI && (c=(getmidi() & 0xff)) == 0x03 )
                        break;
        }
        if ( c != 0x03 ) {
                Reason = "Timeout waiting for 0x03";
                goto getout;
        }
        
        /* next byte is the result code */
        while((b2 = getmidi() & 0xff) == 0xfe)
                ; /* burn active sensing */
        if(b2 != 0x21) {
                Reason = "Write failed - check protect switch!";
                goto getout;
        }

        while((b2 = getmidi() & 0xff) == 0xfe)
                ;       /* want EOX - burn active sensing */
        if ( b2 != EOX )
                Reason = "EOX not received";
        else {
                Reason = "";
                ret = 0;        /* all's well */
        }
        
getout:
        return(ret);
}

/* dw8gbulk - Request and read a bulk dump from the DW8000 */
dw8gbulk(data)
char *data;
{
        int c, n, v, b2, ret = 1;
        long begin, toolong;

        flushmidi();

        for(v = 0; v < Nvoices; v++) {
                /* select voice */
                sendmidi(0xc0 | (Channel - 1));
                sendmidi(v);
                
                /* request the voice */
                sendmidi(0xf0);
                sendmidi(0x42);
                sendmidi(0x30 | (Channel-1));   /* Channel # */
                sendmidi(0x03);
                sendmidi(0x10); 
                sendmidi(EOX);
        
                /* set up for timeout */
                begin = milliclock();
                toolong = begin + 1000 * TIMEOUT;
        
                /* wait for the x40 byte starting the dump */
                while ( milliclock() < toolong ) {
                        if ( STATMIDI && (c=(getmidi() & 0xff)) == 0x40 )
                                break;
                }
                if ( c != 0x40 ) {
                        Reason = "Timeout waiting for 0x40";
                        goto getout;
                }
                
                /* now read 51 bytes of voice data */
                for(n = 0; n < DW8VSIZE; n++) {
                        /* twiddle your thumbs, but not forever */
                        while ( ! STATMIDI ) {
                                if ( milliclock() > toolong )
                                        goto timeout;   /* the end of an era */
                        }
                        while((b2 = getmidi() & 0xff) == 0xfe)
                                ; /* burn active sensing */
                        VOICEBYTE(data,v,n + 20) = b2;  
                }

        timeout:
                if ( n != DW8VSIZE ) {
                        Reason = "Timeout while reading!";
                        goto getout;
                }
                while((b2 = getmidi() & 0xff) == 0xfe)
                        ;       /* want EOX - burn active sensing */
                if ( b2 != EOX )
                        Reason = "EOX not received";
                else {
                        Reason = "";
                        ret = 0;        /* all's well */
                }
        } /* go back for another voice */
        
getout:
        return(ret);
}

/*
 * Below are functions used for display of parameter values
 */

char *
visd8wave(v)
{
        switch (v) {
        case 0: return("ramp");
        case 1: return("square");
        case 2: return("ac. piano");
        case 3: return("el. piano");
        case 4: return("hd. piano");
        case 5: return("clavinet");
        case 6: return("organ");
        case 7: return("brass");
        case 8: return("sax");
        case 9: return("violin");
        case 10: return("a. guitar");
        case 11: return("d. guitar");
        case 12: return("el. bass");
        case 13: return("dg. bass");
        case 14: return("bell");
        case 15: return("sine");
        }
        return("*");
}

char *
visd8oct(v)
{
        switch(v) {
        case 0: return("16");
        case 1: return("8");
        case 2: return("4");
        case 3: return("*");
        }
        return("*");
}

char *
visd8ival(v)
{       
        switch(v) {
        case 0: return("unison");
        case 1: return("min 3rd");
        case 2: return("maj 3rd");
        case 3: return("4th");
        case 4: return("5th");
        case 5: case 6: case 7: return("*");
        }
        return("*");
}

char *
visd8detu(v)
{
        switch(v) {
        case 0: return("in tune");
        case 1: return("1 cent");
        case 2: return("2 cents");
        case 3: return("3 cents");
        case 4: return("4 cents");
        case 5: return("5 cents");
        case 6: return("6 cents");
        case 7: return("*");
        }
        return("*");
}

char *Semicode[] = {
        "none",
        "1 semitone",
        "2 semitones",
        "3 semitones",
        "4 semitones",
        "5 semitones",
        "6 semitones",
        "7 semitones",
        "8 semitones",
        "9 semitones",
        "10 semitones",
        "11 semitones",
        "1 octave"
};

char *
visd8sem(v)
{
        if(v >= 0 && v <= 12) {
                return(Semicode[v]);
        }
        return("*");
}

char *
visd8asel(v)
{
        switch(v) {
        case 0: return("off");
        case 1: return("Osc 1");
        case 2: return("Osc 2");
        case 3: return("Osc 1+2");
        }
        return("*");
}

char *
visd8amod(v)
{
        switch(v) {
        case 0: return("Up");
        case 1: return("Down");
        }
        return("*");
}

char *
visd8pol(v)
{
        switch(v) {
        case 0: return("/-\\");
        case 1: return("\\_/");
        }
        return("*");
}

char *
visd8mode(v)
{
        switch(v) {
        case 0: return("Poly 1");
        case 1: return("Poly 2");
        case 2: return("Uni 1");
        case 3: return("Uni 2");
        }
        return("*");
}

char *
visd8mgw(v)
{
        switch(v) {
        case 0: return("/\\");
        case 1: return("|\\");
        case 2: return("/|");
        case 3: return("_|-|");
        }
        return("*");
}

char *
visd8trk(v)
{
        switch(v) {
        case 0: return("0");
        case 1: return("1/4");
        case 2: return("1/2");
        case 3: return("1");
        }
        return("*");
}

/* end */
