/* MED - music editor © 1989, 1990 by Teijo Kinnunen */
/* med-ed.c: editing functions */
#include "med.h"
#include "medproto.h"

/* WARNING: Beginning programmers!!! Don't look here for examples of good
   programming style!!! This file may contain many sloppy & unprofessional
   techniques. Read at your own risk. */

#define SHIFT (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)
UWORD near periodit[] = { 856,808,762,720,678,640,604,570,538,508,480,453,
			  428,404,381,360,339,320,302,285,269,254,240,226,
			  214,202,190,180,170,160,151,143,135,127,120,113,
			  214,202,190,180,170,160,151,143,135,127,120,113,
			  214,202,190,180,170,160,151,143,135,127,120,113,
			  214,202,190,180,170,160,151,143,135,127,120,113 };
UBYTE firstdisptrk = 0,counter = 0,far recvol;
struct Library *ciaaresource;
extern struct Gadget far gadget6[],far gadget5[],far gadget9[];
extern struct Kappale far song;
extern struct RastPort *wrp;
extern struct Window *window;
extern UWORD volatile pline,pblock,pstate,mousex;
extern UBYTE cursorx,currtrk,samplenum,blocks,currpos,near heksaluku[],waitnx;
extern struct StringInfo strinfo[];
extern struct Lohko far *lohko[];
static struct PrgNote prgn[12];
static UBYTE far instrcode[] = { 0x0a,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
				0x09,0x20,0x35,0x33,0x22,0x12,0x23,0x24,0x25,
				0x17,0x26,0x27,0x28,0x37,0x36,0x18,0x19,0x10,
				0x13,0x21,0x14,0x16,0x34 };
static UBYTE far prgdisp = 0,far shnum = 0;
static BYTE far kbnotes[] = {
	-1,-1,13,15,-1,18,20,22,-1,25,27,-1,30,32,-1,-1,
	12,14,16,17,19,21,23,24,26,28,29,31,-1,-1,-1,-1,
	-1,1,3,-1,6,8,10,-1,13,15,-1,-1,-1,-1,-1,-1,
	-1,0,2,4,5,7,9,11,12,14,16 }; /* end = 0x3a */
UBYTE far nappkoodi[]={ 0x31,0x21,0x32,0x22,0x33,0x34,0x24,0x35,0x25,0x36,0x26,
			0x37,
			0x10,0x02,0x11,0x03,0x12,0x13,0x05,0x14,0x06,0x15,0x07,
			0x16 };
static UWORD chip zerodata = 0;
UWORD far nappokt = 0,editline,*zeroptr = &zerodata;
struct PlayNotedata far keybnote;
extern UWORD nykyinenosio;
extern char linesstr[];

static void __regargs PlayNote(UBYTE,UBYTE);
static void __regargs UpdateScreen(void);
static UBYTE * __regargs CalcAddr(UWORD,UWORD,UBYTE);
static void __regargs PutData(UWORD,UWORD,UBYTE,UBYTE,UBYTE);
static void __regargs VolSlide(void);
static void __regargs SetVol(UWORD,UWORD,UBYTE,UBYTE);
static void __regargs ClrPrg(void);
static void __regargs DispPrgNote(void);
static void __regargs SaveKeys(void);
static void __regargs PushNote(UBYTE *,UBYTE);
static void __regargs HandleNumEntr(UWORD);

static void __regargs PlayNote(UBYTE notenum,UBYTE instr)
{
	keybnote.notenum = notenum;
	keybnote.instrnum = instr;
	keybnote.tracknum = currtrk;
	keybnote.playnote = 1;
	SetICR(ciaaresource,CIAICRF_SETCLR|CIAICRF_TA);
}
	
static void __regargs UpdateScreen()
{
	if(pstate == ALASOITA && (gadget6[25].GadgetID & 0x1000) &&
		(gadget6[0].GadgetID & 0x1000))	pline++;
	if(pline > lohko[pblock]->lines) { pline = 0; PaivitaNaytto(TRUE); }
	else PaivitaNaytto(1234); /* secret code */
}
	
