/* MED - music editor © 1989, 1990 by Teijo Kinnunen */
#ifndef PRECOMPILED
#include <exec/types.h>
#include <exec/io.h>
#include <exec/errors.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <devices/audio.h>
#include <devices/timer.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/screens.h>
#include <intuition/intuition.h>
#include <hardware/cia.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <string.h>
#include <stdlib.h>
#define PRECOMPILED
#else /* Esikääntämistä varten */
#include <exec/interrupts.h>
#include <hardware/intbits.h>
#include <hardware/custom.h>
#include <math.h>
#include "med.h"
#include "medproto.h"
/* for cback.o */
LONG _stack = 4000;
char *_procname = "MED - music editor";
LONG _priority = 0;
LONG _BackGroundIO = 0;

static void __regargs Poistu(char *),Alku(void);
static void __regargs DrawLines(void);
void _main(char *cmdline);
extern UWORD periodit[],chip medpic0[],chip medpic1[],chip mouse1[];
extern struct CIA far ciaa;
extern struct Image far kuviot;
extern struct TextAttr far nsfont;
extern struct NewWindow far nw,far pnw;
extern struct NewScreen far ns;
extern struct Gadget far gadget1[],far gadget3[];
extern struct Custom far custom;
extern UWORD chip pylvaatdata[];
struct Image eq1image = { 0,0,320,56,2,pylvaatdata,0x3,0x0,NULL };
struct RastPort *wrp;
struct ViewPort *vp;
struct BitMap drawbm,screenbm;
struct TextFont *topaz8;
struct Task *maintsk;
struct Kappale far song;
struct Soitin *sample[63];
extern struct Lohko far *lohko[];
extern UBYTE firstdisptrk;
extern BPTR currdir;
UWORD *sprptr;
BOOL trackon[16] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },updscrflag = TRUE;
ULONG updscrmsk,hyppymsk,recmidimsk;
LONG eq1strt0 = 0L,eq1strt1 = 0L,eq1strt2 = 0L,plane0ptr = 0L;
CPTR pl2s[8];
UBYTE eq1height[31] = { 0 };
UBYTE far recmidi;
void __asm VBServ(void);
static struct Interrupt far vbserv = { { NULL,NULL,NT_INTERRUPT,-10,
				"MEDVBInt!" },(APTR)eq1height,VBServ };
static char *initerror[] = { NULL,"MED: Can't allocate signal",
	"MED: Can't open audio.device (channels in use??)",
	"MED: Can't open ciaa.resource","MED: ciaa timer A in use" };
struct Screen *screen;
struct Window *window,*pw;
extern char *verstr;
static long scrupdsign = -1,jumpsign = -1,recmidisig = -1;

ULONG class; /* IntuiMsg stuff */
WORD mousex,mousey;
UWORD code,qual;
APTR iaddr;

void _main(cmdline)
char *cmdline;
{
	struct IntuiMessage *imsg;
	ULONG mask;
	register UWORD quit = FALSE;
	APTR prevwinptr;
	register long waitmsk;
	struct Process *thisproc = (struct Process *)FindTask(0);
	prevwinptr = thisproc->pr_WindowPtr;
	Alku();
	AddIntServer(INTB_VERTB,&vbserv);
	thisproc->pr_WindowPtr = (APTR)window;
	waitmsk = 1<<window->UserPort->mp_SigBit|updscrmsk|hyppymsk|recmidimsk;
	for(;;) {
		mask = Wait(waitmsk);
		if(mask & hyppymsk) SetPointer(window,sprptr,23,16,-1,0);
		if(mask & updscrmsk) PaivitaNaytto(FALSE);
		if(mask & recmidimsk) PutMNote(recmidi);
		while(imsg = (struct IntuiMessage *)GetMsg(window->UserPort)) {
			class = imsg->Class;
			code = imsg->Code;
			qual = imsg->Qualifier;
			iaddr = imsg->IAddress;
			mousex = imsg->MouseX;
			mousey = imsg->MouseY;
			ReplyMsg((struct Message *)imsg);
			if(KasitteleViesti()) {
				quit = TRUE;
				break;
			}
		}
		if(quit) break;
	}
	thisproc->pr_WindowPtr = prevwinptr;
	ciaa.ciapra &= ~CIAF_LED;
	RemIntServer(INTB_VERTB,&vbserv);
	Poistu(NULL);
}

