home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / amiga / midi / med210.lhw / in.adf / Source / med210src.lzh / med-ed.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-23  |  19.3 KB  |  626 lines

  1. /* MED - music editor ⌐á1989, 1990 by Teijo Kinnunen */
  2. /* med-ed.c: editing functions */
  3. #include "med.h"
  4. #include "medproto.h"
  5.  
  6. /* WARNING: Beginning programmers!!! Don't look here for examples of good
  7.    programming style!!! This file may contain many sloppy & unprofessional
  8.    techniques. Read at your own risk. */
  9.  
  10. #define SHIFT (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)
  11. UWORD near periodit[] = { 856,808,762,720,678,640,604,570,538,508,480,453,
  12.               428,404,381,360,339,320,302,285,269,254,240,226,
  13.               214,202,190,180,170,160,151,143,135,127,120,113,
  14.               214,202,190,180,170,160,151,143,135,127,120,113,
  15.               214,202,190,180,170,160,151,143,135,127,120,113,
  16.               214,202,190,180,170,160,151,143,135,127,120,113 };
  17. UBYTE firstdisptrk = 0,counter = 0,far recvol;
  18. struct Library *ciaaresource;
  19. extern struct Gadget far gadget6[],far gadget5[],far gadget9[];
  20. extern struct Kappale far song;
  21. extern struct RastPort *wrp;
  22. extern struct Window *window;
  23. extern UWORD volatile pline,pblock,pstate,mousex;
  24. extern UBYTE cursorx,currtrk,samplenum,blocks,currpos,near heksaluku[],waitnx;
  25. extern struct StringInfo strinfo[];
  26. extern struct Lohko far *lohko[];
  27. static struct PrgNote prgn[12];
  28. static UBYTE far instrcode[] = { 0x0a,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
  29.                 0x09,0x20,0x35,0x33,0x22,0x12,0x23,0x24,0x25,
  30.                 0x17,0x26,0x27,0x28,0x37,0x36,0x18,0x19,0x10,
  31.                 0x13,0x21,0x14,0x16,0x34 };
  32. static UBYTE far prgdisp = 0,far shnum = 0;
  33. static BYTE far kbnotes[] = {
  34.     -1,-1,13,15,-1,18,20,22,-1,25,27,-1,30,32,-1,-1,
  35.     12,14,16,17,19,21,23,24,26,28,29,31,-1,-1,-1,-1,
  36.     -1,1,3,-1,6,8,10,-1,13,15,-1,-1,-1,-1,-1,-1,
  37.     -1,0,2,4,5,7,9,11,12,14,16 }; /* end = 0x3a */
  38. UBYTE far nappkoodi[]={ 0x31,0x21,0x32,0x22,0x33,0x34,0x24,0x35,0x25,0x36,0x26,
  39.             0x37,
  40.             0x10,0x02,0x11,0x03,0x12,0x13,0x05,0x14,0x06,0x15,0x07,
  41.             0x16 };
  42. static UWORD chip zerodata = 0;
  43. UWORD far nappokt = 0,editline,*zeroptr = &zerodata;
  44. struct PlayNotedata far keybnote;
  45. extern UWORD nykyinenosio;
  46. extern char linesstr[];
  47.  
  48. static void __regargs PlayNote(UBYTE,UBYTE);
  49. static void __regargs UpdateScreen(void);
  50. static UBYTE * __regargs CalcAddr(UWORD,UWORD,UBYTE);
  51. static void __regargs PutData(UWORD,UWORD,UBYTE,UBYTE,UBYTE);
  52. static void __regargs VolSlide(void);
  53. static void __regargs SetVol(UWORD,UWORD,UBYTE,UBYTE);
  54. static void __regargs ClrPrg(void);
  55. static void __regargs DispPrgNote(void);
  56. static void __regargs SaveKeys(void);
  57. static void __regargs PushNote(UBYTE *,UBYTE);
  58. static void __regargs HandleNumEntr(UWORD);
  59.  
  60. static void __regargs PlayNote(UBYTE notenum,UBYTE instr)
  61. {
  62.     keybnote.notenum = notenum;
  63.     keybnote.instrnum = instr;
  64.     keybnote.tracknum = currtrk;
  65.     keybnote.playnote = 1;
  66.     SetICR(ciaaresource,CIAICRF_SETCLR|CIAICRF_TA);
  67. }
  68.     
  69. static void __regargs UpdateScreen()
  70. {
  71.     if(pstate == ALASOITA && (gadget6[25].GadgetID & 0x1000) &&
  72.         (gadget6[0].GadgetID & 0x1000))    pline++;
  73.     if(pline > lohko[pblock]->lines) { pline = 0; PaivitaNaytto(TRUE); }
  74.     else PaivitaNaytto(1234); /* secret code */
  75. }
  76.     
  77. static UBYTE * __regargs CalcAddr(block,line,track)
  78. UWORD block,line;
  79. UBYTE track;
  80. {
  81.     if(block > blocks - 1) return(0);
  82.     if(track > lohko[block]->numtracks - 1) return(0);
  83.     if(line > lohko[block]->lines) return(0);
  84.     return(&lohko[block]->music[line * lohko[block]->numtracks * 3 +
  85.         3 * track]);
  86. }
  87.  
  88. void PutNote(block,line,track,note,instr)
  89. UWORD block,line;
  90. UBYTE track,note;
  91. UBYTE instr;
  92. {
  93.     UBYTE *putptr = CalcAddr(block,line,track);
  94.     if(!putptr) return;
  95.     *putptr = note;
  96.     *(putptr+1) = (*(putptr + 1) & 0x0F) | (instr << 4);
  97.     if(instr > 31) {
  98.         *putptr |= 0x40;
  99.         instr -= 31;
  100.     }
  101.     if(instr > 0xF) *putptr |= 0x80;
  102. }
  103.  
  104. static void __regargs PutData(block,line,track,num,val)
  105. UWORD block,line;
  106. UBYTE track,num,val;
  107. {
  108.     UBYTE *putptr = CalcAddr(block,line,track);
  109.     if(!putptr) return;
  110.     switch(num) {
  111.         case 0:
  112.         *(putptr+1) = (*(putptr + 1) & 0x0F) | (val << 4);
  113.         if(val > 31) {
  114.             *putptr |= 0x40;
  115.             val -= 31;
  116.         } else *putptr &= ~0x40;
  117.         if(val > 0xF) *putptr |= 0x80; else *putptr &= ~0x80;
  118.         break;
  119.         case 1:
  120.             *(putptr+1) = (*(putptr + 1) & 0xF0) | val;
  121.         break;
  122.         case 2:
  123.             *(putptr+2) = (*(putptr + 2) & 0x0F) | (val << 4);
  124.         break;
  125.         case 3:
  126.             *(putptr+2) = (*(putptr + 2) & 0xF0) | val;
  127.         break;
  128.     }
  129. }
  130.  
  131. void SetCmd(UWORD block,UWORD line,UBYTE track,UWORD cmd)
  132. {
  133.     UBYTE *ptr = CalcAddr(block,line,track);
  134.     if(!ptr || !(gadget6[0].GadgetID & 0x1000)) return;
  135.     *(ptr + 2) = (UBYTE)cmd;
  136.     *(ptr + 1) = (*(ptr + 1) & 0xF0) | (UBYTE)(cmd >> 8);
  137. }
  138.  
  139. void SoitaNappain(UWORD code,BOOL canberecursive,UWORD qual)
  140. {
  141.     UBYTE notenum = 0,whichnum,keycount,callagain = FALSE,*thisnote;
  142.     UWORD edblock = pblock; /* pblock is volatile!! */
  143.     BYTE num = -1;
  144.     static UBYTE extraoffs[4] = { 8,17,26,35 };
  145.     editline = pline;
  146.     if(waitnx) { HandleNumEntr(code); return; }
  147.     if(code <= 0x3a && kbnotes[code] != -1)
  148.         notenum =  nappokt * 12 + kbnotes[code] + 1;
  149.     if(gadget6[0].GadgetID & 0x1000) {
  150.         if(cursorx == 4||cursorx == 13||cursorx == 22||
  151.             cursorx == 31) {
  152.             if(notenum > 63) return;
  153.             callagain = TRUE;
  154.             if(pstate && counter >= 4 && ++editline > lohko[edblock]->lines) editline = 0;
  155.             if(notenum) PutNote(edblock,editline,
  156.                 currtrk,notenum,(UBYTE)(samplenum+1));
  157.             else if(code == 0x46) PutNote(edblock,editline,
  158.                 currtrk,0,0); /* DEL */
  159.             else callagain = FALSE;
  160.             if(callagain && (qual & (ALTLEFT|ALTRIGHT))) {
  161.                 thisnote = CalcAddr(edblock,editline,currtrk);
  162.                 if(thisnote) {
  163.                     if(qual & ALTLEFT) PushNote(thisnote,10);
  164.                     else PushNote(thisnote,11);
  165.                 }
  166.             }
  167.         } else {
  168.         whichnum = cursorx - extraoffs[currpos];
  169.         for(keycount = 0; keycount < 32; keycount++)
  170.             if(code == instrcode[keycount]) { num = keycount; break; }
  171.         if(code == 0x46) num = 0;
  172.         if((qual & SHIFT) && num != -1) num += 32;
  173.         if(num > 0xF && whichnum) num = -1; /* G-V only in # 1 */
  174.         if(num != -1) PutData(edblock,editline,currtrk,whichnum,num);
  175.         }
  176.         if(notenum || num != -1 || code == 0x46) UpdateScreen();
  177.     }
  178.     if(notenum && num == -1) PlayNote(notenum,samplenum);
  179.     if((gadget6[1].GadgetID & 0x1000) && callagain && canberecursive)
  180.         SoitaNappain(0x46,FALSE,qual); /* DEL, can't be recursive */
  181. }
  182.  
  183. static void __regargs SetVol(UWORD block,UWORD line,UBYTE trk,UBYTE vol)
  184. {
  185.     if(!(song.flags & FLAG_VOLHEX)) vol = ((vol / 10) << 4) | (vol % 10);
  186.     SetCmd(block,line,trk,(UWORD)(0xC00 | vol));
  187. }
  188.  
  189. void PutMNote(UBYTE note)
  190. {
  191.     UBYTE vol = recvol; /* recvol may change during handling... */
  192.     UWORD pb2 = pblock;
  193.     editline = pline;
  194.     if(note < 24 || note > 86) return;
  195.     note -= 23;
  196.     if(gadget6[0].GadgetID & 0x1000) {
  197.         PutNote(pb2,editline,currtrk,note,(UBYTE)(samplenum + 1));
  198.         if(gadget9[23].GadgetID & 0x1000) SetVol(pb2,editline,
  199.             currtrk,(UBYTE)((vol + 1) >> 1));
  200.         UpdateScreen();
  201.     }
  202.     if(!song.sample[samplenum].midich) PlayNote(note,samplenum);
  203.     if(gadget6[1].GadgetID & 0x1000) SoitaNappain(0x46,FALSE,0);
  204. }
  205.  
  206. static void __regargs HandleNumEntr(UWORD code)
  207. {
  208.     UBYTE cnt,mx = (UBYTE)mousex;
  209.     BYTE num = -1,x = 0;
  210.     struct PrgNote *d = &prgn[prgdisp];
  211.     if(mx < 123) return;
  212.     if(code == 0x32) x = -1;
  213.     if(mx < 147) {
  214.         if(x) { d->notenum = 0; d->xnn = 1; }
  215.         else if(code <= 0x3a && kbnotes[code] != -1) {
  216.             cnt = nappokt * 12 + kbnotes[code] + 1;
  217.             if(prgdisp < 10) {
  218.                 d->notenum = cnt;
  219.                 d->xnn = 0;
  220.                 PlayNote(cnt,samplenum);
  221.             }
  222.         }
  223.         else if(code == 0x46 && prgdisp < 10) { d->notenum = 0; d->xnn = 0; }
  224.     } else {
  225.         for(cnt = 0; cnt < 32; cnt++)
  226.             if(code == instrcode[cnt]) { num = cnt; break; }
  227.         if(num == -1 && !x) return; /* nothing important.. */
  228.         if(mx < 157) {
  229.             if(x) { d->num0 = 0; d->x0th = 1; }
  230.             else if(num < 2) { d->num0 = num; d->x0th = 0; }
  231.         } else if(mx < 165) {
  232.             if(x) { d->num1 = 0; d->x1st = 1; }
  233.             else { d->num1 = num; d->x1st = 0; }
  234.         } else if(mx < 173) {
  235.             if(x) { d->num2 = 0; d->x2nd = 1; }
  236.             else if(num < 16) { d->num2 = num; d->x2nd = 0; }
  237.         } else if(mx < 181) {
  238.             if(x) { d->num3 = 0; d->x3rd = 1; }
  239.             else if(num < 16) { d->num3 = num; d->x3rd = 0; }
  240.         } else if(mx < 189) {
  241.             if(x) { d->num4 = 0; d->x4th = 1; }
  242.             else if(num < 16) { d->num4 = num; d->x4th = 0; }
  243.         }
  244.     }
  245.     DispPrgNote();
  246. }
  247.  
  248. void DispPrgData()
  249. {
  250.     UBYTE num;
  251.     if(nykyinenosio == 6) {
  252.         SetAPen(wrp,7);
  253.         Move(wrp,103,37);
  254.         num = shnum + '0';
  255.         Text(wrp,&num,1);
  256.         SetAPen(wrp,0);
  257.     }
  258.     Korosta(&gadget6[26],(BOOL)(prgdisp < 10));
  259.     Korosta(&gadget6[27],(BOOL)(prgdisp == 10));
  260.     Korosta(&gadget6[28],(BOOL)(prgdisp == 11));
  261.     DispPrgNote();
  262. }
  263.  
  264. static void __regargs DispPrgNote()
  265. {
  266.     extern void __stdargs namet(); /* this data is in code section */
  267.     char nbrs[5];
  268.     struct PrgNote *d = &prgn[prgdisp];
  269.     if(nykyinenosio == 6) {
  270.         SetAPen(wrp,7);
  271.         Move(wrp,123,36);
  272.         if(d->xnn) Text(wrp,"xxx",3);
  273.         else if(!d->notenum) Text(wrp,"---",3);
  274.         else Text(wrp,(char *)namet + (d->notenum - 1) * 4,3);
  275.         nbrs[0] = d->x0th ? 'x' : d->num0 ? '1' : ' ';
  276.         nbrs[1] = d->x1st ? 'x' : heksaluku[d->num1];
  277.         nbrs[2] = d->x2nd ? 'x' : heksaluku[d->num2];
  278.         nbrs[3] = d->x3rd ? 'x' : heksaluku[d->num3];
  279.         nbrs[4] = d->x4th ? 'x' : heksaluku[d->num4];
  280.         Move(wrp,149,36);
  281.         Text(wrp,nbrs,5);
  282.         SetAPen(wrp,0);
  283.     }
  284. }
  285.  
  286. static void __regargs ClrPrg()
  287. {
  288.     memset(&prgn[prgdisp],0,sizeof(struct PrgNote));
  289.     if(prgdisp > 9) {
  290.         prgn[prgdisp].xnn = 1;
  291.         prgn[prgdisp].x0th = 1;
  292.         prgn[prgdisp].x1st = 1;
  293.     }
  294. }
  295.  
  296. void LoadKeys()
  297. {
  298.     BPTR file = Open("S:med.defprgkeys",MODE_OLDFILE);
  299.     if(!file) {
  300.         register UBYTE cnt = 0;
  301.         for(;cnt < 12; cnt++) {
  302.             prgdisp = cnt;
  303.             ClrPrg();
  304.         }
  305.         prgdisp = 0;
  306.         return;
  307.     }
  308.     Read(file,(void *)prgn,sizeof(prgn));
  309.     Close(file);
  310. }
  311.  
  312. static void __regargs SaveKeys()
  313. {
  314.     BPTR file = Open("S:med.defprgkeys",MODE_NEWFILE);
  315.     if(!file) return;
  316.     Ilmoita("Saving keys...");
  317.     Write(file,(void *)prgn,sizeof(prgn));
  318.     Close(file);
  319.     Ilmoita(NULL);
  320. }
  321.  
  322. static void __regargs PickNote(UBYTE *p)
  323. {
  324.     ClrPrg();
  325.     if(prgdisp < 10) {
  326.         prgn[prgdisp].notenum = *p & 0x3f;
  327.         prgn[prgdisp].num0 = (*p & 0x40) ? 1 : 0;
  328.         prgn[prgdisp].num1 = ((*p & 0x80) ? 16 : 0) + (*(p+1) >> 4);
  329.     }
  330.     prgn[prgdisp].num2 = (*(p+1)) & 0x0f;
  331.     prgn[prgdisp].num3 = (*(p+2)) >> 4;
  332.     prgn[prgdisp].num4 = (*(p+2)) & 0x0f;
  333.     DispPrgNote();
  334. }
  335.  
  336. static void __regargs PushNote(UBYTE *p,UBYTE num)
  337. {
  338.     struct PrgNote *n = &prgn[num];
  339.     if(n->notenum || (n->xnn && (*p & 0x3f))) { /* v--isn't C easy?? */
  340.         UBYTE newsnum = (UBYTE)((n->x0th ? ((*p & 0x40) ? 32 : 0)
  341.             : (n->num0 ? 32 : 0)) +    (n->x1st ? (((*p & 0x80) ?
  342.             16 : 0) + (*(p+1) >> 4)) : n->num1));
  343.         PlayNote((UBYTE)(n->xnn ? (*p & 0x3f) : n->notenum),(UBYTE)(newsnum - 1));
  344.     }
  345.     if(gadget6[0].GadgetID & 0x1000) {
  346.         if(!(n->xnn)) { *p &= 0xC0; *p |= n->notenum; }
  347.         if(!(n->x0th)) { *p &= ~0x40; if(n->num0) *p |= 0x40; }
  348.         if(!(n->x1st)) { *p &= ~0x80; if(n->num1 > 15) *p |= 0x80;
  349.             *(p+1) &= 0x0f; *(p+1) |= (UBYTE)(n->num1 << 4); }
  350.         if(!(n->x2nd)) { *(p+1) &= 0xf0; *(p+1) |= n->num2; }
  351.         if(!(n->x3rd)) { *(p+2) &= 0x0f; *(p+2) |= (n->num3 << 4); }
  352.         if(!(n->x4th)) {á*(p+2) &= 0xf0; *(p+2) |= n->num4; }
  353.     }
  354. }
  355.  
  356. void EditHandler(gid)    /* this is a local gadget-handler */
  357. UWORD gid;
  358. {
  359.     UBYTE *thisnote = CalcAddr(pblock,editline = pline,currtrk);
  360.     if(!thisnote) return; /* some error...shouldn't happen */
  361.     if(gid >= 0x101 && gid <= 0x10A) { /* Shift+Ctrl+0 - 9 pressed */
  362.         prgdisp = shnum = (gid == 0x10A ? 0 : (gid & 0xff));
  363.         PickNote(thisnote);
  364.         DispPrgData();
  365.     } else if(gid >= 0x01 && gid <= 0x0A) { /* Shift + 0 - 9 */
  366.         PushNote(thisnote,(UBYTE)(gid == 0x0A ? 0 : gid));
  367.         UpdateScreen();
  368.         if(gadget6[1].GadgetID & 0x1000) SoitaNappain(0x46,FALSE,0); /* 2╫ */
  369.     } else if(gid == 0x46 && (gadget6[0].GadgetID & 0x1000)) {
  370.         *thisnote++ = 0; *thisnote++ = 0; *thisnote = 0;
  371.         if(gadget6[1].GadgetID & 0x1000) {
  372.             UpdateScreen();
  373.             thisnote = CalcAddr(pblock,++editline,currtrk);
  374.             if(thisnote) {
  375.                 *thisnote++ = 0; *thisnote++ = 0; *thisnote = 0;
  376.             }
  377.         }
  378.         UpdateScreen();
  379.     } else switch(gid) {
  380.         case 0x617: if(!shnum--) shnum = 9;
  381.                 prgdisp = shnum; DispPrgData(); break;
  382.         case 0x618: if(++shnum > 9) shnum = 0;
  383.         case 0x61A: prgdisp = shnum; DispPrgData(); break;
  384.         case 0x61B: prgdisp = 10; DispPrgData(); break;
  385.         case 0x61C: prgdisp = 11; DispPrgData(); break;
  386.         case 0x61D: PickNote(thisnote); break;
  387.         case 0x61F: VolSlide(); break;
  388.         case 0x620: SaveKeys(); break;
  389.         case 0x621: ClrPrg(); break;
  390.         case 0x622: if(prgdisp < 10) {
  391.                 if(prgn[prgdisp].xnn) {
  392.                     prgn[prgdisp].xnn = 0;
  393.                     prgn[prgdisp].notenum = 0;
  394.                 }
  395.                 else if(prgn[prgdisp].notenum < 63)
  396.                     prgn[prgdisp].notenum++;
  397.                 else prgn[prgdisp].xnn = 1;
  398.                 }
  399.                 break;
  400.         case 0x623: if(prgdisp < 10) {
  401.                 if(prgn[prgdisp].xnn) {
  402.                     prgn[prgdisp].xnn = 0;
  403.                     prgn[prgdisp].notenum = 63;
  404.                 }
  405.                 else if(prgn[prgdisp].notenum)
  406.                     prgn[prgdisp].notenum--;
  407.                 else prgn[prgdisp].xnn = 1;
  408.                 }
  409.                 break;
  410.         case 0x624: if(prgdisp < 10 && prgn[prgdisp].notenum &&
  411.                 !(prgn[prgdisp].xnn))
  412.                     prgn[prgdisp].notenum += 12;
  413.                 break;
  414.         case 0x625: if(prgdisp < 10 && prgn[prgdisp].notenum &&
  415.                 !(prgn[prgdisp].xnn))
  416.                     prgn[prgdisp].notenum -= 12;
  417.                 break;
  418.         case 0x626: if(prgdisp < 10) {
  419.                 prgn[prgdisp].notenum = 0;
  420.                 prgn[prgdisp].xnn = 0;
  421.                 }
  422.                 break;
  423.         case 0x627: if(prgn[prgdisp].x0th) {
  424.                 prgn[prgdisp].x0th = 0;
  425.                 prgn[prgdisp].num0 = 0;
  426.                 } else if(prgn[prgdisp].num0) prgn[prgdisp].x0th = 1;
  427.                 else prgn[prgdisp].num0 = 1;
  428.                 break;
  429.         case 0x628: if(prgn[prgdisp].x1st) prgn[prgdisp].x1st = 0;
  430.                 else if(prgn[prgdisp].num1 < 31) prgn[prgdisp].num1++;
  431.                 else { prgn[prgdisp].num1 = 0; prgn[prgdisp].x1st = 1; }
  432.                 break;
  433.         case 0x629: if(prgn[prgdisp].x1st) {
  434.                 prgn[prgdisp].x1st = 0;
  435.                 prgn[prgdisp].num1 = 31;
  436.                 } else if(prgn[prgdisp].num1) prgn[prgdisp].num1--;
  437.                 else prgn[prgdisp].x1st = 1;
  438.                 break;
  439.         case 0x62A: prgn[prgdisp].x1st = 0; prgn[prgdisp].num1 = 0; break;
  440.         case 0x62B: if(prgn[prgdisp].x2nd) prgn[prgdisp].x2nd = 0;
  441.                 else if(prgn[prgdisp].num2 < 15) prgn[prgdisp].num2++;
  442.                 else { prgn[prgdisp].num2 = 0; prgn[prgdisp].x2nd = 1; }
  443.                 break;
  444.         case 0x62C: if(prgn[prgdisp].x2nd) {
  445.                 prgn[prgdisp].x2nd = 0;
  446.                 prgn[prgdisp].num2 = 15;
  447.                 } else if(prgn[prgdisp].num2) prgn[prgdisp].num2--;
  448.                 else prgn[prgdisp].x2nd = 1;
  449.                 break;
  450.         case 0x62D: prgn[prgdisp].x2nd = 0; prgn[prgdisp].num2 = 0; break;
  451.         case 0x62E: if(prgn[prgdisp].x3rd) prgn[prgdisp].x3rd = 0;
  452.                 else if(prgn[prgdisp].num3 < 15) prgn[prgdisp].num3++;
  453.                 else { prgn[prgdisp].num3 = 0; prgn[prgdisp].x3rd = 1; }
  454.                 break;
  455.         case 0x62F: if(prgn[prgdisp].x3rd) {
  456.                 prgn[prgdisp].x3rd = 0;
  457.                 prgn[prgdisp].num3 = 15;
  458.                 } else if(prgn[prgdisp].num3) prgn[prgdisp].num3--;
  459.                 else prgn[prgdisp].x3rd = 1;
  460.                 break;
  461.         case 0x630: prgn[prgdisp].x3rd = 0; prgn[prgdisp].num3 = 0; break;
  462.         case 0x631: if(prgn[prgdisp].x4th) prgn[prgdisp].x4th = 0;
  463.                 else if(prgn[prgdisp].num4 < 15) prgn[prgdisp].num4++;
  464.                 else { prgn[prgdisp].num4 = 0; prgn[prgdisp].x4th = 1; }
  465.                 break;
  466.         case 0x632: if(prgn[prgdisp].x4th) {
  467.                 prgn[prgdisp].x4th = 0;
  468.                 prgn[prgdisp].num4 = 15;
  469.                 } else if(prgn[prgdisp].num4) prgn[prgdisp].num4--;
  470.                 else prgn[prgdisp].x4th = 1;
  471.                 break;
  472.         case 0x633: prgn[prgdisp].x4th = 0; prgn[prgdisp].num4 = 0;
  473.     }
  474.     if(gid >= 0x621) DispPrgNote();
  475. }
  476.  
  477. static void __regargs VolSlide()
  478. {
  479.     BYTE startvol,endvol;
  480.     UBYTE *nptr;
  481.     WORD sline = pline,eline = sline + 1;
  482.     UWORD blk = pblock,lcnt;
  483.     LONG vchngl,currv; /* volume change / line, current vol */
  484.     if(!(gadget6[0].GadgetID & 0x1000)) return;
  485.     for(;;) {
  486.         nptr = CalcAddr(blk,sline,currtrk);
  487.         if((*(nptr+1) & 0x0F) == 0x0C) break;
  488.         if(!sline--) return;
  489.     }
  490.     startvol = *(nptr + 2);
  491.     if(eline > lohko[blk]->lines) return;
  492.     for(;;) {
  493.         nptr = CalcAddr(blk,eline,currtrk);
  494.         if((*(nptr+1) & 0x0F) == 0x0C) break;
  495.         if(eline++ >= lohko[blk]->lines) return;
  496.     }
  497.     endvol = *(nptr + 2); /* now we know the start/end volumes & lines */
  498.     if(!(song.flags & FLAG_VOLHEX)) {
  499.         startvol = (10 * (startvol >> 4)) + (startvol & 0x0F);
  500.         endvol = (10 * (endvol >> 4)) + (endvol & 0x0F);
  501.     }
  502.     if(startvol < 0 || startvol > 64 || endvol < 0 || endvol > 64) return;
  503.     vchngl = ((endvol - startvol) * 100) / (eline - sline);
  504.     currv = startvol * 100;
  505.     for(lcnt = sline; lcnt < eline; lcnt++) {
  506.         SetVol(blk,lcnt,currtrk,(UBYTE)((currv + 50) / 100));
  507.         currv += vchngl;
  508.     }
  509.     PaivitaNaytto(TRUE);
  510. }
  511.  
  512. void DoSlide(UBYTE type) /* automatic slide generation */
  513. {
  514.     UWORD sblock = pblock,sline = pline,eline = sline,lcnt;
  515.     UWORD div,divhalf;
  516.     ULONG perchngd,persb,step,lval;
  517.     WORD perdiff;
  518.     UBYTE trk = currtrk,*noteptr,fromnote,tonote,slidedown = 0;
  519.     UBYTE *nptr2,n1,n2,stne = 0;
  520.     if(!(gadget6[0].GadgetID & 0x1000)) return;
  521.     if(song.flags & FLAG_STSLIDE) div = song.sliding * 100;
  522.     else div = 600;
  523.     if(!div) return; /* dividing by zero is deadly */
  524.     divhalf = div /á2;
  525.     if(!type && eline-- == 0) return;
  526.     for(;;) { /* search the previous note */
  527.         noteptr = CalcAddr(sblock,eline,trk);
  528.         if(*noteptr & 0x3f) break;
  529.         if(!eline--) return;
  530.     }
  531.     fromnote = *noteptr & 0x3f;
  532.     if(type) eline = sline + 1; else eline = sline;
  533.     if(eline > lohko[sblock]->lines) return;
  534.     for(;;) { /* and the next one too */
  535.         noteptr = CalcAddr(sblock,eline,trk);
  536.         if(*noteptr & 0x3f) break;
  537.         if(eline++ >= lohko[sblock]->lines) return; /* not possible */
  538.     }
  539.     if(type) eline--;
  540.     tonote = *noteptr & 0x3f; /* difference between periods -vv */
  541.     perdiff = (WORD)periodit[fromnote-1] - (WORD)periodit[tonote-1];
  542.     if(perdiff < 0) { /* slide it down */
  543.         slidedown = 1;
  544.         perdiff = -perdiff;
  545.     } /* multiplied by 100 for enough accuracy */
  546.     if(!type) {
  547.         n1 = *noteptr; n2 = *(noteptr+1);
  548.         *noteptr++ = 0; *noteptr = 0;
  549.     }
  550.     lval = perdiff * 100 / (eline - sline + 1); /* period change / line */
  551.     perchngd = persb = 0;
  552.     for(lcnt = sline; lcnt <= eline; lcnt++) {
  553.         persb += lval; /* the period should be this now */
  554.         step = ((persb + divhalf) - perchngd) /ádiv; /* try to do it!! */
  555.         perchngd += div * step; /* period changed actually this */
  556.         if(!step) SetCmd(sblock,lcnt,trk,0); /* just zero */
  557.         else if(!type) {
  558.             if(lcnt == eline && perchngd < persb) step++;
  559.             if(!stne) {
  560.                 nptr2 = CalcAddr(sblock,lcnt,trk);
  561.                 *nptr2++ = n1; *nptr2++ = n2; stne = 1;
  562.             }
  563.             SetCmd(sblock,lcnt,trk,(UWORD)(0x300 | step));
  564.         }
  565.         else SetCmd(sblock,lcnt,trk,(UWORD)((slidedown ? 0x200 : 0x100) | step));
  566.     }
  567.     PaivitaNaytto(TRUE);
  568. }
  569.  
  570. void HLLine(UWORD block,UBYTE line)
  571. {
  572.     ULONG *hlp = lohko[block]->hlmask;
  573.     while(line > 31) { line -= 32; hlp++; }
  574.     *hlp ^= 1 << line;
  575. }
  576.  
  577. void HighLightLines(UWORD block,UWORD index)
  578. {
  579.     static UBYTE spcs[] = { 1,2,3,4,8,16,0 };
  580.     UBYTE spc = spcs[index];
  581.     UWORD lcnt;
  582.     if(!spc) {    /* clear all */
  583.         ULONG *mskp = lohko[block]->hlmask;
  584.         for(lcnt = 0; lcnt < 8; lcnt++) *mskp++ = 0;
  585.     } else    for(lcnt = 0; lcnt < lohko[block]->lines + 1; lcnt++)
  586.             if(!(lcnt % spc)) HLLine(block,(UBYTE)lcnt);
  587.     PaivitaNaytto(TRUE);
  588. }
  589.  
  590. void ShowLineNum()
  591. {
  592.     UWORD pos,lines = lohko[pblock]->lines + 1;
  593.     if(nykyinenosio == 5) pos = RemoveGadget(window,&gadget5[32]);
  594.     strinfo[9].BufferPos = 0;
  595.     strinfo[9].DispPos = 0;
  596.     strinfo[9].LongInt = (LONG)lines;
  597.     stcu_d(linesstr,lines);
  598.     if(nykyinenosio == 5) {
  599.         AddGadget(window,&gadget5[32],pos);
  600.         RefreshGList(&gadget5[32],window,NULL,1);
  601.     }
  602. }
  603.  
  604. void HandleLines(UWORD blk,UWORD gid)
  605. {
  606.     register UWORD newl = (UWORD)(lohko[blk]->lines) + 1;
  607.     LONG lint = strinfo[9].LongInt;
  608.     switch(gid) {
  609.         case 0x51E: if(newl > 10) newl -= 10;
  610.                 break;
  611.         case 0x51F: if(newl > 1) newl--;
  612.                 break;
  613.         case 0x520: if(lint > 0 && lint <= 256) newl = (UWORD)lint;
  614.                 break;
  615.         case 0x521: if(newl < 256) newl++;
  616.                 break;
  617.         case 0x522: if(newl <= 246) newl += 10;
  618.                 break;
  619.     }
  620.     if(newl != lohko[blk]->lines + 1) {
  621.         if(pblock == blk && pline >= newl) pline = newl - 1;
  622.         ChangeBlockSize(blk,(UWORD)(lohko[blk]->numtracks / 4),newl);
  623.         ShowLineNum();
  624.     }
  625. }
  626.