
//      NEW MIDI IN TOOL
//      BY G.O.Jones 1998
//      -----------------

#include "bars.h"
#include <clib/debug_protos.h>
#include <clib/dos_protos.h>
#include <libraries/dos.h>
#include <devices/serial.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <exec/memory.h>
#include <string.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <iffp/debug.h>

#define ID_MIN 0x4D494E
#define LEFT 7
#define TOP  15

struct MsgPort *port;

void removetool(struct OutTool *tool);
void sendsysex(char *buff, short size);
int openserial(char *devicename, int unit);
void closeserial(void);
void starttask(void);
void inputhandle(void);
struct Tool *createtool(struct OutTool *copy);

struct MsgPort  *SerialINMP;         /* Message port pointer */
struct IOExtSer *SerialINIO;         /* I/O request pointer */

struct Task *serialtask;

static struct OutTool *tmp=NULL;

char name[300];
int unit;

static UWORD chip outtool[]=
{
/*-------- plane # 0 --------*/

  0x0000,  0x0000,
  0xffff,  0xfc00,
  0xc000,  0x0c00,
  0xc000,  0x0c00,
  0xc000,  0x0c00,
  0xc000,  0x0c00,
  0xc400,  0x4c00,
  0xc102,  0x0c00,
  0xc030,  0x0c00,
  0xc000,  0x0c00,
  0xffff,  0xfc00,
  0x0000,  0x0000,

/*-------- plane # 1 --------*/

  0x0000,  0x0000,
  0x0000,  0x0c00,
  0x3e31,  0xfc00,
  0x3030,  0x3c00,
  0x2000,  0x1f00,
  0x0000,  0x0f00,
  0x0000,  0x0f00,
  0x2000,  0x1f00,
  0x3000,  0x3c00,
  0x3e01,  0xfc00,
  0x7fff,  0xfc00,
  0x0000,  0x0000,

/*-------- plane # 2 --------*/

  0x0000,  0x0000,
  0x0000,  0x0000,
  0x01ce,  0x0000,
  0x0fcf,  0xc000,
  0x1fff,  0xe000,
  0x3fff,  0xf000,
  0x3bff,  0xb000,
  0x1efd,  0xe000,
  0x0fcf,  0xc000,
  0x01fe,  0x0000,
  0x0000,  0x0000,
  0x0000,  0x0000
};

 struct  Image outtoolimage =
 {
 0,0,
 24 , 12 , 3 ,
 outtool,
 0x7,0x00,
 NULL,
 };

struct OutTool {
                    struct Tool tool;
                    BOOL Note;
                    BOOL Pitch;
                    BOOL MonoAT;
                    BOOL PolyAT;
                    BOOL CChange;
                    BOOL PChange;
                    BOOL SysEx;
               };

extern struct Functions *functions;

// ----------------------------------------------

static struct IntuiText sysexgadText = {
        4,0,JAM1,
        2,1,
        NULL,
        "System Exclusive",
        NULL
};

static struct Gadget sysexgad = {
        NULL,
        LEFT,TOP+66,
        130,9,
        GADGHBOX+GADGHIMAGE,
        RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,
        BOOLGADGET,
        NULL,
        NULL,
        &sysexgadText,
        NULL,
        NULL,
        6,
        NULL
};

static struct IntuiText pchangegadText = {
        4,0,JAM1,
        12,1,
        NULL,
        "Program Change",
        NULL
};

static struct Gadget pchangegad = {
        &sysexgad,
        LEFT,TOP+55,
        130,9,
        GADGHBOX+GADGHIMAGE,
        RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,
        BOOLGADGET,
        NULL,
        NULL,
        &pchangegadText,
        NULL,
        NULL,
        5,
        NULL
};

static struct IntuiText cchangegadText = {
        4,0,JAM1,
        12,1,
        NULL,
        "Control Change",
        NULL
};

static struct Gadget cchangegad = {
        &pchangegad,
        LEFT,TOP+44,
        130,9,
        GADGHBOX+GADGHIMAGE,
        RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,
        BOOLGADGET,
        NULL,
        NULL,
        &cchangegadText,
        NULL,
        NULL,
        4,
        NULL
};

