#include <exec/types.h>
#include <exec/memory.h>
#include <exec/devices.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <devices/audio.h>
#include <devices/trackdisk.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include "rawkey.h"
#include "menus.h"

extern struct DosLibrary *DOSBase;

char IDstring[50] = {"Samplescanner by Steven Lagerweij 160390"};
                                                      /*ddmmyy*/
struct IntuitionBase    *IntuitionBase;
struct GfxBase          *GfxBase;
struct Window           *win,*sswin,*savewin;
struct IntuiMessage     *message;
struct MsgPort          *diskport;
struct IOExtTD          *diskreq;
extern struct MsgPort   *CreatePort();
extern struct IORequest *CreateExtIO();
struct MsgPort          *AudioPort;
struct IOAudio           Audio;

char *LeftMouse = (char *) 0xBFE001;
char Attached[128];
UBYTE Channels[] = { 0x0F };
int AudioDev = NULL;
long to = 0,from = 88;
char file[64];
char dir[64] = {"RAM:"};
struct Gadget *GadgetPtr;
struct MenuItem *Item;
ULONG MessageClass;
USHORT code,MenuItem, GadgetID, block = 0;

long volume = 64, period = 428, drive = 1,val,cnt;

BYTE *diskbuffer, num;

struct Message *GetMsg();

VOID _main()
{
    if((FindUnit("DF1:"))) ThItem2.Flags |= ITEMENABLED;
    if((FindUnit("DF2:"))) ThItem3.Flags |= ITEMENABLED;
    if((FindUnit("DF3:"))) ThItem4.Flags |= ITEMENABLED;
    ThItem1.Flags |= CHECKED; drive = 0;
    OpenAll();
    SetMenuStrip(win,&FirstMenu);
    SetPropTo(block); BufSize(block/88); Grafiek(0);
    for(;;)
       {
        if ((message = (struct IntuiMessage *)
            GetMsg(win->UserPort)) == NULL)
              {
                Wait(1<<win->UserPort->mp_SigBit);
                continue;
              }
        MessageClass = message->Class;
        code      = message->Code;
        ReplyMsg(message);

        if(MessageClass != RAWKEY)
                SetWindowTitles(win,"Sample scanner",NULL);

        switch (MessageClass)
          {
            case CLOSEWINDOW : CloseAll(); break;
            case MENUPICK    : while(code != MENUNULL)
                                 {
                                    MenuItem = ITEMNUM(code);
                                    Item = (struct MenuItem *)
                                           ItemAddress(&FirstMenu, code);
                                    if(WhichMenu(code)) CloseAll();
                                    code = Item->NextSelect;
                                 }
                               break;
            case GADGETUP    : BufSize(ProperInfo.HorizPot/PROPSHIFT);
                               val = ReadBlock(88);
                               if(val != 0)
                                {
                                 if(val > 0)
                                    SetWindowTitles(win,"Error reading disk",NULL);
                                 else {
                                   switch(val) {
                                     case NODISK  : SetWindowTitles(win,"No disk in drive",NULL); break;
                                     case OPENFAIL: SetWindowTitles(win,"Couldn't open trackdisk",NULL); break;
                                     default      : SetWindowTitles(win,"Unspecified error",NULL); break;
                                    }
                                  }
                                 break;
                                }
                               PlayBlock(88);
                               break;
         }
       }
}

BufSize(num)
USHORT num;
{
char tmp[50];
    block = num*88;
    if(block > 1672) block = 1672;
    SetAPen(win->RPort,1);
    sprintf(&tmp[0],"Block: %-4d",block);
    Move(win->RPort,125,18);
    Text(win->RPort,&tmp[0],strlen(&tmp[0]));
    return(0);
}

SetPropTo(num)
USHORT num;
{
    ModifyProp(&ProperGadget,
                win,NULL,
                ProperInfo.Flags,
                ((num/88) * PROPSHIFT), 0,
                ProperInfo.HorizBody,0 );
    return(0);
}


OpenAll()
{
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
GfxBase       = (struct GfxBase *)      OpenLibrary("graphics.library",0);
if(!(win = (struct Window *)OpenWindow(&Newwin)))
 { DisplayBeep(0); CloseAll(); }
if(!(diskbuffer = (BYTE *)AllocMem(88*512,MEMF_CLEAR | MEMF_CHIP)))
 { DisplayBeep(0); Delay(25); DisplayBeep(0); CloseAll(); }
return(0);
}

