#ifndef MAKE_ID
#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))
#endif

#ifdef _DCC
#define __inline
#endif


#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <midi/midi.h>
#include <sys/types.h>
#include <utility/hooks.h>
#include <libraries/mui.h>
#include <proto/muimaster.h>
#include <clib/exec_protos.h>
#include <exec/memory.h>
#include <clib/alib_protos.h>


#define HOOK __saveds __asm
#define A0(stuff) register __a0 stuff
#define A1(stuff) register __a1 stuff
#define A2(stuff) register __a2 stuff

UBYTE Velocity=63;
UBYTE MidiChannel=1;

struct ObjApp
{
	APTR	App;
	APTR	WI_Principale;
	APTR	BT_2;
	APTR	BT_3;
	APTR	BT_5;
	APTR	BT_6;
	APTR	BT_7;
	APTR	BT_A;
	APTR	BT_Z;
	APTR	BT_E;
	APTR	BT_R;
	APTR	BT_T;
	APTR	BT_Y;
	APTR	BT_U;
	APTR	BT_I;
	APTR	BT_S;
	APTR	BT_D;
	APTR	BT_G;
	APTR	BT_H;
	APTR	BT_J;
	APTR	BT_W;
	APTR	BT_X;
	APTR	BT_C;
	APTR	BT_V;
	APTR	BT_B;
	APTR	BT_N;
	APTR	BT_Virgule;
	APTR	BT_PointVirg;
	APTR	SL_velocity;
	APTR	SL_MidiChannel;
};

struct MRoute *RouteOut;
struct MSource *source;
struct ObjApp * App;
struct Library		*MidiBase	= NULL;
struct Library		*MUIMasterBase	= NULL;


ULONG HOOK NoteOn(A0(struct Hook *hook),A2(APTR object),A1(LONG* notenumber))
{
	UBYTE buf[3];
	int len=3;


		buf[0]=	0x90 + ((MidiChannel-1) & 0x0f);
		buf[1]=	(UBYTE)(*notenumber);
		buf[2]=	Velocity;
		
		PutMidiStream(source,NULL,buf,len,len);		

	return 0;
}


ULONG HOOK NoteOff(A0(struct Hook *hook),A2(APTR object),A1(LONG* notenumber))
{
	UBYTE buf[3];
	int len=3;

		buf[0]=	0x80 + ((MidiChannel-1) & 0x0f);
		buf[1]=	(UBYTE)(*notenumber);
		buf[2]=	0x3f;
		
		PutMidiStream(source,NULL,buf,len,len);		

	return 0;
}

ULONG HOOK VelocityChange(A0(struct Hook *hook),A2(APTR object),A1(APTR message))
{
	LONG i;
	ULONG *address=message;
	struct ObjApp *obj=(struct ObjApp *)*address;

	get(obj->SL_velocity,MUIA_Slider_Level,&i);
	Velocity = (UBYTE)i;
	return 0;
}

ULONG HOOK MidiChannelChange(A0(struct Hook *hook),A2(APTR object),A1(APTR message))
{
	LONG i;
	ULONG *address=message;
	struct ObjApp *obj=(struct ObjApp *)*address;

	get(obj->SL_MidiChannel,MUIA_Slider_Level,&i);
	MidiChannel = (UBYTE)i;
	return 0;
}

struct ObjApp * CreateApp(void)
{
	struct ObjApp * Object;

	APTR	GROUP_ROOT_0, GR_alt_aigu, Space_0, Space_1, Space_2, Space_3, Space_4;
	APTR	Space_5, GR_nat_aigu, Space_7, GR_alt_grave, Space_8, Space_9, Space_10;
	APTR	Space_11, Space_12, Space_13, GR_nat_grave, Space_14, obj_aux0, obj_aux1;
	APTR	obj_aux2, obj_aux3;
	static const struct Hook NoteOnHook = { { NULL,NULL },(VOID *)NoteOn,NULL,NULL };
	static const struct Hook NoteOffHook = { { NULL,NULL },(VOID *)NoteOff,NULL,NULL };
	static const struct Hook VelocityChangeHook = { { NULL,NULL },(VOID *)VelocityChange,NULL,NULL };
	static const struct Hook MidiChannelChangeHook = { { NULL,NULL },(VOID *)MidiChannelChange,NULL,NULL };