static struct IntuiText polyATgadText = {
        4,0,JAM1,
        5,1,
        NULL,
        "Poly Aftertouch",
        NULL
};

static struct Gadget polyATgad = {
        &cchangegad,
        LEFT,TOP+33,
        130,9,
        GADGHBOX+GADGHIMAGE,
        RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,
        BOOLGADGET,
        NULL,
        NULL,
        &polyATgadText,
        NULL,
        NULL,
        3,
        NULL
};

static struct IntuiText monoATgadText = {
        4,0,JAM1,
        5,1,
        NULL,
        "Mono Aftertouch",
        NULL
};

static struct Gadget monoATgad = {
        &polyATgad,
        LEFT,TOP+22,
        130,9,
        GADGHBOX+GADGHIMAGE,
        RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,
        BOOLGADGET,
        NULL,
        NULL,
        &monoATgadText,
        NULL,
        NULL,
        2,
        NULL
};

static struct IntuiText pitchgadText = {
        4,0,JAM1,
        23,1,
        NULL,
        "Pitch Wheel",
        NULL
};

static struct Gadget pitchgad = {
        &monoATgad,
        LEFT,TOP+11,
        130,9,
        GADGHBOX+GADGHIMAGE,
        RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,
        BOOLGADGET,
        NULL,
        NULL,
        &pitchgadText,
        NULL,
        NULL,
        1,
        NULL
};

static struct IntuiText notegadText = {
        4,0,JAM1,
        22,1,
        NULL,
        "Note On/Off",
        NULL
};

static struct Gadget notegad = {
        &pitchgad,
        LEFT,TOP,
        130,9,
        GADGHBOX+GADGHIMAGE,
        RELVERIFY+GADGIMMEDIATE+TOGGLESELECT,
        BOOLGADGET,
        NULL,
        NULL,
        &notegadText,
        NULL,
        NULL,
        0,
        NULL
};

// ------------------------------------------------

#define GadgetList  notegad;

static struct NewWindow outNewWindowStructure1 = {
        400,100,
        145,95,
        6,1,
        GADGETDOWN+CLOSEWINDOW,
        WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH,
        &notegad,
        NULL,
        "New MIDI In",
        NULL,
        NULL,
        5,5,
        -1,-1,
        CUSTOMSCREEN
};

void setgadgettext(struct Window *window, short id, char *text)
{
    struct Gadget *gadget = (struct Gadget *) (*functions->GetGadget)(window,id);
    if (gadget) {
        gadget->GadgetText->IText = text;
        (functions->DrawEmbossed)(window,id);
    }
}