CloseAll()
{
    if(diskbuffer)    FreeMem(diskbuffer,88*512);
    if(win)           { ClearMenuStrip(win); CloseWindow(win); }
    if(GfxBase)       CloseLibrary(GfxBase);
    if(IntuitionBase) CloseLibrary(IntuitionBase);
exit(0); return(0);
}

struct IORequest *CreateExtIO(ioReplyPort,size) /* create extended I/O */
      struct MsgPort *ioReplyPort;
      LONG size;
{
      struct IORequest *ioReq;

   if(ioReplyPort == 0)
      return((struct IORequest *) 0);

   ioReq = (struct IORequest *)AllocMem (size,MEMF_CLEAR | MEMF_PUBLIC);
   if(ioReq==0)
      return((struct IORequest *) 0);
   ioReq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
   ioReq->io_Message.mn_Node.ln_Pri = 0;
   ioReq->io_Message.mn_ReplyPort = ioReplyPort;
   return(ioReq);
}

DeleteExtIO(ioExt,size) /* Remove Extendend I/O */
   struct IORequest *ioExt;
   LONG size;
{
   ioExt->io_Message.mn_Node.ln_Type = 0xff;
   ioExt->io_Device = (struct Device *) -1;
   ioExt->io_Unit = (struct Unit *) -1;
   FreeMem(ioExt,size);
return(0);
}


ReadBlock(len)
short len;
{
short readerr,ret = -1,dev = TRUE;

   if((block < 0) || (block > 1759)) return(OUTOFRANGE);
   if(!(diskport = CreatePort(0,0))) return(ret);

   if(!(diskreq = (struct IOExtTD *)
        CreateExtIO(diskport,sizeof(struct IOExtTD)))) goto quit;

   if((dev = OpenDevice(TD_NAME,drive,diskreq,0))) goto quit;

   diskreq->iotd_Req.io_Command = TD_CHANGESTATE;
   DoIO(diskreq);
   if(diskreq->iotd_Req.io_Actual != 0) { ret = NODISK; goto quit; }

   diskreq->iotd_Req.io_Length  = 1;
   diskreq->iotd_Req.io_Command = TD_MOTOR;
   DoIO(diskreq);


   diskreq->iotd_Req.io_Length  = len*512;
   diskreq->iotd_Req.io_Data    = (APTR)diskbuffer;
   diskreq->iotd_Req.io_Command = CMD_READ;
   diskreq->iotd_Req.io_Offset  = block*512;
   DoIO(diskreq);

   readerr=diskreq->iotd_Req.io_Error;

   diskreq->iotd_Req.io_Length  = 0;
   diskreq->iotd_Req.io_Command = TD_MOTOR;
   DoIO(diskreq);

   if(readerr != 0) ret = readerr;
   else             ret = 0;
quit:
   if(!dev)     CloseDevice(diskreq);
   if(diskreq)  DeleteExtIO(diskreq,sizeof(struct IOExtTD));
   if(diskport) DeletePort(diskport);
return(ret);
}

PlayBlock(len)
short len;
{
    AudioDev = NULL;
    AudioPort = 0;
    if(!(AudioPort = CreatePort("Audioport scanner"))) goto quit;
    Audio.ioa_Request.io_Message.mn_Node.ln_Pri = 128;
    Audio.ioa_Request.io_Message.mn_ReplyPort   = AudioPort;
    Audio.ioa_Request.io_Command                = ADCMD_ALLOCATE;
    Audio.ioa_Data                              = Channels;
    Audio.ioa_Length                            = (long)sizeof(Channels);

    AudioDev = OpenDevice(AUDIONAME,0,&Audio,0);
    if(AudioDev != NULL) goto quit;
ag:
    Audio.ioa_Request.io_Command = CMD_WRITE;
    Audio.ioa_Request.io_Flags   = ADIOF_PERVOL | ADIOF_SYNCCYCLE;
    Audio.ioa_Request.io_Unit    = (struct Unit *)1;
    Audio.ioa_Data               = (UBYTE *)diskbuffer;
    Audio.ioa_Length             = len*512;
    Audio.ioa_Period             = period;
    Audio.ioa_Volume             = volume;
    Audio.ioa_Cycles             = 1;

    BeginIO(&Audio);
    if(CheckIO(&Audio))
      {
        WaitIO(&Audio);
        goto ag;
      }
    Grafiek(1);
    WaitIO(&Audio);
quit:
    if(!AudioDev)   CloseDevice(&Audio);
    if(AudioPort)   DeletePort(AudioPort);
return(0);
}


