-rw-r--r-- | core/multimedia/opieplayer/modplug/load_amf.cpp | 2 | ||||
-rw-r--r-- | core/multimedia/opieplayer/modplug/load_ams.cpp | 2 | ||||
-rw-r--r-- | core/multimedia/opieplayer/modplug/load_mdl.cpp | 2 |
3 files changed, 3 insertions, 3 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_amf.cpp b/core/multimedia/opieplayer/modplug/load_amf.cpp index 188b5f5..2cf131b 100644 --- a/core/multimedia/opieplayer/modplug/load_amf.cpp +++ b/core/multimedia/opieplayer/modplug/load_amf.cpp | |||
@@ -1,420 +1,420 @@ | |||
1 | /* | 1 | /* |
2 | * This program is free software; you can redistribute it and modify it | 2 | * This program is free software; you can redistribute it and modify it |
3 | * under the terms of the GNU General Public License as published by the | 3 | * under the terms of the GNU General Public License as published by the |
4 | * Free Software Foundation; either version 2 of the license or (at your | 4 | * Free Software Foundation; either version 2 of the license or (at your |
5 | * option) any later version. | 5 | * option) any later version. |
6 | * | 6 | * |
7 | * Authors: Olivier Lapicque <olivierl@jps.net> | 7 | * Authors: Olivier Lapicque <olivierl@jps.net> |
8 | */ | 8 | */ |
9 | 9 | ||
10 | /////////////////////////////////////////////////// | 10 | /////////////////////////////////////////////////// |
11 | // | 11 | // |
12 | // AMF module loader | 12 | // AMF module loader |
13 | // | 13 | // |
14 | // There is 2 types of AMF files: | 14 | // There is 2 types of AMF files: |
15 | // - ASYLUM Music Format | 15 | // - ASYLUM Music Format |
16 | // - Advanced Music Format(DSM) | 16 | // - Advanced Music Format(DSM) |
17 | // | 17 | // |
18 | /////////////////////////////////////////////////// | 18 | /////////////////////////////////////////////////// |
19 | #include "stdafx.h" | 19 | #include "stdafx.h" |
20 | #include "sndfile.h" | 20 | #include "sndfile.h" |
21 | 21 | ||
22 | //#define AMFLOG | 22 | //#define AMFLOG |
23 | 23 | ||
24 | //#pragma warning(disable:4244) | 24 | //#pragma warning(disable:4244) |
25 | 25 | ||
26 | #pragma pack(1) | 26 | #pragma pack(1) |
27 | 27 | ||
28 | typedef struct _AMFFILEHEADER | 28 | typedef struct _AMFFILEHEADER |
29 | { | 29 | { |
30 | UCHAR szAMF[3]; | 30 | UCHAR szAMF[3]; |
31 | UCHAR version; | 31 | UCHAR version; |
32 | CHAR title[32]; | 32 | CHAR title[32]; |
33 | UCHAR numsamples; | 33 | UCHAR numsamples; |
34 | UCHAR numorders; | 34 | UCHAR numorders; |
35 | USHORT numtracks; | 35 | USHORT numtracks; |
36 | UCHAR numchannels; | 36 | UCHAR numchannels; |
37 | } Q_PACKED AMFFILEHEADER; | 37 | } Q_PACKED AMFFILEHEADER; |
38 | 38 | ||
39 | typedef struct _AMFSAMPLE | 39 | typedef struct _AMFSAMPLE |
40 | { | 40 | { |
41 | UCHAR type; | 41 | UCHAR type; |
42 | CHAR samplename[32]; | 42 | CHAR samplename[32]; |
43 | CHAR filename[13]; | 43 | CHAR filename[13]; |
44 | ULONG offset; | 44 | ULONG offset; |
45 | ULONG length; | 45 | ULONG length; |
46 | USHORT c2spd; | 46 | USHORT c2spd; |
47 | UCHAR volume; | 47 | UCHAR volume; |
48 | } Q_PACKED AMFSAMPLE; | 48 | } Q_PACKED AMFSAMPLE; |
49 | 49 | ||
50 | 50 | ||
51 | #pragma pack() | 51 | #pragma pack() |
52 | 52 | ||
53 | 53 | ||
54 | #ifdef AMFLOG | 54 | #ifdef AMFLOG |
55 | extern void Log(LPCSTR, ...); | 55 | extern void Log(LPCSTR, ...); |
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels) | 58 | VOID AMF_Unpack(MODCOMMAND *pPat, const BYTE *pTrack, UINT nRows, UINT nChannels) |
59 | //------------------------------------------------------------------------------- | 59 | //------------------------------------------------------------------------------- |
60 | { | 60 | { |
61 | UINT lastinstr = 0; | 61 | UINT lastinstr = 0; |
62 | UINT nTrkSize = *(USHORT *)pTrack; | 62 | UINT nTrkSize = *(USHORT *)pTrack; |
63 | nTrkSize += (UINT)pTrack[2] << 16; | 63 | nTrkSize += (UINT)pTrack[2] << 16; |
64 | pTrack += 3; | 64 | pTrack += 3; |
65 | while (nTrkSize--) | 65 | while (nTrkSize--) |
66 | { | 66 | { |
67 | UINT row = pTrack[0]; | 67 | UINT row = pTrack[0]; |
68 | UINT cmd = pTrack[1]; | 68 | UINT cmd = pTrack[1]; |
69 | UINT arg = pTrack[2]; | 69 | UINT arg = pTrack[2]; |
70 | if (row >= nRows) break; | 70 | if (row >= nRows) break; |
71 | MODCOMMAND *m = pPat + row * nChannels; | 71 | MODCOMMAND *m = pPat + row * nChannels; |
72 | if (cmd < 0x7F) // note+vol | 72 | if (cmd < 0x7F) // note+vol |
73 | { | 73 | { |
74 | m->note = cmd+1; | 74 | m->note = cmd+1; |
75 | if (!m->instr) m->instr = lastinstr; | 75 | if (!m->instr) m->instr = lastinstr; |
76 | m->volcmd = VOLCMD_VOLUME; | 76 | m->volcmd = VOLCMD_VOLUME; |
77 | m->vol = arg; | 77 | m->vol = arg; |
78 | } else | 78 | } else |
79 | if (cmd == 0x7F) // duplicate row | 79 | if (cmd == 0x7F) // duplicate row |
80 | { | 80 | { |
81 | signed char rdelta = (signed char)arg; | 81 | signed char rdelta = (signed char)arg; |
82 | int rowsrc = (int)row + (int)rdelta; | 82 | int rowsrc = (int)row + (int)rdelta; |
83 | if ((rowsrc >= 0) && (rowsrc < (int)nRows)) *m = pPat[rowsrc*nChannels]; | 83 | if ((rowsrc >= 0) && (rowsrc < (int)nRows)) *m = pPat[rowsrc*nChannels]; |
84 | } else | 84 | } else |
85 | if (cmd == 0x80) // instrument | 85 | if (cmd == 0x80) // instrument |
86 | { | 86 | { |
87 | m->instr = arg+1; | 87 | m->instr = arg+1; |
88 | lastinstr = m->instr; | 88 | lastinstr = m->instr; |
89 | } else | 89 | } else |
90 | if (cmd == 0x83) // volume | 90 | if (cmd == 0x83) // volume |
91 | { | 91 | { |
92 | m->volcmd = VOLCMD_VOLUME; | 92 | m->volcmd = VOLCMD_VOLUME; |
93 | m->vol = arg; | 93 | m->vol = arg; |
94 | } else | 94 | } else |
95 | // effect | 95 | // effect |
96 | { | 96 | { |
97 | UINT command = cmd & 0x7F; | 97 | UINT command = cmd & 0x7F; |
98 | UINT param = arg; | 98 | UINT param = arg; |
99 | switch(command) | 99 | switch(command) |
100 | { | 100 | { |
101 | // 0x01: Set Speed | 101 | // 0x01: Set Speed |
102 | case 0x01:command = CMD_SPEED; break; | 102 | case 0x01:command = CMD_SPEED; break; |
103 | // 0x02: Volume Slide | 103 | // 0x02: Volume Slide |
104 | // 0x0A: Tone Porta + Vol Slide | 104 | // 0x0A: Tone Porta + Vol Slide |
105 | // 0x0B: Vibrato + Vol Slide | 105 | // 0x0B: Vibrato + Vol Slide |
106 | case 0x02:command = CMD_VOLUMESLIDE; | 106 | case 0x02:command = CMD_VOLUMESLIDE; |
107 | case 0x0A:if (command == 0x0A) command = CMD_TONEPORTAVOL; | 107 | case 0x0A:if (command == 0x0A) command = CMD_TONEPORTAVOL; |
108 | case 0x0B:if (command == 0x0B) command = CMD_VIBRATOVOL; | 108 | case 0x0B:if (command == 0x0B) command = CMD_VIBRATOVOL; |
109 | if (param & 0x80) param = (-(signed char)param)&0x0F; | 109 | if (param & 0x80) param = (-(signed char)param)&0x0F; |
110 | else param = (param&0x0F)<<4; | 110 | else param = (param&0x0F)<<4; |
111 | break; | 111 | break; |
112 | // 0x04: Porta Up/Down | 112 | // 0x04: Porta Up/Down |
113 | case 0x04:if (param & 0x80) { command = CMD_PORTAMENTOUP; param = -(signed char)param; } | 113 | case 0x04:if (param & 0x80) { command = CMD_PORTAMENTOUP; param = -(signed char)param; } |
114 | else { command = CMD_PORTAMENTODOWN; } break; | 114 | else { command = CMD_PORTAMENTODOWN; } break; |
115 | // 0x06: Tone Portamento | 115 | // 0x06: Tone Portamento |
116 | case 0x06:command = CMD_TONEPORTAMENTO; break; | 116 | case 0x06:command = CMD_TONEPORTAMENTO; break; |
117 | // 0x07: Tremor | 117 | // 0x07: Tremor |
118 | case 0x07:command = CMD_TREMOR; break; | 118 | case 0x07:command = CMD_TREMOR; break; |
119 | // 0x08: Arpeggio | 119 | // 0x08: Arpeggio |
120 | case 0x08:command = CMD_ARPEGGIO; break; | 120 | case 0x08:command = CMD_ARPEGGIO; break; |
121 | // 0x09: Vibrato | 121 | // 0x09: Vibrato |
122 | case 0x09:command = CMD_VIBRATO; break; | 122 | case 0x09:command = CMD_VIBRATO; break; |
123 | // 0x0C: Pattern Break | 123 | // 0x0C: Pattern Break |
124 | case 0x0C:command = CMD_PATTERNBREAK; break; | 124 | case 0x0C:command = CMD_PATTERNBREAK; break; |
125 | // 0x0D: Position Jump | 125 | // 0x0D: Position Jump |
126 | case 0x0D:command = CMD_POSITIONJUMP; break; | 126 | case 0x0D:command = CMD_POSITIONJUMP; break; |
127 | // 0x0F: Retrig | 127 | // 0x0F: Retrig |
128 | case 0x0F:command = CMD_RETRIG; break; | 128 | case 0x0F:command = CMD_RETRIG; break; |
129 | // 0x10: Offset | 129 | // 0x10: Offset |
130 | case 0x10:command = CMD_OFFSET; break; | 130 | case 0x10:command = CMD_OFFSET; break; |
131 | // 0x11: Fine Volume Slide | 131 | // 0x11: Fine Volume Slide |
132 | case 0x11:if (param) { command = CMD_VOLUMESLIDE; | 132 | case 0x11:if (param) { command = CMD_VOLUMESLIDE; |
133 | if (param & 0x80) param = 0xF0|((-(signed char)param)&0x0F); | 133 | if (param & 0x80) param = 0xF0|((-(signed char)param)&0x0F); |
134 | else param = 0x0F|((param&0x0F)<<4); | 134 | else param = 0x0F|((param&0x0F)<<4); |
135 | } else command = 0; break; | 135 | } else command = 0; break; |
136 | // 0x12: Fine Portamento | 136 | // 0x12: Fine Portamento |
137 | // 0x16: Extra Fine Portamento | 137 | // 0x16: Extra Fine Portamento |
138 | case 0x12: | 138 | case 0x12: |
139 | case 0x16:if (param) { int mask = (command == 0x16) ? 0xE0 : 0xF0; | 139 | case 0x16:if (param) { int mask = (command == 0x16) ? 0xE0 : 0xF0; |
140 | command = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; | 140 | command = (param & 0x80) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN; |
141 | if (param & 0x80) param = mask|((-(signed char)param)&0x0F); | 141 | if (param & 0x80) param = mask|((-(signed char)param)&0x0F); |
142 | else param |= mask; | 142 | else param |= mask; |
143 | } else command = 0; break; | 143 | } else command = 0; break; |
144 | // 0x13: Note Delay | 144 | // 0x13: Note Delay |
145 | case 0x13:command = CMD_S3MCMDEX; param = 0xD0|(param & 0x0F); break; | 145 | case 0x13:command = CMD_S3MCMDEX; param = 0xD0|(param & 0x0F); break; |
146 | // 0x14: Note Cut | 146 | // 0x14: Note Cut |
147 | case 0x14:command = CMD_S3MCMDEX; param = 0xC0|(param & 0x0F); break; | 147 | case 0x14:command = CMD_S3MCMDEX; param = 0xC0|(param & 0x0F); break; |
148 | // 0x15: Set Tempo | 148 | // 0x15: Set Tempo |
149 | case 0x15:command = CMD_TEMPO; break; | 149 | case 0x15:command = CMD_TEMPO; break; |
150 | // 0x17: Panning | 150 | // 0x17: Panning |
151 | case 0x17:param = (param+64)&0x7F; | 151 | case 0x17:param = (param+64)&0x7F; |
152 | if (m->command) { if (!m->volcmd) { m->volcmd = VOLCMD_PANNING; m->vol = param/2; } command = 0; } | 152 | if (m->command) { if (!m->volcmd) { m->volcmd = VOLCMD_PANNING; m->vol = param/2; } command = 0; } |
153 | else { command = CMD_PANNING8; } | 153 | else { command = CMD_PANNING8; } |
154 | // Unknown effects | 154 | // Unknown effects |
155 | default:command = param = 0; | 155 | default:command = param = 0; |
156 | } | 156 | } |
157 | if (command) | 157 | if (command) |
158 | { | 158 | { |
159 | m->command = command; | 159 | m->command = command; |
160 | m->param = param; | 160 | m->param = param; |
161 | } | 161 | } |
162 | } | 162 | } |
163 | pTrack += 3; | 163 | pTrack += 3; |
164 | } | 164 | } |
165 | } | 165 | } |
166 | 166 | ||
167 | 167 | ||
168 | 168 | ||
169 | BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, DWORD dwMemLength) | 169 | BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, DWORD dwMemLength) |
170 | //----------------------------------------------------------- | 170 | //----------------------------------------------------------- |
171 | { | 171 | { |
172 | AMFFILEHEADER *pfh = (AMFFILEHEADER *)lpStream; | 172 | AMFFILEHEADER *pfh = (AMFFILEHEADER *)lpStream; |
173 | DWORD dwMemPos; | 173 | DWORD dwMemPos; |
174 | 174 | ||
175 | if ((!lpStream) || (dwMemLength < 2048)) return FALSE; | 175 | if ((!lpStream) || (dwMemLength < 2048)) return FALSE; |
176 | if ((!strncmp((LPCTSTR)lpStream, "ASYLUM Music Format V1.0", 25)) && (dwMemLength > 4096)) | 176 | if ((!strncmp((LPCTSTR)lpStream, "ASYLUM Music Format V1.0", 25)) && (dwMemLength > 4096)) |
177 | { | 177 | { |
178 | UINT numorders, numpats, numsamples; | 178 | UINT numorders, numpats, numsamples; |
179 | 179 | ||
180 | dwMemPos = 32; | 180 | dwMemPos = 32; |
181 | numpats = lpStream[dwMemPos+3]; | 181 | numpats = lpStream[dwMemPos+3]; |
182 | numorders = lpStream[dwMemPos+4]; | 182 | numorders = lpStream[dwMemPos+4]; |
183 | numsamples = 64; | 183 | numsamples = 64; |
184 | dwMemPos += 6; | 184 | dwMemPos += 6; |
185 | if ((!numpats) || (numpats > MAX_PATTERNS) || (!numorders) | 185 | if ((!numpats) || (numpats > MAX_PATTERNS) || (!numorders) |
186 | || (numpats*64*32 + 294 + 37*64 >= dwMemLength)) return FALSE; | 186 | || (numpats*64*32 + 294 + 37*64 >= dwMemLength)) return FALSE; |
187 | m_nType = MOD_TYPE_AMF0; | 187 | m_nType = MOD_TYPE_AMF0; |
188 | m_nChannels = 8; | 188 | m_nChannels = 8; |
189 | m_nInstruments = 0; | 189 | m_nInstruments = 0; |
190 | m_nSamples = 31; | 190 | m_nSamples = 31; |
191 | m_nDefaultTempo = 125; | 191 | m_nDefaultTempo = 125; |
192 | m_nDefaultSpeed = 6; | 192 | m_nDefaultSpeed = 6; |
193 | for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++) | 193 | for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++) |
194 | { | 194 | { |
195 | Order[iOrd] = (iOrd < numorders) ? lpStream[dwMemPos+iOrd] : 0xFF; | 195 | Order[iOrd] = (iOrd < numorders) ? lpStream[dwMemPos+iOrd] : 0xFF; |
196 | } | 196 | } |
197 | dwMemPos = 294; // ??? | 197 | dwMemPos = 294; // ??? |
198 | for (UINT iSmp=0; iSmp<numsamples; iSmp++) | 198 | for (UINT iSmp=0; iSmp<numsamples; iSmp++) |
199 | { | 199 | { |
200 | MODINSTRUMENT *psmp = &Ins[iSmp+1]; | 200 | MODINSTRUMENT *psmp = &Ins[iSmp+1]; |
201 | memcpy(m_szNames[iSmp+1], lpStream+dwMemPos, 22); | 201 | memcpy(m_szNames[iSmp+1], lpStream+dwMemPos, 22); |
202 | psmp->nFineTune = MOD2XMFineTune(lpStream[dwMemPos+22]); | 202 | psmp->nFineTune = MOD2XMFineTune(lpStream[dwMemPos+22]); |
203 | psmp->nVolume = lpStream[dwMemPos+23]; | 203 | psmp->nVolume = lpStream[dwMemPos+23]; |
204 | psmp->nGlobalVol = 64; | 204 | psmp->nGlobalVol = 64; |
205 | if (psmp->nVolume > 0x40) psmp->nVolume = 0x40; | 205 | if (psmp->nVolume > 0x40) psmp->nVolume = 0x40; |
206 | psmp->nVolume <<= 2; | 206 | psmp->nVolume <<= 2; |
207 | psmp->nLength = *((LPDWORD)(lpStream+dwMemPos+25)); | 207 | psmp->nLength = *((LPDWORD)(lpStream+dwMemPos+25)); |
208 | psmp->nLoopStart = *((LPDWORD)(lpStream+dwMemPos+29)); | 208 | psmp->nLoopStart = *((LPDWORD)(lpStream+dwMemPos+29)); |
209 | psmp->nLoopEnd = psmp->nLoopStart + *((LPDWORD)(lpStream+dwMemPos+33)); | 209 | psmp->nLoopEnd = psmp->nLoopStart + *((LPDWORD)(lpStream+dwMemPos+33)); |
210 | if ((psmp->nLoopEnd > psmp->nLoopStart) && (psmp->nLoopEnd <= psmp->nLength)) | 210 | if ((psmp->nLoopEnd > psmp->nLoopStart) && (psmp->nLoopEnd <= psmp->nLength)) |
211 | { | 211 | { |
212 | psmp->uFlags = CHN_LOOP; | 212 | psmp->uFlags = CHN_LOOP; |
213 | } else | 213 | } else |
214 | { | 214 | { |
215 | psmp->nLoopStart = psmp->nLoopEnd = 0; | 215 | psmp->nLoopStart = psmp->nLoopEnd = 0; |
216 | } | 216 | } |
217 | if ((psmp->nLength) && (iSmp>31)) m_nSamples = iSmp+1; | 217 | if ((psmp->nLength) && (iSmp>31)) m_nSamples = iSmp+1; |
218 | dwMemPos += 37; | 218 | dwMemPos += 37; |
219 | } | 219 | } |
220 | for (UINT iPat=0; iPat<numpats; iPat++) | 220 | for (UINT iPat=0; iPat<numpats; iPat++) |
221 | { | 221 | { |
222 | MODCOMMAND *p = AllocatePattern(64, m_nChannels); | 222 | MODCOMMAND *p = AllocatePattern(64, m_nChannels); |
223 | if (!p) break; | 223 | if (!p) break; |
224 | Patterns[iPat] = p; | 224 | Patterns[iPat] = p; |
225 | PatternSize[iPat] = 64; | 225 | PatternSize[iPat] = 64; |
226 | const UCHAR *pin = lpStream + dwMemPos; | 226 | const UCHAR *pin = lpStream + dwMemPos; |
227 | for (UINT i=0; i<8*64; i++) | 227 | for (UINT i=0; i<8*64; i++) |
228 | { | 228 | { |
229 | p->note = 0; | 229 | p->note = 0; |
230 | 230 | ||
231 | if (pin[0]) | 231 | if (pin[0]) |
232 | { | 232 | { |
233 | p->note = pin[0] + 13; | 233 | p->note = pin[0] + 13; |
234 | } | 234 | } |
235 | p->instr = pin[1]; | 235 | p->instr = pin[1]; |
236 | p->command = pin[2]; | 236 | p->command = pin[2]; |
237 | p->param = pin[3]; | 237 | p->param = pin[3]; |
238 | if (p->command > 0x0F) | 238 | if (p->command > 0x0F) |
239 | { | 239 | { |
240 | #ifdef AMFLOG | 240 | #ifdef AMFLOG |
241 | Log("0x%02X.0x%02X ?", p->command, p->param); | 241 | Log("0x%02X.0x%02X ?", p->command, p->param); |
242 | #endif | 242 | #endif |
243 | p->command = 0; | 243 | p->command = 0; |
244 | } | 244 | } |
245 | ConvertModCommand(p); | 245 | ConvertModCommand(p); |
246 | pin += 4; | 246 | pin += 4; |
247 | p++; | 247 | p++; |
248 | } | 248 | } |
249 | dwMemPos += 64*32; | 249 | dwMemPos += 64*32; |
250 | } | 250 | } |
251 | // Read samples | 251 | // Read samples |
252 | for (UINT iData=0; iData<m_nSamples; iData++) | 252 | for (UINT iData=0; iData<m_nSamples; iData++) |
253 | { | 253 | { |
254 | MODINSTRUMENT *psmp = &Ins[iData+1]; | 254 | MODINSTRUMENT *psmp = &Ins[iData+1]; |
255 | if (psmp->nLength) | 255 | if (psmp->nLength) |
256 | { | 256 | { |
257 | dwMemPos += ReadSample(psmp, RS_PCM8S, (LPCSTR)(lpStream+dwMemPos), dwMemLength); | 257 | dwMemPos += ReadSample(psmp, RS_PCM8S, (LPCSTR)(lpStream+dwMemPos), dwMemLength); |
258 | } | 258 | } |
259 | } | 259 | } |
260 | return TRUE; | 260 | return TRUE; |
261 | } | 261 | } |
262 | //////////////////////////// | 262 | //////////////////////////// |
263 | // DSM/AMF | 263 | // DSM/AMF |
264 | USHORT *ptracks[MAX_PATTERNS]; | 264 | USHORT *ptracks[MAX_PATTERNS]; |
265 | DWORD sampleseekpos[MAX_SAMPLES]; | 265 | DWORD sampleseekpos[MAX_SAMPLES]; |
266 | 266 | ||
267 | if ((pfh->szAMF[0] != 'A') || (pfh->szAMF[1] != 'M') || (pfh->szAMF[2] != 'F') | 267 | if ((pfh->szAMF[0] != 'A') || (pfh->szAMF[1] != 'M') || (pfh->szAMF[2] != 'F') |
268 | || (pfh->version < 10) || (pfh->version > 14) || (!pfh->numtracks) | 268 | || (pfh->version < 10) || (pfh->version > 14) || (!pfh->numtracks) |
269 | || (!pfh->numorders) || (pfh->numorders > MAX_PATTERNS) | 269 | || (!pfh->numorders) || (pfh->numorders > MAX_PATTERNS) |
270 | || (!pfh->numsamples) || (pfh->numsamples > MAX_SAMPLES) | 270 | || (!pfh->numsamples) || (pfh->numsamples > MAX_SAMPLES) |
271 | || (pfh->numchannels < 4) || (pfh->numchannels > 32)) | 271 | || (pfh->numchannels < 4) || (pfh->numchannels > 32)) |
272 | return FALSE; | 272 | return FALSE; |
273 | memcpy(m_szNames[0], pfh->title, 32); | 273 | memcpy(m_szNames[0], pfh->title, 32); |
274 | dwMemPos = sizeof(AMFFILEHEADER); | 274 | dwMemPos = sizeof(AMFFILEHEADER); |
275 | m_nType = MOD_TYPE_AMF; | 275 | m_nType = MOD_TYPE_AMF; |
276 | m_nChannels = pfh->numchannels; | 276 | m_nChannels = pfh->numchannels; |
277 | m_nSamples = pfh->numsamples; | 277 | m_nSamples = pfh->numsamples; |
278 | m_nInstruments = 0; | 278 | m_nInstruments = 0; |
279 | // Setup Channel Pan Positions | 279 | // Setup Channel Pan Positions |
280 | if (pfh->version >= 11) | 280 | if (pfh->version >= 11) |
281 | { | 281 | { |
282 | signed char *panpos = (signed char *)(lpStream + dwMemPos); | 282 | signed char *panpos = (signed char *)(lpStream + dwMemPos); |
283 | UINT nchannels = (pfh->version >= 13) ? 32 : 16; | 283 | UINT nchannels = (pfh->version >= 13) ? 32 : 16; |
284 | for (UINT i=0; i<nchannels; i++) | 284 | for (UINT i=0; i<nchannels; i++) |
285 | { | 285 | { |
286 | int pan = (panpos[i] + 64) * 2; | 286 | int pan = (panpos[i] + 64) * 2; |
287 | if (pan < 0) pan = 0; | 287 | if (pan < 0) pan = 0; |
288 | if (pan > 256) { pan = 128; ChnSettings[i].dwFlags |= CHN_SURROUND; } | 288 | if (pan > 256) { pan = 128; ChnSettings[i].dwFlags |= CHN_SURROUND; } |
289 | ChnSettings[i].nPan = pan; | 289 | ChnSettings[i].nPan = pan; |
290 | } | 290 | } |
291 | dwMemPos += nchannels; | 291 | dwMemPos += nchannels; |
292 | } else | 292 | } else |
293 | { | 293 | { |
294 | for (UINT i=0; i<16; i++) | 294 | for (UINT i=0; i<16; i++) |
295 | { | 295 | { |
296 | ChnSettings[i].nPan = (lpStream[dwMemPos+i] & 1) ? 0x30 : 0xD0; | 296 | ChnSettings[i].nPan = (lpStream[dwMemPos+i] & 1) ? 0x30 : 0xD0; |
297 | } | 297 | } |
298 | dwMemPos += 16; | 298 | dwMemPos += 16; |
299 | } | 299 | } |
300 | // Get Tempo/Speed | 300 | // Get Tempo/Speed |
301 | m_nDefaultTempo = 125; | 301 | m_nDefaultTempo = 125; |
302 | m_nDefaultSpeed = 6; | 302 | m_nDefaultSpeed = 6; |
303 | if (pfh->version >= 13) | 303 | if (pfh->version >= 13) |
304 | { | 304 | { |
305 | if (lpStream[dwMemPos] >= 32) m_nDefaultTempo = lpStream[dwMemPos]; | 305 | if (lpStream[dwMemPos] >= 32) m_nDefaultTempo = lpStream[dwMemPos]; |
306 | if (lpStream[dwMemPos+1] <= 32) m_nDefaultSpeed = lpStream[dwMemPos+1]; | 306 | if (lpStream[dwMemPos+1] <= 32) m_nDefaultSpeed = lpStream[dwMemPos+1]; |
307 | dwMemPos += 2; | 307 | dwMemPos += 2; |
308 | } | 308 | } |
309 | // Setup sequence list | 309 | // Setup sequence list |
310 | for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++) | 310 | for (UINT iOrd=0; iOrd<MAX_ORDERS; iOrd++) |
311 | { | 311 | { |
312 | Order[iOrd] = 0xFF; | 312 | Order[iOrd] = 0xFF; |
313 | if (iOrd < pfh->numorders) | 313 | if (iOrd < pfh->numorders) |
314 | { | 314 | { |
315 | Order[iOrd] = iOrd; | 315 | Order[iOrd] = iOrd; |
316 | PatternSize[iOrd] = 64; | 316 | PatternSize[iOrd] = 64; |
317 | if (pfh->version >= 14) | 317 | if (pfh->version >= 14) |
318 | { | 318 | { |
319 | PatternSize[iOrd] = *(USHORT *)(lpStream+dwMemPos); | 319 | PatternSize[iOrd] = *(USHORT *)(lpStream+dwMemPos); |
320 | dwMemPos += 2; | 320 | dwMemPos += 2; |
321 | } | 321 | } |
322 | ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos); | 322 | ptracks[iOrd] = (USHORT *)(lpStream+dwMemPos); |
323 | dwMemPos += m_nChannels * sizeof(USHORT); | 323 | dwMemPos += m_nChannels * sizeof(USHORT); |
324 | } | 324 | } |
325 | } | 325 | } |
326 | if (dwMemPos + m_nSamples * (sizeof(AMFSAMPLE)+8) > dwMemLength) return TRUE; | 326 | if (dwMemPos + m_nSamples * (sizeof(AMFSAMPLE)+8) > dwMemLength) return TRUE; |
327 | // Read Samples | 327 | // Read Samples |
328 | UINT maxsampleseekpos = 0; | 328 | UINT maxsampleseekpos = 0; |
329 | for (UINT iIns=0; iIns<m_nSamples; iIns++) | 329 | for (UINT iIns=0; iIns<m_nSamples; iIns++) |
330 | { | 330 | { |
331 | MODINSTRUMENT *pins = &Ins[iIns+1]; | 331 | MODINSTRUMENT *pins = &Ins[iIns+1]; |
332 | AMFSAMPLE *psh = (AMFSAMPLE *)(lpStream + dwMemPos); | 332 | AMFSAMPLE *psh = (AMFSAMPLE *)(lpStream + dwMemPos); |
333 | 333 | ||
334 | dwMemPos += sizeof(AMFSAMPLE); | 334 | dwMemPos += sizeof(AMFSAMPLE); |
335 | memcpy(m_szNames[iIns+1], psh->samplename, 32); | 335 | memcpy(m_szNames[iIns+1], psh->samplename, 32); |
336 | memcpy(pins->name, psh->filename, 13); | 336 | memcpy(pins->name, psh->filename, 13); |
337 | pins->nLength = psh->length; | 337 | pins->nLength = psh->length; |
338 | pins->nC4Speed = psh->c2spd; | 338 | pins->nC4Speed = psh->c2spd; |
339 | pins->nGlobalVol = 64; | 339 | pins->nGlobalVol = 64; |
340 | pins->nVolume = psh->volume * 4; | 340 | pins->nVolume = psh->volume * 4; |
341 | if (pfh->version >= 11) | 341 | if (pfh->version >= 11) |
342 | { | 342 | { |
343 | pins->nLoopStart = *(DWORD *)(lpStream+dwMemPos); | 343 | pins->nLoopStart = *(DWORD *)(lpStream+dwMemPos); |
344 | pins->nLoopEnd = *(DWORD *)(lpStream+dwMemPos+4); | 344 | pins->nLoopEnd = *(DWORD *)(lpStream+dwMemPos+4); |
345 | dwMemPos += 8; | 345 | dwMemPos += 8; |
346 | } else | 346 | } else |
347 | { | 347 | { |
348 | pins->nLoopStart = *(WORD *)(lpStream+dwMemPos); | 348 | pins->nLoopStart = *(WORD *)(lpStream+dwMemPos); |
349 | pins->nLoopEnd = pins->nLength; | 349 | pins->nLoopEnd = pins->nLength; |
350 | dwMemPos += 2; | 350 | dwMemPos += 2; |
351 | } | 351 | } |
352 | sampleseekpos[iIns] = 0; | 352 | sampleseekpos[iIns] = 0; |
353 | if ((psh->type) && (psh->offset < dwMemLength-1)) | 353 | if ((psh->type) && (psh->offset < dwMemLength-1)) |
354 | { | 354 | { |
355 | sampleseekpos[iIns] = psh->offset; | 355 | sampleseekpos[iIns] = psh->offset; |
356 | if (psh->offset > maxsampleseekpos) maxsampleseekpos = psh->offset; | 356 | if (psh->offset > maxsampleseekpos) maxsampleseekpos = psh->offset; |
357 | if ((pins->nLoopEnd > pins->nLoopStart + 2) | 357 | if ((pins->nLoopEnd > pins->nLoopStart + 2) |
358 | && (pins->nLoopEnd <= pins->nLength)) pins->uFlags |= CHN_LOOP; | 358 | && (pins->nLoopEnd <= pins->nLength)) pins->uFlags |= CHN_LOOP; |
359 | } | 359 | } |
360 | } | 360 | } |
361 | // Read Track Mapping Table | 361 | // Read Track Mapping Table |
362 | USHORT *pTrackMap = (USHORT *)(lpStream+dwMemPos); | 362 | USHORT *pTrackMap = (USHORT *)(lpStream+dwMemPos); |
363 | UINT realtrackcnt = 0; | 363 | UINT realtrackcnt = 0; |
364 | dwMemPos += pfh->numtracks * sizeof(USHORT); | 364 | dwMemPos += pfh->numtracks * sizeof(USHORT); |
365 | for (UINT iTrkMap=0; iTrkMap<pfh->numtracks; iTrkMap++) | 365 | for (UINT iTrkMap=0; iTrkMap<pfh->numtracks; iTrkMap++) |
366 | { | 366 | { |
367 | if (realtrackcnt < pTrackMap[iTrkMap]) realtrackcnt = pTrackMap[iTrkMap]; | 367 | if (realtrackcnt < pTrackMap[iTrkMap]) realtrackcnt = pTrackMap[iTrkMap]; |
368 | } | 368 | } |
369 | // Store tracks positions | 369 | // Store tracks positions |
370 | BYTE **pTrackData = new BYTE *[realtrackcnt]; | 370 | BYTE **pTrackData = new BYTE *[realtrackcnt]; |
371 | memset(pTrackData, 0, sizeof(pTrackData)); | 371 | memset(pTrackData, 0, sizeof(pTrackData)); |
372 | for (UINT iTrack=0; iTrack<realtrackcnt; iTrack++) if (dwMemPos + 3 <= dwMemLength) | 372 | for (UINT iTrack=0; iTrack<realtrackcnt; iTrack++) if (dwMemPos + 3 <= dwMemLength) |
373 | { | 373 | { |
374 | UINT nTrkSize = *(USHORT *)(lpStream+dwMemPos); | 374 | UINT nTrkSize = *(USHORT *)(lpStream+dwMemPos); |
375 | nTrkSize += (UINT)lpStream[dwMemPos+2] << 16; | 375 | nTrkSize += (UINT)lpStream[dwMemPos+2] << 16; |
376 | if (dwMemPos + nTrkSize * 3 + 3 <= dwMemLength) | 376 | if (dwMemPos + nTrkSize * 3 + 3 <= dwMemLength) |
377 | { | 377 | { |
378 | pTrackData[iTrack] = (BYTE *)(lpStream + dwMemPos); | 378 | pTrackData[iTrack] = (BYTE *)(lpStream + dwMemPos); |
379 | } | 379 | } |
380 | dwMemPos += nTrkSize * 3 + 3; | 380 | dwMemPos += nTrkSize * 3 + 3; |
381 | } | 381 | } |
382 | // Create the patterns from the list of tracks | 382 | // Create the patterns from the list of tracks |
383 | for (UINT iPat=0; iPat<pfh->numorders; iPat++) | 383 | for (UINT iPat=0; iPat<pfh->numorders; iPat++) |
384 | { | 384 | { |
385 | MODCOMMAND *p = AllocatePattern(PatternSize[iPat], m_nChannels); | 385 | MODCOMMAND *p = AllocatePattern(PatternSize[iPat], m_nChannels); |
386 | if (!p) break; | 386 | if (!p) break; |
387 | Patterns[iPat] = p; | 387 | Patterns[iPat] = p; |
388 | for (UINT iChn=0; iChn<m_nChannels; iChn++) | 388 | for (UINT iChn=0; iChn<m_nChannels; iChn++) |
389 | { | 389 | { |
390 | UINT nTrack = ptracks[iPat][iChn]; | 390 | UINT nTrack = ptracks[iPat][iChn]; |
391 | if ((nTrack) && (nTrack <= pfh->numtracks)) | 391 | if ((nTrack) && (nTrack <= pfh->numtracks)) |
392 | { | 392 | { |
393 | UINT realtrk = pTrackMap[nTrack-1]; | 393 | UINT realtrk = pTrackMap[nTrack-1]; |
394 | if (realtrk) | 394 | if (realtrk) |
395 | { | 395 | { |
396 | realtrk--; | 396 | realtrk--; |
397 | if ((realtrk < realtrackcnt) && (pTrackData[realtrk])) | 397 | if ((realtrk < realtrackcnt) && (pTrackData[realtrk])) |
398 | { | 398 | { |
399 | AMF_Unpack(p+iChn, pTrackData[realtrk], PatternSize[iPat], m_nChannels); | 399 | AMF_Unpack(p+iChn, pTrackData[realtrk], PatternSize[iPat], m_nChannels); |
400 | } | 400 | } |
401 | } | 401 | } |
402 | } | 402 | } |
403 | } | 403 | } |
404 | } | 404 | } |
405 | delete pTrackData; | 405 | delete [] pTrackData; |
406 | // Read Sample Data | 406 | // Read Sample Data |
407 | for (UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++) | 407 | for (UINT iSeek=1; iSeek<=maxsampleseekpos; iSeek++) |
408 | { | 408 | { |
409 | if (dwMemPos >= dwMemLength) break; | 409 | if (dwMemPos >= dwMemLength) break; |
410 | for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (iSeek == sampleseekpos[iSmp]) | 410 | for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (iSeek == sampleseekpos[iSmp]) |
411 | { | 411 | { |
412 | MODINSTRUMENT *pins = &Ins[iSmp+1]; | 412 | MODINSTRUMENT *pins = &Ins[iSmp+1]; |
413 | dwMemPos += ReadSample(pins, RS_PCM8U, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); | 413 | dwMemPos += ReadSample(pins, RS_PCM8U, (LPCSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); |
414 | break; | 414 | break; |
415 | } | 415 | } |
416 | } | 416 | } |
417 | return TRUE; | 417 | return TRUE; |
418 | } | 418 | } |
419 | 419 | ||
420 | 420 | ||
diff --git a/core/multimedia/opieplayer/modplug/load_ams.cpp b/core/multimedia/opieplayer/modplug/load_ams.cpp index 3dd1c2b..ad1cc01 100644 --- a/core/multimedia/opieplayer/modplug/load_ams.cpp +++ b/core/multimedia/opieplayer/modplug/load_ams.cpp | |||
@@ -1,631 +1,631 @@ | |||
1 | /* | 1 | /* |
2 | * This program is free software; you can redistribute it and modify it | 2 | * This program is free software; you can redistribute it and modify it |
3 | * under the terms of the GNU General Public License as published by the | 3 | * under the terms of the GNU General Public License as published by the |
4 | * Free Software Foundation; either version 2 of the license or (at your | 4 | * Free Software Foundation; either version 2 of the license or (at your |
5 | * option) any later version. | 5 | * option) any later version. |
6 | * | 6 | * |
7 | * Authors: Olivier Lapicque <olivierl@jps.net> | 7 | * Authors: Olivier Lapicque <olivierl@jps.net> |
8 | */ | 8 | */ |
9 | 9 | ||
10 | ////////////////////////////////////////////// | 10 | ////////////////////////////////////////////// |
11 | // AMS module loader // | 11 | // AMS module loader // |
12 | ////////////////////////////////////////////// | 12 | ////////////////////////////////////////////// |
13 | #include "stdafx.h" | 13 | #include "stdafx.h" |
14 | #include "sndfile.h" | 14 | #include "sndfile.h" |
15 | 15 | ||
16 | //#pragma warning(disable:4244) | 16 | //#pragma warning(disable:4244) |
17 | 17 | ||
18 | #pragma pack(1) | 18 | #pragma pack(1) |
19 | 19 | ||
20 | typedef struct AMSFILEHEADER | 20 | typedef struct AMSFILEHEADER |
21 | { | 21 | { |
22 | char szHeader[7];// "Extreme" // changed from CHAR | 22 | char szHeader[7];// "Extreme" // changed from CHAR |
23 | BYTE verlo, verhi;// 0x??,0x01 | 23 | BYTE verlo, verhi;// 0x??,0x01 |
24 | BYTE chncfg; | 24 | BYTE chncfg; |
25 | BYTE samples; | 25 | BYTE samples; |
26 | WORD patterns; | 26 | WORD patterns; |
27 | WORD orders; | 27 | WORD orders; |
28 | BYTE vmidi; | 28 | BYTE vmidi; |
29 | WORD extra; | 29 | WORD extra; |
30 | } Q_PACKED AMSFILEHEADER; | 30 | } Q_PACKED AMSFILEHEADER; |
31 | 31 | ||
32 | typedef struct AMSSAMPLEHEADER | 32 | typedef struct AMSSAMPLEHEADER |
33 | { | 33 | { |
34 | DWORD length; | 34 | DWORD length; |
35 | DWORD loopstart; | 35 | DWORD loopstart; |
36 | DWORD loopend; | 36 | DWORD loopend; |
37 | BYTE finetune_and_pan; | 37 | BYTE finetune_and_pan; |
38 | WORD samplerate;// C-2 = 8363 | 38 | WORD samplerate;// C-2 = 8363 |
39 | BYTE volume; // 0-127 | 39 | BYTE volume; // 0-127 |
40 | BYTE infobyte; | 40 | BYTE infobyte; |
41 | } Q_PACKED AMSSAMPLEHEADER; | 41 | } Q_PACKED AMSSAMPLEHEADER; |
42 | 42 | ||
43 | 43 | ||
44 | #pragma pack() | 44 | #pragma pack() |
45 | 45 | ||
46 | 46 | ||
47 | 47 | ||
48 | BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength) | 48 | BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength) |
49 | //----------------------------------------------------------- | 49 | //----------------------------------------------------------- |
50 | { | 50 | { |
51 | BYTE pkinf[MAX_SAMPLES]; | 51 | BYTE pkinf[MAX_SAMPLES]; |
52 | AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream; | 52 | AMSFILEHEADER *pfh = (AMSFILEHEADER *)lpStream; |
53 | DWORD dwMemPos; | 53 | DWORD dwMemPos; |
54 | UINT tmp, tmp2; | 54 | UINT tmp, tmp2; |
55 | 55 | ||
56 | if ((!lpStream) || (dwMemLength < 1024)) return FALSE; | 56 | if ((!lpStream) || (dwMemLength < 1024)) return FALSE; |
57 | if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7)) | 57 | if ((pfh->verhi != 0x01) || (strncmp(pfh->szHeader, "Extreme", 7)) |
58 | || (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples > MAX_SAMPLES) | 58 | || (!pfh->patterns) || (!pfh->orders) || (!pfh->samples) || (pfh->samples > MAX_SAMPLES) |
59 | || (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS)) | 59 | || (pfh->patterns > MAX_PATTERNS) || (pfh->orders > MAX_ORDERS)) |
60 | { | 60 | { |
61 | return ReadAMS2(lpStream, dwMemLength); | 61 | return ReadAMS2(lpStream, dwMemLength); |
62 | } | 62 | } |
63 | dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra; | 63 | dwMemPos = sizeof(AMSFILEHEADER) + pfh->extra; |
64 | if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) + 256 >= dwMemLength) return FALSE; | 64 | if (dwMemPos + pfh->samples * sizeof(AMSSAMPLEHEADER) + 256 >= dwMemLength) return FALSE; |
65 | m_nType = MOD_TYPE_AMS; | 65 | m_nType = MOD_TYPE_AMS; |
66 | m_nInstruments = 0; | 66 | m_nInstruments = 0; |
67 | m_nChannels = (pfh->chncfg & 0x1F) + 1; | 67 | m_nChannels = (pfh->chncfg & 0x1F) + 1; |
68 | m_nSamples = pfh->samples; | 68 | m_nSamples = pfh->samples; |
69 | for (UINT nSmp=1; nSmp<=m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER)) | 69 | for (UINT nSmp=1; nSmp<=m_nSamples; nSmp++, dwMemPos += sizeof(AMSSAMPLEHEADER)) |
70 | { | 70 | { |
71 | AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos); | 71 | AMSSAMPLEHEADER *psh = (AMSSAMPLEHEADER *)(lpStream + dwMemPos); |
72 | MODINSTRUMENT *pins = &Ins[nSmp]; | 72 | MODINSTRUMENT *pins = &Ins[nSmp]; |
73 | pins->nLength = psh->length; | 73 | pins->nLength = psh->length; |
74 | pins->nLoopStart = psh->loopstart; | 74 | pins->nLoopStart = psh->loopstart; |
75 | pins->nLoopEnd = psh->loopend; | 75 | pins->nLoopEnd = psh->loopend; |
76 | pins->nGlobalVol = 64; | 76 | pins->nGlobalVol = 64; |
77 | pins->nVolume = psh->volume << 1; | 77 | pins->nVolume = psh->volume << 1; |
78 | pins->nC4Speed = psh->samplerate; | 78 | pins->nC4Speed = psh->samplerate; |
79 | pins->nPan = (psh->finetune_and_pan & 0xF0); | 79 | pins->nPan = (psh->finetune_and_pan & 0xF0); |
80 | if (pins->nPan < 0x80) pins->nPan += 0x10; | 80 | if (pins->nPan < 0x80) pins->nPan += 0x10; |
81 | pins->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F); | 81 | pins->nFineTune = MOD2XMFineTune(psh->finetune_and_pan & 0x0F); |
82 | pins->uFlags = (psh->infobyte & 0x80) ? CHN_16BIT : 0; | 82 | pins->uFlags = (psh->infobyte & 0x80) ? CHN_16BIT : 0; |
83 | if ((pins->nLoopEnd <= pins->nLength) && (pins->nLoopStart+4 <= pins->nLoopEnd)) pins->uFlags |= CHN_LOOP; | 83 | if ((pins->nLoopEnd <= pins->nLength) && (pins->nLoopStart+4 <= pins->nLoopEnd)) pins->uFlags |= CHN_LOOP; |
84 | pkinf[nSmp] = psh->infobyte; | 84 | pkinf[nSmp] = psh->infobyte; |
85 | } | 85 | } |
86 | // Read Song Name | 86 | // Read Song Name |
87 | tmp = lpStream[dwMemPos++]; | 87 | tmp = lpStream[dwMemPos++]; |
88 | if (dwMemPos + tmp + 1 >= dwMemLength) return TRUE; | 88 | if (dwMemPos + tmp + 1 >= dwMemLength) return TRUE; |
89 | tmp2 = (tmp < 32) ? tmp : 31; | 89 | tmp2 = (tmp < 32) ? tmp : 31; |
90 | if (tmp2) memcpy(m_szNames[0], lpStream+dwMemPos, tmp2); | 90 | if (tmp2) memcpy(m_szNames[0], lpStream+dwMemPos, tmp2); |
91 | m_szNames[0][tmp2] = 0; | 91 | m_szNames[0][tmp2] = 0; |
92 | dwMemPos += tmp; | 92 | dwMemPos += tmp; |
93 | // Read sample names | 93 | // Read sample names |
94 | for (UINT sNam=1; sNam<=m_nSamples; sNam++) | 94 | for (UINT sNam=1; sNam<=m_nSamples; sNam++) |
95 | { | 95 | { |
96 | if (dwMemPos + 32 >= dwMemLength) return TRUE; | 96 | if (dwMemPos + 32 >= dwMemLength) return TRUE; |
97 | tmp = lpStream[dwMemPos++]; | 97 | tmp = lpStream[dwMemPos++]; |
98 | tmp2 = (tmp < 32) ? tmp : 31; | 98 | tmp2 = (tmp < 32) ? tmp : 31; |
99 | if (tmp2) memcpy(m_szNames[sNam], lpStream+dwMemPos, tmp2); | 99 | if (tmp2) memcpy(m_szNames[sNam], lpStream+dwMemPos, tmp2); |
100 | dwMemPos += tmp; | 100 | dwMemPos += tmp; |
101 | } | 101 | } |
102 | // Skip Channel names | 102 | // Skip Channel names |
103 | for (UINT cNam=0; cNam<m_nChannels; cNam++) | 103 | for (UINT cNam=0; cNam<m_nChannels; cNam++) |
104 | { | 104 | { |
105 | if (dwMemPos + 32 >= dwMemLength) return TRUE; | 105 | if (dwMemPos + 32 >= dwMemLength) return TRUE; |
106 | tmp = lpStream[dwMemPos++]; | 106 | tmp = lpStream[dwMemPos++]; |
107 | dwMemPos += tmp; | 107 | dwMemPos += tmp; |
108 | } | 108 | } |
109 | // Read Pattern Names | 109 | // Read Pattern Names |
110 | m_lpszPatternNames = new char[pfh->patterns * 32]; // changed from CHAR | 110 | m_lpszPatternNames = new char[pfh->patterns * 32]; // changed from CHAR |
111 | if (!m_lpszPatternNames) return TRUE; | 111 | if (!m_lpszPatternNames) return TRUE; |
112 | m_nPatternNames = pfh->patterns; | 112 | m_nPatternNames = pfh->patterns; |
113 | memset(m_lpszPatternNames, 0, m_nPatternNames * 32); | 113 | memset(m_lpszPatternNames, 0, m_nPatternNames * 32); |
114 | for (UINT pNam=0; pNam < m_nPatternNames; pNam++) | 114 | for (UINT pNam=0; pNam < m_nPatternNames; pNam++) |
115 | { | 115 | { |
116 | if (dwMemPos + 32 >= dwMemLength) return TRUE; | 116 | if (dwMemPos + 32 >= dwMemLength) return TRUE; |
117 | tmp = lpStream[dwMemPos++]; | 117 | tmp = lpStream[dwMemPos++]; |
118 | tmp2 = (tmp < 32) ? tmp : 31; | 118 | tmp2 = (tmp < 32) ? tmp : 31; |
119 | if (tmp2) memcpy(m_lpszPatternNames+pNam*32, lpStream+dwMemPos, tmp2); | 119 | if (tmp2) memcpy(m_lpszPatternNames+pNam*32, lpStream+dwMemPos, tmp2); |
120 | dwMemPos += tmp; | 120 | dwMemPos += tmp; |
121 | } | 121 | } |
122 | // Read Song Comments | 122 | // Read Song Comments |
123 | tmp = *((WORD *)(lpStream+dwMemPos)); | 123 | tmp = *((WORD *)(lpStream+dwMemPos)); |
124 | dwMemPos += 2; | 124 | dwMemPos += 2; |
125 | if (dwMemPos + tmp >= dwMemLength) return TRUE; | 125 | if (dwMemPos + tmp >= dwMemLength) return TRUE; |
126 | if (tmp) | 126 | if (tmp) |
127 | { | 127 | { |
128 | m_lpszSongComments = new char[tmp+1]; // changed from CHAR | 128 | m_lpszSongComments = new char[tmp+1]; // changed from CHAR |
129 | if (!m_lpszSongComments) return TRUE; | 129 | if (!m_lpszSongComments) return TRUE; |
130 | memset(m_lpszSongComments, 0, tmp+1); | 130 | memset(m_lpszSongComments, 0, tmp+1); |
131 | memcpy(m_lpszSongComments, lpStream + dwMemPos, tmp); | 131 | memcpy(m_lpszSongComments, lpStream + dwMemPos, tmp); |
132 | dwMemPos += tmp; | 132 | dwMemPos += tmp; |
133 | } | 133 | } |
134 | // Read Order List | 134 | // Read Order List |
135 | for (UINT iOrd=0; iOrd<pfh->orders; iOrd++, dwMemPos += 2) | 135 | for (UINT iOrd=0; iOrd<pfh->orders; iOrd++, dwMemPos += 2) |
136 | { | 136 | { |
137 | UINT n = *((WORD *)(lpStream+dwMemPos)); | 137 | UINT n = *((WORD *)(lpStream+dwMemPos)); |
138 | Order[iOrd] = (BYTE)n; | 138 | Order[iOrd] = (BYTE)n; |
139 | } | 139 | } |
140 | // Read Patterns | 140 | // Read Patterns |
141 | for (UINT iPat=0; iPat<pfh->patterns; iPat++) | 141 | for (UINT iPat=0; iPat<pfh->patterns; iPat++) |
142 | { | 142 | { |
143 | if (dwMemPos + 4 >= dwMemLength) return TRUE; | 143 | if (dwMemPos + 4 >= dwMemLength) return TRUE; |
144 | UINT len = *((DWORD *)(lpStream + dwMemPos)); | 144 | UINT len = *((DWORD *)(lpStream + dwMemPos)); |
145 | dwMemPos += 4; | 145 | dwMemPos += 4; |
146 | if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE; | 146 | if ((len >= dwMemLength) || (dwMemPos + len > dwMemLength)) return TRUE; |
147 | PatternSize[iPat] = 64; | 147 | PatternSize[iPat] = 64; |
148 | MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels); | 148 | MODCOMMAND *m = AllocatePattern(PatternSize[iPat], m_nChannels); |
149 | if (!m) return TRUE; | 149 | if (!m) return TRUE; |
150 | Patterns[iPat] = m; | 150 | Patterns[iPat] = m; |
151 | const BYTE *p = lpStream + dwMemPos; | 151 | const BYTE *p = lpStream + dwMemPos; |
152 | UINT row = 0, i = 0; | 152 | UINT row = 0, i = 0; |
153 | while ((row < PatternSize[iPat]) && (i+2 < len)) | 153 | while ((row < PatternSize[iPat]) && (i+2 < len)) |
154 | { | 154 | { |
155 | BYTE b0 = p[i++]; | 155 | BYTE b0 = p[i++]; |
156 | BYTE b1 = p[i++]; | 156 | BYTE b1 = p[i++]; |
157 | BYTE b2 = 0; | 157 | BYTE b2 = 0; |
158 | UINT ch = b0 & 0x3F; | 158 | UINT ch = b0 & 0x3F; |
159 | // Note+Instr | 159 | // Note+Instr |
160 | if (!(b0 & 0x40)) | 160 | if (!(b0 & 0x40)) |
161 | { | 161 | { |
162 | b2 = p[i++]; | 162 | b2 = p[i++]; |
163 | if (ch < m_nChannels) | 163 | if (ch < m_nChannels) |
164 | { | 164 | { |
165 | if (b1 & 0x7F) m[ch].note = (b1 & 0x7F) + 25; | 165 | if (b1 & 0x7F) m[ch].note = (b1 & 0x7F) + 25; |
166 | m[ch].instr = b2; | 166 | m[ch].instr = b2; |
167 | } | 167 | } |
168 | if (b1 & 0x80) | 168 | if (b1 & 0x80) |
169 | { | 169 | { |
170 | b0 |= 0x40; | 170 | b0 |= 0x40; |
171 | b1 = p[i++]; | 171 | b1 = p[i++]; |
172 | } | 172 | } |
173 | } | 173 | } |
174 | // Effect | 174 | // Effect |
175 | if (b0 & 0x40) | 175 | if (b0 & 0x40) |
176 | { | 176 | { |
177 | anothercommand: | 177 | anothercommand: |
178 | if (b1 & 0x40) | 178 | if (b1 & 0x40) |
179 | { | 179 | { |
180 | if (ch < m_nChannels) | 180 | if (ch < m_nChannels) |
181 | { | 181 | { |
182 | m[ch].volcmd = VOLCMD_VOLUME; | 182 | m[ch].volcmd = VOLCMD_VOLUME; |
183 | m[ch].vol = b1 & 0x3F; | 183 | m[ch].vol = b1 & 0x3F; |
184 | } | 184 | } |
185 | } else | 185 | } else |
186 | { | 186 | { |
187 | b2 = p[i++]; | 187 | b2 = p[i++]; |
188 | if (ch < m_nChannels) | 188 | if (ch < m_nChannels) |
189 | { | 189 | { |
190 | UINT cmd = b1 & 0x3F; | 190 | UINT cmd = b1 & 0x3F; |
191 | if (cmd == 0x0C) | 191 | if (cmd == 0x0C) |
192 | { | 192 | { |
193 | m[ch].volcmd = VOLCMD_VOLUME; | 193 | m[ch].volcmd = VOLCMD_VOLUME; |
194 | m[ch].vol = b2 >> 1; | 194 | m[ch].vol = b2 >> 1; |
195 | } else | 195 | } else |
196 | if (cmd == 0x0E) | 196 | if (cmd == 0x0E) |
197 | { | 197 | { |
198 | if (!m[ch].command) | 198 | if (!m[ch].command) |
199 | { | 199 | { |
200 | UINT command = CMD_S3MCMDEX; | 200 | UINT command = CMD_S3MCMDEX; |
201 | UINT param = b2; | 201 | UINT param = b2; |
202 | switch(param & 0xF0) | 202 | switch(param & 0xF0) |
203 | { | 203 | { |
204 | case 0x00:if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break; | 204 | case 0x00:if (param & 0x08) { param &= 0x07; param |= 0x90; } else {command=param=0;} break; |
205 | case 0x10:command = CMD_PORTAMENTOUP; param |= 0xF0; break; | 205 | case 0x10:command = CMD_PORTAMENTOUP; param |= 0xF0; break; |
206 | case 0x20:command = CMD_PORTAMENTODOWN; param |= 0xF0; break; | 206 | case 0x20:command = CMD_PORTAMENTODOWN; param |= 0xF0; break; |
207 | case 0x30:param = (param & 0x0F) | 0x10; break; | 207 | case 0x30:param = (param & 0x0F) | 0x10; break; |
208 | case 0x40:param = (param & 0x0F) | 0x30; break; | 208 | case 0x40:param = (param & 0x0F) | 0x30; break; |
209 | case 0x50:param = (param & 0x0F) | 0x20; break; | 209 | case 0x50:param = (param & 0x0F) | 0x20; break; |
210 | case 0x60:param = (param & 0x0F) | 0xB0; break; | 210 | case 0x60:param = (param & 0x0F) | 0xB0; break; |
211 | case 0x70:param = (param & 0x0F) | 0x40; break; | 211 | case 0x70:param = (param & 0x0F) | 0x40; break; |
212 | case 0x90:command = CMD_RETRIG; param &= 0x0F; break; | 212 | case 0x90:command = CMD_RETRIG; param &= 0x0F; break; |
213 | case 0xA0:if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command=param=0; break; | 213 | case 0xA0:if (param & 0x0F) { command = CMD_VOLUMESLIDE; param = (param << 4) | 0x0F; } else command=param=0; break; |
214 | case 0xB0:if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command=param=0; break; | 214 | case 0xB0:if (param & 0x0F) { command = CMD_VOLUMESLIDE; param |= 0xF0; } else command=param=0; break; |
215 | } | 215 | } |
216 | m[ch].command = command; | 216 | m[ch].command = command; |
217 | m[ch].param = param; | 217 | m[ch].param = param; |
218 | } | 218 | } |
219 | } else | 219 | } else |
220 | { | 220 | { |
221 | m[ch].command = cmd; | 221 | m[ch].command = cmd; |
222 | m[ch].param = b2; | 222 | m[ch].param = b2; |
223 | ConvertModCommand(&m[ch]); | 223 | ConvertModCommand(&m[ch]); |
224 | } | 224 | } |
225 | } | 225 | } |
226 | } | 226 | } |
227 | if (b1 & 0x80) | 227 | if (b1 & 0x80) |
228 | { | 228 | { |
229 | b1 = p[i++]; | 229 | b1 = p[i++]; |
230 | if (i <= len) goto anothercommand; | 230 | if (i <= len) goto anothercommand; |
231 | } | 231 | } |
232 | } | 232 | } |
233 | if (b0 & 0x80) | 233 | if (b0 & 0x80) |
234 | { | 234 | { |
235 | row++; | 235 | row++; |
236 | m += m_nChannels; | 236 | m += m_nChannels; |
237 | } | 237 | } |
238 | } | 238 | } |
239 | dwMemPos += len; | 239 | dwMemPos += len; |
240 | } | 240 | } |
241 | // Read Samples | 241 | // Read Samples |
242 | for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength) | 242 | for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength) |
243 | { | 243 | { |
244 | if (dwMemPos >= dwMemLength - 9) return TRUE; | 244 | if (dwMemPos >= dwMemLength - 9) return TRUE; |
245 | UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8; | 245 | UINT flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8; |
246 | dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); | 246 | dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); |
247 | } | 247 | } |
248 | return TRUE; | 248 | return TRUE; |
249 | } | 249 | } |
250 | 250 | ||
251 | 251 | ||
252 | ///////////////////////////////////////////////////////////////////// | 252 | ///////////////////////////////////////////////////////////////////// |
253 | // AMS 2.2 loader | 253 | // AMS 2.2 loader |
254 | 254 | ||
255 | #pragma pack(1) | 255 | #pragma pack(1) |
256 | 256 | ||
257 | typedef struct AMS2FILEHEADER | 257 | typedef struct AMS2FILEHEADER |
258 | { | 258 | { |
259 | DWORD dwHdr1; // AMShdr | 259 | DWORD dwHdr1; // AMShdr |
260 | WORD wHdr2; | 260 | WORD wHdr2; |
261 | BYTE b1A; // 0x1A | 261 | BYTE b1A; // 0x1A |
262 | BYTE titlelen; // 30-bytes max | 262 | BYTE titlelen; // 30-bytes max |
263 | CHAR szTitle[30];// [titlelen] | 263 | CHAR szTitle[30];// [titlelen] |
264 | } Q_PACKED AMS2FILEHEADER; | 264 | } Q_PACKED AMS2FILEHEADER; |
265 | 265 | ||
266 | typedef struct AMS2SONGHEADER | 266 | typedef struct AMS2SONGHEADER |
267 | { | 267 | { |
268 | WORD version; | 268 | WORD version; |
269 | BYTE instruments; | 269 | BYTE instruments; |
270 | WORD patterns; | 270 | WORD patterns; |
271 | WORD orders; | 271 | WORD orders; |
272 | WORD bpm; | 272 | WORD bpm; |
273 | BYTE speed; | 273 | BYTE speed; |
274 | BYTE channels; | 274 | BYTE channels; |
275 | BYTE commands; | 275 | BYTE commands; |
276 | BYTE rows; | 276 | BYTE rows; |
277 | WORD flags; | 277 | WORD flags; |
278 | } Q_PACKED AMS2SONGHEADER; | 278 | } Q_PACKED AMS2SONGHEADER; |
279 | 279 | ||
280 | typedef struct AMS2INSTRUMENT | 280 | typedef struct AMS2INSTRUMENT |
281 | { | 281 | { |
282 | BYTE samples; | 282 | BYTE samples; |
283 | BYTE notemap[120]; | 283 | BYTE notemap[120]; |
284 | } Q_PACKED AMS2INSTRUMENT; | 284 | } Q_PACKED AMS2INSTRUMENT; |
285 | 285 | ||
286 | typedef struct AMS2ENVELOPE | 286 | typedef struct AMS2ENVELOPE |
287 | { | 287 | { |
288 | BYTE speed; | 288 | BYTE speed; |
289 | BYTE sustain; | 289 | BYTE sustain; |
290 | BYTE loopbegin; | 290 | BYTE loopbegin; |
291 | BYTE loopend; | 291 | BYTE loopend; |
292 | BYTE points; | 292 | BYTE points; |
293 | BYTE info[3]; | 293 | BYTE info[3]; |
294 | } Q_PACKED AMS2ENVELOPE; | 294 | } Q_PACKED AMS2ENVELOPE; |
295 | 295 | ||
296 | typedef struct AMS2SAMPLE | 296 | typedef struct AMS2SAMPLE |
297 | { | 297 | { |
298 | DWORD length; | 298 | DWORD length; |
299 | DWORD loopstart; | 299 | DWORD loopstart; |
300 | DWORD loopend; | 300 | DWORD loopend; |
301 | WORD frequency; | 301 | WORD frequency; |
302 | BYTE finetune; | 302 | BYTE finetune; |
303 | WORD c4speed; | 303 | WORD c4speed; |
304 | CHAR transpose; | 304 | CHAR transpose; |
305 | BYTE volume; | 305 | BYTE volume; |
306 | BYTE flags; | 306 | BYTE flags; |
307 | } Q_PACKED AMS2SAMPLE; | 307 | } Q_PACKED AMS2SAMPLE; |
308 | 308 | ||
309 | 309 | ||
310 | #pragma pack() | 310 | #pragma pack() |
311 | 311 | ||
312 | 312 | ||
313 | BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength) | 313 | BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength) |
314 | //------------------------------------------------------------ | 314 | //------------------------------------------------------------ |
315 | { | 315 | { |
316 | AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream; | 316 | AMS2FILEHEADER *pfh = (AMS2FILEHEADER *)lpStream; |
317 | AMS2SONGHEADER *psh; | 317 | AMS2SONGHEADER *psh; |
318 | DWORD dwMemPos; | 318 | DWORD dwMemPos; |
319 | BYTE smpmap[16]; | 319 | BYTE smpmap[16]; |
320 | BYTE packedsamples[MAX_SAMPLES]; | 320 | BYTE packedsamples[MAX_SAMPLES]; |
321 | 321 | ||
322 | if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264) | 322 | if ((pfh->dwHdr1 != 0x68534D41) || (pfh->wHdr2 != 0x7264) |
323 | || (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return FALSE; | 323 | || (pfh->b1A != 0x1A) || (pfh->titlelen > 30)) return FALSE; |
324 | dwMemPos = pfh->titlelen + 8; | 324 | dwMemPos = pfh->titlelen + 8; |
325 | psh = (AMS2SONGHEADER *)(lpStream + dwMemPos); | 325 | psh = (AMS2SONGHEADER *)(lpStream + dwMemPos); |
326 | if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments) | 326 | if (((psh->version & 0xFF00) != 0x0200) || (!psh->instruments) |
327 | || (psh->instruments > MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return FALSE; | 327 | || (psh->instruments > MAX_INSTRUMENTS) || (!psh->patterns) || (!psh->orders)) return FALSE; |
328 | dwMemPos += sizeof(AMS2SONGHEADER); | 328 | dwMemPos += sizeof(AMS2SONGHEADER); |
329 | if (pfh->titlelen) | 329 | if (pfh->titlelen) |
330 | { | 330 | { |
331 | memcpy(m_szNames, pfh->szTitle, pfh->titlelen); | 331 | memcpy(m_szNames, pfh->szTitle, pfh->titlelen); |
332 | m_szNames[0][pfh->titlelen] = 0; | 332 | m_szNames[0][pfh->titlelen] = 0; |
333 | } | 333 | } |
334 | m_nType = MOD_TYPE_AMS; | 334 | m_nType = MOD_TYPE_AMS; |
335 | m_nChannels = 32; | 335 | m_nChannels = 32; |
336 | m_nDefaultTempo = psh->bpm >> 8; | 336 | m_nDefaultTempo = psh->bpm >> 8; |
337 | m_nDefaultSpeed = psh->speed; | 337 | m_nDefaultSpeed = psh->speed; |
338 | m_nInstruments = psh->instruments; | 338 | m_nInstruments = psh->instruments; |
339 | m_nSamples = 0; | 339 | m_nSamples = 0; |
340 | if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES; | 340 | if (psh->flags & 0x40) m_dwSongFlags |= SONG_LINEARSLIDES; |
341 | for (UINT nIns=1; nIns<=m_nInstruments; nIns++) | 341 | for (UINT nIns=1; nIns<=m_nInstruments; nIns++) |
342 | { | 342 | { |
343 | UINT insnamelen = lpStream[dwMemPos]; | 343 | UINT insnamelen = lpStream[dwMemPos]; |
344 | CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1); | 344 | CHAR *pinsname = (CHAR *)(lpStream+dwMemPos+1); |
345 | dwMemPos += insnamelen + 1; | 345 | dwMemPos += insnamelen + 1; |
346 | AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos); | 346 | AMS2INSTRUMENT *pins = (AMS2INSTRUMENT *)(lpStream + dwMemPos); |
347 | dwMemPos += sizeof(AMS2INSTRUMENT); | 347 | dwMemPos += sizeof(AMS2INSTRUMENT); |
348 | if (dwMemPos + 1024 >= dwMemLength) return TRUE; | 348 | if (dwMemPos + 1024 >= dwMemLength) return TRUE; |
349 | AMS2ENVELOPE *volenv, *panenv, *pitchenv; | 349 | AMS2ENVELOPE *volenv, *panenv, *pitchenv; |
350 | volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); | 350 | volenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); |
351 | dwMemPos += 5 + volenv->points*3; | 351 | dwMemPos += 5 + volenv->points*3; |
352 | panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); | 352 | panenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); |
353 | dwMemPos += 5 + panenv->points*3; | 353 | dwMemPos += 5 + panenv->points*3; |
354 | pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); | 354 | pitchenv = (AMS2ENVELOPE *)(lpStream+dwMemPos); |
355 | dwMemPos += 5 + pitchenv->points*3; | 355 | dwMemPos += 5 + pitchenv->points*3; |
356 | INSTRUMENTHEADER *penv = new INSTRUMENTHEADER; | 356 | INSTRUMENTHEADER *penv = new INSTRUMENTHEADER; |
357 | if (!penv) return TRUE; | 357 | if (!penv) return TRUE; |
358 | memset(smpmap, 0, sizeof(smpmap)); | 358 | memset(smpmap, 0, sizeof(smpmap)); |
359 | memset(penv, 0, sizeof(INSTRUMENTHEADER)); | 359 | memset(penv, 0, sizeof(INSTRUMENTHEADER)); |
360 | for (UINT ismpmap=0; ismpmap<pins->samples; ismpmap++) | 360 | for (UINT ismpmap=0; ismpmap<pins->samples; ismpmap++) |
361 | { | 361 | { |
362 | if ((ismpmap >= 16) || (m_nSamples+1 >= MAX_SAMPLES)) break; | 362 | if ((ismpmap >= 16) || (m_nSamples+1 >= MAX_SAMPLES)) break; |
363 | m_nSamples++; | 363 | m_nSamples++; |
364 | smpmap[ismpmap] = m_nSamples; | 364 | smpmap[ismpmap] = m_nSamples; |
365 | } | 365 | } |
366 | penv->nGlobalVol = 64; | 366 | penv->nGlobalVol = 64; |
367 | penv->nPan = 128; | 367 | penv->nPan = 128; |
368 | penv->nPPC = 60; | 368 | penv->nPPC = 60; |
369 | Headers[nIns] = penv; | 369 | Headers[nIns] = penv; |
370 | if (insnamelen) | 370 | if (insnamelen) |
371 | { | 371 | { |
372 | if (insnamelen > 31) insnamelen = 31; | 372 | if (insnamelen > 31) insnamelen = 31; |
373 | memcpy(penv->name, pinsname, insnamelen); | 373 | memcpy(penv->name, pinsname, insnamelen); |
374 | penv->name[insnamelen] = 0; | 374 | penv->name[insnamelen] = 0; |
375 | } | 375 | } |
376 | for (UINT inotemap=0; inotemap<120; inotemap++) | 376 | for (UINT inotemap=0; inotemap<120; inotemap++) |
377 | { | 377 | { |
378 | penv->NoteMap[inotemap] = inotemap+1; | 378 | penv->NoteMap[inotemap] = inotemap+1; |
379 | penv->Keyboard[inotemap] = smpmap[pins->notemap[inotemap] & 0x0F]; | 379 | penv->Keyboard[inotemap] = smpmap[pins->notemap[inotemap] & 0x0F]; |
380 | } | 380 | } |
381 | // Volume Envelope | 381 | // Volume Envelope |
382 | { | 382 | { |
383 | UINT pos = 0; | 383 | UINT pos = 0; |
384 | penv->nVolEnv = (volenv->points > 16) ? 16 : volenv->points; | 384 | penv->nVolEnv = (volenv->points > 16) ? 16 : volenv->points; |
385 | penv->nVolSustainBegin = penv->nVolSustainEnd = volenv->sustain; | 385 | penv->nVolSustainBegin = penv->nVolSustainEnd = volenv->sustain; |
386 | penv->nVolLoopStart = volenv->loopbegin; | 386 | penv->nVolLoopStart = volenv->loopbegin; |
387 | penv->nVolLoopEnd = volenv->loopend; | 387 | penv->nVolLoopEnd = volenv->loopend; |
388 | for (UINT i=0; i<penv->nVolEnv; i++) | 388 | for (UINT i=0; i<penv->nVolEnv; i++) |
389 | { | 389 | { |
390 | penv->VolEnv[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1); | 390 | penv->VolEnv[i] = (BYTE)((volenv->info[i*3+2] & 0x7F) >> 1); |
391 | pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8); | 391 | pos += volenv->info[i*3] + ((volenv->info[i*3+1] & 1) << 8); |
392 | penv->VolPoints[i] = (WORD)pos; | 392 | penv->VolPoints[i] = (WORD)pos; |
393 | } | 393 | } |
394 | } | 394 | } |
395 | penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3; | 395 | penv->nFadeOut = (((lpStream[dwMemPos+2] & 0x0F) << 8) | (lpStream[dwMemPos+1])) << 3; |
396 | UINT envflags = lpStream[dwMemPos+3]; | 396 | UINT envflags = lpStream[dwMemPos+3]; |
397 | if (envflags & 0x01) penv->dwFlags |= ENV_VOLLOOP; | 397 | if (envflags & 0x01) penv->dwFlags |= ENV_VOLLOOP; |
398 | if (envflags & 0x02) penv->dwFlags |= ENV_VOLSUSTAIN; | 398 | if (envflags & 0x02) penv->dwFlags |= ENV_VOLSUSTAIN; |
399 | if (envflags & 0x04) penv->dwFlags |= ENV_VOLUME; | 399 | if (envflags & 0x04) penv->dwFlags |= ENV_VOLUME; |
400 | dwMemPos += 5; | 400 | dwMemPos += 5; |
401 | // Read Samples | 401 | // Read Samples |
402 | for (UINT ismp=0; ismp<pins->samples; ismp++) | 402 | for (UINT ismp=0; ismp<pins->samples; ismp++) |
403 | { | 403 | { |
404 | MODINSTRUMENT *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Ins[smpmap[ismp]] : NULL; | 404 | MODINSTRUMENT *psmp = ((ismp < 16) && (smpmap[ismp])) ? &Ins[smpmap[ismp]] : NULL; |
405 | UINT smpnamelen = lpStream[dwMemPos]; | 405 | UINT smpnamelen = lpStream[dwMemPos]; |
406 | if ((psmp) && (smpnamelen) && (smpnamelen <= 22)) | 406 | if ((psmp) && (smpnamelen) && (smpnamelen <= 22)) |
407 | { | 407 | { |
408 | memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen); | 408 | memcpy(m_szNames[smpmap[ismp]], lpStream+dwMemPos+1, smpnamelen); |
409 | } | 409 | } |
410 | dwMemPos += smpnamelen + 1; | 410 | dwMemPos += smpnamelen + 1; |
411 | if (psmp) | 411 | if (psmp) |
412 | { | 412 | { |
413 | AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos); | 413 | AMS2SAMPLE *pams = (AMS2SAMPLE *)(lpStream+dwMemPos); |
414 | psmp->nGlobalVol = 64; | 414 | psmp->nGlobalVol = 64; |
415 | psmp->nPan = 128; | 415 | psmp->nPan = 128; |
416 | psmp->nLength = pams->length; | 416 | psmp->nLength = pams->length; |
417 | psmp->nLoopStart = pams->loopstart; | 417 | psmp->nLoopStart = pams->loopstart; |
418 | psmp->nLoopEnd = pams->loopend; | 418 | psmp->nLoopEnd = pams->loopend; |
419 | psmp->nC4Speed = pams->c4speed; | 419 | psmp->nC4Speed = pams->c4speed; |
420 | psmp->RelativeTone = pams->transpose; | 420 | psmp->RelativeTone = pams->transpose; |
421 | psmp->nVolume = pams->volume / 2; | 421 | psmp->nVolume = pams->volume / 2; |
422 | packedsamples[smpmap[ismp]] = pams->flags; | 422 | packedsamples[smpmap[ismp]] = pams->flags; |
423 | if (pams->flags & 0x04) psmp->uFlags |= CHN_16BIT; | 423 | if (pams->flags & 0x04) psmp->uFlags |= CHN_16BIT; |
424 | if (pams->flags & 0x08) psmp->uFlags |= CHN_LOOP; | 424 | if (pams->flags & 0x08) psmp->uFlags |= CHN_LOOP; |
425 | if (pams->flags & 0x10) psmp->uFlags |= CHN_PINGPONGLOOP; | 425 | if (pams->flags & 0x10) psmp->uFlags |= CHN_PINGPONGLOOP; |
426 | } | 426 | } |
427 | dwMemPos += sizeof(AMS2SAMPLE); | 427 | dwMemPos += sizeof(AMS2SAMPLE); |
428 | } | 428 | } |
429 | } | 429 | } |
430 | if (dwMemPos + 256 >= dwMemLength) return TRUE; | 430 | if (dwMemPos + 256 >= dwMemLength) return TRUE; |
431 | // Comments | 431 | // Comments |
432 | { | 432 | { |
433 | UINT composernamelen = lpStream[dwMemPos]; | 433 | UINT composernamelen = lpStream[dwMemPos]; |
434 | if (composernamelen) | 434 | if (composernamelen) |
435 | { | 435 | { |
436 | m_lpszSongComments = new char[composernamelen+1]; // changed from CHAR | 436 | m_lpszSongComments = new char[composernamelen+1]; // changed from CHAR |
437 | if (m_lpszSongComments) | 437 | if (m_lpszSongComments) |
438 | { | 438 | { |
439 | memcpy(m_lpszSongComments, lpStream+dwMemPos+1, composernamelen); | 439 | memcpy(m_lpszSongComments, lpStream+dwMemPos+1, composernamelen); |
440 | m_lpszSongComments[composernamelen] = 0; | 440 | m_lpszSongComments[composernamelen] = 0; |
441 | } | 441 | } |
442 | } | 442 | } |
443 | dwMemPos += composernamelen + 1; | 443 | dwMemPos += composernamelen + 1; |
444 | // channel names | 444 | // channel names |
445 | for (UINT i=0; i<32; i++) | 445 | for (UINT i=0; i<32; i++) |
446 | { | 446 | { |
447 | UINT chnnamlen = lpStream[dwMemPos]; | 447 | UINT chnnamlen = lpStream[dwMemPos]; |
448 | if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME)) | 448 | if ((chnnamlen) && (chnnamlen < MAX_CHANNELNAME)) |
449 | { | 449 | { |
450 | memcpy(ChnSettings[i].szName, lpStream+dwMemPos+1, chnnamlen); | 450 | memcpy(ChnSettings[i].szName, lpStream+dwMemPos+1, chnnamlen); |
451 | } | 451 | } |
452 | dwMemPos += chnnamlen + 1; | 452 | dwMemPos += chnnamlen + 1; |
453 | if (dwMemPos + chnnamlen + 256 >= dwMemLength) return TRUE; | 453 | if (dwMemPos + chnnamlen + 256 >= dwMemLength) return TRUE; |
454 | } | 454 | } |
455 | // packed comments (ignored) | 455 | // packed comments (ignored) |
456 | UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos)); | 456 | UINT songtextlen = *((LPDWORD)(lpStream+dwMemPos)); |
457 | dwMemPos += songtextlen; | 457 | dwMemPos += songtextlen; |
458 | if (dwMemPos + 256 >= dwMemLength) return TRUE; | 458 | if (dwMemPos + 256 >= dwMemLength) return TRUE; |
459 | } | 459 | } |
460 | // Order List | 460 | // Order List |
461 | { | 461 | { |
462 | for (UINT i=0; i<MAX_ORDERS; i++) | 462 | for (UINT i=0; i<MAX_ORDERS; i++) |
463 | { | 463 | { |
464 | Order[i] = 0xFF; | 464 | Order[i] = 0xFF; |
465 | if (dwMemPos + 2 >= dwMemLength) return TRUE; | 465 | if (dwMemPos + 2 >= dwMemLength) return TRUE; |
466 | if (i < psh->orders) | 466 | if (i < psh->orders) |
467 | { | 467 | { |
468 | Order[i] = lpStream[dwMemPos]; | 468 | Order[i] = lpStream[dwMemPos]; |
469 | dwMemPos += 2; | 469 | dwMemPos += 2; |
470 | } | 470 | } |
471 | } | 471 | } |
472 | } | 472 | } |
473 | // Pattern Data | 473 | // Pattern Data |
474 | for (UINT ipat=0; ipat<psh->patterns; ipat++) | 474 | for (UINT ipat=0; ipat<psh->patterns; ipat++) |
475 | { | 475 | { |
476 | if (dwMemPos+8 >= dwMemLength) return TRUE; | 476 | if (dwMemPos+8 >= dwMemLength) return TRUE; |
477 | UINT packedlen = *((LPDWORD)(lpStream+dwMemPos)); | 477 | UINT packedlen = *((LPDWORD)(lpStream+dwMemPos)); |
478 | UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]); | 478 | UINT numrows = 1 + (UINT)(lpStream[dwMemPos+4]); |
479 | //UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F); | 479 | //UINT patchn = 1 + (UINT)(lpStream[dwMemPos+5] & 0x1F); |
480 | //UINT patcmds = 1 + (UINT)(lpStream[dwMemPos+5] >> 5); | 480 | //UINT patcmds = 1 + (UINT)(lpStream[dwMemPos+5] >> 5); |
481 | UINT patnamlen = lpStream[dwMemPos+6]; | 481 | UINT patnamlen = lpStream[dwMemPos+6]; |
482 | dwMemPos += 4; | 482 | dwMemPos += 4; |
483 | if ((ipat < MAX_PATTERNS) && (packedlen < dwMemLength-dwMemPos) && (numrows >= 8)) | 483 | if ((ipat < MAX_PATTERNS) && (packedlen < dwMemLength-dwMemPos) && (numrows >= 8)) |
484 | { | 484 | { |
485 | if ((patnamlen) && (patnamlen < MAX_PATTERNNAME)) | 485 | if ((patnamlen) && (patnamlen < MAX_PATTERNNAME)) |
486 | { | 486 | { |
487 | char s[MAX_PATTERNNAME]; // changed from CHAR | 487 | char s[MAX_PATTERNNAME]; // changed from CHAR |
488 | memcpy(s, lpStream+dwMemPos+3, patnamlen); | 488 | memcpy(s, lpStream+dwMemPos+3, patnamlen); |
489 | s[patnamlen] = 0; | 489 | s[patnamlen] = 0; |
490 | SetPatternName(ipat, s); | 490 | SetPatternName(ipat, s); |
491 | } | 491 | } |
492 | PatternSize[ipat] = numrows; | 492 | PatternSize[ipat] = numrows; |
493 | Patterns[ipat] = AllocatePattern(numrows, m_nChannels); | 493 | Patterns[ipat] = AllocatePattern(numrows, m_nChannels); |
494 | if (!Patterns[ipat]) return TRUE; | 494 | if (!Patterns[ipat]) return TRUE; |
495 | // Unpack Pattern Data | 495 | // Unpack Pattern Data |
496 | LPCBYTE psrc = lpStream + dwMemPos; | 496 | LPCBYTE psrc = lpStream + dwMemPos; |
497 | UINT pos = 3 + patnamlen; | 497 | UINT pos = 3 + patnamlen; |
498 | UINT row = 0; | 498 | UINT row = 0; |
499 | while ((pos < packedlen) && (row < numrows)) | 499 | while ((pos < packedlen) && (row < numrows)) |
500 | { | 500 | { |
501 | MODCOMMAND *m = Patterns[ipat] + row * m_nChannels; | 501 | MODCOMMAND *m = Patterns[ipat] + row * m_nChannels; |
502 | UINT byte1 = psrc[pos++]; | 502 | UINT byte1 = psrc[pos++]; |
503 | UINT ch = byte1 & 0x1F; | 503 | UINT ch = byte1 & 0x1F; |
504 | // Read Note + Instr | 504 | // Read Note + Instr |
505 | if (!(byte1 & 0x40)) | 505 | if (!(byte1 & 0x40)) |
506 | { | 506 | { |
507 | UINT byte2 = psrc[pos++]; | 507 | UINT byte2 = psrc[pos++]; |
508 | UINT note = byte2 & 0x7F; | 508 | UINT note = byte2 & 0x7F; |
509 | if (note) m[ch].note = (note > 1) ? (note-1) : 0xFF; | 509 | if (note) m[ch].note = (note > 1) ? (note-1) : 0xFF; |
510 | m[ch].instr = psrc[pos++]; | 510 | m[ch].instr = psrc[pos++]; |
511 | // Read Effect | 511 | // Read Effect |
512 | while (byte2 & 0x80) | 512 | while (byte2 & 0x80) |
513 | { | 513 | { |
514 | byte2 = psrc[pos++]; | 514 | byte2 = psrc[pos++]; |
515 | if (byte2 & 0x40) | 515 | if (byte2 & 0x40) |
516 | { | 516 | { |
517 | m[ch].volcmd = VOLCMD_VOLUME; | 517 | m[ch].volcmd = VOLCMD_VOLUME; |
518 | m[ch].vol = byte2 & 0x3F; | 518 | m[ch].vol = byte2 & 0x3F; |
519 | } else | 519 | } else |
520 | { | 520 | { |
521 | UINT command = byte2 & 0x3F; | 521 | UINT command = byte2 & 0x3F; |
522 | UINT param = psrc[pos++]; | 522 | UINT param = psrc[pos++]; |
523 | if (command == 0x0C) | 523 | if (command == 0x0C) |
524 | { | 524 | { |
525 | m[ch].volcmd = VOLCMD_VOLUME; | 525 | m[ch].volcmd = VOLCMD_VOLUME; |
526 | m[ch].vol = param / 2; | 526 | m[ch].vol = param / 2; |
527 | } else | 527 | } else |
528 | if (command < 0x10) | 528 | if (command < 0x10) |
529 | { | 529 | { |
530 | m[ch].command = command; | 530 | m[ch].command = command; |
531 | m[ch].param = param; | 531 | m[ch].param = param; |
532 | ConvertModCommand(&m[ch]); | 532 | ConvertModCommand(&m[ch]); |
533 | } else | 533 | } else |
534 | { | 534 | { |
535 | // TODO: AMS effects | 535 | // TODO: AMS effects |
536 | } | 536 | } |
537 | } | 537 | } |
538 | } | 538 | } |
539 | } | 539 | } |
540 | if (byte1 & 0x80) row++; | 540 | if (byte1 & 0x80) row++; |
541 | } | 541 | } |
542 | } | 542 | } |
543 | dwMemPos += packedlen; | 543 | dwMemPos += packedlen; |
544 | } | 544 | } |
545 | // Read Samples | 545 | // Read Samples |
546 | for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength) | 546 | for (UINT iSmp=1; iSmp<=m_nSamples; iSmp++) if (Ins[iSmp].nLength) |
547 | { | 547 | { |
548 | if (dwMemPos >= dwMemLength - 9) return TRUE; | 548 | if (dwMemPos >= dwMemLength - 9) return TRUE; |
549 | UINT flags; | 549 | UINT flags; |
550 | if (packedsamples[iSmp] & 0x03) | 550 | if (packedsamples[iSmp] & 0x03) |
551 | { | 551 | { |
552 | flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8; | 552 | flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_AMS16 : RS_AMS8; |
553 | } else | 553 | } else |
554 | { | 554 | { |
555 | flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; | 555 | flags = (Ins[iSmp].uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; |
556 | } | 556 | } |
557 | dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); | 557 | dwMemPos += ReadSample(&Ins[iSmp], flags, (LPSTR)(lpStream+dwMemPos), dwMemLength-dwMemPos); |
558 | } | 558 | } |
559 | return TRUE; | 559 | return TRUE; |
560 | } | 560 | } |
561 | 561 | ||
562 | 562 | ||
563 | ///////////////////////////////////////////////////////////////////// | 563 | ///////////////////////////////////////////////////////////////////// |
564 | // AMS Sample unpacking | 564 | // AMS Sample unpacking |
565 | 565 | ||
566 | void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter) | 566 | void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter) |
567 | { | 567 | { |
568 | UINT tmplen = dmax; | 568 | UINT tmplen = dmax; |
569 | signed char *amstmp = new signed char[tmplen]; | 569 | signed char *amstmp = new signed char[tmplen]; |
570 | 570 | ||
571 | if (!amstmp) return; | 571 | if (!amstmp) return; |
572 | // Unpack Loop | 572 | // Unpack Loop |
573 | { | 573 | { |
574 | signed char *p = amstmp; | 574 | signed char *p = amstmp; |
575 | UINT i=0, j=0; | 575 | UINT i=0, j=0; |
576 | while ((i < inputlen) && (j < tmplen)) | 576 | while ((i < inputlen) && (j < tmplen)) |
577 | { | 577 | { |
578 | signed char ch = psrc[i++]; | 578 | signed char ch = psrc[i++]; |
579 | if (ch == packcharacter) | 579 | if (ch == packcharacter) |
580 | { | 580 | { |
581 | BYTE ch2 = psrc[i++]; | 581 | BYTE ch2 = psrc[i++]; |
582 | if (ch2) | 582 | if (ch2) |
583 | { | 583 | { |
584 | ch = psrc[i++]; | 584 | ch = psrc[i++]; |
585 | while (ch2--) | 585 | while (ch2--) |
586 | { | 586 | { |
587 | p[j++] = ch; | 587 | p[j++] = ch; |
588 | if (j >= tmplen) break; | 588 | if (j >= tmplen) break; |
589 | } | 589 | } |
590 | } else p[j++] = packcharacter; | 590 | } else p[j++] = packcharacter; |
591 | } else p[j++] = ch; | 591 | } else p[j++] = ch; |
592 | } | 592 | } |
593 | } | 593 | } |
594 | // Bit Unpack Loop | 594 | // Bit Unpack Loop |
595 | { | 595 | { |
596 | signed char *p = amstmp; | 596 | signed char *p = amstmp; |
597 | UINT bitcount = 0x80, dh; | 597 | UINT bitcount = 0x80, dh; |
598 | UINT k=0; | 598 | UINT k=0; |
599 | for (UINT i=0; i<dmax; i++) | 599 | for (UINT i=0; i<dmax; i++) |
600 | { | 600 | { |
601 | BYTE al = *p++; | 601 | BYTE al = *p++; |
602 | dh = 0; | 602 | dh = 0; |
603 | for (UINT count=0; count<8; count++) | 603 | for (UINT count=0; count<8; count++) |
604 | { | 604 | { |
605 | UINT bl = al & bitcount; | 605 | UINT bl = al & bitcount; |
606 | bl = ((bl|(bl<<8)) >> ((dh+8-count) & 7)) & 0xFF; | 606 | bl = ((bl|(bl<<8)) >> ((dh+8-count) & 7)) & 0xFF; |
607 | bitcount = ((bitcount|(bitcount<<8)) >> 1) & 0xFF; | 607 | bitcount = ((bitcount|(bitcount<<8)) >> 1) & 0xFF; |
608 | pdest[k++] |= bl; | 608 | pdest[k++] |= bl; |
609 | if (k >= dmax) | 609 | if (k >= dmax) |
610 | { | 610 | { |
611 | k = 0; | 611 | k = 0; |
612 | dh++; | 612 | dh++; |
613 | } | 613 | } |
614 | } | 614 | } |
615 | bitcount = ((bitcount|(bitcount<<8)) >> dh) & 0xFF; | 615 | bitcount = ((bitcount|(bitcount<<8)) >> dh) & 0xFF; |
616 | } | 616 | } |
617 | } | 617 | } |
618 | // Delta Unpack | 618 | // Delta Unpack |
619 | { | 619 | { |
620 | signed char old = 0; | 620 | signed char old = 0; |
621 | for (UINT i=0; i<dmax; i++) | 621 | for (UINT i=0; i<dmax; i++) |
622 | { | 622 | { |
623 | int pos = ((LPBYTE)pdest)[i]; | 623 | int pos = ((LPBYTE)pdest)[i]; |
624 | if ((pos != 128) && (pos & 0x80)) pos = -(pos & 0x7F); | 624 | if ((pos != 128) && (pos & 0x80)) pos = -(pos & 0x7F); |
625 | old -= (signed char)pos; | 625 | old -= (signed char)pos; |
626 | pdest[i] = old; | 626 | pdest[i] = old; |
627 | } | 627 | } |
628 | } | 628 | } |
629 | delete amstmp; | 629 | delete [] amstmp; |
630 | } | 630 | } |
631 | 631 | ||
diff --git a/core/multimedia/opieplayer/modplug/load_mdl.cpp b/core/multimedia/opieplayer/modplug/load_mdl.cpp index 806b68b..e1f78d5 100644 --- a/core/multimedia/opieplayer/modplug/load_mdl.cpp +++ b/core/multimedia/opieplayer/modplug/load_mdl.cpp | |||
@@ -1,506 +1,506 @@ | |||
1 | /* | 1 | /* |
2 | * This program is free software; you can redistribute it and modify it | 2 | * This program is free software; you can redistribute it and modify it |
3 | * under the terms of the GNU General Public License as published by the | 3 | * under the terms of the GNU General Public License as published by the |
4 | * Free Software Foundation; either version 2 of the license or (at your | 4 | * Free Software Foundation; either version 2 of the license or (at your |
5 | * option) any later version. | 5 | * option) any later version. |
6 | * | 6 | * |
7 | * Authors: Olivier Lapicque <olivierl@jps.net> | 7 | * Authors: Olivier Lapicque <olivierl@jps.net> |
8 | */ | 8 | */ |
9 | 9 | ||
10 | ////////////////////////////////////////////// | 10 | ////////////////////////////////////////////// |
11 | // DigiTracker (MDL) module loader // | 11 | // DigiTracker (MDL) module loader // |
12 | ////////////////////////////////////////////// | 12 | ////////////////////////////////////////////// |
13 | #include "stdafx.h" | 13 | #include "stdafx.h" |
14 | #include "sndfile.h" | 14 | #include "sndfile.h" |
15 | 15 | ||
16 | //#pragma warning(disable:4244) | 16 | //#pragma warning(disable:4244) |
17 | 17 | ||
18 | typedef struct MDLSONGHEADER | 18 | typedef struct MDLSONGHEADER |
19 | { | 19 | { |
20 | DWORD id;// "DMDL" = 0x4C444D44 | 20 | DWORD id;// "DMDL" = 0x4C444D44 |
21 | BYTE version; | 21 | BYTE version; |
22 | } Q_PACKED MDLSONGHEADER; | 22 | } Q_PACKED MDLSONGHEADER; |
23 | 23 | ||
24 | 24 | ||
25 | typedef struct MDLINFOBLOCK | 25 | typedef struct MDLINFOBLOCK |
26 | { | 26 | { |
27 | CHAR songname[32]; | 27 | CHAR songname[32]; |
28 | CHAR composer[20]; | 28 | CHAR composer[20]; |
29 | WORD norders; | 29 | WORD norders; |
30 | WORD repeatpos; | 30 | WORD repeatpos; |
31 | BYTE globalvol; | 31 | BYTE globalvol; |
32 | BYTE speed; | 32 | BYTE speed; |
33 | BYTE tempo; | 33 | BYTE tempo; |
34 | BYTE channelinfo[32]; | 34 | BYTE channelinfo[32]; |
35 | BYTE seq[256]; | 35 | BYTE seq[256]; |
36 | } Q_PACKED MDLINFOBLOCK; | 36 | } Q_PACKED MDLINFOBLOCK; |
37 | 37 | ||
38 | 38 | ||
39 | typedef struct MDLPATTERNDATA | 39 | typedef struct MDLPATTERNDATA |
40 | { | 40 | { |
41 | BYTE channels; | 41 | BYTE channels; |
42 | BYTE lastrow;// nrows = lastrow+1 | 42 | BYTE lastrow;// nrows = lastrow+1 |
43 | CHAR name[16]; | 43 | CHAR name[16]; |
44 | WORD data[1]; | 44 | WORD data[1]; |
45 | } Q_PACKED MDLPATTERNDATA; | 45 | } Q_PACKED MDLPATTERNDATA; |
46 | 46 | ||
47 | 47 | ||
48 | void ConvertMDLCommand(MODCOMMAND *m, UINT eff, UINT data) | 48 | void ConvertMDLCommand(MODCOMMAND *m, UINT eff, UINT data) |
49 | //-------------------------------------------------------- | 49 | //-------------------------------------------------------- |
50 | { | 50 | { |
51 | UINT command = 0, param = data; | 51 | UINT command = 0, param = data; |
52 | switch(eff) | 52 | switch(eff) |
53 | { | 53 | { |
54 | case 0x01:command = CMD_PORTAMENTOUP; break; | 54 | case 0x01:command = CMD_PORTAMENTOUP; break; |
55 | case 0x02:command = CMD_PORTAMENTODOWN; break; | 55 | case 0x02:command = CMD_PORTAMENTODOWN; break; |
56 | case 0x03:command = CMD_TONEPORTAMENTO; break; | 56 | case 0x03:command = CMD_TONEPORTAMENTO; break; |
57 | case 0x04:command = CMD_VIBRATO; break; | 57 | case 0x04:command = CMD_VIBRATO; break; |
58 | case 0x05:command = CMD_ARPEGGIO; break; | 58 | case 0x05:command = CMD_ARPEGGIO; break; |
59 | case 0x07:command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break; | 59 | case 0x07:command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break; |
60 | case 0x08:command = CMD_PANNING8; param <<= 1; break; | 60 | case 0x08:command = CMD_PANNING8; param <<= 1; break; |
61 | case 0x0B:command = CMD_POSITIONJUMP; break; | 61 | case 0x0B:command = CMD_POSITIONJUMP; break; |
62 | case 0x0C:command = CMD_GLOBALVOLUME; break; | 62 | case 0x0C:command = CMD_GLOBALVOLUME; break; |
63 | case 0x0D:command = CMD_PATTERNBREAK; param = (data & 0x0F) + (data>>4)*10; break; | 63 | case 0x0D:command = CMD_PATTERNBREAK; param = (data & 0x0F) + (data>>4)*10; break; |
64 | case 0x0E: | 64 | case 0x0E: |
65 | command = CMD_S3MCMDEX; | 65 | command = CMD_S3MCMDEX; |
66 | switch(data & 0xF0) | 66 | switch(data & 0xF0) |
67 | { | 67 | { |
68 | case 0x00:command = 0; break; // What is E0x in MDL (there is a bunch) ? | 68 | case 0x00:command = 0; break; // What is E0x in MDL (there is a bunch) ? |
69 | case 0x10:if (param & 0x0F) { param |= 0xF0; command = CMD_PANNINGSLIDE; } else command = 0; break; | 69 | case 0x10:if (param & 0x0F) { param |= 0xF0; command = CMD_PANNINGSLIDE; } else command = 0; break; |
70 | case 0x20:if (param & 0x0F) { param = (param << 4) | 0x0F; command = CMD_PANNINGSLIDE; } else command = 0; break; | 70 | case 0x20:if (param & 0x0F) { param = (param << 4) | 0x0F; command = CMD_PANNINGSLIDE; } else command = 0; break; |
71 | case 0x30:param = (data & 0x0F) | 0x10; break; // glissando | 71 | case 0x30:param = (data & 0x0F) | 0x10; break; // glissando |
72 | case 0x40:param = (data & 0x0F) | 0x30; break; // vibrato waveform | 72 | case 0x40:param = (data & 0x0F) | 0x30; break; // vibrato waveform |
73 | case 0x60:param = (data & 0x0F) | 0xB0; break; | 73 | case 0x60:param = (data & 0x0F) | 0xB0; break; |
74 | case 0x70:param = (data & 0x0F) | 0x40; break; // tremolo waveform | 74 | case 0x70:param = (data & 0x0F) | 0x40; break; // tremolo waveform |
75 | case 0x90:command = CMD_RETRIG; param &= 0x0F; break; | 75 | case 0x90:command = CMD_RETRIG; param &= 0x0F; break; |
76 | case 0xA0:param = (data & 0x0F) << 4; command = CMD_GLOBALVOLSLIDE; break; | 76 | case 0xA0:param = (data & 0x0F) << 4; command = CMD_GLOBALVOLSLIDE; break; |
77 | case 0xB0:param = data & 0x0F; command = CMD_GLOBALVOLSLIDE; break; | 77 | case 0xB0:param = data & 0x0F; command = CMD_GLOBALVOLSLIDE; break; |
78 | case 0xF0:param = ((data >> 8) & 0x0F) | 0xA0; break; | 78 | case 0xF0:param = ((data >> 8) & 0x0F) | 0xA0; break; |
79 | } | 79 | } |
80 | break; | 80 | break; |
81 | case 0x0F:command = CMD_SPEED; break; | 81 | case 0x0F:command = CMD_SPEED; break; |
82 | case 0x10:if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) == 0xF0) param = ((param << 4) | 0x0F); else param >>= 2; } break; | 82 | case 0x10:if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) == 0xF0) param = ((param << 4) | 0x0F); else param >>= 2; } break; |
83 | case 0x20:if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) != 0xF0) param >>= 2; } break; | 83 | case 0x20:if ((param & 0xF0) != 0xE0) { command = CMD_VOLUMESLIDE; if ((param & 0xF0) != 0xF0) param >>= 2; } break; |
84 | case 0x30:command = CMD_RETRIG; break; | 84 | case 0x30:command = CMD_RETRIG; break; |
85 | case 0x40:command = CMD_TREMOLO; break; | 85 | case 0x40:command = CMD_TREMOLO; break; |
86 | case 0x50:command = CMD_TREMOR; break; | 86 | case 0x50:command = CMD_TREMOR; break; |
87 | case 0xEF:if (param > 0xFF) param = 0xFF; command = CMD_OFFSET; break; | 87 | case 0xEF:if (param > 0xFF) param = 0xFF; command = CMD_OFFSET; break; |
88 | } | 88 | } |
89 | if (command) | 89 | if (command) |
90 | { | 90 | { |
91 | m->command = command; | 91 | m->command = command; |
92 | m->param = param; | 92 | m->param = param; |
93 | } | 93 | } |
94 | } | 94 | } |
95 | 95 | ||
96 | 96 | ||
97 | void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks) | 97 | void UnpackMDLTrack(MODCOMMAND *pat, UINT nChannels, UINT nRows, UINT nTrack, const BYTE *lpTracks) |
98 | //------------------------------------------------------------------------------------------------- | 98 | //------------------------------------------------------------------------------------------------- |
99 | { | 99 | { |
100 | MODCOMMAND cmd, *m = pat; | 100 | MODCOMMAND cmd, *m = pat; |
101 | UINT len = *((WORD *)lpTracks); | 101 | UINT len = *((WORD *)lpTracks); |
102 | UINT pos = 0, row = 0, i; | 102 | UINT pos = 0, row = 0, i; |
103 | lpTracks += 2; | 103 | lpTracks += 2; |
104 | for (UINT ntrk=1; ntrk<nTrack; ntrk++) | 104 | for (UINT ntrk=1; ntrk<nTrack; ntrk++) |
105 | { | 105 | { |
106 | lpTracks += len; | 106 | lpTracks += len; |
107 | len = *((WORD *)lpTracks); | 107 | len = *((WORD *)lpTracks); |
108 | lpTracks += 2; | 108 | lpTracks += 2; |
109 | } | 109 | } |
110 | cmd.note = cmd.instr = 0; | 110 | cmd.note = cmd.instr = 0; |
111 | cmd.volcmd = cmd.vol = 0; | 111 | cmd.volcmd = cmd.vol = 0; |
112 | cmd.command = cmd.param = 0; | 112 | cmd.command = cmd.param = 0; |
113 | while ((row < nRows) && (pos < len)) | 113 | while ((row < nRows) && (pos < len)) |
114 | { | 114 | { |
115 | UINT xx; | 115 | UINT xx; |
116 | BYTE b = lpTracks[pos++]; | 116 | BYTE b = lpTracks[pos++]; |
117 | xx = b >> 2; | 117 | xx = b >> 2; |
118 | switch(b & 0x03) | 118 | switch(b & 0x03) |
119 | { | 119 | { |
120 | case 0x01: | 120 | case 0x01: |
121 | for (i=0; i<=xx; i++) | 121 | for (i=0; i<=xx; i++) |
122 | { | 122 | { |
123 | if (row) *m = *(m-nChannels); | 123 | if (row) *m = *(m-nChannels); |
124 | m += nChannels; | 124 | m += nChannels; |
125 | row++; | 125 | row++; |
126 | if (row >= nRows) break; | 126 | if (row >= nRows) break; |
127 | } | 127 | } |
128 | break; | 128 | break; |
129 | 129 | ||
130 | case 0x02: | 130 | case 0x02: |
131 | if (xx < row) *m = pat[nChannels*xx]; | 131 | if (xx < row) *m = pat[nChannels*xx]; |
132 | m += nChannels; | 132 | m += nChannels; |
133 | row++; | 133 | row++; |
134 | break; | 134 | break; |
135 | 135 | ||
136 | case 0x03: | 136 | case 0x03: |
137 | { | 137 | { |
138 | cmd.note = (xx & 0x01) ? lpTracks[pos++] : 0; | 138 | cmd.note = (xx & 0x01) ? lpTracks[pos++] : 0; |
139 | cmd.instr = (xx & 0x02) ? lpTracks[pos++] : 0; | 139 | cmd.instr = (xx & 0x02) ? lpTracks[pos++] : 0; |
140 | cmd.volcmd = cmd.vol = 0; | 140 | cmd.volcmd = cmd.vol = 0; |
141 | cmd.command = cmd.param = 0; | 141 | cmd.command = cmd.param = 0; |
142 | if ((cmd.note < 120-12) && (cmd.note)) cmd.note += 12; | 142 | if ((cmd.note < 120-12) && (cmd.note)) cmd.note += 12; |
143 | UINT volume = (xx & 0x04) ? lpTracks[pos++] : 0; | 143 | UINT volume = (xx & 0x04) ? lpTracks[pos++] : 0; |
144 | UINT commands = (xx & 0x08) ? lpTracks[pos++] : 0; | 144 | UINT commands = (xx & 0x08) ? lpTracks[pos++] : 0; |
145 | UINT command1 = commands & 0x0F; | 145 | UINT command1 = commands & 0x0F; |
146 | UINT command2 = commands & 0xF0; | 146 | UINT command2 = commands & 0xF0; |
147 | UINT param1 = (xx & 0x10) ? lpTracks[pos++] : 0; | 147 | UINT param1 = (xx & 0x10) ? lpTracks[pos++] : 0; |
148 | UINT param2 = (xx & 0x20) ? lpTracks[pos++] : 0; | 148 | UINT param2 = (xx & 0x20) ? lpTracks[pos++] : 0; |
149 | if ((command1 == 0x0E) && ((param1 & 0xF0) == 0xF0) && (!command2)) | 149 | if ((command1 == 0x0E) && ((param1 & 0xF0) == 0xF0) && (!command2)) |
150 | { | 150 | { |
151 | param1 = ((param1 & 0x0F) << 8) | param2; | 151 | param1 = ((param1 & 0x0F) << 8) | param2; |
152 | command1 = 0xEF; | 152 | command1 = 0xEF; |
153 | command2 = param2 = 0; | 153 | command2 = param2 = 0; |
154 | } | 154 | } |
155 | if (volume) | 155 | if (volume) |
156 | { | 156 | { |
157 | cmd.volcmd = VOLCMD_VOLUME; | 157 | cmd.volcmd = VOLCMD_VOLUME; |
158 | cmd.vol = (volume+1) >> 2; | 158 | cmd.vol = (volume+1) >> 2; |
159 | } | 159 | } |
160 | ConvertMDLCommand(&cmd, command1, param1); | 160 | ConvertMDLCommand(&cmd, command1, param1); |
161 | if ((cmd.command != CMD_SPEED) | 161 | if ((cmd.command != CMD_SPEED) |
162 | && (cmd.command != CMD_TEMPO) | 162 | && (cmd.command != CMD_TEMPO) |
163 | && (cmd.command != CMD_PATTERNBREAK)) | 163 | && (cmd.command != CMD_PATTERNBREAK)) |
164 | ConvertMDLCommand(&cmd, command2, param2); | 164 | ConvertMDLCommand(&cmd, command2, param2); |
165 | *m = cmd; | 165 | *m = cmd; |
166 | m += nChannels; | 166 | m += nChannels; |
167 | row++; | 167 | row++; |
168 | } | 168 | } |
169 | break; | 169 | break; |
170 | 170 | ||
171 | // Empty Slots | 171 | // Empty Slots |
172 | default: | 172 | default: |
173 | row += xx+1; | 173 | row += xx+1; |
174 | m += (xx+1)*nChannels; | 174 | m += (xx+1)*nChannels; |
175 | if (row >= nRows) break; | 175 | if (row >= nRows) break; |
176 | } | 176 | } |
177 | } | 177 | } |
178 | } | 178 | } |
179 | 179 | ||
180 | 180 | ||
181 | 181 | ||
182 | BOOL CSoundFile::ReadMDL(const BYTE *lpStream, DWORD dwMemLength) | 182 | BOOL CSoundFile::ReadMDL(const BYTE *lpStream, DWORD dwMemLength) |
183 | //--------------------------------------------------------------- | 183 | //--------------------------------------------------------------- |
184 | { | 184 | { |
185 | DWORD dwMemPos, dwPos, blocklen, dwTrackPos; | 185 | DWORD dwMemPos, dwPos, blocklen, dwTrackPos; |
186 | const MDLSONGHEADER *pmsh = (const MDLSONGHEADER *)lpStream; | 186 | const MDLSONGHEADER *pmsh = (const MDLSONGHEADER *)lpStream; |
187 | MDLINFOBLOCK *pmib; | 187 | MDLINFOBLOCK *pmib; |
188 | MDLPATTERNDATA *pmpd; | 188 | MDLPATTERNDATA *pmpd; |
189 | UINT i,j, norders = 0, npatterns = 0, ntracks = 0; | 189 | UINT i,j, norders = 0, npatterns = 0, ntracks = 0; |
190 | UINT ninstruments = 0, nsamples = 0; | 190 | UINT ninstruments = 0, nsamples = 0; |
191 | WORD block; | 191 | WORD block; |
192 | WORD patterntracks[MAX_PATTERNS*32]; | 192 | WORD patterntracks[MAX_PATTERNS*32]; |
193 | BYTE smpinfo[MAX_SAMPLES]; | 193 | BYTE smpinfo[MAX_SAMPLES]; |
194 | BYTE insvolenv[MAX_INSTRUMENTS]; | 194 | BYTE insvolenv[MAX_INSTRUMENTS]; |
195 | BYTE inspanenv[MAX_INSTRUMENTS]; | 195 | BYTE inspanenv[MAX_INSTRUMENTS]; |
196 | LPCBYTE pvolenv, ppanenv, ppitchenv; | 196 | LPCBYTE pvolenv, ppanenv, ppitchenv; |
197 | UINT nvolenv, npanenv, npitchenv; | 197 | UINT nvolenv, npanenv, npitchenv; |
198 | 198 | ||
199 | if ((!lpStream) || (dwMemLength < 1024)) return FALSE; | 199 | if ((!lpStream) || (dwMemLength < 1024)) return FALSE; |
200 | if ((pmsh->id != 0x4C444D44) || ((pmsh->version & 0xF0) > 0x10)) return FALSE; | 200 | if ((pmsh->id != 0x4C444D44) || ((pmsh->version & 0xF0) > 0x10)) return FALSE; |
201 | memset(patterntracks, 0, sizeof(patterntracks)); | 201 | memset(patterntracks, 0, sizeof(patterntracks)); |
202 | memset(smpinfo, 0, sizeof(smpinfo)); | 202 | memset(smpinfo, 0, sizeof(smpinfo)); |
203 | memset(insvolenv, 0, sizeof(insvolenv)); | 203 | memset(insvolenv, 0, sizeof(insvolenv)); |
204 | memset(inspanenv, 0, sizeof(inspanenv)); | 204 | memset(inspanenv, 0, sizeof(inspanenv)); |
205 | dwMemPos = 5; | 205 | dwMemPos = 5; |
206 | dwTrackPos = 0; | 206 | dwTrackPos = 0; |
207 | pvolenv = ppanenv = ppitchenv = NULL; | 207 | pvolenv = ppanenv = ppitchenv = NULL; |
208 | nvolenv = npanenv = npitchenv = 0; | 208 | nvolenv = npanenv = npitchenv = 0; |
209 | m_nSamples = m_nInstruments = 0; | 209 | m_nSamples = m_nInstruments = 0; |
210 | while (dwMemPos+6 < dwMemLength) | 210 | while (dwMemPos+6 < dwMemLength) |
211 | { | 211 | { |
212 | block = *((WORD *)(lpStream+dwMemPos)); | 212 | block = *((WORD *)(lpStream+dwMemPos)); |
213 | blocklen = *((DWORD *)(lpStream+dwMemPos+2)); | 213 | blocklen = *((DWORD *)(lpStream+dwMemPos+2)); |
214 | dwMemPos += 6; | 214 | dwMemPos += 6; |
215 | if (dwMemPos + blocklen > dwMemLength) | 215 | if (dwMemPos + blocklen > dwMemLength) |
216 | { | 216 | { |
217 | if (dwMemPos == 11) return FALSE; | 217 | if (dwMemPos == 11) return FALSE; |
218 | break; | 218 | break; |
219 | } | 219 | } |
220 | switch(block) | 220 | switch(block) |
221 | { | 221 | { |
222 | // IN: infoblock | 222 | // IN: infoblock |
223 | case 0x4E49: | 223 | case 0x4E49: |
224 | pmib = (MDLINFOBLOCK *)(lpStream+dwMemPos); | 224 | pmib = (MDLINFOBLOCK *)(lpStream+dwMemPos); |
225 | memcpy(m_szNames[0], pmib->songname, 32); | 225 | memcpy(m_szNames[0], pmib->songname, 32); |
226 | norders = pmib->norders; | 226 | norders = pmib->norders; |
227 | if (norders > MAX_ORDERS) norders = MAX_ORDERS; | 227 | if (norders > MAX_ORDERS) norders = MAX_ORDERS; |
228 | m_nRestartPos = pmib->repeatpos; | 228 | m_nRestartPos = pmib->repeatpos; |
229 | m_nDefaultGlobalVolume = pmib->globalvol; | 229 | m_nDefaultGlobalVolume = pmib->globalvol; |
230 | m_nDefaultTempo = pmib->tempo; | 230 | m_nDefaultTempo = pmib->tempo; |
231 | m_nDefaultSpeed = pmib->speed; | 231 | m_nDefaultSpeed = pmib->speed; |
232 | m_nChannels = 4; | 232 | m_nChannels = 4; |
233 | for (i=0; i<32; i++) | 233 | for (i=0; i<32; i++) |
234 | { | 234 | { |
235 | ChnSettings[i].nVolume = 64; | 235 | ChnSettings[i].nVolume = 64; |
236 | ChnSettings[i].nPan = (pmib->channelinfo[i] & 0x7F) << 1; | 236 | ChnSettings[i].nPan = (pmib->channelinfo[i] & 0x7F) << 1; |
237 | if (pmib->channelinfo[i] & 0x80) | 237 | if (pmib->channelinfo[i] & 0x80) |
238 | ChnSettings[i].dwFlags |= CHN_MUTE; | 238 | ChnSettings[i].dwFlags |= CHN_MUTE; |
239 | else | 239 | else |
240 | m_nChannels = i+1; | 240 | m_nChannels = i+1; |
241 | } | 241 | } |
242 | for (j=0; j<norders; j++) Order[j] = pmib->seq[j]; | 242 | for (j=0; j<norders; j++) Order[j] = pmib->seq[j]; |
243 | break; | 243 | break; |
244 | // ME: song message | 244 | // ME: song message |
245 | case 0x454D: | 245 | case 0x454D: |
246 | if (blocklen) | 246 | if (blocklen) |
247 | { | 247 | { |
248 | if (m_lpszSongComments) delete m_lpszSongComments; | 248 | if (m_lpszSongComments) delete [] m_lpszSongComments; |
249 | m_lpszSongComments = new char[blocklen]; | 249 | m_lpszSongComments = new char[blocklen]; |
250 | if (m_lpszSongComments) | 250 | if (m_lpszSongComments) |
251 | { | 251 | { |
252 | memcpy(m_lpszSongComments, lpStream+dwMemPos, blocklen); | 252 | memcpy(m_lpszSongComments, lpStream+dwMemPos, blocklen); |
253 | m_lpszSongComments[blocklen-1] = 0; | 253 | m_lpszSongComments[blocklen-1] = 0; |
254 | } | 254 | } |
255 | } | 255 | } |
256 | break; | 256 | break; |
257 | // PA: Pattern Data | 257 | // PA: Pattern Data |
258 | case 0x4150: | 258 | case 0x4150: |
259 | npatterns = lpStream[dwMemPos]; | 259 | npatterns = lpStream[dwMemPos]; |
260 | if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS; | 260 | if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS; |
261 | dwPos = dwMemPos + 1; | 261 | dwPos = dwMemPos + 1; |
262 | for (i=0; i<npatterns; i++) | 262 | for (i=0; i<npatterns; i++) |
263 | { | 263 | { |
264 | if (dwPos+18 >= dwMemLength) break; | 264 | if (dwPos+18 >= dwMemLength) break; |
265 | pmpd = (MDLPATTERNDATA *)(lpStream + dwPos); | 265 | pmpd = (MDLPATTERNDATA *)(lpStream + dwPos); |
266 | if (pmpd->channels > 32) break; | 266 | if (pmpd->channels > 32) break; |
267 | PatternSize[i] = pmpd->lastrow+1; | 267 | PatternSize[i] = pmpd->lastrow+1; |
268 | if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels; | 268 | if (m_nChannels < pmpd->channels) m_nChannels = pmpd->channels; |
269 | dwPos += 18 + 2*pmpd->channels; | 269 | dwPos += 18 + 2*pmpd->channels; |
270 | for (j=0; j<pmpd->channels; j++) | 270 | for (j=0; j<pmpd->channels; j++) |
271 | { | 271 | { |
272 | patterntracks[i*32+j] = pmpd->data[j]; | 272 | patterntracks[i*32+j] = pmpd->data[j]; |
273 | } | 273 | } |
274 | } | 274 | } |
275 | break; | 275 | break; |
276 | // TR: Track Data | 276 | // TR: Track Data |
277 | case 0x5254: | 277 | case 0x5254: |
278 | if (dwTrackPos) break; | 278 | if (dwTrackPos) break; |
279 | ntracks = *((WORD *)(lpStream+dwMemPos)); | 279 | ntracks = *((WORD *)(lpStream+dwMemPos)); |
280 | dwTrackPos = dwMemPos+2; | 280 | dwTrackPos = dwMemPos+2; |
281 | break; | 281 | break; |
282 | // II: Instruments | 282 | // II: Instruments |
283 | case 0x4949: | 283 | case 0x4949: |
284 | ninstruments = lpStream[dwMemPos]; | 284 | ninstruments = lpStream[dwMemPos]; |
285 | dwPos = dwMemPos+1; | 285 | dwPos = dwMemPos+1; |
286 | for (i=0; i<ninstruments; i++) | 286 | for (i=0; i<ninstruments; i++) |
287 | { | 287 | { |
288 | UINT nins = lpStream[dwPos]; | 288 | UINT nins = lpStream[dwPos]; |
289 | if ((nins >= MAX_INSTRUMENTS) || (!nins)) break; | 289 | if ((nins >= MAX_INSTRUMENTS) || (!nins)) break; |
290 | if (m_nInstruments < nins) m_nInstruments = nins; | 290 | if (m_nInstruments < nins) m_nInstruments = nins; |
291 | if (!Headers[nins]) | 291 | if (!Headers[nins]) |
292 | { | 292 | { |
293 | UINT note = 12; | 293 | UINT note = 12; |
294 | if ((Headers[nins] = new INSTRUMENTHEADER) == NULL) break; | 294 | if ((Headers[nins] = new INSTRUMENTHEADER) == NULL) break; |
295 | INSTRUMENTHEADER *penv = Headers[nins]; | 295 | INSTRUMENTHEADER *penv = Headers[nins]; |
296 | memset(penv, 0, sizeof(INSTRUMENTHEADER)); | 296 | memset(penv, 0, sizeof(INSTRUMENTHEADER)); |
297 | memcpy(penv->name, lpStream+dwPos+2, 32); | 297 | memcpy(penv->name, lpStream+dwPos+2, 32); |
298 | penv->nGlobalVol = 64; | 298 | penv->nGlobalVol = 64; |
299 | penv->nPPC = 5*12; | 299 | penv->nPPC = 5*12; |
300 | for (j=0; j<lpStream[dwPos+1]; j++) | 300 | for (j=0; j<lpStream[dwPos+1]; j++) |
301 | { | 301 | { |
302 | const BYTE *ps = lpStream+dwPos+34+14*j; | 302 | const BYTE *ps = lpStream+dwPos+34+14*j; |
303 | while ((note < (UINT)(ps[1]+12)) && (note < 120)) | 303 | while ((note < (UINT)(ps[1]+12)) && (note < 120)) |
304 | { | 304 | { |
305 | penv->NoteMap[note] = note+1; | 305 | penv->NoteMap[note] = note+1; |
306 | if (ps[0] < MAX_SAMPLES) | 306 | if (ps[0] < MAX_SAMPLES) |
307 | { | 307 | { |
308 | int ismp = ps[0]; | 308 | int ismp = ps[0]; |
309 | penv->Keyboard[note] = ps[0]; | 309 | penv->Keyboard[note] = ps[0]; |
310 | Ins[ismp].nVolume = ps[2]; | 310 | Ins[ismp].nVolume = ps[2]; |
311 | Ins[ismp].nPan = ps[4] << 1; | 311 | Ins[ismp].nPan = ps[4] << 1; |
312 | Ins[ismp].nVibType = ps[11]; | 312 | Ins[ismp].nVibType = ps[11]; |
313 | Ins[ismp].nVibSweep = ps[10]; | 313 | Ins[ismp].nVibSweep = ps[10]; |
314 | Ins[ismp].nVibDepth = ps[9]; | 314 | Ins[ismp].nVibDepth = ps[9]; |
315 | Ins[ismp].nVibRate = ps[8]; | 315 | Ins[ismp].nVibRate = ps[8]; |
316 | } | 316 | } |
317 | penv->nFadeOut = (ps[7] << 8) | ps[6]; | 317 | penv->nFadeOut = (ps[7] << 8) | ps[6]; |
318 | if (penv->nFadeOut == 0xFFFF) penv->nFadeOut = 0; | 318 | if (penv->nFadeOut == 0xFFFF) penv->nFadeOut = 0; |
319 | note++; | 319 | note++; |
320 | } | 320 | } |
321 | // Use volume envelope ? | 321 | // Use volume envelope ? |
322 | if (ps[3] & 0x80) | 322 | if (ps[3] & 0x80) |
323 | { | 323 | { |
324 | penv->dwFlags |= ENV_VOLUME; | 324 | penv->dwFlags |= ENV_VOLUME; |
325 | insvolenv[nins] = (ps[3] & 0x3F) + 1; | 325 | insvolenv[nins] = (ps[3] & 0x3F) + 1; |
326 | } | 326 | } |
327 | // Use panning envelope ? | 327 | // Use panning envelope ? |
328 | if (ps[5] & 0x80) | 328 | if (ps[5] & 0x80) |
329 | { | 329 | { |
330 | penv->dwFlags |= ENV_PANNING; | 330 | penv->dwFlags |= ENV_PANNING; |
331 | inspanenv[nins] = (ps[5] & 0x3F) + 1; | 331 | inspanenv[nins] = (ps[5] & 0x3F) + 1; |
332 | } | 332 | } |
333 | } | 333 | } |
334 | } | 334 | } |
335 | dwPos += 34 + 14*lpStream[dwPos+1]; | 335 | dwPos += 34 + 14*lpStream[dwPos+1]; |
336 | } | 336 | } |
337 | for (j=1; j<=m_nInstruments; j++) if (!Headers[j]) | 337 | for (j=1; j<=m_nInstruments; j++) if (!Headers[j]) |
338 | { | 338 | { |
339 | Headers[j] = new INSTRUMENTHEADER; | 339 | Headers[j] = new INSTRUMENTHEADER; |
340 | if (Headers[j]) memset(Headers[j], 0, sizeof(INSTRUMENTHEADER)); | 340 | if (Headers[j]) memset(Headers[j], 0, sizeof(INSTRUMENTHEADER)); |
341 | } | 341 | } |
342 | break; | 342 | break; |
343 | // VE: Volume Envelope | 343 | // VE: Volume Envelope |
344 | case 0x4556: | 344 | case 0x4556: |
345 | if ((nvolenv = lpStream[dwMemPos]) == 0) break; | 345 | if ((nvolenv = lpStream[dwMemPos]) == 0) break; |
346 | if (dwMemPos + nvolenv*32 + 1 <= dwMemLength) pvolenv = lpStream + dwMemPos + 1; | 346 | if (dwMemPos + nvolenv*32 + 1 <= dwMemLength) pvolenv = lpStream + dwMemPos + 1; |
347 | break; | 347 | break; |
348 | // PE: Panning Envelope | 348 | // PE: Panning Envelope |
349 | case 0x4550: | 349 | case 0x4550: |
350 | if ((npanenv = lpStream[dwMemPos]) == 0) break; | 350 | if ((npanenv = lpStream[dwMemPos]) == 0) break; |
351 | if (dwMemPos + npanenv*32 + 1 <= dwMemLength) ppanenv = lpStream + dwMemPos + 1; | 351 | if (dwMemPos + npanenv*32 + 1 <= dwMemLength) ppanenv = lpStream + dwMemPos + 1; |
352 | break; | 352 | break; |
353 | // FE: Pitch Envelope | 353 | // FE: Pitch Envelope |
354 | case 0x4546: | 354 | case 0x4546: |
355 | if ((npitchenv = lpStream[dwMemPos]) == 0) break; | 355 | if ((npitchenv = lpStream[dwMemPos]) == 0) break; |
356 | if (dwMemPos + npitchenv*32 + 1 <= dwMemLength) ppitchenv = lpStream + dwMemPos + 1; | 356 | if (dwMemPos + npitchenv*32 + 1 <= dwMemLength) ppitchenv = lpStream + dwMemPos + 1; |
357 | break; | 357 | break; |
358 | // IS: Sample Infoblock | 358 | // IS: Sample Infoblock |
359 | case 0x5349: | 359 | case 0x5349: |
360 | nsamples = lpStream[dwMemPos]; | 360 | nsamples = lpStream[dwMemPos]; |
361 | dwPos = dwMemPos+1; | 361 | dwPos = dwMemPos+1; |
362 | for (i=0; i<nsamples; i++, dwPos += 59) | 362 | for (i=0; i<nsamples; i++, dwPos += 59) |
363 | { | 363 | { |
364 | UINT nins = lpStream[dwPos]; | 364 | UINT nins = lpStream[dwPos]; |
365 | if ((nins >= MAX_SAMPLES) || (!nins)) continue; | 365 | if ((nins >= MAX_SAMPLES) || (!nins)) continue; |
366 | if (m_nSamples < nins) m_nSamples = nins; | 366 | if (m_nSamples < nins) m_nSamples = nins; |
367 | MODINSTRUMENT *pins = &Ins[nins]; | 367 | MODINSTRUMENT *pins = &Ins[nins]; |
368 | memcpy(m_szNames[nins], lpStream+dwPos+1, 32); | 368 | memcpy(m_szNames[nins], lpStream+dwPos+1, 32); |
369 | memcpy(pins->name, lpStream+dwPos+33, 8); | 369 | memcpy(pins->name, lpStream+dwPos+33, 8); |
370 | pins->nC4Speed = *((DWORD *)(lpStream+dwPos+41)); | 370 | pins->nC4Speed = *((DWORD *)(lpStream+dwPos+41)); |
371 | pins->nLength = *((DWORD *)(lpStream+dwPos+45)); | 371 | pins->nLength = *((DWORD *)(lpStream+dwPos+45)); |
372 | pins->nLoopStart = *((DWORD *)(lpStream+dwPos+49)); | 372 | pins->nLoopStart = *((DWORD *)(lpStream+dwPos+49)); |
373 | pins->nLoopEnd = pins->nLoopStart + *((DWORD *)(lpStream+dwPos+53)); | 373 | pins->nLoopEnd = pins->nLoopStart + *((DWORD *)(lpStream+dwPos+53)); |
374 | if (pins->nLoopEnd > pins->nLoopStart) pins->uFlags |= CHN_LOOP; | 374 | if (pins->nLoopEnd > pins->nLoopStart) pins->uFlags |= CHN_LOOP; |
375 | pins->nGlobalVol = 64; | 375 | pins->nGlobalVol = 64; |
376 | if (lpStream[dwPos+58] & 0x01) | 376 | if (lpStream[dwPos+58] & 0x01) |
377 | { | 377 | { |
378 | pins->uFlags |= CHN_16BIT; | 378 | pins->uFlags |= CHN_16BIT; |
379 | pins->nLength >>= 1; | 379 | pins->nLength >>= 1; |
380 | pins->nLoopStart >>= 1; | 380 | pins->nLoopStart >>= 1; |
381 | pins->nLoopEnd >>= 1; | 381 | pins->nLoopEnd >>= 1; |
382 | } | 382 | } |
383 | if (lpStream[dwPos+58] & 0x02) pins->uFlags |= CHN_PINGPONGLOOP; | 383 | if (lpStream[dwPos+58] & 0x02) pins->uFlags |= CHN_PINGPONGLOOP; |
384 | smpinfo[nins] = (lpStream[dwPos+58] >> 2) & 3; | 384 | smpinfo[nins] = (lpStream[dwPos+58] >> 2) & 3; |
385 | } | 385 | } |
386 | break; | 386 | break; |
387 | // SA: Sample Data | 387 | // SA: Sample Data |
388 | case 0x4153: | 388 | case 0x4153: |
389 | dwPos = dwMemPos; | 389 | dwPos = dwMemPos; |
390 | for (i=1; i<=m_nSamples; i++) if ((Ins[i].nLength) && (!Ins[i].pSample) && (smpinfo[i] != 3) && (dwPos < dwMemLength)) | 390 | for (i=1; i<=m_nSamples; i++) if ((Ins[i].nLength) && (!Ins[i].pSample) && (smpinfo[i] != 3) && (dwPos < dwMemLength)) |
391 | { | 391 | { |
392 | MODINSTRUMENT *pins = &Ins[i]; | 392 | MODINSTRUMENT *pins = &Ins[i]; |
393 | UINT flags = (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; | 393 | UINT flags = (pins->uFlags & CHN_16BIT) ? RS_PCM16S : RS_PCM8S; |
394 | if (!smpinfo[i]) | 394 | if (!smpinfo[i]) |
395 | { | 395 | { |
396 | dwPos += ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwMemLength - dwPos); | 396 | dwPos += ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwMemLength - dwPos); |
397 | } else | 397 | } else |
398 | { | 398 | { |
399 | DWORD dwLen = *((DWORD *)(lpStream+dwPos)); | 399 | DWORD dwLen = *((DWORD *)(lpStream+dwPos)); |
400 | dwPos += 4; | 400 | dwPos += 4; |
401 | if ((dwPos+dwLen <= dwMemLength) && (dwLen > 4)) | 401 | if ((dwPos+dwLen <= dwMemLength) && (dwLen > 4)) |
402 | { | 402 | { |
403 | flags = (pins->uFlags & CHN_16BIT) ? RS_MDL16 : RS_MDL8; | 403 | flags = (pins->uFlags & CHN_16BIT) ? RS_MDL16 : RS_MDL8; |
404 | ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwLen); | 404 | ReadSample(pins, flags, (LPSTR)(lpStream+dwPos), dwLen); |
405 | } | 405 | } |
406 | dwPos += dwLen; | 406 | dwPos += dwLen; |
407 | } | 407 | } |
408 | } | 408 | } |
409 | break; | 409 | break; |
410 | } | 410 | } |
411 | dwMemPos += blocklen; | 411 | dwMemPos += blocklen; |
412 | } | 412 | } |
413 | // Unpack Patterns | 413 | // Unpack Patterns |
414 | if ((dwTrackPos) && (npatterns) && (m_nChannels) && (ntracks)) | 414 | if ((dwTrackPos) && (npatterns) && (m_nChannels) && (ntracks)) |
415 | { | 415 | { |
416 | for (UINT ipat=0; ipat<npatterns; ipat++) | 416 | for (UINT ipat=0; ipat<npatterns; ipat++) |
417 | { | 417 | { |
418 | if ((Patterns[ipat] = AllocatePattern(PatternSize[ipat], m_nChannels)) == NULL) break; | 418 | if ((Patterns[ipat] = AllocatePattern(PatternSize[ipat], m_nChannels)) == NULL) break; |
419 | for (UINT chn=0; chn<m_nChannels; chn++) if ((patterntracks[ipat*32+chn]) && (patterntracks[ipat*32+chn] <= ntracks)) | 419 | for (UINT chn=0; chn<m_nChannels; chn++) if ((patterntracks[ipat*32+chn]) && (patterntracks[ipat*32+chn] <= ntracks)) |
420 | { | 420 | { |
421 | MODCOMMAND *m = Patterns[ipat] + chn; | 421 | MODCOMMAND *m = Patterns[ipat] + chn; |
422 | UnpackMDLTrack(m, m_nChannels, PatternSize[ipat], patterntracks[ipat*32+chn], lpStream+dwTrackPos); | 422 | UnpackMDLTrack(m, m_nChannels, PatternSize[ipat], patterntracks[ipat*32+chn], lpStream+dwTrackPos); |
423 | } | 423 | } |
424 | } | 424 | } |
425 | } | 425 | } |
426 | // Set up envelopes | 426 | // Set up envelopes |
427 | for (UINT iIns=1; iIns<=m_nInstruments; iIns++) if (Headers[iIns]) | 427 | for (UINT iIns=1; iIns<=m_nInstruments; iIns++) if (Headers[iIns]) |
428 | { | 428 | { |
429 | INSTRUMENTHEADER *penv = Headers[iIns]; | 429 | INSTRUMENTHEADER *penv = Headers[iIns]; |
430 | // Setup volume envelope | 430 | // Setup volume envelope |
431 | if ((nvolenv) && (pvolenv) && (insvolenv[iIns])) | 431 | if ((nvolenv) && (pvolenv) && (insvolenv[iIns])) |
432 | { | 432 | { |
433 | LPCBYTE pve = pvolenv; | 433 | LPCBYTE pve = pvolenv; |
434 | for (UINT nve=0; nve<nvolenv; nve++, pve+=33) if (pve[0]+1 == insvolenv[iIns]) | 434 | for (UINT nve=0; nve<nvolenv; nve++, pve+=33) if (pve[0]+1 == insvolenv[iIns]) |
435 | { | 435 | { |
436 | WORD vtick = 1; | 436 | WORD vtick = 1; |
437 | penv->nVolEnv = 15; | 437 | penv->nVolEnv = 15; |
438 | for (UINT iv=0; iv<15; iv++) | 438 | for (UINT iv=0; iv<15; iv++) |
439 | { | 439 | { |
440 | if (iv) vtick += pve[iv*2+1]; | 440 | if (iv) vtick += pve[iv*2+1]; |
441 | penv->VolPoints[iv] = vtick; | 441 | penv->VolPoints[iv] = vtick; |
442 | penv->VolEnv[iv] = pve[iv*2+2]; | 442 | penv->VolEnv[iv] = pve[iv*2+2]; |
443 | if (!pve[iv*2+1]) | 443 | if (!pve[iv*2+1]) |
444 | { | 444 | { |
445 | penv->nVolEnv = iv+1; | 445 | penv->nVolEnv = iv+1; |
446 | break; | 446 | break; |
447 | } | 447 | } |
448 | } | 448 | } |
449 | penv->nVolSustainBegin = penv->nVolSustainEnd = pve[31] & 0x0F; | 449 | penv->nVolSustainBegin = penv->nVolSustainEnd = pve[31] & 0x0F; |
450 | if (pve[31] & 0x10) penv->dwFlags |= ENV_VOLSUSTAIN; | 450 | if (pve[31] & 0x10) penv->dwFlags |= ENV_VOLSUSTAIN; |
451 | if (pve[31] & 0x20) penv->dwFlags |= ENV_VOLLOOP; | 451 | if (pve[31] & 0x20) penv->dwFlags |= ENV_VOLLOOP; |
452 | penv->nVolLoopStart = pve[32] & 0x0F; | 452 | penv->nVolLoopStart = pve[32] & 0x0F; |
453 | penv->nVolLoopEnd = pve[32] >> 4; | 453 | penv->nVolLoopEnd = pve[32] >> 4; |
454 | } | 454 | } |
455 | } | 455 | } |
456 | // Setup panning envelope | 456 | // Setup panning envelope |
457 | if ((npanenv) && (ppanenv) && (inspanenv[iIns])) | 457 | if ((npanenv) && (ppanenv) && (inspanenv[iIns])) |
458 | { | 458 | { |
459 | LPCBYTE ppe = ppanenv; | 459 | LPCBYTE ppe = ppanenv; |
460 | for (UINT npe=0; npe<npanenv; npe++, ppe+=33) if (ppe[0]+1 == inspanenv[iIns]) | 460 | for (UINT npe=0; npe<npanenv; npe++, ppe+=33) if (ppe[0]+1 == inspanenv[iIns]) |
461 | { | 461 | { |
462 | WORD vtick = 1; | 462 | WORD vtick = 1; |
463 | penv->nPanEnv = 15; | 463 | penv->nPanEnv = 15; |
464 | for (UINT iv=0; iv<15; iv++) | 464 | for (UINT iv=0; iv<15; iv++) |
465 | { | 465 | { |
466 | if (iv) vtick += ppe[iv*2+1]; | 466 | if (iv) vtick += ppe[iv*2+1]; |
467 | penv->PanPoints[iv] = vtick; | 467 | penv->PanPoints[iv] = vtick; |
468 | penv->PanEnv[iv] = ppe[iv*2+2]; | 468 | penv->PanEnv[iv] = ppe[iv*2+2]; |
469 | if (!ppe[iv*2+1]) | 469 | if (!ppe[iv*2+1]) |
470 | { | 470 | { |
471 | penv->nPanEnv = iv+1; | 471 | penv->nPanEnv = iv+1; |
472 | break; | 472 | break; |
473 | } | 473 | } |
474 | } | 474 | } |
475 | if (ppe[31] & 0x10) penv->dwFlags |= ENV_PANSUSTAIN; | 475 | if (ppe[31] & 0x10) penv->dwFlags |= ENV_PANSUSTAIN; |
476 | if (ppe[31] & 0x20) penv->dwFlags |= ENV_PANLOOP; | 476 | if (ppe[31] & 0x20) penv->dwFlags |= ENV_PANLOOP; |
477 | penv->nPanLoopStart = ppe[32] & 0x0F; | 477 | penv->nPanLoopStart = ppe[32] & 0x0F; |
478 | penv->nPanLoopEnd = ppe[32] >> 4; | 478 | penv->nPanLoopEnd = ppe[32] >> 4; |
479 | } | 479 | } |
480 | } | 480 | } |
481 | } | 481 | } |
482 | m_dwSongFlags |= SONG_LINEARSLIDES; | 482 | m_dwSongFlags |= SONG_LINEARSLIDES; |
483 | m_nType = MOD_TYPE_MDL; | 483 | m_nType = MOD_TYPE_MDL; |
484 | return TRUE; | 484 | return TRUE; |
485 | } | 485 | } |
486 | 486 | ||
487 | 487 | ||
488 | ///////////////////////////////////////////////////////////////////////// | 488 | ///////////////////////////////////////////////////////////////////////// |
489 | // MDL Sample Unpacking | 489 | // MDL Sample Unpacking |
490 | 490 | ||
491 | // MDL Huffman ReadBits compression | 491 | // MDL Huffman ReadBits compression |
492 | WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n) | 492 | WORD MDLReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n) |
493 | //----------------------------------------------------------------- | 493 | //----------------------------------------------------------------- |
494 | { | 494 | { |
495 | WORD v = (WORD)(bitbuf & ((1 << n) - 1) ); | 495 | WORD v = (WORD)(bitbuf & ((1 << n) - 1) ); |
496 | bitbuf >>= n; | 496 | bitbuf >>= n; |
497 | bitnum -= n; | 497 | bitnum -= n; |
498 | if (bitnum <= 24) | 498 | if (bitnum <= 24) |
499 | { | 499 | { |
500 | bitbuf |= (((DWORD)(*ibuf++)) << bitnum); | 500 | bitbuf |= (((DWORD)(*ibuf++)) << bitnum); |
501 | bitnum += 8; | 501 | bitnum += 8; |
502 | } | 502 | } |
503 | return v; | 503 | return v; |
504 | } | 504 | } |
505 | 505 | ||
506 | 506 | ||