void edittoolcode(struct OutTool *tool)
{
    struct IntuiMessage *message;
    struct Window *window;
    long class, code;
    short refresh = 1;
    struct Gadget *gadget;
    struct NewWindow *newwindow;

    

    outNewWindowStructure1.Screen = functions->screen;
    if (tool->tool.touched & TOUCH_EDIT) {
        outNewWindowStructure1.LeftEdge = tool->tool.left;
        outNewWindowStructure1.TopEdge = tool->tool.top;
    }
    if (!tool->tool.touched) {
        tool->tool.touched = TOUCH_INIT;

                    tool->Note= TRUE;
                    tool->Pitch= TRUE;
                    tool->MonoAT= TRUE;
                    tool->PolyAT= TRUE;
                    tool->CChange= TRUE;
                    tool->PChange= TRUE;
                    tool->SysEx= FALSE;
    }

    newwindow = (struct NewWindow *)
        (*functions->DupeNewWindow)(&outNewWindowStructure1);
    if (!newwindow) return;
    newwindow->Title = 0;
    newwindow->Flags |= BORDERLESS;
    newwindow->Flags &= ~0xF;
    newwindow->DetailPen = 0;
    newwindow->BlockPen = 0;
    window = (struct Window *)
        (*functions->FlashyOpenWindow)(newwindow);
    if (!window) return;
    tool->tool.window = window;
    (*functions->EmbossWindowOn)(window,WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG,
        "New Midi In",(short)-1,(short)-1,0,0);

    (*functions->EmbossOn)(window,0,1);
    (*functions->EmbossOn)(window,1,1);
    (*functions->EmbossOn)(window,2,1);
    (*functions->EmbossOn)(window,3,1);
    (*functions->EmbossOn)(window,4,1);
    (*functions->EmbossOn)(window,5,1);
    (*functions->EmbossOn)(window,6,1);


    for (;;) {
        if (refresh)
        {

            (*functions->SelectEmbossed)(window,0,tool->Note);
            (*functions->SelectEmbossed)(window,1,tool->Pitch);
            (*functions->SelectEmbossed)(window,2,tool->MonoAT);
            (*functions->SelectEmbossed)(window,3,tool->PolyAT);
            (*functions->SelectEmbossed)(window,4,tool->CChange);
            (*functions->SelectEmbossed)(window,5,tool->PChange);
            (*functions->SelectEmbossed)(window,6,tool->SysEx);

        }
        refresh = 0;
        message = (struct IntuiMessage *) (*functions->GetIntuiMessage)(window);
        class = message->Class;
        code = message->Code;
        gadget = (struct Gadget *) message->IAddress;
        class = (*functions->SystemGadgets)(window,class,gadget,code);
        ReplyMsg((struct Message *)message);
        if (class == CLOSEWINDOW) break;
        else if (class == GADGETDOWN) {


            }


        else if (class == GADGETUP)  {

            switch(gadget->GadgetID)
            {
                      case 0:
                      tool->Note = !tool->Note;
                      refresh = 1;
                      break;

                      case 1:
                      tool->Pitch = !tool->Pitch;
                      refresh = 1;
                      break;

                      case 2:
                      tool->MonoAT = !tool->MonoAT;
                      refresh = 1;
                      break;

                      case 3:
                      tool->PolyAT = !tool->PolyAT;
                      refresh = 1;
                      break;

                      case 4:
                      tool->CChange = !tool->CChange;
                      refresh = 1;
                      break;

                      case 5:
                      tool->PChange = !tool->PChange;
                      refresh = 1;
                      break;

                      case 6:
                      tool->SysEx = !tool->SysEx;
                      refresh = 1;
                      break;

                      default:
                        break;

            }
       }
    }

    (*functions->EmbossOff)(window,0);
    (*functions->EmbossOff)(window,1);
    (*functions->EmbossOff)(window,2);
    (*functions->EmbossOff)(window,3);
    (*functions->EmbossOff)(window,4);
    (*functions->EmbossOff)(window,5);
    (*functions->EmbossOff)(window,6);

    tool->tool.window = 0;
    tool->tool.left = window->LeftEdge;
    tool->tool.top = window->TopEdge;
    tool->tool.touched = TOUCH_INIT | TOUCH_EDIT;
    (*functions->FlashyCloseWindow)(window);
    (*functions->DeleteNewWindow)(newwindow);
}

extern printf();

static struct Event *processeventcode(struct Event *event)
{
    struct OutTool *tool = (struct OutTool *) event->tool;

    tmp = tool;

    if (!tool->tool.touched) {
        tool->tool.touched = TOUCH_INIT;

                    tool->Note= TRUE;
                    tool->Pitch= TRUE;
                    tool->MonoAT= TRUE;
                    tool->PolyAT= TRUE;
                    tool->CChange= TRUE;
                    tool->PChange= TRUE;
                    tool->SysEx= FALSE;
    }

    event->tool = event->tool->next;
return event;
}


static struct ToolMaster master;


void removetool(struct OutTool *tool)
{
    Forbid();
    if (port) DeletePort(port);
    DeleteTask(serialtask);
    closeserial();
    Permit();
}

int openserial(char *devicename, int unit)
{
if (SerialINMP=CreateMsgPort() )
        {
            if (SerialINIO=(struct IOExtSer *)CreateExtIO(SerialINMP,sizeof(struct IOExtSer)) )
            {
                SerialINIO->io_SerFlags |= SERF_SHARED;

                if (OpenDevice(devicename,unit,(struct IORequest *)SerialINIO,0))
                {
                    return 0;
                }
                else
                {
                    SerialINIO->IOSer.io_Command  = SDCMD_QUERY;
                    DoIO((struct IORequest *)SerialINIO);             /* execute query */

                    SerialINIO->IOSer.io_Command  = SDCMD_SETPARAMS;
                    SerialINIO->io_SerFlags &= ~SERF_PARTY_ON;
                    SerialINIO->io_SerFlags|=(SERF_RAD_BOOGIE|SERF_XDISABLED);
                    SerialINIO->io_Baud = 31250;
                    DoIO((struct IORequest *)SerialINIO);

                }
            }
            else return 1;
        }
        else return 2;
return 3;
}