Grafiek(from)
int from;
{
    long ybase = 100,x = 44,cnt,bufpos = 0;
    LONG sum,sumlen;

    SetAPen(win->RPort,0);
    RectFill(win->RPort,4,(ybase-65),560,(ybase+85));
    ShowNums(ybase);

    sumlen = (512*88)/512; /* Haha! */

    SetAPen(win->RPort,3);
    Move(win->RPort,x,ybase);
    for(x=44;x<556;x++)
      {
        sum = 0;
        for(cnt=0;cnt<sumlen;cnt++)
           {
             if(((*LeftMouse & 0x40) != 0x40) &&
               (IntuitionBase->ActiveWindow == win))
               {
                 if(from) AbortIO(&Audio);
                 goto quit;
               }
             sum += diskbuffer[bufpos];
             bufpos++;
           }
        sum = (sum / sumlen)/2; /* (average)/2 (/2 = only 128 pixels available)*/
        Draw(win->RPort,x,ybase+sum);
      }
quit:
    return(0);
}


ShowNums(ybase)
long ybase;
{
long cnt,tblk = block;
char tmp[6];
    SetAPen(win->RPort,1);
    Move(win->RPort,2,ybase+3);  Text(win->RPort,"   0",4);
    Move(win->RPort,2,ybase-61); Text(win->RPort,"-128",4);
    Move(win->RPort,2,ybase+67); Text(win->RPort,"+128",4);
    SetAPen(win->RPort,2);
    Move(win->RPort,36,ybase-64);  Draw(win->RPort,36,ybase+64);
    Move(win->RPort,44,ybase+70);  Draw(win->RPort,555,ybase+70);
    SetAPen(win->RPort,1);
    Move(win->RPort,36,ybase);     Draw(win->RPort,40,ybase);
    Move(win->RPort,36,ybase-64);  Draw(win->RPort,40,ybase-64);
    Move(win->RPort,36,ybase+64);  Draw(win->RPort,40,ybase+64);
    for(cnt=44;cnt<557;cnt+=64)
      {
        Move(win->RPort,cnt,ybase+67);
        Draw(win->RPort,cnt,ybase+73);
        Move(win->RPort,cnt-3,ybase+83);
        sprintf(&tmp[0],"%-4d",tblk);
        Text(win->RPort,&tmp[0],4);
        tblk += 11;
      }


return(0);
}

WhichMenu(wcode)
USHORT wcode;
{
   USHORT whichMenu, whichItem, whichSubItem;

   whichMenu     = MENUNUM(wcode);
   whichItem     = ITEMNUM(wcode);
   whichSubItem  = SUBNUM(wcode);

   switch(whichMenu)
   {
      case 0 : /* Options */
               switch(whichItem)
                 {
                   case 1 : return(TRUE);
                   case 0 : BlocksToFile(); break;
                 }
               break;
      case 1 : /* Play */
               switch(whichItem)
                 {
                   case 3 : FilterToggle(); break;
                   case 2 : SampleSets(); break;
                   case 1 :
                            for(block=block;block<1759;block+=88)
                             {
                               BufSize(block/88);
                               SetPropTo(block);
                               if(((*LeftMouse & 0x40) != 0x40) &&
                                 (IntuitionBase->ActiveWindow == win)) goto quit;
                               val = ReadBlock(88);
                               if(val != 0)
                                {
                                 if(val > 0)
                                    SetWindowTitles(win,"Error reading disk",NULL);
                                 else {
                                   switch(val) {
                                     case NODISK  : SetWindowTitles(win,"No disk in drive",NULL); break;
                                     case OPENFAIL: SetWindowTitles(win,"Couldn't open trackdisk",NULL); break;
                                     default      : SetWindowTitles(win,"Unspecified error",NULL); break;
                                    }
                                  }
                                 break;
                                }
                               PlayBlock(88);
                             }
                            block = 0;
                            BufSize(0);
                            SetPropTo(block);
                            break;
                   case 0 : PlayBlock(88); break;
                 }
               break;
      case 2 : /* Options */
               switch(whichItem)
                 {
                   case 3 : ThItem4.Flags |= CHECKED; drive = 3; break;
                   case 2 : ThItem3.Flags |= CHECKED; drive = 2; break;
                   case 1 : ThItem2.Flags |= CHECKED; drive = 1; break;
                   case 0 : ThItem1.Flags |= CHECKED; drive = 0; break;
                 }
               break;
   }
quit:
   return(0);
}