static UBYTE * __regargs CalcAddr(block,line,track)
UWORD block,line;
UBYTE track;
{
	if(block > blocks - 1) return(0);
	if(track > lohko[block]->numtracks - 1) return(0);
	if(line > lohko[block]->lines) return(0);
	return(&lohko[block]->music[line * lohko[block]->numtracks * 3 +
		3 * track]);
}

void PutNote(block,line,track,note,instr)
UWORD block,line;
UBYTE track,note;
UBYTE instr;
{
	UBYTE *putptr = CalcAddr(block,line,track);
	if(!putptr) return;
	*putptr = note;
	*(putptr+1) = (*(putptr + 1) & 0x0F) | (instr << 4);
	if(instr > 31) {
		*putptr |= 0x40;
		instr -= 31;
	}
	if(instr > 0xF) *putptr |= 0x80;
}

static void __regargs PutData(block,line,track,num,val)
UWORD block,line;
UBYTE track,num,val;
{
	UBYTE *putptr = CalcAddr(block,line,track);
	if(!putptr) return;
	switch(num) {
	    case 0:
		*(putptr+1) = (*(putptr + 1) & 0x0F) | (val << 4);
		if(val > 31) {
			*putptr |= 0x40;
			val -= 31;
		} else *putptr &= ~0x40;
		if(val > 0xF) *putptr |= 0x80; else *putptr &= ~0x80;
		break;
	    case 1:
	    	*(putptr+1) = (*(putptr + 1) & 0xF0) | val;
		break;
	    case 2:
	    	*(putptr+2) = (*(putptr + 2) & 0x0F) | (val << 4);
		break;
	    case 3:
	    	*(putptr+2) = (*(putptr + 2) & 0xF0) | val;
		break;
	}
}

void SetCmd(UWORD block,UWORD line,UBYTE track,UWORD cmd)
{
	UBYTE *ptr = CalcAddr(block,line,track);
	if(!ptr || !(gadget6[0].GadgetID & 0x1000)) return;
	*(ptr + 2) = (UBYTE)cmd;
	*(ptr + 1) = (*(ptr + 1) & 0xF0) | (UBYTE)(cmd >> 8);
}

void SoitaNappain(UWORD code,BOOL canberecursive,UWORD qual)
{
	UBYTE notenum = 0,whichnum,keycount,callagain = FALSE,*thisnote;
	UWORD edblock = pblock; /* pblock is volatile!! */
	BYTE num = -1;
	static UBYTE extraoffs[4] = { 8,17,26,35 };
	editline = pline;
	if(waitnx) { HandleNumEntr(code); return; }
	if(code <= 0x3a && kbnotes[code] != -1)
		notenum =  nappokt * 12 + kbnotes[code] + 1;
	if(gadget6[0].GadgetID & 0x1000) {
	    if(cursorx == 4||cursorx == 13||cursorx == 22||
	    	cursorx == 31) {
			if(notenum > 63) return;
			callagain = TRUE;
			if(pstate && counter >= 4 && ++editline > lohko[edblock]->lines) editline = 0;
			if(notenum) PutNote(edblock,editline,
				currtrk,notenum,(UBYTE)(samplenum+1));
			else if(code == 0x46) PutNote(edblock,editline,
				currtrk,0,0); /* DEL */
			else callagain = FALSE;
			if(callagain && (qual & (ALTLEFT|ALTRIGHT))) {
				thisnote = CalcAddr(edblock,editline,currtrk);
				if(thisnote) {
					if(qual & ALTLEFT) PushNote(thisnote,10);
					else PushNote(thisnote,11);
				}
			}
	    } else {
		whichnum = cursorx - extraoffs[currpos];
		for(keycount = 0; keycount < 32; keycount++)
			if(code == instrcode[keycount]) { num = keycount; break; }
		if(code == 0x46) num = 0;
		if((qual & SHIFT) && num != -1) num += 32;
		if(num > 0xF && whichnum) num = -1; /* G-V only in # 1 */
		if(num != -1) PutData(edblock,editline,currtrk,whichnum,num);
	    }
	    if(notenum || num != -1 || code == 0x46) UpdateScreen();
	}
	if(notenum && num == -1) PlayNote(notenum,samplenum);
	if((gadget6[1].GadgetID & 0x1000) && callagain && canberecursive)
		SoitaNappain(0x46,FALSE,qual); /* DEL, can't be recursive */
}