	if (!(Object = AllocVec(sizeof(struct ObjApp), MEMF_PUBLIC|MEMF_CLEAR)))
		return(NULL);

	Space_0 = HSpace(0);

	Object->BT_2 = SimpleButton("_2 C#4");

	Object->BT_3 = SimpleButton("_3 D#4");

	Space_1 = HSpace(0);

	Space_2 = HSpace(0);

	Object->BT_5 = SimpleButton("_5 F#4");

	Object->BT_6 = SimpleButton("_6 G#4");

	Object->BT_7 = SimpleButton("_7 A#4");

	Space_3 = HSpace(0);

	Space_4 = HSpace(0);

	Space_5 = HSpace(0);

	GR_alt_aigu = GroupObject,
		MUIA_HelpNode, "GR_alt_aigu",
		MUIA_Group_Horiz, TRUE,
		Child, Space_0,
		Child, Object->BT_2,
		Child, Object->BT_3,
		Child, Space_1,
		Child, Space_2,
		Child, Object->BT_5,
		Child, Object->BT_6,
		Child, Object->BT_7,
		Child, Space_3,
		Child, Space_4,
		Child, Space_5,
	End;

	Object->BT_A = SimpleButton("_Q C4");

	Object->BT_Z = SimpleButton("_W D4");

	Object->BT_E = SimpleButton("_E E4");

	Object->BT_R = SimpleButton("_R F4");

	Object->BT_T = SimpleButton("_T G4");

	Object->BT_Y = SimpleButton("_Y A4");

	Object->BT_U = SimpleButton("_U B4");

	Object->BT_I = SimpleButton("_I C5");

	GR_nat_aigu = GroupObject,
		MUIA_HelpNode, "GR_nat_aigu",
		MUIA_Group_Horiz, TRUE,
		Child, Object->BT_A,
		Child, Object->BT_Z,
		Child, Object->BT_E,
		Child, Object->BT_R,
		Child, Object->BT_T,
		Child, Object->BT_Y,
		Child, Object->BT_U,
		Child, Object->BT_I,
	End;

	Space_7 = VSpace(20);

	Space_8 = HSpace(0);

	Object->BT_S = SimpleButton("_S C#3");

	Object->BT_D = SimpleButton("_D D#3");

	Space_9 = HSpace(0);

	Space_10 = HSpace(0);

	Object->BT_G = SimpleButton("_G F#3");

	Object->BT_H = SimpleButton("_H G#3");

	Object->BT_J = SimpleButton("_J A#3");

	Space_11 = HSpace(0);

	Space_12 = HSpace(0);

	Space_13 = HSpace(0);

	GR_alt_grave = GroupObject,
		MUIA_HelpNode, "GR_alt_grave",
		MUIA_Group_Horiz, TRUE,
		Child, Space_8,
		Child, Object->BT_S,
		Child, Object->BT_D,
		Child, Space_9,
		Child, Space_10,
		Child, Object->BT_G,
		Child, Object->BT_H,
		Child, Object->BT_J,
		Child, Space_11,
		Child, Space_12,
		Child, Space_13,
	End;

	Object->BT_W = SimpleButton("_Z C3");

	Object->BT_X = SimpleButton("_X D3");

	Object->BT_C = SimpleButton("_C E3");

	Object->BT_V = SimpleButton("_V F3");

	Object->BT_B = SimpleButton("_B G3");

	Object->BT_N = SimpleButton("_N A3");

	Object->BT_Virgule = SimpleButton("_M B3");

	Object->BT_PointVirg = SimpleButton("_, C4");

	GR_nat_grave = GroupObject,
		MUIA_HelpNode, "GR_nat_grave",
		MUIA_Group_Horiz, TRUE,
		Child, Object->BT_W,
		Child, Object->BT_X,
		Child, Object->BT_C,
		Child, Object->BT_V,
		Child, Object->BT_B,
		Child, Object->BT_N,
		Child, Object->BT_Virgule,
		Child, Object->BT_PointVirg,
	End;