static void __regargs Poistu(char *err)
{
	char alerttxt[100];
	if(err) {
		alerttxt[0] = 0; alerttxt[1] = 20; alerttxt[2] = 16;
		strcpy(&alerttxt[3],err);
		alerttxt[strlen(err)+4] = '\0';
		DisplayAlert(RECOVERY_ALERT,alerttxt,30);
	}
	RemEqualizer();
	AudioRem();
	FreeSerial();
	FreeAllBlocks();
	if(currdir) UnLock(currdir);
	FreeFDatas();
	FreeBuffer();
	VapautaSoittimet();
	FreePaths();
	if(topaz8) CloseFont(topaz8);
	if(drawbm.Planes[0]) FreeRaster(drawbm.Planes[0],320,120);
	if(window) CloseWindow(window);
	if(screen) CloseScreen(screen);
	if(IntuitionBase) {
		OpenWorkBench(); /* OK, =RJ=!! */
		CloseLibrary(IntuitionBase);
	}
	if(GfxBase) CloseLibrary(GfxBase);
	if(recmidisig != -1) FreeSignal(recmidisig);
	if(scrupdsign != -1) FreeSignal(scrupdsign);
	if(jumpsign != -1) FreeSignal(jumpsign);
	XCEXIT(0);
}

void VapautaSoittimet()
{
	UCOUNT slsk;
	for(slsk = 0; slsk < 63; slsk++)
		if(sample[slsk]) {
			FreeMem((void *)sample[slsk],sample[slsk]->length +
				sizeof(struct Soitin));
			sample[slsk] = NULL;
			song.sample[slsk].sname[0] = '\0';
		}
}

void SammutaAanet(arg)
UWORD arg;
{
	static UBYTE mididata[3] = { 0xb0,0x7b,0x0 }; /* MIDI: All notes off */
	extern struct Gadget far gadget9[];
	if(arg == 999) {
		ChannelOff(0);	/* stop Amiga audio channels by calling */
		ChannelOff(1);  /* ChannelOff().. */
		ChannelOff(2);
		ChannelOff(3);
		if(gadget9[0].GadgetID & 0x1000) /* ..and MIDI this way */
		for(mididata[0] = 0xB0; mididata[0] <= 0xBF; mididata[0]++)
			AddMIDIData(mididata,3);
	}
	else ChannelOff((UBYTE)arg);
}

static void __regargs Alku()
{
	long error;
	if(!(IntuitionBase = OpenLibrary("intuition.library",33)))
	  Poistu(NULL); /* DisplayAlert() vaatii intuition.libraryn! */
	scrupdsign = AllocSignal(-1);
	jumpsign = AllocSignal(-1);
	recmidisig = AllocSignal(-1);
	if(scrupdsign == -1 || jumpsign == -1 || recmidisig == -1)
		Poistu("MED: No free signal bits");
	updscrmsk = 1 << scrupdsign;
	hyppymsk = 1 << jumpsign;
	recmidimsk = 1 << recmidisig;
	if(!(GfxBase = OpenLibrary("graphics.library",0)))
		Poistu("MED: No graphics.library");
	if(!(screen = OpenScreen(&ns)))
		Poistu("MED: Can't open screen (out of memory?)");
	topaz8 = OpenFont(&nsfont);
	nw.Height = screen->Height;
	nw.Screen = screen;
	maintsk = FindTask(0);
	if(!(window = OpenWindow(&nw)))
		Poistu("MED: Can't open window (out of memory?)");
	ShowTitle(screen,FALSE);
	wrp = window->RPort;
	vp = ViewPortAddress(window);
	NollaaVarit();
	SetRGB4(vp,17,0xe,0xa,0xa); /* sprite */
	SetRGB4(vp,18,0xf,0xf,0xf);
	SetRGB4(vp,19,0x4,0x8,0xf);
	InitBitMap(&screenbm,2,320,77);
	screenbm.Planes[0] = (PLANEPTR)medpic0;
	screenbm.Planes[1] = (PLANEPTR)medpic1;
	BltBitMapRastPort(&screenbm,0,0,wrp,0,0,320,77,0xc0);
	DrawLines();
	OsionValinta(&gadget1[0]);
	if(screen->Height >= 256) {
		DrawImage(&(screen->RastPort),&eq1image,0,200);
		eq1strt0 = (LONG)(screen->BitMap.Planes[0]) + 8484;
		eq1strt1 = (LONG)(screen->BitMap.Planes[1]) + 8484;
		eq1strt2 = (LONG)(screen->BitMap.Planes[2]) + 8484;
	}
	else {
		pnw.Screen = screen;
		eq1strt1 = (LONG)(screen->BitMap.Planes[1]) + 1124;
		eq1strt2 = (LONG)(screen->BitMap.Planes[2]) + 1124;
		gadget3[6].GadgetID &= ~0x1000; /* pylväät-gadget ei korostu */
	}
	pl2s[0] = (CPTR)(screen->BitMap.Planes[2]) + 6563;
	pl2s[2] = pl2s[0] + 9;
	pl2s[4] = pl2s[2] + 9;
	pl2s[6] = pl2s[4] + 9;
	pl2s[1] = (CPTR)(screen->BitMap.Planes[1]) + 6563;
	pl2s[3] = pl2s[1] + 9;
	pl2s[5] = pl2s[3] + 9;
	pl2s[7] = pl2s[5] + 9;
	InitDisp();
	InitBitMap(&drawbm,1,320,120);
	if(!(drawbm.Planes[0] = (PLANEPTR)AllocRaster(320,120)))
		Poistu("MED: No memory for bit plane");
	plane0ptr = (LONG)drawbm.Planes[0];
	BltClear((char *)plane0ptr,((120 << 16) + 40),3);
	wrp->Mask = 0x2; /* Tehdään palkki, muuttamalla bittitaso 2 ykkösiksi */
	SetDrMd(wrp,COMPLEMENT);
	RectFill(wrp,4,132,315,140);
	wrp->Mask = 0xff;
	NaytaKursori();
	SetDrMd(wrp,JAM2);
	SetAPen(wrp,1);
	SetBPen(wrp,0);
	Move(wrp,276,10);
	Text(wrp,verstr,5); /* version */
	SetAPen(wrp,0);
	SetBPen(wrp,3);
	if(error = AudioInit()) Poistu(initerror[error]);
	SetPointer(window,&mouse1[0],23,16,-1,0);
	LoadKeys();
	LoadPathFile();
	if(AlustaKappale(TRUE)) Poistu("MED: Too little memory");
	DispInfoGadgets();
	InitEqualizer();
	PaivitaNaytto(TRUE);
}