static void __regargs SetVol(UWORD block,UWORD line,UBYTE trk,UBYTE vol)
{
	if(!(song.flags & FLAG_VOLHEX)) vol = ((vol / 10) << 4) | (vol % 10);
	SetCmd(block,line,trk,(UWORD)(0xC00 | vol));
}

void PutMNote(UBYTE note)
{
	UBYTE vol = recvol; /* recvol may change during handling... */
	UWORD pb2 = pblock;
	editline = pline;
	if(note < 24 || note > 86) return;
	note -= 23;
	if(gadget6[0].GadgetID & 0x1000) {
		PutNote(pb2,editline,currtrk,note,(UBYTE)(samplenum + 1));
		if(gadget9[23].GadgetID & 0x1000) SetVol(pb2,editline,
			currtrk,(UBYTE)((vol + 1) >> 1));
		UpdateScreen();
	}
	if(!song.sample[samplenum].midich) PlayNote(note,samplenum);
	if(gadget6[1].GadgetID & 0x1000) SoitaNappain(0x46,FALSE,0);
}

static void __regargs HandleNumEntr(UWORD code)
{
	UBYTE cnt,mx = (UBYTE)mousex;
	BYTE num = -1,x = 0;
	struct PrgNote *d = &prgn[prgdisp];
	if(mx < 123) return;
	if(code == 0x32) x = -1;
	if(mx < 147) {
		if(x) { d->notenum = 0; d->xnn = 1; }
		else if(code <= 0x3a && kbnotes[code] != -1) {
			cnt = nappokt * 12 + kbnotes[code] + 1;
			if(prgdisp < 10) {
				d->notenum = cnt;
				d->xnn = 0;
				PlayNote(cnt,samplenum);
			}
		}
		else if(code == 0x46 && prgdisp < 10) { d->notenum = 0; d->xnn = 0; }
	} else {
		for(cnt = 0; cnt < 32; cnt++)
			if(code == instrcode[cnt]) { num = cnt; break; }
		if(num == -1 && !x) return; /* nothing important.. */
		if(mx < 157) {
			if(x) { d->num0 = 0; d->x0th = 1; }
			else if(num < 2) { d->num0 = num; d->x0th = 0; }
		} else if(mx < 165) {
			if(x) { d->num1 = 0; d->x1st = 1; }
			else { d->num1 = num; d->x1st = 0; }
		} else if(mx < 173) {
			if(x) { d->num2 = 0; d->x2nd = 1; }
			else if(num < 16) { d->num2 = num; d->x2nd = 0; }
		} else if(mx < 181) {
			if(x) { d->num3 = 0; d->x3rd = 1; }
			else if(num < 16) { d->num3 = num; d->x3rd = 0; }
		} else if(mx < 189) {
			if(x) { d->num4 = 0; d->x4th = 1; }
			else if(num < 16) { d->num4 = num; d->x4th = 0; }
		}
	}
	DispPrgNote();
}

void DispPrgData()
{
	UBYTE num;
	if(nykyinenosio == 6) {
		SetAPen(wrp,7);
		Move(wrp,103,37);
		num = shnum + '0';
		Text(wrp,&num,1);
		SetAPen(wrp,0);
	}
	Korosta(&gadget6[26],(BOOL)(prgdisp < 10));
	Korosta(&gadget6[27],(BOOL)(prgdisp == 10));
	Korosta(&gadget6[28],(BOOL)(prgdisp == 11));
	DispPrgNote();
}

static void __regargs DispPrgNote()
{
	extern void __stdargs namet(); /* this data is in code section */
	char nbrs[5];
	struct PrgNote *d = &prgn[prgdisp];
	if(nykyinenosio == 6) {
		SetAPen(wrp,7);
		Move(wrp,123,36);
		if(d->xnn) Text(wrp,"xxx",3);
		else if(!d->notenum) Text(wrp,"---",3);
		else Text(wrp,(char *)namet + (d->notenum - 1) * 4,3);
		nbrs[0] = d->x0th ? 'x' : d->num0 ? '1' : ' ';
		nbrs[1] = d->x1st ? 'x' : heksaluku[d->num1];
		nbrs[2] = d->x2nd ? 'x' : heksaluku[d->num2];
		nbrs[3] = d->x3rd ? 'x' : heksaluku[d->num3];
		nbrs[4] = d->x4th ? 'x' : heksaluku[d->num4];
		Move(wrp,149,36);
		Text(wrp,nbrs,5);
		SetAPen(wrp,0);
	}
}

