Mercurial > audlegacy-plugins
comparison src/modplug/load_stm.cxx @ 136:6b5a52635b3b trunk
[svn] - like with so many other things, modplug is now maintained by us.
author | nenolod |
---|---|
date | Sun, 29 Oct 2006 01:04:52 -0700 |
parents | |
children | 032053ca08ab 3673c7ec4ea2 |
comparison
equal
deleted
inserted
replaced
135:33d24bd94ccc | 136:6b5a52635b3b |
---|---|
1 /* | |
2 * This source code is public domain. | |
3 * | |
4 * Authors: Olivier Lapicque <olivierl@jps.net> | |
5 */ | |
6 | |
7 #include "stdafx.h" | |
8 #include "sndfile.h" | |
9 | |
10 //#pragma warning(disable:4244) | |
11 | |
12 #pragma pack(1) | |
13 | |
14 typedef struct tagSTMNOTE | |
15 { | |
16 BYTE note; | |
17 BYTE insvol; | |
18 BYTE volcmd; | |
19 BYTE cmdinf; | |
20 } STMNOTE; | |
21 | |
22 | |
23 // Raw STM sampleinfo struct: | |
24 typedef struct tagSTMSAMPLE | |
25 { | |
26 CHAR filename[14]; // Can't have long comments - just filename comments :) | |
27 WORD reserved; // ISA in memory when in ST 2 | |
28 WORD length; // Sample length | |
29 WORD loopbeg; // Loop start point | |
30 WORD loopend; // Loop end point | |
31 BYTE volume; // Volume | |
32 BYTE reserved2; // More reserved crap | |
33 WORD c2spd; // Good old c2spd | |
34 BYTE reserved3[6]; // Yet more of PSi's reserved crap | |
35 } STMSAMPLE; | |
36 | |
37 | |
38 // Raw STM header struct: | |
39 typedef struct tagSTMHEADER | |
40 { | |
41 char songname[20]; // changed from CHAR | |
42 char trackername[8]; // !SCREAM! for ST 2.xx // changed from CHAR | |
43 CHAR unused; // 0x1A | |
44 CHAR filetype; // 1=song, 2=module (only 2 is supported, of course) :) | |
45 CHAR ver_major; // Like 2 | |
46 CHAR ver_minor; // "ditto" | |
47 BYTE inittempo; // initspeed= stm inittempo>>4 | |
48 BYTE numpat; // number of patterns | |
49 BYTE globalvol; // <- WoW! a RiGHT TRiANGLE =8*) | |
50 BYTE reserved[13]; // More of PSi's internal crap | |
51 STMSAMPLE sample[31]; // STM sample data | |
52 BYTE patorder[128]; // Docs say 64 - actually 128 | |
53 } STMHEADER; | |
54 | |
55 #pragma pack() | |
56 | |
57 | |
58 | |
59 BOOL CSoundFile::ReadSTM(const BYTE *lpStream, DWORD dwMemLength) | |
60 //--------------------------------------------------------------- | |
61 { | |
62 STMHEADER *phdr = (STMHEADER *)lpStream; | |
63 DWORD dwMemPos = 0; | |
64 | |
65 if ((!lpStream) || (dwMemLength < sizeof(STMHEADER))) return FALSE; | |
66 if ((phdr->filetype != 2) || (phdr->unused != 0x1A) | |
67 || ((strnicmp(phdr->trackername, "!SCREAM!", 8)) | |
68 && (strnicmp(phdr->trackername, "BMOD2STM", 8)))) return FALSE; | |
69 memcpy(m_szNames[0], phdr->songname, 20); | |
70 // Read STM header | |
71 m_nType = MOD_TYPE_STM; | |
72 m_nSamples = 31; | |
73 m_nChannels = 4; | |
74 m_nInstruments = 0; | |
75 m_nMinPeriod = 64; | |
76 m_nMaxPeriod = 0x7FFF; | |
77 m_nDefaultSpeed = phdr->inittempo >> 4; | |
78 if (m_nDefaultSpeed < 1) m_nDefaultSpeed = 1; | |
79 m_nDefaultTempo = 125; | |
80 m_nDefaultGlobalVolume = phdr->globalvol << 2; | |
81 if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256; | |
82 memcpy(Order, phdr->patorder, 128); | |
83 // Setting up channels | |
84 for (UINT nSet=0; nSet<4; nSet++) | |
85 { | |
86 ChnSettings[nSet].dwFlags = 0; | |
87 ChnSettings[nSet].nVolume = 64; | |
88 ChnSettings[nSet].nPan = (nSet & 1) ? 0x40 : 0xC0; | |
89 } | |
90 // Reading samples | |
91 for (UINT nIns=0; nIns<31; nIns++) | |
92 { | |
93 MODINSTRUMENT *pIns = &Ins[nIns+1]; | |
94 STMSAMPLE *pStm = &phdr->sample[nIns]; // STM sample data | |
95 memcpy(pIns->name, pStm->filename, 13); | |
96 memcpy(m_szNames[nIns+1], pStm->filename, 12); | |
97 pIns->nC4Speed = bswapLE16(pStm->c2spd); | |
98 pIns->nGlobalVol = 64; | |
99 pIns->nVolume = pStm->volume << 2; | |
100 if (pIns->nVolume > 256) pIns->nVolume = 256; | |
101 pIns->nLength = bswapLE16(pStm->length); | |
102 if ((pIns->nLength < 4) || (!pIns->nVolume)) pIns->nLength = 0; | |
103 pIns->nLoopStart = bswapLE16(pStm->loopbeg); | |
104 pIns->nLoopEnd = bswapLE16(pStm->loopend); | |
105 if ((pIns->nLoopEnd > pIns->nLoopStart) && (pIns->nLoopEnd != 0xFFFF)) pIns->uFlags |= CHN_LOOP; | |
106 } | |
107 dwMemPos = sizeof(STMHEADER); | |
108 for (UINT nOrd=0; nOrd<MAX_ORDERS; nOrd++) if (Order[nOrd] >= 99) Order[nOrd] = 0xFF; | |
109 UINT nPatterns = phdr->numpat; | |
110 for (UINT nPat=0; nPat<nPatterns; nPat++) | |
111 { | |
112 if (dwMemPos + 64*4*4 > dwMemLength) return TRUE; | |
113 PatternSize[nPat] = 64; | |
114 if ((Patterns[nPat] = AllocatePattern(64, m_nChannels)) == NULL) return TRUE; | |
115 MODCOMMAND *m = Patterns[nPat]; | |
116 STMNOTE *p = (STMNOTE *)(lpStream + dwMemPos); | |
117 for (UINT n=0; n<64*4; n++, p++, m++) | |
118 { | |
119 UINT note,ins,vol,cmd; | |
120 // extract the various information from the 4 bytes that | |
121 // make up a single note | |
122 note = p->note; | |
123 ins = p->insvol >> 3; | |
124 vol = (p->insvol & 0x07) + (p->volcmd >> 1); | |
125 cmd = p->volcmd & 0x0F; | |
126 if ((ins) && (ins < 32)) m->instr = ins; | |
127 // special values of [SBYTE0] are handled here -> | |
128 // we have no idea if these strange values will ever be encountered | |
129 // but it appears as though stms sound correct. | |
130 if ((note == 0xFE) || (note == 0xFC)) m->note = 0xFE; else | |
131 // if note < 251, then all three bytes are stored in the file | |
132 if (note < 0xFC) m->note = (note >> 4)*12 + (note&0xf) + 37; | |
133 if (vol <= 64) { m->volcmd = VOLCMD_VOLUME; m->vol = vol; } | |
134 m->param = p->cmdinf; | |
135 switch(cmd) | |
136 { | |
137 // Axx set speed to xx | |
138 case 1: m->command = CMD_SPEED; m->param >>= 4; break; | |
139 // Bxx position jump | |
140 case 2: m->command = CMD_POSITIONJUMP; break; | |
141 // Cxx patternbreak to row xx | |
142 case 3: m->command = CMD_PATTERNBREAK; m->param = (m->param & 0xF0) * 10 + (m->param & 0x0F); break; | |
143 // Dxy volumeslide | |
144 case 4: m->command = CMD_VOLUMESLIDE; break; | |
145 // Exy toneslide down | |
146 case 5: m->command = CMD_PORTAMENTODOWN; break; | |
147 // Fxy toneslide up | |
148 case 6: m->command = CMD_PORTAMENTOUP; break; | |
149 // Gxx Tone portamento,speed xx | |
150 case 7: m->command = CMD_TONEPORTAMENTO; break; | |
151 // Hxy vibrato | |
152 case 8: m->command = CMD_VIBRATO; break; | |
153 // Ixy tremor, ontime x, offtime y | |
154 case 9: m->command = CMD_TREMOR; break; | |
155 // Jxy arpeggio | |
156 case 10: m->command = CMD_ARPEGGIO; break; | |
157 // Kxy Dual command H00 & Dxy | |
158 case 11: m->command = CMD_VIBRATOVOL; break; | |
159 // Lxy Dual command G00 & Dxy | |
160 case 12: m->command = CMD_TONEPORTAVOL; break; | |
161 // Xxx amiga command 8xx | |
162 case 0x18: m->command = CMD_PANNING8; break; | |
163 default: | |
164 m->command = m->param = 0; | |
165 } | |
166 } | |
167 dwMemPos += 64*4*4; | |
168 } | |
169 // Reading Samples | |
170 for (UINT nSmp=1; nSmp<=31; nSmp++) | |
171 { | |
172 MODINSTRUMENT *pIns = &Ins[nSmp]; | |
173 dwMemPos = (dwMemPos + 15) & (~15); | |
174 if (pIns->nLength) | |
175 { | |
176 UINT nPos = ((UINT)phdr->sample[nSmp-1].reserved) << 4; | |
177 if ((nPos >= sizeof(STMHEADER)) && (nPos+pIns->nLength <= dwMemLength)) dwMemPos = nPos; | |
178 if (dwMemPos < dwMemLength) | |
179 { | |
180 dwMemPos += ReadSample(pIns, RS_PCM8S, (LPSTR)(lpStream+dwMemPos),dwMemLength-dwMemPos); | |
181 } | |
182 } | |
183 } | |
184 return TRUE; | |
185 } | |
186 |