void closeserial(void)
{
    if (SerialINIO)
    {
        if (!(CheckIO(SerialINIO)))
        {
            AbortIO((struct IORequest *)SerialINIO);
        }
        WaitIO((struct IORequest *)SerialINIO);
        CloseDevice((struct IORequest *)SerialINIO);
        DeleteExtIO((struct IORequest *)SerialINIO);
        DeletePort(SerialINMP);
    }
}

void starttask(void)
{
    serialtask = CreateTask("New_Midi_In",0,inputhandle,6000L);
}



void inputhandle(void)
{
    UBYTE *data=NULL;
    struct Event *newevent;
    int channel=0;
    UBYTE command[3];
    LONG rlen;
    struct Track *track;
    struct Tool *tool;

    if((openserial(name, unit)) == 3)
    {
        for(;;)
        {
               SerialINIO->IOSer.io_Flags |= IOF_QUICK;  /* Set QuickIO Flag */
               SerialINIO->IOSer.io_Command  = CMD_READ;
               SerialINIO->IOSer.io_Length   = 1;
               SerialINIO->IOSer.io_Data     = (APTR)command;
               DoIO((struct IORequest *)SerialINIO);
                rlen = 0;

                switch(command[0])
                {
                    

                    case MIDI_SYSX:
                    break;

                    case MIDI_MTC:
                    rlen = 1;
                    break;

                    case MIDI_SONGPP:
                    rlen = 2;
                    break;

                    case MIDI_SONGS:
                    rlen = 1;
                    break;

                    case MIDI_START:
                    rlen = 0;
                    break;

                    case MIDI_STOP:
                    rlen = 0;
                    break;

                    case MIDI_CONTINUE:
                    rlen = 0;
                    break;

                    case MIDI_SENSE:
                    rlen = 0;
                    break;

                    default:

                    channel = command[0];
                    command[0] = command[0]& 0xF0;
                    channel = channel - command[0];

                    switch(command[0])
                    {
                        case MIDI_NOTEON:
                        rlen = 2;
                        break;

                        case MIDI_NOTEOFF:
                        rlen = 2;
                        break;

                        case MIDI_CCHANGE:
                        rlen = 2;
                        break;

                        case MIDI_PCHANGE:
                        rlen = 1;
                        break;

                        case MIDI_PTOUCH:
                        rlen = 2;
                        break;

                        case MIDI_MTOUCH:
                        rlen = 1;
                        break;

                        case MIDI_PBEND:
                        rlen = 2;
                        break;

                        default:
                        break;
                    }
                    break;

                }
            
                if (rlen >0)
                {
                    data = AllocVec(rlen+1, MEMF_CLEAR|MEMF_PUBLIC);

                    SerialINIO->IOSer.io_Command  = CMD_READ;
                    SerialINIO->IOSer.io_Length   = rlen;
                    SerialINIO->IOSer.io_Data     = (APTR)&data[0];
                    DoIO((struct IORequest *)SerialINIO);    /* execute write */

                    newevent = (struct Event *) (*functions->allocevent)();
                    newevent->status = command[0];
                    newevent->type = EVENT_VOICE;

                        switch(command[0])
                        {
                            case MIDI_NOTEON:
                            newevent->byte1 = data[0];
                            newevent->byte2 = data[1];
                            break;

                            case MIDI_NOTEOFF:

                            newevent->byte1 = data[0];
                            newevent->byte2 = 0;
                            break;

                            case MIDI_CCHANGE:
                            newevent->byte1 = data[0];
                            newevent->byte2 = data[1];
                            break;

                            case MIDI_PCHANGE:
                            newevent->byte1 = data[0];
                            newevent->byte2 = 0;
                            break;

                            case MIDI_PTOUCH:
                            newevent->byte1 = data[0];
                            newevent->byte2 = data[1];
                            break;

                            case MIDI_MTOUCH:
                            newevent->byte1 = data[0];
                            newevent->byte2 = data[1];
                            break;

                            case MIDI_PBEND:
                            newevent->byte1 = data[0];
                            newevent->byte2 = data[1];
                            break;
                        }
                }
                else
                {
                    newevent = (struct Event *) (*functions->allocevent)();
                    newevent->status = command[0];
                    newevent->type = EVENT_ONTIME;

                    switch(command[0])
                    {
                        case MIDI_SYSX:
                        break;

                        case MIDI_MTC:
                        newevent->byte1 = command[0];
                        newevent->byte2 = 0;
                        break;

                        case MIDI_SONGPP:
                        newevent->byte1 = command[0];
                        newevent->byte2 = command[1];
                        break;

                        case MIDI_SONGS:
                        newevent->byte1 = command[0];
                        newevent->byte2 = 0;
                        break;

                        case MIDI_START:
                        newevent->byte1 = 0;
                        newevent->byte2 = 0;
                        break;

                        case MIDI_STOP:
                        newevent->byte1 = 0;
                        newevent->byte2 = 0;
                        break;

                        case MIDI_CONTINUE:
                        newevent->byte1 = 0;
                        newevent->byte2 = 0;
                        break;

                        case MIDI_SENSE:
                        newevent->byte1 = 0;
                        newevent->byte2 = 0;
                        break;

                    }
                }
                //--------------------

                track = (struct Track *)functions->tracklist;

                if(functions->multiin && channel == track->channelin)
                {
                    if(functions->tracklist)
                    {
                        for(; track!=NULL; track=track->next)
                        {
                            tool = track->toollist;

                            if(tool)
                                if(tool->toolid == ID_MIN)
                                   tmp->tool = *tool;
                        }
                    }

                    if(tmp && tmp->tool.next)
                    {
                        newevent->time = functions->timenow;
                        newevent->tool = tmp->tool.next;
                        newevent->next = NULL;
                        (*functions->qevent)(newevent);
                    }

                    else
                    {
                        (*functions->freeevent)(newevent);
                    }
               }
               else if(tmp && tmp->tool.next)
               {
                        newevent->time = functions->timenow;
                        newevent->tool = tmp->tool.next;
                        newevent->next = NULL;
                        (*functions->qevent)(newevent);
               }
               else
               {
                   (*functions->freeevent)(newevent);
               }

               if(data){ FreeVec(data); data = NULL;}

       }
   }
   else Wait(0);
}