static void __regargs ClrPrg()
{
	memset(&prgn[prgdisp],0,sizeof(struct PrgNote));
	if(prgdisp > 9) {
		prgn[prgdisp].xnn = 1;
		prgn[prgdisp].x0th = 1;
		prgn[prgdisp].x1st = 1;
	}
}

void LoadKeys()
{
	BPTR file = Open("S:med.defprgkeys",MODE_OLDFILE);
	if(!file) {
		register UBYTE cnt = 0;
		for(;cnt < 12; cnt++) {
			prgdisp = cnt;
			ClrPrg();
		}
		prgdisp = 0;
		return;
	}
	Read(file,(void *)prgn,sizeof(prgn));
	Close(file);
}

static void __regargs SaveKeys()
{
	BPTR file = Open("S:med.defprgkeys",MODE_NEWFILE);
	if(!file) return;
	Ilmoita("Saving keys...");
	Write(file,(void *)prgn,sizeof(prgn));
	Close(file);
	Ilmoita(NULL);
}

static void __regargs PickNote(UBYTE *p)
{
	ClrPrg();
	if(prgdisp < 10) {
		prgn[prgdisp].notenum = *p & 0x3f;
		prgn[prgdisp].num0 = (*p & 0x40) ? 1 : 0;
		prgn[prgdisp].num1 = ((*p & 0x80) ? 16 : 0) + (*(p+1) >> 4);
	}
	prgn[prgdisp].num2 = (*(p+1)) & 0x0f;
	prgn[prgdisp].num3 = (*(p+2)) >> 4;
	prgn[prgdisp].num4 = (*(p+2)) & 0x0f;
	DispPrgNote();
}

static void __regargs PushNote(UBYTE *p,UBYTE num)
{
	struct PrgNote *n = &prgn[num];
	if(n->notenum || (n->xnn && (*p & 0x3f))) { /* v--isn't C easy?? */
		UBYTE newsnum = (UBYTE)((n->x0th ? ((*p & 0x40) ? 32 : 0)
			: (n->num0 ? 32 : 0)) +	(n->x1st ? (((*p & 0x80) ?
			16 : 0) + (*(p+1) >> 4)) : n->num1));
		PlayNote((UBYTE)(n->xnn ? (*p & 0x3f) : n->notenum),(UBYTE)(newsnum - 1));
	}
	if(gadget6[0].GadgetID & 0x1000) {
		if(!(n->xnn)) { *p &= 0xC0; *p |= n->notenum; }
		if(!(n->x0th)) { *p &= ~0x40; if(n->num0) *p |= 0x40; }
		if(!(n->x1st)) { *p &= ~0x80; if(n->num1 > 15) *p |= 0x80;
			*(p+1) &= 0x0f; *(p+1) |= (UBYTE)(n->num1 << 4); }
		if(!(n->x2nd)) { *(p+1) &= 0xf0; *(p+1) |= n->num2; }
		if(!(n->x3rd)) { *(p+2) &= 0x0f; *(p+2) |= (n->num3 << 4); }
		if(!(n->x4th)) { *(p+2) &= 0xf0; *(p+2) |= n->num4; }
	}
}

