/*
(c) Copyright 1988-1994 Microsoft Corporation.

Microsoft Bars&Pipes Professional Source Code License

This License governs use of the accompanying Software.  
Microsoft hopes you find this Software useful.

You are licensed to do anything you want with the Software. 

In return, we simply require that you agree:

1.      Not to remove any copyright notices from the Software.

2.      That the Software comes "as is", with no warranties.  
        None whatsoever. This means no implied warranty of merchantability or 
        fitness for a particular purpose or any warranty of non-infringement.  
        Also, you must pass this disclaimer on whenever you distribute the Software.

3.      That we will not be liable for any of those types of damages known as indirect, 
        special, consequential, or incidental related to the Software or this License, 
        to the maximum extent the law permits. Also, you must pass this limitation of 
        liability on whenever you distribute the Software.

4.      That if you sue anyone over patents that you think may apply to the Software 
        for that person’s use of the Software, your license to the Software ends automatically.

5.      That the patent rights Microsoft is licensing only apply to the Software, 
        not to any derivatives you make.

6.      That your rights under the License end automatically if you breach this in any way.
*/

#include "/CompilerSpecific.h"
#include <libraries/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <string.h>
#include <intuition/intuition.h>
#include "/v.h"

#define ID_QANT 0x51414E54

CHIP static UWORD Quantize[]=
{
/*-------- plane # 0 --------*/

  0x0000,  0x0000,
  0x3fff,  0xfc00,
  0x3000,  0x0c00,
  0x3000,  0x0c00,
  0x3000,  0x0c00,
  0x3000,  0x0c00,
  0x3000,  0x0c00,
  0x3000,  0x0c00,
  0x3000,  0x0c00,
  0x3000,  0x0c00,
  0x3fff,  0xfc00,
  0x0000,  0x0000,

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

  0x0000,  0x0000,
  0x0000,  0x0400,
  0x0f70,  0x0c00,
  0x0f70,  0x0c00,
  0xcc70,  0x0f00,
  0xcff0,  0x0f00,
  0xc00f,  0xff00,
  0xc00f,  0x7f00,
  0x000f,  0x7c00,
  0x000c,  0x7c00,
  0x1fff,  0xfc00,
  0x0000,  0x0000,

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

  0x0000,  0x0000,
  0x0000,  0x0000,
  0x0f7f,  0x7000,
  0x0f7f,  0x7000,
  0x0c7c,  0x7000,
  0x0fff,  0xf000,
  0x0fff,  0xf000,
  0x0f7f,  0x7000,
  0x0f7f,  0x7000,
  0x0c7c,  0x7000,
  0x0000,  0x0000,
  0x0000,  0x0000
};

static struct Image Quantizeimage=
{
  0,0,24,12,3,
  Quantize,
  0x7,0x0,NULL
};

struct QuantizeTool {
    struct Tool tool;
    long tightness;
    short offset;
    short resolution;
    short noteindex;
    long capture;
    short range;
    char on;
    char off;
    char triplet;
};


extern struct Functions *functions;

extern printf();


SAVEDS struct Event *processeventcode(struct NoteEvent *event)
{
    struct QuantizeTool *tool = (struct QuantizeTool *) event->tool;
    long time;
    short res;
    short half;
    long range;
    struct Track *track;
    track = tool->tool.track;
    event->tool = tool->tool.next;
    if (!(event->type & EVENT_PADEDIT) && track) {
        if (!functions->running) return((struct Event *)event);
        if (!tool->tool.intool && (track->mode & TRACK_RECORD) && functions->recording)
            return((struct Event *)event);
    }
    if (!tool->tool.touched) {
        tool->on = 1;
        tool->noteindex = 3;
        tool->resolution = 96;
        tool->tool.touched = TOUCH_INIT;
        tool->capture = 64800;
        tool->range = 48;
        tool->tightness = 64800;
    }
    res = tool->resolution;
    half = res >> 1;
    range = tool->range;
    if (event->status == MIDI_NOTEON) {
        if (!event->velocity) event->status = MIDI_NOTEOFF;
        if (tool->on) {
            time = event->time + half;
            time = IDivU(time,res);
            time = IMulU(time,res);
            time += tool->offset;
            time = time - event->time;
            if ((time >= -range) && (time <= range)) {
                if (tool->tightness < 64800) {
                    time = time * tool->tightness;
                    time = time >> 16;
                }
                event->time += time;
                if (event->time < 0) event->time = 0;
            }
        }
        if (event->type & EVENT_PADEDIT) {
            if (tool->off) {
                time = event->time + event->duration + half;
                time = IDivU(time,res);
                time = IMulU(time,res);
                time = time - (event->time + event->duration);
                time += tool->offset;
                if ((time >= -range) && (time <= range)) {
                    if (tool->tightness < 64800) {
                        time = time*tool->tightness;
                        time = time >> 16;
                    }
                    event->duration += time;
                    if (event->duration < res) event->duration = res;
                    if (event->duration > 60000) event->duration = res;
                }
            }
        }
    }
    if (event->status == MIDI_NOTEOFF) {
        if (tool->off) {
            time = event->time + half;
            time = IDivU(time,res);
            time = IMulU(time,res);
            time += tool->offset;
            time = time - event->time;
            if ((time >= -range) && (time <= range)) {
                if (tool->tightness < 64800) {
                    time = time*tool->tightness;
                    time = time >> 16;
                }
                event->time += time;
                if (event->time < 0) event->time = 0;
            }
        }
    }
    return((struct Event *)event);
}