	Space_14 = VSpace(20);

	Object->SL_velocity = SliderObject,
		MUIA_HelpNode, "SL_velocity",
		MUIA_Slider_Min, 0,
		MUIA_Slider_Max, 127,
		MUIA_Slider_Level, 63,
	End;

	obj_aux1 = Label2("Velocity");

	obj_aux0 = GroupObject,
		MUIA_Group_Columns, 2,
		Child, obj_aux1,
		Child, Object->SL_velocity,
	End;

	Object->SL_MidiChannel = SliderObject,
		MUIA_HelpNode, "SL_MidiChannel",
		MUIA_Slider_Min, 1,
		MUIA_Slider_Max, 16,
		MUIA_Slider_Level, 1,
	End;

	obj_aux3 = Label2("Midi Channel");

	obj_aux2 = GroupObject,
		MUIA_Group_Columns, 2,
		Child, obj_aux3,
		Child, Object->SL_MidiChannel,
	End;

	GROUP_ROOT_0 = GroupObject,
		Child, GR_alt_aigu,
		Child, GR_nat_aigu,
		Child, Space_7,
		Child, GR_alt_grave,
		Child, GR_nat_grave,
		Child, Space_14,
		Child, obj_aux0,
		Child, obj_aux2,
	End;

	Object->WI_Principale = WindowObject,
		MUIA_Window_Title, "NoteOn",
		MUIA_Window_ID, MAKE_ID('0', 'W', 'I', 'N'),
		WindowContents, GROUP_ROOT_0,
	End;

	Object->App = ApplicationObject,
		MUIA_Application_Author, "Stanis Humez",
		MUIA_Application_Base, "NOTEON",
		MUIA_Application_Title, "NoteOn",
		MUIA_Application_Version, "$VER: NoteOn 1.00 (30.01.1995)",
		MUIA_Application_Copyright, "© 1995 Stanis Humez",
		MUIA_Application_Description, "Midi Keyboard",
		SubWindow, Object->WI_Principale,
	End;


	if (!Object->App)
	{
		FreeVec(Object);
		return(NULL);
	}

	DoMethod(Object->WI_Principale,
		MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
		Object->App,
		2,
		MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit
		);

	DoMethod(Object->BT_2,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,61
		);

	DoMethod(Object->BT_2,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,61
		);

	DoMethod(Object->BT_3,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,63
		);

	DoMethod(Object->BT_3,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,63
		);

	DoMethod(Object->BT_5,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,66
		);

	DoMethod(Object->BT_5,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,66
		);

	DoMethod(Object->BT_6,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,68
		);

	DoMethod(Object->BT_6,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,68
		);

	DoMethod(Object->BT_7,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,70
		);

	DoMethod(Object->BT_7,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,70
		);

	DoMethod(Object->BT_A,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,60
		);

	DoMethod(Object->BT_A,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,60
		);

	DoMethod(Object->BT_Z,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,62
		);

	DoMethod(Object->BT_Z,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,62
		);

	DoMethod(Object->BT_E,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,64
		);

	DoMethod(Object->BT_E,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,64
		);

	DoMethod(Object->BT_R,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,65
		);

	DoMethod(Object->BT_R,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,65
		);

	DoMethod(Object->BT_T,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,67
		);

	DoMethod(Object->BT_T,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,67
		);

	DoMethod(Object->BT_Y,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,69
		);

	DoMethod(Object->BT_Y,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,69
		);

	DoMethod(Object->BT_U,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,71
		);

	DoMethod(Object->BT_U,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,71
		);

	DoMethod(Object->BT_I,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,72
		);

	DoMethod(Object->BT_I,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,72
		);

	DoMethod(Object->BT_S,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,49
		);

	DoMethod(Object->BT_S,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,49
		);

	DoMethod(Object->BT_D,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,51
		);

	DoMethod(Object->BT_D,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,51
		);

	DoMethod(Object->BT_G,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,54
		);

	DoMethod(Object->BT_G,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,54
		);

	DoMethod(Object->BT_H,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,56
		);