void EditHandler(gid)	/* this is a local gadget-handler */
UWORD gid;
{
	UBYTE *thisnote = CalcAddr(pblock,editline = pline,currtrk);
	if(!thisnote) return; /* some error...shouldn't happen */
	if(gid >= 0x101 && gid <= 0x10A) { /* Shift+Ctrl+0 - 9 pressed */
		prgdisp = shnum = (gid == 0x10A ? 0 : (gid & 0xff));
		PickNote(thisnote);
		DispPrgData();
	} else if(gid >= 0x01 && gid <= 0x0A) { /* Shift + 0 - 9 */
		PushNote(thisnote,(UBYTE)(gid == 0x0A ? 0 : gid));
		UpdateScreen();
		if(gadget6[1].GadgetID & 0x1000) SoitaNappain(0x46,FALSE,0); /* 2× */
	} else if(gid == 0x46 && (gadget6[0].GadgetID & 0x1000)) {
		*thisnote++ = 0; *thisnote++ = 0; *thisnote = 0;
		if(gadget6[1].GadgetID & 0x1000) {
			UpdateScreen();
			thisnote = CalcAddr(pblock,++editline,currtrk);
			if(thisnote) {
				*thisnote++ = 0; *thisnote++ = 0; *thisnote = 0;
			}
		}
		UpdateScreen();
	} else switch(gid) {
		case 0x617: if(!shnum--) shnum = 9;
			    prgdisp = shnum; DispPrgData(); break;
		case 0x618: if(++shnum > 9) shnum = 0;
		case 0x61A: prgdisp = shnum; DispPrgData(); break;
		case 0x61B: prgdisp = 10; DispPrgData(); break;
		case 0x61C: prgdisp = 11; DispPrgData(); break;
		case 0x61D: PickNote(thisnote); break;
		case 0x61F: VolSlide(); break;
		case 0x620: SaveKeys(); break;
		case 0x621: ClrPrg(); break;
		case 0x622: if(prgdisp < 10) {
				if(prgn[prgdisp].xnn) {
					prgn[prgdisp].xnn = 0;
					prgn[prgdisp].notenum = 0;
				}
				else if(prgn[prgdisp].notenum < 63)
					prgn[prgdisp].notenum++;
				else prgn[prgdisp].xnn = 1;
			    }
			    break;
		case 0x623: if(prgdisp < 10) {
				if(prgn[prgdisp].xnn) {
					prgn[prgdisp].xnn = 0;
					prgn[prgdisp].notenum = 63;
				}
				else if(prgn[prgdisp].notenum)
					prgn[prgdisp].notenum--;
				else prgn[prgdisp].xnn = 1;
			    }
			    break;
		case 0x624: if(prgdisp < 10 && prgn[prgdisp].notenum &&
				!(prgn[prgdisp].xnn))
					prgn[prgdisp].notenum += 12;
			    break;
		case 0x625: if(prgdisp < 10 && prgn[prgdisp].notenum &&
				!(prgn[prgdisp].xnn))
					prgn[prgdisp].notenum -= 12;
			    break;
		case 0x626: if(prgdisp < 10) {
				prgn[prgdisp].notenum = 0;
				prgn[prgdisp].xnn = 0;
			    }
			    break;
		case 0x627: if(prgn[prgdisp].x0th) {
				prgn[prgdisp].x0th = 0;
				prgn[prgdisp].num0 = 0;
			    } else if(prgn[prgdisp].num0) prgn[prgdisp].x0th = 1;
			    else prgn[prgdisp].num0 = 1;
			    break;
		case 0x628: if(prgn[prgdisp].x1st) prgn[prgdisp].x1st = 0;
			    else if(prgn[prgdisp].num1 < 31) prgn[prgdisp].num1++;
			    else { prgn[prgdisp].num1 = 0; prgn[prgdisp].x1st = 1; }
			    break;
		case 0x629: if(prgn[prgdisp].x1st) {
				prgn[prgdisp].x1st = 0;
				prgn[prgdisp].num1 = 31;
			    } else if(prgn[prgdisp].num1) prgn[prgdisp].num1--;
			    else prgn[prgdisp].x1st = 1;
			    break;
		case 0x62A: prgn[prgdisp].x1st = 0; prgn[prgdisp].num1 = 0; break;
		case 0x62B: if(prgn[prgdisp].x2nd) prgn[prgdisp].x2nd = 0;
			    else if(prgn[prgdisp].num2 < 15) prgn[prgdisp].num2++;
			    else { prgn[prgdisp].num2 = 0; prgn[prgdisp].x2nd = 1; }
			    break;
		case 0x62C: if(prgn[prgdisp].x2nd) {
				prgn[prgdisp].x2nd = 0;
				prgn[prgdisp].num2 = 15;
			    } else if(prgn[prgdisp].num2) prgn[prgdisp].num2--;
			    else prgn[prgdisp].x2nd = 1;
			    break;
		case 0x62D: prgn[prgdisp].x2nd = 0; prgn[prgdisp].num2 = 0; break;
		case 0x62E: if(prgn[prgdisp].x3rd) prgn[prgdisp].x3rd = 0;
			    else if(prgn[prgdisp].num3 < 15) prgn[prgdisp].num3++;
			    else { prgn[prgdisp].num3 = 0; prgn[prgdisp].x3rd = 1; }
			    break;
		case 0x62F: if(prgn[prgdisp].x3rd) {
				prgn[prgdisp].x3rd = 0;
				prgn[prgdisp].num3 = 15;
			    } else if(prgn[prgdisp].num3) prgn[prgdisp].num3--;
			    else prgn[prgdisp].x3rd = 1;
			    break;
		case 0x630: prgn[prgdisp].x3rd = 0; prgn[prgdisp].num3 = 0; break;
		case 0x631: if(prgn[prgdisp].x4th) prgn[prgdisp].x4th = 0;
			    else if(prgn[prgdisp].num4 < 15) prgn[prgdisp].num4++;
			    else { prgn[prgdisp].num4 = 0; prgn[prgdisp].x4th = 1; }
			    break;
		case 0x632: if(prgn[prgdisp].x4th) {
				prgn[prgdisp].x4th = 0;
				prgn[prgdisp].num4 = 15;
			    } else if(prgn[prgdisp].num4) prgn[prgdisp].num4--;
			    else prgn[prgdisp].x4th = 1;
			    break;
		case 0x633: prgn[prgdisp].x4th = 0; prgn[prgdisp].num4 = 0;
	}
	if(gid >= 0x621) DispPrgNote();
}

