00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "stdafx.h"
00011 #include "sndfile.h"
00012
00013
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
00027 typedef struct tagSTMSAMPLE
00028 {
00029 CHAR filename[14];
00030 WORD reserved;
00031 WORD length;
00032 WORD loopbeg;
00033 WORD loopend;
00034 BYTE volume;
00035 BYTE reserved2;
00036 WORD c2spd;
00037 BYTE reserved3[6];
00038 } Q_PACKED STMSAMPLE;
00039
00040
00041
00042 typedef struct tagSTMHEADER
00043 {
00044 char songname[20];
00045 char trackername[8];
00046 CHAR unused;
00047 CHAR filetype;
00048 CHAR ver_major;
00049 CHAR ver_minor;
00050 BYTE inittempo;
00051 BYTE numpat;
00052 BYTE globalvol;
00053 BYTE reserved[13];
00054 STMSAMPLE sample[31];
00055 BYTE patorder[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
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
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
00094 for (UINT nIns=0; nIns<31; nIns++)
00095 {
00096 MODINSTRUMENT *pIns = &Ins[nIns+1];
00097 STMSAMPLE *pStm = &phdr->sample[nIns];
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
00124
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
00131
00132
00133 if ((note == 0xFE) || (note == 0xFC)) m->note = 0xFE; else
00134
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
00141 case 1: m->command = CMD_SPEED; m->param >>= 4; break;
00142
00143 case 2: m->command = CMD_POSITIONJUMP; break;
00144
00145 case 3: m->command = CMD_PATTERNBREAK; m->param = (m->param & 0xF0) * 10 + (m->param & 0x0F); break;
00146
00147 case 4: m->command = CMD_VOLUMESLIDE; break;
00148
00149 case 5: m->command = CMD_PORTAMENTODOWN; break;
00150
00151 case 6: m->command = CMD_PORTAMENTOUP; break;
00152
00153 case 7: m->command = CMD_TONEPORTAMENTO; break;
00154
00155 case 8: m->command = CMD_VIBRATO; break;
00156
00157 case 9: m->command = CMD_TREMOR; break;
00158
00159 case 10: m->command = CMD_ARPEGGIO; break;
00160
00161 case 11: m->command = CMD_VIBRATOVOL; break;
00162
00163 case 12: m->command = CMD_TONEPORTAVOL; break;
00164
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
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