#ifdef FRENCH
#include "quantwf.c"
/* #else
extern struct NewWindow quantizeNewWindowStructure1; */
#endif

#ifdef GERMAN
#include "quantwg.c"
#endif

#ifdef ENGLISH
#include "quantw.c"
#endif


SAVEDS static long tightroutine(struct Window *window,
                                struct Gadget *gadget,
                                unsigned long x)
{
    char text[20];
    struct RastPort *rp = window->RPort;
    Move(rp,gadget->LeftEdge + gadget->Width + 50,gadget->TopEdge + 7);
    SetAPen(rp,1);
    SetBPen(rp,0);
    SetDrMd(rp,JAM2);
    sprintf(text,"%ld%%   ",x);
    Text(rp,text,4);
    return(long)(x * 649);
}


SAVEDS static long offsetroutine(struct Window *window,
                                 struct Gadget *gadget,
                                 long x)
{
    char text[20];
    struct RastPort *rp = window->RPort;
    Move(rp,gadget->LeftEdge + gadget->Width + 50,gadget->TopEdge + 7);
    SetAPen(rp,1);
    SetBPen(rp,0);
    SetDrMd(rp,JAM2);
    x -= 50;
    if (x <= 0) sprintf(text,"%ld   ",x);
    else sprintf(text,"+%ld  ",x);
    Text(rp,text,4);
    return(x);
}


SAVEDS 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);
    }
}