static void __regargs VolSlide()
{
	BYTE startvol,endvol;
	UBYTE *nptr;
	WORD sline = pline,eline = sline + 1;
	UWORD blk = pblock,lcnt;
	LONG vchngl,currv; /* volume change / line, current vol */
	if(!(gadget6[0].GadgetID & 0x1000)) return;
	for(;;) {
		nptr = CalcAddr(blk,sline,currtrk);
		if((*(nptr+1) & 0x0F) == 0x0C) break;
		if(!sline--) return;
	}
	startvol = *(nptr + 2);
	if(eline > lohko[blk]->lines) return;
	for(;;) {
		nptr = CalcAddr(blk,eline,currtrk);
		if((*(nptr+1) & 0x0F) == 0x0C) break;
		if(eline++ >= lohko[blk]->lines) return;
	}
	endvol = *(nptr + 2); /* now we know the start/end volumes & lines */
	if(!(song.flags & FLAG_VOLHEX)) {
		startvol = (10 * (startvol >> 4)) + (startvol & 0x0F);
		endvol = (10 * (endvol >> 4)) + (endvol & 0x0F);
	}
	if(startvol < 0 || startvol > 64 || endvol < 0 || endvol > 64) return;
	vchngl = ((endvol - startvol) * 100) / (eline - sline);
	currv = startvol * 100;
	for(lcnt = sline; lcnt < eline; lcnt++) {
		SetVol(blk,lcnt,currtrk,(UBYTE)((currv + 50) / 100));
		currv += vchngl;
	}
	PaivitaNaytto(TRUE);
}