SampleSets()
{
char tmp[10];
    sswin = NULL;
    if(!(sswin = (struct Window *)OpenWindow(&newsswin)))
      { SetWindowTitles(win,"Not enough memory for window",NULL); return(FALSE); }
    ModifyProp(&VolumeGadget, sswin,NULL, VolumeInfo.Flags,
                (MAXBODY/64) * volume, 0, VolumeInfo.HorizBody,0 );
    ModifyProp(&PeriodGadget, sswin,NULL, PeriodInfo.Flags,
                ((MAXBODY/64) * ((period-128)/10)), 0, PeriodInfo.HorizBody,0 );
    for(;;)
      {
        SetAPen(sswin->RPort,1);
        sprintf(&tmp[0],"%-2ld",volume);
        Move(sswin->RPort,22,26);  Text(sswin->RPort,"Volume",6);
        Move(sswin->RPort,145,26); Text(sswin->RPort,&tmp[0],2);

        sprintf(&tmp[0],"%-4ld",period);
        Move(sswin->RPort,22,38); Text(sswin->RPort,"Period",6);
        Move(sswin->RPort,145,38); Text(sswin->RPort,&tmp[0],4);

        if(!(message = (struct IntuiMessage *)GetMsg(sswin->UserPort)))
          {
            Wait(1<<sswin->UserPort->mp_SigBit);
            continue;
          }
        MessageClass = message->Class;
        code         = message->Code;
        GadgetPtr    = (struct Gadget *) message->IAddress;
        GadgetID     = GadgetPtr->GadgetID;
        ReplyMsg(message);


        switch (MessageClass)
          {
            case CLOSEWINDOW : goto quit;
            case GADGETUP    :
              switch(GadgetID)
                {
                  case 1 :volume = (VolumeInfo.HorizPot/(MAXBODY/64));
                          break;
                  case 2 :period = 128+((PeriodInfo.HorizPot/(MAXBODY/64))*10);
                          break;
                }
          }
      }
quit:
    if(sswin) CloseWindow(sswin);
    return(TRUE);
}



BlocksToFile()
{
char tmp[28];
long ret;

    savewin = NULL;
    if(!(savewin = (struct Window *)OpenWindow(&newsavewin)))
      { SetWindowTitles(win,"Not enough memory for window",NULL); return(FALSE); }
    ActivateGadget(&FromGadget,savewin,NULL);
    for(;;)
      {
        SetAPen(savewin->RPort,3);
        sprintf(&tmp[0],"From drive : DF%ld",drive);
        Move(savewin->RPort,10,18);
        Text(savewin->RPort,&tmp[0],16);
        Move(savewin->RPort,10,28);
        Text(savewin->RPort,"From block :",12);
        Move(savewin->RPort,10,38);
        Text(savewin->RPort,"To block   :",12);
        Move(savewin->RPort,10,48);
        Text(savewin->RPort,"To file    :",12);
        if(!(message = (struct IntuiMessage *)GetMsg(savewin->UserPort)))
          {
            Wait(1<<savewin->UserPort->mp_SigBit);
            continue;
          }
        MessageClass = message->Class;
        code         = message->Code;
        GadgetPtr    = (struct Gadget *) message->IAddress;
        GadgetID     = GadgetPtr->GadgetID;
        ReplyMsg(message);

        switch (MessageClass)
          {
            case CLOSEWINDOW : goto quit;
            case GADGETUP    :
                switch(GadgetID)
                  {
/*filename String*/ case 1 : ActivateGadget(&FromGadget,savewin,NULL); break;
/*to gadget */      case 2 : to = atoi(ToBuf);
                             if((to < 0) || (to > 1759))
                               {
                                 to = 1; ToBuf[0] = '1'; ToBuf[1] = '\0';
                                 RefreshGadgets(&ToGadget,savewin,NULL);
                               }
                             ActivateGadget(&StringGadget,savewin,NULL); break;
/* from gadget */   case 3 : from = atoi(Frombuf);
                             if((from < 0) || (from > 1759))
                               {
                                 from = 0; Frombuf[0] = '0'; Frombuf[1] = '\0';
                                 RefreshGadgets(&FromGadget,savewin,NULL);
                               }
                             ActivateGadget(&ToGadget,savewin,NULL); break;
                    case 4 :
                             if(to <= from)
                               {
                                 SetWindowTitles(savewin,"To must be > from",NULL);
                                 break;
                               }
                             if(SaveToFile()) goto quit;
                             break;
                    case 5 :
                             ret = arpreq("GET FILENAME", file, dir,NULL);
                             if((ret != 0) && (file[0] != '\0'))
                               {
                                 Koppel(&dir[0],&file[0]);
                                 sprintf(&StringBuffer[0],"%s",&Attached[0]);
                                 RefreshGadgets(&StringGadget,savewin,NULL);
                               }
                             ActivateGadget(&FromGadget,savewin,NULL);
                             break;

                  }
            break;
          }
      }
quit:
    if(savewin) CloseWindow(savewin);
    return(TRUE);
}

