Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

load_stm.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is  free software; you can redistribute it  and modify it
00003  * under the terms of the GNU  General Public License as published by the
00004  * Free Software Foundation; either version 2  of the license or (at your
00005  * option) any later version.
00006  *
00007  * Authors: Olivier Lapicque <olivierl@jps.net>
00008 */
00009 
00010 #include "stdafx.h"
00011 #include "sndfile.h"
00012 
00013 //#pragma warning(disable:4244)
00014 
00015 #pragma pack(1)
00016 
00017 typedef struct tagSTMNOTE
00018 {
00019         BYTE note;
00020         BYTE insvol;
00021         BYTE volcmd;
00022         BYTE cmdinf;
00023 } Q_PACKED STMNOTE;
00024 
00025 
00026 // Raw STM sampleinfo struct:
00027 typedef struct tagSTMSAMPLE
00028 {
00029         CHAR filename[14];      // Can't have long comments - just filename comments :)
00030         WORD reserved;          // ISA in memory when in ST 2
00031         WORD length;            // Sample length
00032         WORD loopbeg;           // Loop start point
00033         WORD loopend;           // Loop end point
00034         BYTE volume;            // Volume
00035         BYTE reserved2;         // More reserved crap
00036         WORD c2spd;                     // Good old c2spd
00037         BYTE reserved3[6];      // Yet more of PSi's reserved crap
00038 } Q_PACKED STMSAMPLE;
00039 
00040 
00041 // Raw STM header struct:
00042 typedef struct tagSTMHEADER
00043 {
00044         char songname[20];      // changed from CHAR
00045         char trackername[8];    // !SCREAM! for ST 2.xx  // changed from CHAR
00046         CHAR unused;                    // 0x1A
00047         CHAR filetype;                  // 1=song, 2=module (only 2 is supported, of course) :)
00048         CHAR ver_major;                 // Like 2
00049         CHAR ver_minor;                 // "ditto"
00050         BYTE inittempo;                 // initspeed= stm inittempo>>4
00051         BYTE numpat;                    // number of patterns
00052         BYTE globalvol;                 // <- WoW! a RiGHT TRiANGLE =8*)
00053         BYTE reserved[13];              // More of PSi's internal crap
00054         STMSAMPLE sample[31];   // STM sample data
00055         BYTE patorder[128];             // Docs say 64 - actually 128
00056 } Q_PACKED STMHEADER;
00057 
00058 #pragma pack()
00059 
00060 
00061 
00062 BOOL CSoundFile::ReadSTM(const BYTE *lpStream, DWORD dwMemLength)
00063 //---------------------------------------------------------------
00064 {
00065         STMHEADER *phdr = (STMHEADER *)lpStream;
00066         DWORD dwMemPos = 0;
00067         
00068         if ((!lpStream) || (dwMemLength < sizeof(STMHEADER))) return FALSE;
00069         if ((phdr->filetype != 2) || (phdr->unused != 0x1A)
00070          || ((strnicmp(phdr->trackername, "!SCREAM!", 8))
00071           && (strnicmp(phdr->trackername, "BMOD2STM", 8)))) return FALSE;
00072         memcpy(m_szNames[0], phdr->songname, 20);
00073         // Read STM header
00074         m_nType = MOD_TYPE_STM;
00075         m_nSamples = 31;
00076         m_nChannels = 4;
00077         m_nInstruments = 0;
00078         m_nMinPeriod = 64;
00079         m_nMaxPeriod = 0x7FFF;
00080         m_nDefaultSpeed = phdr->inittempo >> 4;
00081         if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 1;
00082         m_nDefaultTempo = 125;
00083         m_nDefaultGlobalVolume = phdr->globalvol << 2;
00084         if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256;
00085         memcpy(Order, phdr->patorder, 128);
00086         // Setting up channels
00087         for (UINT nSet=0; nSet<4; nSet++)
00088         {
00089                 ChnSettings[nSet].dwFlags = 0;
00090                 ChnSettings[nSet].nVolume = 64;
00091                 ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0;
00092         }
00093         // Reading samples
00094         for (UINT nIns=0; nIns<31; nIns++)
00095         {
00096                 MODINSTRUMENT *pIns = &Ins[nIns+1];
00097                 STMSAMPLE *pStm = &phdr->sample[nIns];  // STM sample data
00098                 memcpy(pIns->name, pStm->filename, 13);
00099                 memcpy(m_szNames[nIns+1], pStm->filename, 12);
00100                 pIns->nC4Speed = pStm->c2spd;
00101                 pIns->nGlobalVol = 64;
00102                 pIns->nVolume = pStm->volume << 2;
00103                 if (pIns->nVolume > 256) pIns->nVolume = 256;
00104                 pIns->nLength = pStm->length;
00105                 if ((pIns->nLength < 4) || (!pIns->nVolume)) pIns->nLength = 0;
00106                 pIns->nLoopStart = pStm->loopbeg;
00107                 pIns->nLoopEnd = pStm->loopend;
00108                 if ((pIns->nLoopEnd > pIns->nLoopStart) && (pIns->nLoopEnd != 0xFFFF)) pIns->uFlags |= CHN_LOOP;
00109         }
00110         dwMemPos = sizeof(STMHEADER);
00111         for (UINT nOrd=0; nOrd<MAX_ORDERS; nOrd++) if (Order[nOrd] >= 99) Order[nOrd] = 0xFF;
00112         UINT nPatterns = phdr->numpat;
00113         for (UINT nPat=0; nPat<nPatterns; nPat++)
00114         {
00115                 if (dwMemPos + 64*4*4 > dwMemLength) return TRUE;
00116                 PatternSize[nPat] = 64;
00117                 if ((Patterns[nPat] = AllocatePattern(64, m_nChannels)) == NULL) return TRUE;
00118                 MODCOMMAND *m = Patterns[nPat];
00119                 STMNOTE *p = (STMNOTE *)(lpStream + dwMemPos);
00120                 for (UINT n=0; n<64*4; n++, p++, m++)
00121                 {
00122                         UINT note,ins,vol,cmd;
00123                         // extract the various information from the 4 bytes that
00124                         // make up a single note
00125                         note = p->note;
00126                         ins = p->insvol >> 3;
00127                         vol = (p->insvol & 0x07) + (p->volcmd >> 1);
00128                         cmd = p->volcmd & 0x0F;
00129                         if ((ins) && (ins < 32)) m->instr = ins;
00130                         // special values of [SBYTE0] are handled here ->
00131                         // we have no idea if these strange values will ever be encountered
00132                         // but it appears as though stms sound correct.
00133                         if ((note == 0xFE) || (note == 0xFC)) m->note = 0xFE; else
00134                         // if note < 251, then all three bytes are stored in the file
00135                         if (note < 0xFC) m->note = (note >> 4)*12 + (note&0xf) + 37;
00136                         if (vol <= 64) { m->volcmd = VOLCMD_VOLUME; m->vol = vol; }
00137                         m->param = p->cmdinf;
00138                         switch(cmd)
00139                         {
00140                         // Axx set speed to xx
00141                         case 1: m->command = CMD_SPEED; m->param >>= 4; break;
00142                         // Bxx position jump
00143                         case 2: m->command = CMD_POSITIONJUMP; break;
00144                         // Cxx patternbreak to row xx
00145                         case 3: m->command = CMD_PATTERNBREAK; m->param = (m->param & 0xF0) * 10 + (m->param & 0x0F);   break;
00146                         // Dxy volumeslide
00147                         case 4: m->command = CMD_VOLUMESLIDE; break;
00148                         // Exy toneslide down
00149                         case 5: m->command = CMD_PORTAMENTODOWN; break;
00150                         // Fxy toneslide up
00151                         case 6: m->command = CMD_PORTAMENTOUP; break;
00152                         // Gxx Tone portamento,speed xx
00153                         case 7: m->command = CMD_TONEPORTAMENTO; break;
00154                         // Hxy vibrato
00155                         case 8: m->command = CMD_VIBRATO; break;
00156                         // Ixy tremor, ontime x, offtime y
00157                         case 9: m->command = CMD_TREMOR; break;
00158                         // Jxy arpeggio
00159                         case 10: m->command = CMD_ARPEGGIO; break;
00160                         // Kxy Dual command H00 & Dxy
00161                         case 11: m->command = CMD_VIBRATOVOL; break;
00162                         // Lxy Dual command G00 & Dxy
00163                         case 12: m->command = CMD_TONEPORTAVOL; break;
00164                         // Xxx amiga command 8xx
00165                         case 0x18:      m->command = CMD_PANNING8; break;
00166                         default:
00167                                 m->command = m->param = 0;
00168                         }
00169                 }
00170                 dwMemPos += 64*4*4;
00171         }
00172         // Reading Samples
00173         for (UINT nSmp=1; nSmp<=31; nSmp++)
00174         {
00175                 MODINSTRUMENT *pIns = &Ins[nSmp];
00176                 dwMemPos = (dwMemPos + 15) & (~15);
00177                 if (pIns->nLength)
00178                 {
00179                         UINT nPos = ((UINT)phdr->sample[nSmp-1].reserved) << 4;
00180                         if ((nPos >= sizeof(STMHEADER)) && (nPos+pIns->nLength <= dwMemLength)) dwMemPos = nPos;
00181                         if (dwMemPos < dwMemLength)
00182                         {
00183                                 dwMemPos += ReadSample(pIns, RS_PCM8S, (LPSTR)(lpStream+dwMemPos),dwMemLength-dwMemPos);
00184                         }
00185                 }
00186         }
00187         return TRUE;
00188 }
00189 

Generated on Sat Nov 5 16:15:40 2005 for OPIE by  doxygen 1.4.2