/* MED - music editor by Teijo Kinnunen 1989, 1990 */
#ifndef PRECOMPILED	/* These files are precompiled to med.sym */
#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 /* For precompiling */
#include <exec/interrupts.h>
#include <hardware/intbits.h>
#include <hardware/custom.h>
#include <math.h>
#include "med.h"
void VapautaSoittimet(),Poistu(),SammutaAanet(),Alku(),FreeAllBlocks();
extern void __asm PaivitaNaytto(register __d0 BOOL);
extern void __asm AddMIDIData(register __a0 char *,register __d0 ULONG);
extern void NollaaVarit(),AudioRem(),LataaSoitinLista(),VapautaSoitinLista();
extern void DispInfoGadgets(),PylvKesk();
extern BOOL __asm KasitteleViesti(register __d0 ULONG,register __d1 UWORD,
				  register __d2 UWORD,register __a0 APTR);
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 pylvasimage = { 0,0,320,56,2,pylvaatdata,0x3,0x0,NULL };
struct RastPort *wrp;
struct ViewPort *vp;
struct BitMap piirtobm,nayttobm;
struct TextFont *topaz8;
struct Task *maintsk;
struct Kappale far tamakappale;
struct SoundTrackerKappale far ladattu;
struct Soitin *soitin[32];
extern long AudioInit();
extern struct Lohko far *lohko[50];
extern UBYTE firstdisptrk;
extern BOOL AlustaKappale();
extern BPTR currdir;
UWORD *sprptr;
BOOL aanipaalla[16] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 },naytonpaivitys = TRUE;
ULONG nayttomsk,hyppymsk,recmidimsk;
LONG pylvasalku0 = 0L,pylvasalku1 = 0L,pylvasalku2 = 0L,plane0ptr = 0L;
UBYTE pylvkork[31] = { 0 },far recmidi; /* joka pylvään korkeus */
static struct Interrupt far pylvintr = { { NULL,NULL,NT_INTERRUPT,0,
				"MEDVBInt!" },(APTR)pylvkork,PylvKesk };