	DoMethod(Object->BT_H,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,56
		);

	DoMethod(Object->BT_J,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,58
		);

	DoMethod(Object->BT_J,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,58
		);

	DoMethod(Object->BT_W,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,48
		);

	DoMethod(Object->BT_W,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,48
		);

	DoMethod(Object->BT_X,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,50
		);

	DoMethod(Object->BT_X,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,50
		);

	DoMethod(Object->BT_C,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,52
		);

	DoMethod(Object->BT_C,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,52
		);

	DoMethod(Object->BT_V,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,53
		);

	DoMethod(Object->BT_V,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,53
		);

	DoMethod(Object->BT_B,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,55
		);

	DoMethod(Object->BT_B,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,55
		);

	DoMethod(Object->BT_N,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,57
		);

	DoMethod(Object->BT_N,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,57
		);

	DoMethod(Object->BT_Virgule,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,59
		);

	DoMethod(Object->BT_Virgule,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,59
		);

	DoMethod(Object->BT_PointVirg,
		MUIM_Notify, MUIA_Pressed, TRUE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOnHook,60
		);

	DoMethod(Object->BT_PointVirg,
		MUIM_Notify, MUIA_Pressed, FALSE,
		Object->App,
		3,
		MUIM_CallHook, &NoteOffHook,60
		);

	DoMethod(Object->SL_velocity,
		MUIM_Notify, MUIA_Slider_Level, MUIV_EveryTime,
		Object->App,
		3,
		MUIM_CallHook, &VelocityChangeHook, Object
		);

	DoMethod(Object->SL_MidiChannel,
		MUIM_Notify, MUIA_Slider_Level, MUIV_EveryTime,
		Object->App,
		3,
		MUIM_CallHook, &MidiChannelChangeHook, Object
		);

	DoMethod(Object->WI_Principale,
		MUIM_Window_SetCycleChain, Object->BT_2,
		Object->BT_3,
		Object->BT_5,
		Object->BT_6,
		Object->BT_7,
		Object->BT_A,
		Object->BT_Z,
		Object->BT_E,
		Object->BT_R,
		Object->BT_T,
		Object->BT_Y,
		Object->BT_U,
		Object->BT_I,
		Object->BT_S,
		Object->BT_D,
		Object->BT_G,
		Object->BT_H,
		Object->BT_J,
		Object->BT_W,
		Object->BT_X,
		Object->BT_C,
		Object->BT_V,
		Object->BT_B,
		Object->BT_N,
		Object->BT_Virgule,
		Object->BT_PointVirg,
		Object->SL_velocity,
		Object->SL_MidiChannel,
		0
		);

	set(Object->WI_Principale,
		MUIA_Window_Open, TRUE
		);


	return(Object);
}


void DisposeApp(struct ObjApp * Object)
{
	MUI_DisposeObject(Object->App);
	FreeVec(Object);
}

main(void)
{
	BOOL	running = TRUE;
	ULONG	signal;

	if (!(MUIMasterBase=OpenLibrary("muimaster.library",0)))
	{
		printf("Can't open muimaster.library...");
		goto fin;
	}

	if (!(MidiBase=OpenLibrary(MIDINAME,MIDIVERSION)))
	{
		printf("Can't open midi library...");
		goto fin;
	}

	if (!(source = CreateMSource(NULL,NULL)))
	{
		printf("Can't create source\n");
		goto fin;
	}

	if (!(RouteOut = MRouteSource(source,"MidiOut",NULL)))
	{
		printf("Can't find MidiOut\n");
		goto fin;
	}


	App = CreateApp();

	while (running)
        {
                switch (DoMethod(App->App,MUIM_Application_Input,&signal))
                {
                case MUIV_Application_ReturnID_Quit:
                        running = FALSE;
                        break;
                }
	if (running && signal) Wait(signal);
        }
	DisposeApp(App);


fin:
	if (source) DeleteMSource(source);
	if (RouteOut) DeleteMRoute(RouteOut);
	if (MUIMasterBase) CloseLibrary(MUIMasterBase);
	if (MidiBase) CloseLibrary(MidiBase);
	
	exit(0);		
}