static void __regargs DrawLines()
{
	SetDrMd(wrp,JAM1);
	SetAPen(wrp,2);
	Move(wrp,0,77);	Draw(wrp,0,199);
	Move(wrp,1,77);	Draw(wrp,1,199);
	Move(wrp,2,199);	Draw(wrp,318,199);
	Move(wrp,316,197);	Draw(wrp,316,77);
	SetAPen(wrp,3);
	Move(wrp,2,76);	Draw(wrp,2,198);
	Draw(wrp,317,198);	Draw(wrp,317,77);
	SetAPen(wrp,1);
	Move(wrp,3,77);	Draw(wrp,3,197);
	Draw(wrp,315,197);	Move(wrp,319,199);
	Draw(wrp,319,77);	Move(wrp,318,77);
	Draw(wrp,318,198);
}

void FreeBlock(num)
UWORD num;
{
	if(lohko[num]) {
		FreeMem(lohko[num],BLKHDRSZ + lohko[num]->numtracks * 3 *
			(lohko[num]->lines + 1));
		lohko[num] = 0L;
	}
}

BOOL AllocBlock(UWORD num,UBYTE tracks,UWORD lines) /* TRUE=err, FALSE=ok!! */
{
	if(lohko[num]) {
		if(lohko[num]->numtracks == tracks &&
		   lohko[num]->lines == (UBYTE)(lines - 1)) return(FALSE);
		FreeBlock(num);
	}
	if(!(lohko[num] = AllocMem(BLKHDRSZ + 3 * lines * tracks,MEMF_PUBLIC|
		MEMF_CLEAR))) return(TRUE);
	lohko[num]->numtracks = tracks;
	lohko[num]->lines = (UBYTE)(lines - 1);
	return(FALSE);
}

void FreeAllBlocks()
{
	UWORD cnt;
	for(cnt = 0; cnt < 100; cnt++) FreeBlock(cnt);
}

BOOL ChangeBlockSize(UWORD num,UWORD width,UWORD lines)
{
	struct Lohko *newblock,*oldblock;
	UBYTE trk;
	UWORD oldtrk,newtrk,line;
	if(!lohko[num]) return(TRUE);
	newblock = AllocMem(BLKHDRSZ + 12 * lines * width,MEMF_PUBLIC|MEMF_CLEAR);
	if(!newblock) return(TRUE);
	newblock->numtracks = 4 * width;
	newblock->lines = lines - 1;
	oldblock = lohko[num];
	for(line = 0; line < 8; line++) newblock->hlmask[line] =
		oldblock->hlmask[line];
	for(line = 0; line < min(lines,oldblock->lines + 1); line++) {
		newtrk = newblock->numtracks * 3 * line;
		oldtrk = lohko[num]->numtracks * 3 * line;
		for(trk = 0; trk < min(newblock->numtracks,lohko[num]->
			numtracks); trk++) {
			newblock->music[newtrk + 3 * trk] =
				oldblock->music[oldtrk + 3 * trk];
			newblock->music[newtrk + 3 * trk + 1] =
				oldblock->music[oldtrk + 3 * trk + 1];
			newblock->music[newtrk + 3 * trk + 2] =
				oldblock->music[oldtrk + 3 * trk + 2];
		}
	}
	lohko[num] = newblock;
	FreeMem(oldblock,BLKHDRSZ + oldblock->numtracks * (oldblock->lines + 1) * 3);
	firstdisptrk = 0;
	PaivitaNaytto(TRUE);
	return(FALSE);
}
#endif
