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-files.c < prev    next >
C/C++ Source or Header  |  1990-06-17  |  24KB  |  762 lines

  1. /* MED - music editor ⌐ 1989, 1990 by Teijo Kinnunen */
  2. /* MED-files.c: some file loading/saving routines */
  3.  
  4. #include <workbench/icon.h>
  5. #include <workbench/workbench.h>
  6. #include <proto/icon.h>
  7. #include "med.h"
  8. #include "medproto.h"
  9. extern BPTR fh;
  10. extern struct Gadget far gadget1[],far gadget2[];
  11. extern struct Kappale far song;
  12. extern UBYTE blocks,samplenum;
  13. extern UWORD nykyinenosio;
  14. extern struct Lohko *lohko[];
  15. extern struct Soitin *sample[];
  16. extern struct Window *window;
  17. extern struct Screen *screen;
  18. extern char kappaleennimi[];
  19. #define HLMSK0ZERO    0x1
  20. #define HLMSK1ZERO    0x2
  21. #define HLMSK2ZERO    0x4
  22. #define HLMSK3ZERO    0x8
  23. struct SCMask { /* finally, something use for bit fields!! */
  24.     unsigned free0 : 1;
  25.     unsigned strans0 : 1;
  26.     unsigned svol64 : 1;
  27.     unsigned svol0 : 1;
  28.     unsigned midipres0 : 1;
  29.     unsigned midich0 : 1;
  30.     unsigned replen0 : 1;
  31.     unsigned rep0 : 1;
  32.     unsigned free1 : 2;
  33.     unsigned snamelen : 6;
  34. };
  35.  
  36. static BOOL __regargs FWrite(char *,long);
  37. static BOOL __regargs FRead(char *,long);
  38. static void __regargs PutNibble(UBYTE *,UWORD *,UBYTE);
  39. static UBYTE __regargs GetNibble(UBYTE *,UWORD *);
  40. static void __regargs PutNibbles(UBYTE *,UWORD *,UWORD,UBYTE);
  41. static UWORD __regargs GetNibbles(UBYTE *,UWORD *,UBYTE);
  42. static BOOL __regargs SaveBlock(UWORD);
  43. static void __regargs UnpackData(ULONG *,ULONG *,UBYTE *,UBYTE *,UWORD,UBYTE);
  44. static char * __regargs Read200Block(UBYTE);
  45. static char * __regargs Read210Block(UBYTE);
  46. static char * __regargs LoadBlocks(BOOL);
  47.  
  48. static BOOL __regargs FWrite(char *ptr,long len)
  49. {
  50.     return((BOOL)(Write(fh,ptr,len) != len));
  51. }
  52.  
  53. static BOOL __regargs FRead(char *ptr,long len)
  54. {
  55.     return((BOOL)(Read(fh,ptr,len) != len));
  56. }
  57.  
  58. static void __regargs PutNibble(UBYTE *mem,UWORD *nbnum,UBYTE nibble)
  59. {
  60.     UBYTE *mloc = mem + (*nbnum / 2);
  61.     if(*nbnum & 0x1) *mloc |= (nibble & 0x0f);
  62.     else *mloc |= (nibble << 4);
  63.     (*nbnum)++;
  64. }
  65.  
  66. static UBYTE __regargs GetNibble(UBYTE *mem,UWORD *nbnum)
  67. {
  68.     UBYTE *mloc = mem + (*nbnum / 2),res;
  69.     if(*nbnum & 0x1) res = *mloc & 0x0f;
  70.     else res = *mloc >> 4;
  71.     (*nbnum)++;
  72.     return(res);
  73. }
  74.  
  75. static void __regargs PutNibbles(UBYTE *mem,UWORD *nbnum,UWORD nbls,UBYTE nbs)
  76. {
  77.     switch(nbs) {
  78.         case 0x4:    PutNibble(mem,nbnum,(UBYTE)(nbls >> 12));
  79.         case 0x3:    PutNibble(mem,nbnum,(UBYTE)(nbls >> 8));
  80.         case 0x2:    PutNibble(mem,nbnum,(UBYTE)(nbls >> 4));
  81.         case 0x1:    PutNibble(mem,nbnum,(UBYTE)nbls);
  82.     }
  83. }
  84.  
  85. static UWORD __regargs GetNibbles(UBYTE *mem,UWORD *nbnum,UBYTE nbs)
  86. {
  87.     UWORD res = 0;
  88.     while(nbs--) { res <<= 4; res |= GetNibble(mem,nbnum); }
  89.     return(res);
  90. }
  91.  
  92. /* MED File Format (V2.10) -- block header:
  93.    UBYTE header size    length of the remaining part of header
  94.    UBYTE numtracks    (number of tracks in this block [4,8,12,16])
  95.    UBYTE lines        lines in this block (default = 63)
  96.    UWORD blocklen    length of the packed block (in bytes)
  97.    UBYTE lmskmsks[1..4]    masks for linemasks (if they're 0xffff.. or 0L)
  98.    ULONG linemasks[0..8] the masks for lines (first linemsk, then cmdmsk)
  99.    UBYTE hlmaskmsk    mask for highlightmasks
  100.    ULONG hlmask[0..4]    masks for line highlighting
  101.    Note: longwords/words are fetched nibble at a time, no alignment needed
  102.    and finally the packed block:
  103. if the line mask is for example,
  104.    10000010001011000000000000001000001000010000000010000001000000
  105.    |     |   |
  106. there are notes in line 0,6,10 etc. (bit is 1), if bit is 0 the notes of the
  107. line will be filled with zeros.
  108. Effect (command) mask works in the same way.
  109.  
  110. line:
  111. first a nibble (when there are only 4 tracks)
  112.    0101
  113.     | |
  114. there are notes in tracks 1 and 3. If the numbers of the notes were 0x12
  115. and 0x22, and sample numbers would be 0xF and 0x7, the data for one line
  116. would look like (hex): 512F227
  117.   bin 0101 = hex 5 ----^
  118. simple, isn't it?? (No!!) */
  119.  
  120. static BOOL __regargs SaveBlock(UWORD num)
  121. {
  122.     UBYTE *tmpfr,trkn = lohko[num]->numtracks,hlbits = 0;
  123.     UWORD lmsk0,lmsk1,ton = 0,data,hdr[40],hdrnn = 0,lcnt;
  124.     UBYTE *conv = AllocMem(3 * (lohko[num]->lines + 1) * (trkn + 2),MEMF_PUBLIC|MEMF_CLEAR),
  125.         *from,bcnt,*hdrs = (UBYTE *)hdr,hdrsz;
  126.     ULONG linemsk[8] = { 0 },*lmptr = &linemsk[0];
  127.     ULONG cmdmsk[8] = { 0 },*cmptr = &cmdmsk[0];
  128.     if(!conv) return(TRUE);
  129.     from = lohko[num]->music;
  130.     for(lcnt = 0; lcnt < lohko[num]->lines + 1; lcnt++) {
  131.         lmsk0 = lmsk1 = 0;
  132.         if(!(lcnt % 32)) { /* we need new mask lw */
  133.             lmptr = &linemsk[lcnt / 32];
  134.             cmptr = &cmdmsk[lcnt / 32];
  135.         }
  136.         *lmptr <<= 1; *cmptr <<= 1; /* shift left masks */
  137.         tmpfr = from;
  138.         for(bcnt = 0; bcnt < trkn; bcnt++) {
  139.             lmsk0 <<= 1; lmsk1 <<= 1;
  140.             if(*tmpfr || (*(tmpfr+1) & 0xf0)) lmsk0 |= 1;
  141.             if((*(tmpfr+1) & 0x0f) || *(tmpfr+2)) lmsk1 |= 1;
  142.             tmpfr += 3;
  143.         }
  144.         if(lmsk0) {
  145.             *lmptr |= 1;
  146.             PutNibbles(conv,&ton,lmsk0,(UBYTE)(trkn / 4));
  147.             tmpfr = from;
  148.             for(bcnt = 0; bcnt < trkn; bcnt++) {
  149.                 if(*tmpfr || (*(tmpfr+1) & 0xf0)) {
  150.                     data = (UWORD)((*tmpfr << 4) |
  151.                         ((*(tmpfr+1) & 0xf0) >> 4));
  152.                     PutNibbles(conv,&ton,data,3);
  153.                 }
  154.                 tmpfr += 3;
  155.             }
  156.         }
  157.         if(lmsk1) {
  158.             *cmptr |= 1;
  159.             PutNibbles(conv,&ton,lmsk1,(UBYTE)(trkn / 4));
  160.             tmpfr = from + 1;
  161.             for(bcnt = 0; bcnt < trkn; bcnt++) {
  162.                 if((*tmpfr & 0x0f) || *(tmpfr+1)) {
  163.                     data = (UWORD)(((*tmpfr & 0x0f)
  164.                         << 8) | (*(tmpfr+1)));
  165.                     PutNibbles(conv,&ton,data,3);
  166.                 }
  167.                 tmpfr += 3;
  168.             }
  169.         }
  170.         from += 3 * trkn;
  171.     }
  172.     for(lcnt = lohko[num]->lines + 1; lcnt % 32; lcnt++) {
  173.         *lmptr <<= 1; *cmptr <<= 1;
  174.     }
  175.     memset((void *)hdr,0,80);
  176.     hdrnn = 2;    /* leave 1 byte for header size */
  177.     PutNibbles(hdrs,&hdrnn,(UWORD)(lohko[num]->numtracks),2);
  178.     PutNibbles(hdrs,&hdrnn,(UWORD)(lohko[num]->lines),2);
  179.     PutNibbles(hdrs,&hdrnn,(UWORD)((ton + 1) / 2),4); /* len of packed data */
  180.     bcnt = (lohko[num]->lines /á32) + 1; /* # of masks */
  181.     data = 0;
  182.     for(lcnt = 0; lcnt < bcnt; lcnt++) {
  183.         if(linemsk[lcnt] == 0xffffffff) data |= 8;
  184.         else if(linemsk[lcnt] == 0x00000000) data |= 4;
  185.         if(cmdmsk[lcnt] == 0xffffffff) data |= 2;
  186.         else if(cmdmsk[lcnt] == 0x00000000) data |= 1;
  187.         PutNibble(hdrs,&hdrnn,(UBYTE)data);
  188.         data = 0;
  189.     }
  190.     if(bcnt & 0x1) PutNibble(hdrs,&hdrnn,(UBYTE)data); /* zero */
  191.     for(lcnt = 0; lcnt < bcnt; lcnt++) {
  192.         if(linemsk[lcnt] != 0xffffffff && linemsk[lcnt] != 0L) {
  193.             PutNibbles(hdrs,&hdrnn,(UWORD)(linemsk[lcnt] >> 16),4);
  194.             PutNibbles(hdrs,&hdrnn,(UWORD)(linemsk[lcnt] & 0xffff),4);
  195.         }
  196.         if(cmdmsk[lcnt] != 0xffffffff && cmdmsk[lcnt] != 0L) {
  197.             PutNibbles(hdrs,&hdrnn,(UWORD)(cmdmsk[lcnt] >> 16),4);
  198.             PutNibbles(hdrs,&hdrnn,(UWORD)(cmdmsk[lcnt] & 0xffff),4);
  199.         }
  200.     }
  201.     for(lcnt = 0; lcnt < 8; lcnt++)
  202.         if(!lohko[num]->hlmask[lcnt]) hlbits |= 0x80 >> lcnt;
  203.     PutNibbles(hdrs,&hdrnn,(UWORD)hlbits,2);
  204.     for(lcnt = 0; lcnt < 8; lcnt++) {
  205.         ULONG msk = lohko[num]->hlmask[lcnt];
  206.         if(msk) {
  207.             PutNibbles(hdrs,&hdrnn,(UWORD)(msk >> 16),4);
  208.             PutNibbles(hdrs,&hdrnn,(UWORD)(msk & 0xffff),4);
  209.         }
  210.     }
  211.     hdrsz = hdrnn /á2;
  212.     hdrnn = 0;
  213.     PutNibbles(hdrs,&hdrnn,(UWORD)(hdrsz - 1),2);
  214.     if(FWrite((char *)hdrs,hdrsz)) goto sberr;
  215.     if(FWrite(conv,(ton + 1) / 2)) goto sberr;
  216.     FreeMem(conv,3 * (lohko[num]->lines + 1) * (trkn + 2));
  217.     return(FALSE);
  218. sberr:    FreeMem(conv,3 * (lohko[num]->lines + 1) * (trkn + 2));
  219.     return(TRUE);
  220. }
  221.  
  222. static void __regargs UnpackData(ULONG *lmptr,ULONG *cmptr,UBYTE *from,UBYTE *to,UWORD lines,UBYTE trkn)
  223. {
  224.     UBYTE *fromst = from,*tmpto,bcnt;
  225.     UWORD fromn = 0,lmsk,lcnt;
  226.     for(lcnt = 0; lcnt < lines; lcnt++) {
  227.         if(!(lcnt % 32) && lcnt) { lmptr++; cmptr++; }
  228.         if(*lmptr & 0x80000000) {
  229.             lmsk = GetNibbles(fromst,&fromn,(UBYTE)(trkn /á4));
  230.             lmsk <<= (16 - trkn);
  231.             tmpto = to;
  232.             for(bcnt = 0; bcnt < trkn; bcnt++) {
  233.                 if(lmsk & 0x8000) {
  234.                     *tmpto = (UBYTE)GetNibbles(fromst,
  235.                         &fromn,2);
  236.                     *(tmpto+1) = (GetNibble(fromst,
  237.                             &fromn) << 4);
  238.                 }
  239.                 lmsk <<= 1; tmpto += 3;
  240.             }
  241.         }
  242.         if(*cmptr & 0x80000000) {
  243.             lmsk = GetNibbles(fromst,&fromn,(UBYTE)(trkn /á4));
  244.             lmsk <<= (16 - trkn);
  245.             tmpto = to;
  246.             for(bcnt = 0; bcnt < trkn; bcnt++) {
  247.                 if(lmsk & 0x8000) {
  248.                     *(tmpto+1) |= GetNibble(fromst,
  249.                             &fromn);
  250.                     *(tmpto+2) = (UBYTE)GetNibbles(
  251.                         fromst,&fromn,2);
  252.                 }
  253.                 lmsk <<= 1; tmpto += 3;
  254.             }
  255.         }
  256.         to += 3 * trkn;
  257.         *lmptr <<= 1; *cmptr <<= 1;
  258.     }
  259. }
  260.     
  261. static char * __regargs Read210Block(UBYTE num)
  262. {
  263.     UBYTE hdrsz,hdr[80],trks,lines,mskmsks[8],msks,msk2,msk3 = 0,*conv = 0L;
  264.     UWORD hdrsn = 0,convsz;
  265.     ULONG lmsk[8],cmmsk[8];
  266.     if(FRead(&hdrsz,1)) return(DISKERR);
  267.     if(FRead(hdr,hdrsz)) return(DISKERR);
  268.     trks = GetNibbles(hdr,&hdrsn,2);
  269.     lines = GetNibbles(hdr,&hdrsn,2);
  270.     if(AllocBlock((UWORD)num,trks,(UWORD)((UWORD)lines + 1))) return(nomem);
  271.     convsz = GetNibbles(hdr,&hdrsn,4);
  272.     if(convsz && !(conv = AllocMem(convsz,MEMF_CLEAR))) return(nomem);
  273.     msk2 = msks = (lines /á32) + 1; /* # of masks */
  274.     while(msks--) mskmsks[msk3++] = GetNibble(hdr,&hdrsn);
  275.     if(msk2 & 0x1) (void)GetNibble(hdr,&hdrsn); /* empty */
  276.     for(msks = 0; msks < msk2; msks++) {
  277.         if(mskmsks[msks] & 8) lmsk[msks] = 0xffffffff;
  278.         else if(mskmsks[msks] & 4) lmsk[msks] = 0L;
  279.         else lmsk[msks] = (GetNibbles(hdr,&hdrsn,4) << 16) |
  280.                 GetNibbles(hdr,&hdrsn,4);
  281.         if(mskmsks[msks] & 2) cmmsk[msks] = 0xffffffff;
  282.         else if(mskmsks[msks] & 1) cmmsk[msks] = 0L;
  283.         else cmmsk[msks] = (GetNibbles(hdr,&hdrsn,4) << 16) |
  284.                 GetNibbles(hdr,&hdrsn,4);
  285.     }
  286.     msk3 = GetNibbles(hdr,&hdrsn,2);
  287.     for(msks = 0; msks < 8; msks++) {
  288.         if(msk3 & 0x80) lohko[num]->hlmask[msks] = 0L;
  289.         else lohko[num]->hlmask[msks] = (GetNibbles(hdr,&hdrsn,4)
  290.             << 16) | GetNibbles(hdr,&hdrsn,4);
  291.         msk3 <<= 1;
  292.     }
  293.     if(FRead(conv,convsz)) return(DISKERR);
  294.     UnpackData(lmsk,cmmsk,conv,lohko[num]->music,(UWORD)(lines + 1),trks);
  295.     if(conv) FreeMem(conv,convsz);
  296.     return(NOERR);
  297. }
  298.  
  299. static char * __regargs Read200Block(UBYTE num)
  300. {
  301.     ULONG lmsk[2],cmdmsk[2];
  302.     UWORD convsz;
  303.     UBYTE *conv,trks,mask;
  304.     if(FRead(&trks,1)) return(DISKERR);
  305.     if(AllocBlock((UWORD)num,trks,64)) return(nomem);
  306.     if(FRead(&mask,1)) return(DISKERR);
  307.     if(FRead((char *)(&convsz),2)) return(DISKERR);
  308.     if(mask & 0x10) lmsk[0] = 0L;
  309.     else if(mask & 0x1) lmsk[0] = 0xffffffff;
  310.     else if(FRead((UBYTE *)lmsk,4)) return(DISKERR);
  311.     if(mask & 0x20) lmsk[1] = 0L;
  312.     else if(mask & 2) lmsk[1] = 0xffffffff;
  313.     else if(FRead((UBYTE *)(&lmsk[1]),4)) return(DISKERR);
  314.     if(mask & 0x40) cmdmsk[0] = 0L;
  315.     else if(mask & 0x4) cmdmsk[0] = 0xffffffff;
  316.     else if(FRead((UBYTE *)cmdmsk,4)) return(DISKERR);
  317.     if(mask & 0x80) cmdmsk[1] = 0L;
  318.     else if(mask & 0x8) cmdmsk[1] = 0xffffffff;
  319.     else if(FRead((UBYTE *)(&cmdmsk[1]),4)) return(DISKERR);
  320.     conv = 0;
  321.     if(convsz) {
  322.         if(!(conv = AllocMem(convsz,MEMF_CLEAR))) return(nomem);
  323.         if(FRead(conv,convsz)) {
  324.             FreeMem(conv,convsz);
  325.             return(DISKERR);
  326.         }
  327.     } /* if convsz = 0, this block is empty, just pass "mask" (dummy) */
  328.     UnpackData(lmsk,cmdmsk,conv ? conv : &mask,lohko[num]->music,64,trks);
  329.     if(conv) FreeMem(conv,convsz);
  330.     return(NOERR);
  331. }
  332.  
  333. static char * __regargs LoadBlocks(BOOL v210)
  334. {
  335.     UBYTE blkcnt;
  336.     char *res;
  337.     blocks = 0;
  338.     for(blkcnt = 0; blkcnt < song.numblocks; blkcnt++) {
  339.         if(v210) res = Read210Block(blkcnt);
  340.         else res = Read200Block(blkcnt);
  341.         if(lohko[blocks]) blocks++;
  342.         TulostaLohkoJaSoitin();
  343.         if(res) return(res);
  344.     }
  345.     return(NOERR);
  346. }
  347.  
  348. char *SaveInstruments()
  349. {
  350.     ULONG imsk[2] = { 0,0 },*mskptr = imsk;
  351.     UBYTE scnt;
  352.     Ilmoita("Saving samples...");
  353.     *mskptr |= 1; /* bit #0 of first mask means 63 samples */
  354.     for(scnt = 0; scnt < 63; scnt++) {
  355.         if(scnt == 31) mskptr++;
  356.         *mskptr <<= 1;
  357.         if(sample[scnt]) *mskptr |= 1;
  358.     }
  359.     if(FWrite((char *)imsk,8)) return(DISKERR);
  360.     for(scnt = 0; scnt < 63; scnt++) {
  361.         if(sample[scnt] && FWrite((char *)sample[scnt],
  362.             sample[scnt]->length + sizeof(struct Soitin)))
  363.                 return(DISKERR);
  364.     }
  365.     return(NOERR);
  366. }
  367.  
  368. /* MED File format (V2.10) -- Song header:
  369.    "MED\x04"    id
  370.    Mask1        (1 byte: mask for sample mask, 1 bit = 8 samples)
  371.    SampleMask0    Both 1 longword, if bit is 1, there's Sample-structure for
  372.    SampleMask1    this sample. Bit #0 of SampleMask1 is 0
  373. For each sample:
  374.    SCMask    (1 word: bit0-6 length of sample name, if bit8=1 rep = 0,
  375.            if bit9=1 replen = 0, if bit10=1 midich=0, if bit11=1
  376.         midipreset = 0, if bit12=1 svol=0, if bit13=1, svol=64)
  377.    all data for that sample, sample name not 0-terminated
  378.  
  379.    numblocks, songlen (both UWORD)
  380.    playseq    <songlen> bytes
  381.    deftempo, playtransp,flags,sliding,jumpmask,rgb,trkvol,mastervol = 43 bytes
  382.  
  383. and blocks... (see above) */
  384.  
  385. char *SaveSong(char *name,BOOL sinstr,UBYTE icon)
  386. {
  387.     UBYTE scnt,oldexists = 0,smskmsk = 0,*sdptr;
  388.     UWORD sdata[4] = {0};
  389.     ULONG samplemask[2] = { 0,0 },*smaskptr = samplemask;
  390.     struct SCMask scmask;
  391.     struct SongSample *ss;
  392.     extern struct ViewPort *vp;
  393.     if(*name == '\0') return(AskName());
  394.     if(IsHere(name)) {
  395.         Ilmoita(fileex);
  396.         oldexists = 1;
  397.         if(!Continue()) return(notsaved);
  398.     }
  399.     if(sinstr) song.flags |= FLAG_INSTRSATT;
  400.     else song.flags &= ~FLAG_INSTRSATT;
  401.     if(!(fh = Open2(name,MODE_NEWFILE))) return(DISKERR);
  402.     Ilmoita("Saving song...");
  403.     if(FWrite("MED\x04",4)) return(DISKERR);
  404.     for(scnt = 0; scnt < 63; scnt++) {
  405.         ss = &song.sample[scnt];
  406.         *smaskptr <<= 1;
  407.         if(ss->sname[0] || ss->svol || ss->rep || ss->replen ||
  408.            ss->midich || ss->midipreset)
  409.             *smaskptr |= 1;
  410.         if(scnt == 31) smaskptr++;
  411.     }
  412.     *smaskptr <<= 1;
  413.     for(scnt = 0; scnt < 8; scnt++) {
  414.         smskmsk <<= 1;
  415.         if(*((UBYTE *)samplemask + scnt)) smskmsk |= 1;
  416.     }
  417.     if(FWrite(&smskmsk,1)) return(DISKERR);
  418.     for(scnt = 0; scnt < 8; scnt++)
  419.         if(*((UBYTE *)samplemask + scnt))
  420.             if(FWrite((char *)samplemask + scnt,1)) return(DISKERR);
  421.     smaskptr = samplemask;
  422.     for(scnt = 0; scnt < 63; scnt++) {
  423.         if(scnt == 32) smaskptr++;
  424.         ss = &song.sample[scnt];
  425.         memset((void *)&scmask,0,sizeof(scmask));
  426.         if(*smaskptr & 0x80000000) {
  427.             if(!ss->rep) scmask.rep0 = 1;
  428.             if(!ss->replen) scmask.replen0 = 1;
  429.             if(!ss->midich) scmask.midich0 = 1;
  430.             if(!ss->midipreset) scmask.midipres0 = 1;
  431.             if(!ss->svol) scmask.svol0 = 1;
  432.             if(!ss->strans) scmask.strans0 = 1;
  433.             if(ss->svol == 64) scmask.svol64 = 1;
  434.             scmask.snamelen = strlen(ss->sname);
  435.             if(FWrite((char *)(&scmask),2)) return(DISKERR);
  436.             if(scmask.snamelen && FWrite(ss->sname,
  437.                 scmask.snamelen)) return(DISKERR);
  438.             sdptr = (UBYTE *)sdata;
  439.             if(!scmask.rep0) { /* remember, no alignment */
  440.                 *sdptr = ss->rep >> 8;
  441.                 *(sdptr+1) = ss->rep & 0x00ff;
  442.                 sdptr += 2;
  443.             }
  444.             if(!scmask.replen0) {
  445.                 *sdptr = ss->replen >> 8;
  446.                 *(sdptr+1) = ss->replen & 0x00ff;
  447.                 sdptr += 2;
  448.             }
  449.             if(!scmask.midich0) *sdptr++ = ss->midich;
  450.             if(!scmask.midipres0) *sdptr++ = ss->midipreset;
  451.             if(!scmask.svol0 && !scmask.svol64) *sdptr++ = ss->svol;
  452.             if(!scmask.strans0) *sdptr++ = ss->strans;
  453.             if((UBYTE *)sdata < sdptr && FWrite((char *)sdata,
  454.                 sdptr - (UBYTE *)sdata)) return(DISKERR);
  455.         }
  456.         *smaskptr <<= 1;
  457.     }
  458.     song.numblocks = blocks;
  459.     if(FWrite((char *)(&song.numblocks),4)) return(DISKERR);
  460.     if(FWrite(song.playseq,song.songlen)) return(DISKERR);
  461.     for(scnt = 0; scnt < 8; scnt++)
  462.         song.rgb[scnt] = GetRGB4(vp->ColorMap,scnt);
  463.     if(FWrite((char *)(&song.deftempo),43)) return(DISKERR);
  464.     for(scnt = 0; scnt < blocks; scnt++)
  465.         if(SaveBlock((UWORD)scnt)) return(DISKERR);
  466.     if(sinstr) {
  467.         char *sires = SaveInstruments();
  468.         if(sires != NOERR) return(sires);
  469.     }
  470.     if(fh) { Close(fh); fh = 0L; }
  471.     if(!oldexists) InsertSavedFile(name);
  472.     if(icon) {
  473.         Ilmoita("Creating icon...");
  474.         if(WriteIcon(name)) return(NOERR);
  475.     }
  476.     Ilmoita("Song saved.");
  477.     return(NOERR);
  478. }
  479.  
  480. char *Load210Song()
  481. {
  482.     ULONG samplemask[2],*smskptr = samplemask;
  483.     UBYTE smskmsk,*smptr0 = (UBYTE *)samplemask,scnt,midifound = 0;
  484.     struct SCMask scmask;
  485.     struct SongSample *ss;
  486.     Ilmoita("Loading MED2.10-song...");
  487.     if(FRead((char *)samplemask,4)) return(DISKERR); /* MED\x04 */
  488.     if(FRead(&smskmsk,1)) return(DISKERR);
  489.     for(scnt = 0; scnt < 8; scnt++) {
  490.         if(!(smskmsk & 0x80)) *(smptr0+scnt) = 0;
  491.         else if(FRead(smptr0+scnt,1)) return(DISKERR);
  492.         smskmsk <<= 1;
  493.     }
  494.     for(scnt = 0; scnt < 63; scnt++) {
  495.         if(scnt == 32) smskptr++;
  496.         ss = &song.sample[scnt];
  497.         if(*smskptr & 0x80000000) {
  498.             if(FRead((char *)&scmask,2)) return(DISKERR);
  499.             if(scmask.snamelen && FRead(ss->sname,
  500.                 scmask.snamelen)) return(DISKERR);
  501.             ss->sname[scmask.snamelen] = 0;
  502.             if(scmask.rep0) ss->rep = 0;
  503.             else if(FRead((char *)&song.sample[scnt].rep,2)) return(DISKERR);
  504.             if(scmask.replen0) ss->replen = 0;
  505.             else if(FRead((char *)&(ss->replen),2)) return(DISKERR);
  506.             if(scmask.midich0) ss->midich = 0;
  507.             else if(FRead(&(ss->midich),1)) return(DISKERR);
  508.             if(scmask.midipres0) ss->midipreset = 0;
  509.             else if(FRead(&(ss->midipreset),1)) return(DISKERR);
  510.             if(scmask.svol0) ss->svol = 0;
  511.             else if(scmask.svol64) ss->svol = 64;
  512.             else if(FRead(&(ss->svol),1)) return(DISKERR);
  513.             if(scmask.strans0) ss->strans = 0;
  514.             else if(FRead(&(ss->strans),1)) return(DISKERR);
  515.         } else {
  516.             ss->sname[0] = 0;
  517.             ss->rep = 0;
  518.             ss->replen = 0;
  519.             ss->midich = 0;
  520.             ss->midipreset = 0;
  521.             ss->strans = 0;
  522.             ss->svol = 0;
  523.         }
  524.         *smskptr <<= 1;
  525.         if(ss->midich) midifound = 1;
  526.     }
  527.     DeleteSamplesNotUsed();
  528.     if(FRead((char *)(&song.numblocks),4)) return(DISKERR);
  529.     if(FRead(song.playseq,song.songlen)) return(DISKERR);
  530.     if(FRead((char *)(&song.deftempo),43)) return(DISKERR);
  531.     if(midifound) MIDIon();
  532.     return(LoadBlocks(TRUE));
  533. }
  534.  
  535. char *Load200Song()
  536. {
  537.     ULONG zmsk;
  538.     UBYTE scnt,*nameptr,midifound = 0,dummy;
  539.     struct SongSample *ss;
  540.     Ilmoita("Loading MED2.00-song...");
  541.     if(FRead((char *)(&zmsk),4)) return(DISKERR); /* MED\x03 */
  542.     if(FRead(&dummy,1)) return(DISKERR);
  543.     for(scnt = 0; scnt < 31; scnt++) {
  544.         ss = &song.sample[scnt];
  545.         nameptr = ss->sname;
  546.         for(;;) {
  547.             if(FRead(nameptr,1)) return(DISKERR);
  548.             if(*nameptr++ == '\0') break;
  549.         }
  550.         ss->strans = 0;
  551.     }
  552.     DeleteSamplesNotUsed();
  553.     clrxtoy(31,63);
  554.     if(FRead((char *)(&zmsk),4)) return(DISKERR);
  555.     if(zmsk & 0x80000000 && FRead(&dummy,1)) return(DISKERR);
  556.     for(scnt = 0; scnt < 31; scnt++) {
  557.         ss = &song.sample[scnt];
  558.         zmsk <<= 1;
  559.         if(zmsk & 0x80000000) {
  560.             if(FRead(&ss->svol,1)) return(DISKERR);
  561.         } else ss->svol = 0;
  562.     }
  563.     if(FRead((char *)(&zmsk),4)) return(DISKERR);
  564.     for(scnt = 0; scnt < 31; scnt++) {
  565.         ss = &song.sample[scnt];
  566.         zmsk <<= 1;
  567.         if(zmsk & 0x80000000) {
  568.             if(FRead((char *)(&ss->rep),2)) return(DISKERR);
  569.             ss->rep >>= 1;
  570.         } else ss->rep = 0;
  571.     }
  572.     if(FRead((char *)(&zmsk),4)) return(DISKERR);
  573.     for(scnt = 0; scnt < 31; scnt++) {
  574.         ss = &song.sample[scnt];
  575.         zmsk <<= 1;
  576.         if(zmsk & 0x80000000) {
  577.             if(FRead((char *)(&ss->replen),2)) return(DISKERR);
  578.             ss->replen >>= 1;
  579.         } else ss->replen = 0;
  580.     }
  581.     if(FRead((char *)(&song.numblocks),2)) return(DISKERR);
  582.     if(FRead((char *)(&song.songlen),2)) return(DISKERR);
  583.     if(FRead(song.playseq,song.songlen)) return(DISKERR);
  584.     if(FRead((char *)(&song.deftempo),26)) return(DISKERR);
  585.     song.jumpmask >>= 1;
  586.     if(FRead((char *)(&zmsk),4)) return(DISKERR);
  587.     for(scnt = 0; scnt < 31; scnt++) {
  588.         ss = &song.sample[scnt];
  589.         zmsk <<= 1;
  590.         if(zmsk & 0x80000000) {
  591.             if(FRead(&ss->midich,1)) return(DISKERR);
  592.             midifound = 1;
  593.         } else ss->midich = 0;
  594.     }
  595.     if(FRead((char *)(&zmsk),4)) return(DISKERR);
  596.     for(scnt = 0; scnt < 31; scnt++) {
  597.         ss = &song.sample[scnt];
  598.         zmsk <<= 1;
  599.         if(zmsk & 0x80000000) {
  600.             if(FRead(&ss->midipreset,1)) return(DISKERR);
  601.         } else ss->midipreset = 0;
  602.     }
  603.     if(midifound) MIDIon();
  604.     return(LoadBlocks(FALSE));
  605. }
  606.  
  607. static UWORD chip icondata[] = {
  608. 0xffff,0xffff,0xff80,0xc000,0x0,0x180,0xc020,0xbfbe,0x180,0xc031,0x999b,0x180,
  609. 0xc03b,0x9819,0x8180,0xc03f,0x9e19,0x8180,0xc035,0x9819,0x8180,0xc031,0x999b,0x180,
  610. 0xc031,0xbfbe,0x180,0xc3c0,0x0,0x180,0xc660,0x0,0x180,0xc703,0xc7c3,0xb180,
  611. 0xc386,0x6666,0x6180,0xc0e6,0x6666,0x6180,0xc666,0x6663,0xc180,0xc3c3,0xc66c,0x6180,
  612. 0xc000,0x7,0xc180,0xc000,0x0,0x180,0xc000,0x0,0x180,0xffff,0xffff,0xff80,
  613. 0x0,0x0,0x0, /*------ plane # 1: --------*/
  614. 0x0,0x0,0x0,0x3fff,0xffff,0xfe60,0x3020,0xbfbe,0x60,0x3039,0xbfff,0x8060,
  615. 0x303f,0xfe7f,0xc060,0x303f,0xfe1f,0xe060,0x303f,0xff9f,0xe060,0x303d,0xff9f,0x6060,
  616. 0x303d,0xfffe,0xc060,0x33cc,0x6fef,0x8060,0x36f0,0x0,0x60,0x379b,0xc7c3,0xb060,
  617. 0x33c6,0xf7f6,0xec60,0x30e7,0xffff,0xf860,0x367f,0xfffb,0xd860,0x33db,0xdffc,0xf060,
  618. 0x30f0,0xf19f,0xd860,0x3000,0x1,0xf060,0x3000,0x0,0x60,0x0,0x0,0x60,
  619. 0x3fff,0xffff,0xffe0 };
  620.  
  621. BOOL WriteIcon(char *name)
  622. {
  623.     static struct Image dimg = {
  624.         0,0,43,21,2,icondata,0x3,0x0,NULL };
  625.     static struct DiskObject dobj = {
  626.         WB_DISKMAGIC,WB_DISKVERSION,{
  627.             NULL,0,0,43,21,GADGIMAGE|GADGHCOMP,
  628.             GADGIMMEDIATE|RELVERIFY,BOOLGADGET,(APTR)&dimg,
  629.             NULL,NULL,NULL,NULL,0,NULL
  630.         },WBPROJECT,"MEDPlayer",NULL,NO_ICON_POSITION,
  631.         NO_ICON_POSITION,NULL,NULL,NULL
  632.     }; /* vv - This wouldn't work without <proto/icon.h> */
  633.     struct Library *IconBase = OpenLibrary(ICONNAME,0);
  634.     LONG status;
  635.     extern BPTR currdir;
  636.     BPTR prevdir;
  637.     if(!IconBase) {
  638.         Ilmoita("No icon.library: no icon.");
  639.         return(TRUE);
  640.     }
  641.     if(currdir) prevdir = CurrentDir(currdir);
  642.     status = PutDiskObject(name,&dobj);
  643.     if(currdir) CurrentDir(prevdir);
  644.     CloseLibrary(IconBase);
  645.     if(!status) {
  646.         Ilmoita("Failed to create icon.");
  647.         return(TRUE);
  648.     }
  649.     return(FALSE);
  650. }
  651.  
  652. static UWORD chip contdata[] = {
  653. 0x7fff,0xffff,0xffff,0xffff,0x3fff,0xffff,0xffff,0xffff,0x3fff,0xffff,0xffff,0xffff,
  654. 0x3fff,0xffff,0xffff,0xffff,0x2000,0x0,0x80,0x7,0x3fff,0xffff,0xfeff,0xfff7,
  655. 0x3ccd,0xa2b5,0xa2f2,0x3337,0x3bb4,0xb695,0xaeef,0x6d57,0x3bb5,0x36a5,0xa6f3,0x6d37,
  656. 0x3bb5,0xb6b5,0xaefd,0x6d77,0x3ccd,0xb6b6,0x62e3,0x7377,0x3fff,0xffff,0xfeff,0xfff7,
  657. 0x3fff,0xffff,0xfeff,0xfff7,0x3fff,0xffff,0xffff,0xffff,0x3fff,0xffff,0xffff,0xffff,
  658. 0x0,0x0,0x0,0x3,0x0,0x0,0x0,0x1, /*------ plane # 1: --------*/
  659. 0x8000,0x0,0x0,0x0,0xc000,0x0,0x0,0x0,0xffff,0xffff,0xffff,0xfffc,
  660. 0xffff,0xffff,0xffff,0xfffc,0xffff,0xffff,0xffff,0xfffc,0xefff,0xffff,0xffbf,0xfffc,
  661. 0xeccd,0xa2b5,0xa3b2,0x333c,0xebb4,0xb695,0xafaf,0x6d5c,0xebb5,0x36a5,0xa7b3,0x6d3c,
  662. 0xebb5,0xb6b5,0xafbd,0x6d7c,0xeccd,0xb6b6,0x63a3,0x737c,0xefff,0xffff,0xffbf,0xfffc,
  663. 0xe000,0x0,0x180,0xc,0xffff,0xffff,0xffff,0xfffc,0xffff,0xffff,0xffff,0xfffc,
  664. 0xffff,0xffff,0xffff,0xfffc,0xffff,0xffff,0xffff,0xfffe };
  665.  
  666. BOOL Continue()
  667. {
  668.     static struct Image contimg = { 0,0,64,17,2,contdata,0x3,0x0,NULL };
  669.     static struct Gadget cgadg[] = {
  670.     { &cgadg[1],4,5,35,7,GADGHCOMP,RELVERIFY,BOOLGADGET,NULL,NULL,
  671.       NULL,NULL,NULL,0,NULL },
  672.     { NULL,42,5,18,7,GADGHCOMP,RELVERIFY,BOOLGADGET,NULL,NULL,
  673.       NULL,NULL,NULL,0,NULL } };
  674.     static struct NewWindow cneww = { 160,20,64,17,0,0,GADGETUP|RAWKEY,
  675.         SMART_REFRESH|BORDERLESS|ACTIVATE|RMBTRAP,&cgadg[0],
  676.         NULL,NULL,NULL,NULL,0,0,0,0,CUSTOMSCREEN };
  677.     struct Window *cwin = NULL;
  678.     struct IntuiMessage *msg;
  679.     UWORD res = 0;
  680.     cneww.Screen = screen;
  681.     if(!(cwin = OpenWindow(&cneww))) return(FALSE);
  682.     DrawImage(cwin->RPort,&contimg,0,0);
  683.     for(;;) {
  684.         WaitPort(cwin->UserPort);
  685.         msg = (struct IntuiMessage *)GetMsg(cwin->UserPort);
  686.         if(msg->Class == GADGETUP) {
  687.             if(msg->IAddress == (APTR)&cgadg[0]) res = 1;
  688.             else res = 2;
  689.         } else if(msg->Class == RAWKEY) {
  690.             if(msg->Code == 0x33) res = 1;
  691.             else if(msg->Code == 0x21 || msg->Code == 0x45) res = 2;
  692.         }
  693.         ReplyMsg((struct Message *)msg);
  694.         if(res) break;
  695.     }
  696.     CloseWindow(cwin);
  697.     if(res == 1) return(TRUE);
  698.     return(FALSE);
  699. }
  700.  
  701. char *AskName()
  702. {
  703.     OsionValinta(&gadget1[0]);
  704.     if(nykyinenosio == 2) {
  705.         ActivateGadget(&gadget2[9],window,NULL);
  706.         return("Type in the name:");
  707.     } else return(NOERR);
  708. }
  709.  
  710. char *LoadAttachedInstrs()
  711. {
  712.     ULONG imsk[2] = { 0,0 },*imptr = imsk;
  713.     UBYTE snum = 0;
  714.     struct Soitin loaded;
  715.     if(FRead((char *)imsk,4)) return(DISKERR);
  716.     if((*imsk & 0x80000000) && FRead((char *)(&imsk[1]),4)) return(DISKERR);
  717.     while(snum < 63) {
  718.         *imptr <<= 1;    /* There's no instrument #0 */
  719.         if(snum == 31) imptr++;
  720.         if(*imptr & 0x80000000) {
  721.             if(FRead((char *)(&loaded),sizeof(struct Soitin)))
  722.                 return(DISKERR);
  723.             if(NewInstrument(loaded.length,snum)) return(nomem);
  724.             sample[snum]->type = loaded.type;
  725.             if(FRead(((char *)sample[snum]) + sizeof(struct
  726.                 Soitin),loaded.length)) return(DISKERR);
  727.         }
  728.         SeurSoitin();
  729.         snum++;
  730.     }
  731.     return(NOERR);
  732. }
  733.  
  734. char *SaveRawSample(char *name)
  735. {
  736.     UBYTE oldexists = 0;
  737.     if(!sample[samplenum])    return("No sample in memory!!!");
  738.     if(*name == '\0') {
  739.         UWORD pos;
  740.         if(nykyinenosio == 2) pos = RemoveGadget(window,&gadget2[9]);
  741.         strcpy(kappaleennimi,song.sample[samplenum].sname);
  742.         if(nykyinenosio == 2) {
  743.             AddGadget(window,&gadget2[9],pos);
  744.             RefreshGList(&gadget2[9],window,NULL,1);
  745.         }
  746.         return(NOERR);
  747.     }
  748.     if(IsHere(name)) {
  749.         Ilmoita(fileex);
  750.         oldexists = 1;
  751.         if(!Continue()) return(notsaved);
  752.     }
  753.     if(!(fh = Open2(name,MODE_NEWFILE))) return(DISKERR);
  754.     if(FWrite(((char *)(sample[samplenum])) + sizeof(struct Soitin),
  755.         sample[samplenum]->length & 0xfffffffe)) return(DISKERR);
  756.     if(fh) Close(fh);
  757.     fh = 0L;
  758.     if(!oldexists) InsertSavedFile(name);
  759.     Ilmoita("Sample saved.");
  760.     return(NOERR);
  761. }
  762.