SAVEDS void edittoolcode(struct QuantizeTool *tool)
{
    struct IntuiMessage *message;
    struct Window *window;
    long class, code;
    char refresh = 1;
    static char *convert[] =
        {"1","1/2","1/4","1/8","1/16","1/32", "1/64"};
    struct Gadget *gadget;
    struct NewWindow *newwindow;
    static struct Menu TitleMenu = {
        NULL,0,0,480,10,MENUENABLED,0,NULL
    };
    char menuname[100];

    strcpy(menuname,"Quantize v 2.2 © 1991,1993 The Blue Ribbon SoundWorks, Ltd.");
    TitleMenu.MenuName = menuname;
    quantizeNewWindowStructure1.Screen = functions->screen;
    if (tool->tool.touched & TOUCH_EDIT) {
        quantizeNewWindowStructure1.LeftEdge = tool->tool.left;
        quantizeNewWindowStructure1.TopEdge = tool->tool.top;
    }
    if (!tool->tool.touched) {
        tool->on = 1;
        tool->noteindex = 3;
        tool->resolution = 96;
        tool->tool.touched = TOUCH_INIT;
        tool->capture = 64800;
        tool->range = 48;
        tool->tightness = 64800;
    }
    newwindow = (struct NewWindow *)
        (*functions->DupeNewWindow)(&quantizeNewWindowStructure1);
    if (!newwindow) return;
    newwindow->Title = NULL;
    newwindow->Flags |= BORDERLESS;
    newwindow->Flags &= ~0xF;
    newwindow->BlockPen = 0;
    newwindow->DetailPen = 0;
    window = (struct Window *)
        (*functions->FlashyOpenWindow)(newwindow);
    if (!window) return;
    SetMenuStrip(window,&TitleMenu);
    tool->tool.window = window;
    (*functions->EmbossWindowOn)(window,WINDOWCLOSE|WINDOWDEPTH|WINDOWDRAG,
        "Quantize",(short)-1,(short)-1,0,0);
    (*functions->EmbossOn)(window,3,0);
    (*functions->EmbossOn)(window,4,1);
    (*functions->EmbossOn)(window,5,1);
    (*functions->EmbossOn)(window,6,1);
    (*functions->FatEmbossedPropOn)(window,1,8,9,(long_cast)tightroutine,101,1);
    (*functions->FatEmbossedPropOn)(window,2,10,11,(long_cast)offsetroutine,101,1);
    (*functions->FatEmbossedPropOn)(window,7,12,13,(long_cast)tightroutine,101,1);
    for (;;) {
        if (refresh) {
            code = tool->noteindex;
            code = 768 / (1 << code);
            if (tool->triplet) code = (code << 1) / 3;
            tool->resolution = code;
            code = code >> 1;
            code = code * tool->capture;
            code = code / 64800;
            tool->range = code;
            setgadgettext(window,3,convert[tool->noteindex]);
            (*functions->ModifyEmbossedProp)(window,1,tool->tightness/648,0,0,0,0,0);
            (*functions->DrawEmbossedProp)(window,1);
            (*functions->ModifyEmbossedProp)(window,2,tool->offset + 50,0,0,0,0,0);
            (*functions->DrawEmbossedProp)(window,2);
            (*functions->ModifyEmbossedProp)(window,7,tool->capture/648,0,0,0,0,0);
            (*functions->DrawEmbossedProp)(window,7);
            (*functions->SelectEmbossed)(window,4,tool->on);
            (*functions->SelectEmbossed)(window,5,tool->off);
            (*functions->SelectEmbossed)(window,6,tool->triplet);
        }
        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) {
            class = gadget->GadgetID;
            switch (class) {
                case 1 :
                    tool->tightness = (*functions->DragEmbossedProp)(window,1);
                    break;
                case 2 :
                    tool->offset = (*functions->DragEmbossedProp)(window,2);
                    break;
                case 3 :
                    tool->noteindex = (*functions->popupnote)(window,tool->noteindex);
                    refresh = 1;
                    break;
                case 7 :
                    tool->capture = (*functions->DragEmbossedProp)(window,7);
                    refresh = 1;
                    break;
                case 8 :
                    tool->tightness = (*functions->ShiftEmbossedProp)(window,1,-1,0);
                    break;
                case 9 :
                    tool->tightness = (*functions->ShiftEmbossedProp)(window,1,1,0);
                    break;
                case 10 :
                    tool->offset = (*functions->ShiftEmbossedProp)(window,2,-1,0);
                    break;
                case 11 :
                    tool->offset = (*functions->ShiftEmbossedProp)(window,2,1,0);
                    break;
                case 12 :
                    tool->capture = (*functions->ShiftEmbossedProp)(window,7,-1,0);
                    refresh = 1;
                    break;
                case 13 :
                    tool->capture = (*functions->ShiftEmbossedProp)(window,7,1,0);
                    refresh = 1;
                    break;
            }
        }
        else if (class == GADGETUP) {
            class = gadget->GadgetID;
            switch (class) {
                case 4 :
                    tool->on = !tool->on;
                    refresh = 1;
                    break;
                case 5 :
                    tool->off = !tool->off;
                    refresh = 1;
                    break;
                case 6 :
                    tool->triplet = !tool->triplet;
                    refresh = 1;
                    break;
            }
        }
    }
    ClearMenuStrip(window);
    tool->tool.window = NULL;
    tool->tool.left = window->LeftEdge;
    tool->tool.top = window->TopEdge;
    tool->tool.width = window->Width;
    tool->tool.height = window->Height;
    tool->tool.touched = TOUCH_EDIT | TOUCH_INIT;
    (*functions->EmbossOff)(window,3);
    (*functions->EmbossOff)(window,4);
    (*functions->EmbossOff)(window,5);
    (*functions->EmbossOff)(window,6);
    (*functions->FatEmbossedPropOff)(window,1,8,9);
    (*functions->FatEmbossedPropOff)(window,2,10,11);
    (*functions->FatEmbossedPropOff)(window,7,12,13);
    functions->EmbossWindowOff(window);
    (*functions->FlashyCloseWindow)(window);
    (*functions->DeleteNewWindow)(newwindow);
}

static struct ToolMaster master;

extern long stdout;


SAVEDS struct ToolMaster *inittoolmaster()
{
    memset((char *)&master,0,sizeof(struct ToolMaster));
    master.toolid = ID_QANT;
    master.image = &Quantizeimage;
    strcpy(master.name,"Quantize");
    master.edittool = (void_cast)edittoolcode;
    master.processevent = (event_cast)processeventcode;
    master.tooltype = TOOL_NORMAL;
    master.toolsize = sizeof(struct QuantizeTool);
    return(&master);
}