void DoSlide(UBYTE type) /* automatic slide generation */
{
	UWORD sblock = pblock,sline = pline,eline = sline,lcnt;
	UWORD div,divhalf;
	ULONG perchngd,persb,step,lval;
	WORD perdiff;
	UBYTE trk = currtrk,*noteptr,fromnote,tonote,slidedown = 0;
	UBYTE *nptr2,n1,n2,stne = 0;
	if(!(gadget6[0].GadgetID & 0x1000)) return;
	if(song.flags & FLAG_STSLIDE) div = song.sliding * 100;
	else div = 600;
	if(!div) return; /* dividing by zero is deadly */
	divhalf = div / 2;
	if(!type && eline-- == 0) return;
	for(;;) { /* search the previous note */
		noteptr = CalcAddr(sblock,eline,trk);
		if(*noteptr & 0x3f) break;
		if(!eline--) return;
	}
	fromnote = *noteptr & 0x3f;
	if(type) eline = sline + 1; else eline = sline;
	if(eline > lohko[sblock]->lines) return;
	for(;;) { /* and the next one too */
		noteptr = CalcAddr(sblock,eline,trk);
		if(*noteptr & 0x3f) break;
		if(eline++ >= lohko[sblock]->lines) return; /* not possible */
	}
	if(type) eline--;
	tonote = *noteptr & 0x3f; /* difference between periods -vv */
	perdiff = (WORD)periodit[fromnote-1] - (WORD)periodit[tonote-1];
	if(perdiff < 0) { /* slide it down */
		slidedown = 1;
		perdiff = -perdiff;
	} /* multiplied by 100 for enough accuracy */
	if(!type) {
		n1 = *noteptr; n2 = *(noteptr+1);
		*noteptr++ = 0; *noteptr = 0;
	}
	lval = perdiff * 100 / (eline - sline + 1); /* period change / line */
	perchngd = persb = 0;
	for(lcnt = sline; lcnt <= eline; lcnt++) {
		persb += lval; /* the period should be this now */
		step = ((persb + divhalf) - perchngd) / div; /* try to do it!! */
		perchngd += div * step; /* period changed actually this */
		if(!step) SetCmd(sblock,lcnt,trk,0); /* just zero */
		else if(!type) {
			if(lcnt == eline && perchngd < persb) step++;
			if(!stne) {
				nptr2 = CalcAddr(sblock,lcnt,trk);
				*nptr2++ = n1; *nptr2++ = n2; stne = 1;
			}
			SetCmd(sblock,lcnt,trk,(UWORD)(0x300 | step));
		}
		else SetCmd(sblock,lcnt,trk,(UWORD)((slidedown ? 0x200 : 0x100) | step));
	}
	PaivitaNaytto(TRUE);
}

void HLLine(UWORD block,UBYTE line)
{
	ULONG *hlp = lohko[block]->hlmask;
	while(line > 31) { line -= 32; hlp++; }
	*hlp ^= 1 << line;
}

void HighLightLines(UWORD block,UWORD index)
{
	static UBYTE spcs[] = { 1,2,3,4,8,16,0 };
	UBYTE spc = spcs[index];
	UWORD lcnt;
	if(!spc) {	/* clear all */
		ULONG *mskp = lohko[block]->hlmask;
		for(lcnt = 0; lcnt < 8; lcnt++) *mskp++ = 0;
	} else	for(lcnt = 0; lcnt < lohko[block]->lines + 1; lcnt++)
			if(!(lcnt % spc)) HLLine(block,(UBYTE)lcnt);
	PaivitaNaytto(TRUE);
}

void ShowLineNum()
{
	UWORD pos,lines = lohko[pblock]->lines + 1;
	if(nykyinenosio == 5) pos = RemoveGadget(window,&gadget5[32]);
	strinfo[9].BufferPos = 0;
	strinfo[9].DispPos = 0;
	strinfo[9].LongInt = (LONG)lines;
	stcu_d(linesstr,lines);
	if(nykyinenosio == 5) {
		AddGadget(window,&gadget5[32],pos);
		RefreshGList(&gadget5[32],window,NULL,1);
	}
}

void HandleLines(UWORD blk,UWORD gid)
{
	register UWORD newl = (UWORD)(lohko[blk]->lines) + 1;
	LONG lint = strinfo[9].LongInt;
	switch(gid) {
		case 0x51E: if(newl > 10) newl -= 10;
			    break;
		case 0x51F: if(newl > 1) newl--;
			    break;
		case 0x520: if(lint > 0 && lint <= 256) newl = (UWORD)lint;
			    break;
		case 0x521: if(newl < 256) newl++;
			    break;
		case 0x522: if(newl <= 246) newl += 10;
			    break;
	}
	if(newl != lohko[blk]->lines + 1) {
		if(pblock == blk && pline >= newl) pline = newl - 1;
		ChangeBlockSize(blk,(UWORD)(lohko[blk]->numtracks / 4),newl);
		ShowLineNum();
	}
}