static char *initerror[] = { NULL,"MED: Can't allocate signal bit",
	"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 naytonpvsig = -1,hyppysig = -1,recmidisig = -1;

void _main(cmdline)
char *cmdline;
{
	struct IntuiMessage *imsg;
	register ULONG luokka;
	ULONG maski;
	register UWORD koodi,maare,loppu = FALSE;
	APTR entwindowptr;
	register APTR iaddr;
	register long odotusmaski;
	struct Process *thisproc = (struct Process *)FindTask(0);
	entwindowptr = thisproc->pr_WindowPtr;
	Alku();
	AddIntServer(INTB_VERTB,&pylvintr);
	thisproc->pr_WindowPtr = (APTR)window;
	odotusmaski = 1<<window->UserPort->mp_SigBit|nayttomsk|hyppymsk|recmidimsk;
	for(;;) {
		maski = Wait(odotusmaski);
		if(maski & hyppymsk) SetPointer(window,sprptr,23,16,-1,0);
		if(maski & nayttomsk) PaivitaNaytto(FALSE);
		if(maski & recmidimsk) PutMNote(recmidi);
		while(imsg = (struct IntuiMessage *)GetMsg(window->UserPort)) {
			luokka = imsg->Class;
			koodi = imsg->Code;
			maare = imsg->Qualifier;
			iaddr = imsg->IAddress;
			ReplyMsg((struct Message *)imsg);
			if(KasitteleViesti(luokka,koodi,maare,iaddr)) {
				loppu = TRUE;
				break;
			}
		}
		if(loppu) break;
	}
	thisproc->pr_WindowPtr = entwindowptr;
	ciaa.ciapra &= ~CIAF_LED;
	RemIntServer(INTB_VERTB,&pylvintr);
	Poistu(NULL);
}

void Poistu(virhe)
char *virhe;
{
	char alertteksti[100];
	if(virhe) {
		alertteksti[0] = 0; alertteksti[1] = 20; alertteksti[2] = 16;
		strcpy(&alertteksti[3],virhe);
		alertteksti[strlen(virhe)+4] = '\0';
		DisplayAlert(RECOVERY_ALERT,alertteksti,30);
	}
	RemEqualizer();
	AudioRem();
	FreeSerial();
	FreeAllBlocks();
	if(currdir) UnLock(currdir);
	FreeFDatas();
	FreeBuffer();
	VapautaSoittimet();
	VapautaSoitinLista();
	if(topaz8) CloseFont(topaz8);
	if(piirtobm.Planes[0]) FreeRaster(piirtobm.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(naytonpvsig != -1) FreeSignal(naytonpvsig);
	if(hyppysig != -1) FreeSignal(hyppysig);
	XCEXIT(0);
}

void VapautaSoittimet()
{
	UCOUNT slsk;
	for(slsk = 1; slsk < 32; slsk++)
		if(soitin[slsk]) {
			FreeMem((void *)soitin[slsk],soitin[slsk]->length +
				sizeof(struct Soitin));
			soitin[slsk] = NULL;
			tamakappale.soitin[slsk][0] = '\0';
		}
}

void SammutaAanet(arg)
UWORD arg;
{
	static UBYTE mididata[3] = { 0xb0,0x7b,0x0 }; /* MIDI: All notes off */
	extern void __asm ChannelOff(register __d0 UWORD);
	extern struct Gadget far gadget9[];
	if(arg == 999) {
		custom.dmacon = 0xf; /* kaikki pois */
		if(gadget9[0].GadgetID & 0x1000)
		for(mididata[0] = 0xB0; mididata[0] <= 0xBF; mididata[0]++)
			AddMIDIData(mididata,3);
	}
	else ChannelOff(arg);
}

void Alku()
{
	long error;
	if(!(IntuitionBase = OpenLibrary("intuition.library",33)))
	  Poistu(NULL); /* DisplayAlert() vaatii intuition.libraryn! */
	naytonpvsig = AllocSignal(-1);
	hyppysig = AllocSignal(-1);
	recmidisig = AllocSignal(-1);
	if(naytonpvsig == -1 || hyppysig == -1 || recmidisig == -1)
		Poistu(initerror[1]);
	nayttomsk = 1 << naytonpvsig;
	hyppymsk = 1 << hyppysig;
	recmidimsk = 1 << recmidisig;
	if(!(GfxBase = OpenLibrary("graphics.library",0)))
		Poistu("MED: Can't open 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(&nayttobm,2,320,200);
	nayttobm.Planes[0] = (PLANEPTR)medpic0;
	nayttobm.Planes[1] = (PLANEPTR)medpic1;
	BltBitMapRastPort(&nayttobm,0,0,wrp,0,0,320,200,0xc0);
	OsionValinta(&gadget1[0]);
	if(screen->Height >= 256) {
		DrawImage(&(screen->RastPort),&pylvasimage,0,200);
		pylvasalku0 = (LONG)(screen->BitMap.Planes[0]) + 8484;
		pylvasalku1 = (LONG)(screen->BitMap.Planes[1]) + 8484;
		pylvasalku2 = (LONG)(screen->BitMap.Planes[2]) + 8484;
	}
	else {
		pnw.Screen = screen;
		pylvasalku1 = (LONG)(screen->BitMap.Planes[1]) + 1124;
		pylvasalku2 = (LONG)(screen->BitMap.Planes[2]) + 1124;
		gadget3[6].GadgetID &= ~0x1000; /* Don't highlight Eq1 */
	}
	InitBitMap(&piirtobm,1,320,120);
	if(!(piirtobm.Planes[0] = (PLANEPTR)AllocRaster(320,120)))
		Poistu("MED: No memory for bitplane");
	plane0ptr = (LONG)piirtobm.Planes[0];
	BltClear((char *)plane0ptr,((120 << 16) + 40),3);
	wrp->Mask = 0x2; /* Draw a rectangle to bitplane 2 */
	SetDrMd(wrp,COMPLEMENT);
	RectFill(wrp,4,132,315,140);
	wrp->Mask = 0xff;
	NaytaKursori();
	SetAPen(wrp,1);
	SetBPen(wrp,0);
	Move(wrp,276,10);
	Text(wrp,verstr,5); /* version number */
	SetBPen(wrp,3);
	SetAPen(wrp,0);
	if(error = AudioInit()) Poistu(initerror[error]);
	SetPointer(window,&mouse1[0],23,16,-1,0);
	LataaSoitinLista();
	if(AlustaKappale(TRUE)) Poistu("MED: Not enough memory");
	DispInfoGadgets();
	InitEqualizer();
	PaivitaNaytto(TRUE);
}

void FreeBlock(num)
UWORD num;
{
	if(lohko[num]) {
		FreeMem(lohko[num],4 + lohko[num]->numtracks * ONETRKSIZE);
		lohko[num] = 0L;
	}
}

BOOL AllocBlock(UWORD num,UBYTE tracks) /* TRUE = virhe, FALSE = ok!! */
{
	if(lohko[num]) {
		if(lohko[num]->numtracks == tracks) return(FALSE);
		FreeBlock(num);
	}
	if(!(lohko[num] = AllocMem(4 + ONETRKSIZE * tracks,MEMF_PUBLIC|
		MEMF_CLEAR))) return(TRUE);
	lohko[num]->numtracks = tracks;
	return(FALSE);
}

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

BOOL ChangeBlockSize(num,width)
UWORD num,width;
{
	struct Lohko *newblock,*oldblock;
	UBYTE line,trk;
	UWORD oldtrk,newtrk;
	if(!lohko[num]) return(TRUE);
	newblock = AllocMem(FOURTRKSIZE * width + 4,MEMF_PUBLIC|MEMF_CLEAR);
	if(!newblock) return(TRUE);
	newblock->numtracks = 4 * width;
	oldblock = lohko[num];
	for(line = 0; line < 64; 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,4 + oldblock->numtracks * ONETRKSIZE);
	firstdisptrk = 0;
	PaivitaNaytto(TRUE);
	return(FALSE);
}
#endif
