int XM_ReadNote(ref XMNOTE n) { byte cmp, result = 1; n.Clear(); cmp = m_Reader.Read_byte(); if ((cmp & 0x80) != 0) { if ((cmp & 1) != 0) { result++; n.note = m_Reader.Read_byte(); } if ((cmp & 2) != 0) { result++; n.ins = m_Reader.Read_byte(); } if ((cmp & 4) != 0) { result++; n.vol = m_Reader.Read_byte(); } if ((cmp & 8) != 0) { result++; n.eff = m_Reader.Read_byte(); } if ((cmp & 16) != 0) { result++; n.dat = m_Reader.Read_byte(); } } else { n.note = cmp; n.ins = m_Reader.Read_byte(); n.vol = m_Reader.Read_byte(); n.eff = m_Reader.Read_byte(); n.dat = m_Reader.Read_byte(); result += 4; } return(result); }
bool LoadPatterns(bool dummypat) { int t, u, v, numtrk; m_Module.AllocTracks(); m_Module.AllocPatterns(); numtrk = 0; for (t = 0; t < mh.numpat; t++) { XMPATHEADER ph = new XMPATHEADER(); ph.size = m_Reader.Read_Intel_uint(); if (ph.size < (mh.version == 0x0102 ? 8 : 9)) { m_LoadError = MMERR_LOADING_PATTERN; return(false); } ph.packing = m_Reader.Read_byte(); if (ph.packing != 0) { m_LoadError = MMERR_LOADING_PATTERN; return(false); } if (mh.version == 0x0102) { ph.numrows = (ushort)(m_Reader.Read_byte() + 1); } else { ph.numrows = m_Reader.Read_Intel_ushort(); } ph.packsize = (short)m_Reader.Read_Intel_ushort(); ph.size -= (ushort)(mh.version == 0x0102 ? 8 : 9); if (ph.size != 0) { m_Reader.Seek((int)ph.size, SeekOrigin.Current); } m_Module.pattrows[t] = ph.numrows; if (ph.numrows != 0) { xmpat = new XMNOTE[ph.numrows * m_Module.numchn]; for (int i = 0; i < xmpat.Length; i++) { xmpat[i] = new XMNOTE(); } /* when packsize is 0, don't try to load a pattern.. it's empty. */ if (ph.packsize != 0) { for (u = 0; u < ph.numrows; u++) { for (v = 0; v < m_Module.numchn; v++) { if (ph.packsize == 0) { break; } ph.packsize -= (short)XM_ReadNote(ref xmpat[(v * ph.numrows) + u]); if (ph.packsize < 0) { m_LoadError = MMERR_LOADING_PATTERN; return(false); } } } } if (ph.packsize != 0) { m_Reader.Seek(ph.packsize, SeekOrigin.Current); } if (m_Reader.isEOF()) { m_LoadError = MMERR_LOADING_PATTERN; return(false); } for (v = 0; v < m_Module.numchn; v++) { m_Module.tracks[numtrk++] = XM_Convert(xmpat, v * ph.numrows, ph.numrows); } xmpat = null; } else { for (v = 0; v < m_Module.numchn; v++) { m_Module.tracks[numtrk++] = XM_Convert(null, 0, ph.numrows); } } } if (dummypat) { m_Module.pattrows[t] = 64; xmpat = new XMNOTE[64 * m_Module.numchn]; for (int i = 0; i < xmpat.Length; i++) { xmpat[i] = new XMNOTE(); } for (v = 0; v < m_Module.numchn; v++) { m_Module.tracks[numtrk++] = XM_Convert(xmpat, v * 64, 64); } xmpat = null; } return(true); }
byte[] XM_Convert(XMNOTE[] xmtracks, int place, ushort rows) { int t; byte note, ins, vol, eff, dat; UniReset(); for (t = 0; t < rows; t++) { XMNOTE xmtrack = xmtracks[place++]; note = xmtrack.note; ins = xmtrack.ins; vol = xmtrack.vol; eff = xmtrack.eff; dat = xmtrack.dat; if (note != 0) { if (note > XMNOTECNT) { UniEffect(SharpMikCommon.Commands.UNI_KEYFADE, 0); } else { UniNote(note - 1); } } if (ins != 0) { UniInstrument(ins - 1); } switch (vol >> 4) { case 0x6: /* volslide down */ if ((vol & 0xf) != 0) { UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTA, vol & 0xf); } break; case 0x7: /* volslide up */ if ((vol & 0xf) != 0) { UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTA, vol << 4); } break; /* volume-row fine volume slide is compatible with protracker * EBx and EAx effects i.e. a zero nibble means DO NOT SLIDE, as * opposed to 'take the last sliding value'. */ case 0x8: /* finevol down */ UniPTEffect(0xe, 0xb0 | (vol & 0xf)); break; case 0x9: /* finevol up */ UniPTEffect(0xe, 0xa0 | (vol & 0xf)); break; case 0xa: /* set vibrato speed */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECT4, vol << 4); break; case 0xb: /* vibrato */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECT4, vol & 0xf); break; case 0xc: /* set panning */ UniPTEffect(0x8, vol << 4); break; case 0xd: /* panning slide left (only slide when data not zero) */ if ((vol & 0xf) != 0) { UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTP, vol & 0xf); } break; case 0xe: /* panning slide right (only slide when data not zero) */ if ((vol & 0xf) != 0) { UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTP, vol << 4); } break; case 0xf: /* tone porta */ UniPTEffect(0x3, vol << 4); break; default: if ((vol >= 0x10) && (vol <= 0x50)) { UniPTEffect(0xc, vol - 0x10); } break; } switch (eff) { case 0x4: UniEffect(SharpMikCommon.Commands.UNI_XMEFFECT4, dat); break; case 0x6: UniEffect(SharpMikCommon.Commands.UNI_XMEFFECT6, dat); break; case 0xa: UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTA, dat); break; case 0xe: /* Extended effects */ switch (dat >> 4) { case 0x1: /* XM fine porta up */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTE1, dat & 0xf); break; case 0x2: /* XM fine porta down */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTE2, dat & 0xf); break; case 0xa: /* XM fine volume up */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTEA, dat & 0xf); break; case 0xb: /* XM fine volume down */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTEB, dat & 0xf); break; default: UniPTEffect(eff, dat); break; } break; case 'G' - 55: /* G - set global volume */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTG, dat > 64 ? 128 : dat << 1); break; case 'H' - 55: /* H - global volume slide */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTH, dat); break; case 'K' - 55: /* K - keyOff and KeyFade */ UniEffect(SharpMikCommon.Commands.UNI_KEYFADE, dat); break; case 'L' - 55: /* L - set envelope position */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTL, dat); break; case 'P' - 55: /* P - panning slide */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTP, dat); break; case 'R' - 55: /* R - multi retrig note */ UniEffect(SharpMikCommon.Commands.UNI_S3MEFFECTQ, dat); break; case 'T' - 55: /* T - Tremor */ UniEffect(SharpMikCommon.Commands.UNI_S3MEFFECTI, dat); break; case 'X' - 55: switch (dat >> 4) { case 1: /* X1 - Extra Fine Porta up */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTX1, dat & 0xf); break; case 2: /* X2 - Extra Fine Porta down */ UniEffect(SharpMikCommon.Commands.UNI_XMEFFECTX2, dat & 0xf); break; } break; default: if (eff <= 0xf) { /* the pattern jump destination is written in decimal, * but it seems some poor tracker software writes them * in hexadecimal... (sigh) */ if (eff == 0xd) { /* don't change anything if we're sure it's in hexa */ if ((((dat & 0xf0) >> 4) <= 9) && ((dat & 0xf) <= 9)) { /* otherwise, convert from dec to hex */ dat = (byte)((((dat & 0xf0) >> 4) * 10) + (dat & 0xf)); } } UniPTEffect(eff, dat); } break; } UniNewline(); } return(UniDup()); }