SaveToFile()
{
    long remblk = block,numblk,loop = TRUE,realnum;
    char temp[100],*Fileptr = NULL;

    if(!(Fileptr = (char *)Open(&StringBuffer[0],1006)))
      { SetWindowTitles(savewin,"Couldn't open file",NULL); return(FALSE); }

    numblk = to-from;
    block = from;
    while(loop)
      {
        if(numblk >= 88) realnum = 88;
        else realnum = numblk;

        sprintf(&temp[0],"Reading... %-4ld blks     ",realnum);
        Move(savewin->RPort,10,60);
        Text(savewin->RPort,&temp[0],strlen(&temp[0]));
        val = ReadBlock(realnum);
        if(val != 0)
         {
         if(val > 0)
             SetWindowTitles(win,"Error reading disk",NULL);
         else {
            switch(val) {
             case NODISK   : SetWindowTitles(win,"No disk in drive",NULL); break;
              case OPENFAIL: SetWindowTitles(win,"Couldn't open trackdisk",NULL); break;
              default      : SetWindowTitles(win,"Unspecified error",NULL); break;
             }
           }
           goto quit;
         }
        sprintf(&temp[0],"Writing... %-4ld blks left",numblk);
        Move(savewin->RPort,10,60);
        Text(savewin->RPort,&temp[0],strlen(&temp[0]));
        if(Write(Fileptr,diskbuffer,realnum*512) != realnum*512)
         {
           SetWindowTitles(win,"Error while writing !",NULL);
           Delay(25);
           loop = FALSE;
         }
        numblk -= realnum; block += realnum;
        if(numblk < 1) loop = FALSE;
      }
quit:
    if(Fileptr) Close(Fileptr);

block = remblk;
return(TRUE);
}

FindUnit(devname)
char *devname;
{
struct   DeviceList    *zoekdev;
char isithim[50];
zoekdev = (struct DeviceList *) BADDR(((struct DosInfo *)
       BADDR(((struct RootNode *) (DOSBase->dl_Root))->rn_Info))->di_DevInfo);

while(zoekdev != 0)
    {
        sprintf(&isithim[0],"%s:",BADDR(zoekdev->dl_Name)+1);
        if((zoekdev->dl_Type == DLT_DEVICE) &&
           (stcpma(devname,&isithim[0])))
            return(TRUE);
        zoekdev = (struct DeviceList *)BADDR(zoekdev->dl_Next);
    }
return(FALSE);
}


Koppel(dirname,filename) /* Fix arpreq result */
char dirname[64],filename[64];
{
    if(dirname[0] == '\0')
       { sprintf(&Attached[0],"%s",&filename[0]); return(0); };

    if((dirname[strlen(&dirname[0])-1] != ':') &&
       (dirname[strlen(&dirname[0])-1] != '/'))
       sprintf(&Attached[0],"%s/%s",&dirname[0],&filename[0]);
    else                    /* ^ !!!! */
       sprintf(&Attached[0],"%s%s",&dirname[0],&filename[0]);

return(0);
}