struct Tool *createtool(struct OutTool *copy)
{
  struct OutTool *tool=(struct OutTool *)functions->myalloc(sizeof(struct OutTool),MEMF_CLEAR);

  if(tool)
  {
    if(copy)
    {
      *tool=*copy;
      tool->tool.next=NULL;
    }
  }
  return (struct Tool *)tool;
}


static void deletetool(struct OutTool *copy)
{
  Forbid();
  tmp = NULL;
  Permit();
  functions->myfree(copy, sizeof(struct OutTool));
}


struct ToolMaster *inittoolmaster()

{
    
    BPTR prefs;
    char un[300];
    int i;

    memset((char *)&master,0,sizeof(struct ToolMaster));
    master.toolsize = sizeof(struct OutTool);
    master.toolid = ID_MIN;
    master.createtool = createtool;
    master.deletetool = deletetool;
    master.edittool = edittoolcode;
    master.removetool = removetool;
    master.image = &outtoolimage;
    strcpy(master.name,"New MIDI In");
    master.processevent = processeventcode;
    master.tooltype = TOOL_ONTIME|TOOL_INPUT;

    prefs = Open("envarc:NewMidiIn.prefs",MODE_OLDFILE);

    if(prefs)
    {
        FGets(prefs,name,299);
        for(i=0; i<299; i++)
        {
            if(isspace(name[i])) break;
        }

        name[i] = NULL;

        FGets(prefs,un,299);
        for(i=0; i<299; i++)
        {
            if(isspace(un[i])) break;
        }

        un[i] = NULL;
        unit = atoi(un);
        Close(prefs);
    }
    else
    {
        return NULL;
    }
    
    starttask();
    
    return(&master);
}



