Diffstat (limited to 'core/multimedia/opieplayer/modplug/load_it.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/modplug/load_it.cpp | 1415 |
1 files changed, 1415 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_it.cpp b/core/multimedia/opieplayer/modplug/load_it.cpp new file mode 100644 index 0000000..006b746 --- a/dev/null +++ b/core/multimedia/opieplayer/modplug/load_it.cpp | |||
@@ -0,0 +1,1415 @@ | |||
1 | /* | ||
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 | ||
4 | * Free Software Foundation; either version 2 of the license or (at your | ||
5 | * option) any later version. | ||
6 | * | ||
7 | * Authors: Olivier Lapicque <olivierl@jps.net>, | ||
8 | * Adam Goode <adam@evdebs.org> (endian and char fixes for PPC) | ||
9 | */ | ||
10 | |||
11 | #include "stdafx.h" | ||
12 | #include "sndfile.h" | ||
13 | #include "it_defs.h" | ||
14 | |||
15 | #ifdef WIN32 | ||
16 | #pragma warning(disable:4244) | ||
17 | #endif | ||
18 | |||
19 | const BYTE autovibit2xm[8] = | ||
20 | { 0, 3, 1, 4, 2, 0, 0, 0 }; | ||
21 | |||
22 | const BYTE autovibxm2it[8] = | ||
23 | { 0, 2, 4, 1, 3, 0, 0, 0 }; | ||
24 | |||
25 | ////////////////////////////////////////////////////////// | ||
26 | // Impulse Tracker IT file support (import only) | ||
27 | |||
28 | |||
29 | static inline UINT ConvertVolParam(UINT value) | ||
30 | //-------------------------------------------- | ||
31 | { | ||
32 | return (value > 9) ? 9 : value; | ||
33 | } | ||
34 | |||
35 | |||
36 | BOOL CSoundFile::ITInstrToMPT(const void *p, INSTRUMENTHEADER *penv, UINT trkvers) | ||
37 | //-------------------------------------------------------------------------------- | ||
38 | { | ||
39 | if (trkvers < 0x0200) | ||
40 | { | ||
41 | const ITOLDINSTRUMENT *pis = (const ITOLDINSTRUMENT *)p; | ||
42 | memcpy(penv->name, pis->name, 26); | ||
43 | memcpy(penv->filename, pis->filename, 12); | ||
44 | penv->nFadeOut = bswapLE16(pis->fadeout) << 6; | ||
45 | penv->nGlobalVol = 64; | ||
46 | for (UINT j=0; j<120; j++) | ||
47 | { | ||
48 | UINT note = pis->keyboard[j*2]; | ||
49 | UINT ins = pis->keyboard[j*2+1]; | ||
50 | if (ins < MAX_SAMPLES) penv->Keyboard[j] = ins; | ||
51 | if (note < 128) penv->NoteMap[j] = note+1; | ||
52 | else if (note >= 0xFE) penv->NoteMap[j] = note; | ||
53 | } | ||
54 | if (pis->flags & 0x01) penv->dwFlags |= ENV_VOLUME; | ||
55 | if (pis->flags & 0x02) penv->dwFlags |= ENV_VOLLOOP; | ||
56 | if (pis->flags & 0x04) penv->dwFlags |= ENV_VOLSUSTAIN; | ||
57 | penv->nVolLoopStart = pis->vls; | ||
58 | penv->nVolLoopEnd = pis->vle; | ||
59 | penv->nVolSustainBegin = pis->sls; | ||
60 | penv->nVolSustainEnd = pis->sle; | ||
61 | penv->nVolEnv = 25; | ||
62 | for (UINT ev=0; ev<25; ev++) | ||
63 | { | ||
64 | if ((penv->VolPoints[ev] = pis->nodes[ev*2]) == 0xFF) | ||
65 | { | ||
66 | penv->nVolEnv = ev; | ||
67 | break; | ||
68 | } | ||
69 | penv->VolEnv[ev] = pis->nodes[ev*2+1]; | ||
70 | } | ||
71 | penv->nNNA = pis->nna; | ||
72 | penv->nDCT = pis->dnc; | ||
73 | penv->nPan = 0x80; | ||
74 | } else | ||
75 | { | ||
76 | const ITINSTRUMENT *pis = (const ITINSTRUMENT *)p; | ||
77 | memcpy(penv->name, pis->name, 26); | ||
78 | memcpy(penv->filename, pis->filename, 12); | ||
79 | penv->nMidiProgram = pis->mpr; | ||
80 | penv->nMidiChannel = pis->mch; | ||
81 | penv->wMidiBank = bswapLE16(pis->mbank); | ||
82 | penv->nFadeOut = bswapLE16(pis->fadeout) << 5; | ||
83 | penv->nGlobalVol = pis->gbv >> 1; | ||
84 | if (penv->nGlobalVol > 64) penv->nGlobalVol = 64; | ||
85 | for (UINT j=0; j<120; j++) | ||
86 | { | ||
87 | UINT note = pis->keyboard[j*2]; | ||
88 | UINT ins = pis->keyboard[j*2+1]; | ||
89 | if (ins < MAX_SAMPLES) penv->Keyboard[j] = ins; | ||
90 | if (note < 128) penv->NoteMap[j] = note+1; | ||
91 | else if (note >= 0xFE) penv->NoteMap[j] = note; | ||
92 | } | ||
93 | // Volume Envelope | ||
94 | if (pis->volenv.flags & 1) penv->dwFlags |= ENV_VOLUME; | ||
95 | if (pis->volenv.flags & 2) penv->dwFlags |= ENV_VOLLOOP; | ||
96 | if (pis->volenv.flags & 4) penv->dwFlags |= ENV_VOLSUSTAIN; | ||
97 | if (pis->volenv.flags & 8) penv->dwFlags |= ENV_VOLCARRY; | ||
98 | penv->nVolEnv = pis->volenv.num; | ||
99 | if (penv->nVolEnv > 25) penv->nVolEnv = 25; | ||
100 | |||
101 | penv->nVolLoopStart = pis->volenv.lpb; | ||
102 | penv->nVolLoopEnd = pis->volenv.lpe; | ||
103 | penv->nVolSustainBegin = pis->volenv.slb; | ||
104 | penv->nVolSustainEnd = pis->volenv.sle; | ||
105 | // Panning Envelope | ||
106 | if (pis->panenv.flags & 1) penv->dwFlags |= ENV_PANNING; | ||
107 | if (pis->panenv.flags & 2) penv->dwFlags |= ENV_PANLOOP; | ||
108 | if (pis->panenv.flags & 4) penv->dwFlags |= ENV_PANSUSTAIN; | ||
109 | if (pis->panenv.flags & 8) penv->dwFlags |= ENV_PANCARRY; | ||
110 | penv->nPanEnv = pis->panenv.num; | ||
111 | if (penv->nPanEnv > 25) penv->nPanEnv = 25; | ||
112 | penv->nPanLoopStart = pis->panenv.lpb; | ||
113 | penv->nPanLoopEnd = pis->panenv.lpe; | ||
114 | penv->nPanSustainBegin = pis->panenv.slb; | ||
115 | penv->nPanSustainEnd = pis->panenv.sle; | ||
116 | // Pitch Envelope | ||
117 | if (pis->pitchenv.flags & 1) penv->dwFlags |= ENV_PITCH; | ||
118 | if (pis->pitchenv.flags & 2) penv->dwFlags |= ENV_PITCHLOOP; | ||
119 | if (pis->pitchenv.flags & 4) penv->dwFlags |= ENV_PITCHSUSTAIN; | ||
120 | if (pis->pitchenv.flags & 8) penv->dwFlags |= ENV_PITCHCARRY; | ||
121 | if (pis->pitchenv.flags & 0x80) penv->dwFlags |= ENV_FILTER; | ||
122 | penv->nPitchEnv = pis->pitchenv.num; | ||
123 | if (penv->nPitchEnv > 25) penv->nPitchEnv = 25; | ||
124 | penv->nPitchLoopStart = pis->pitchenv.lpb; | ||
125 | penv->nPitchLoopEnd = pis->pitchenv.lpe; | ||
126 | penv->nPitchSustainBegin = pis->pitchenv.slb; | ||
127 | penv->nPitchSustainEnd = pis->pitchenv.sle; | ||
128 | // Envelopes Data | ||
129 | for (UINT ev=0; ev<25; ev++) | ||
130 | { | ||
131 | penv->VolEnv[ev] = pis->volenv.data[ev*3]; | ||
132 | penv->VolPoints[ev] = (pis->volenv.data[ev*3+2] << 8) | (pis->volenv.data[ev*3+1]); | ||
133 | penv->PanEnv[ev] = pis->panenv.data[ev*3] + 32; | ||
134 | penv->PanPoints[ev] = (pis->panenv.data[ev*3+2] << 8) | (pis->panenv.data[ev*3+1]); | ||
135 | penv->PitchEnv[ev] = pis->pitchenv.data[ev*3] + 32; | ||
136 | penv->PitchPoints[ev] = (pis->pitchenv.data[ev*3+2] << 8) | (pis->pitchenv.data[ev*3+1]); | ||
137 | } | ||
138 | penv->nNNA = pis->nna; | ||
139 | penv->nDCT = pis->dct; | ||
140 | penv->nDNA = pis->dca; | ||
141 | penv->nPPS = pis->pps; | ||
142 | penv->nPPC = pis->ppc; | ||
143 | penv->nIFC = pis->ifc; | ||
144 | penv->nIFR = pis->ifr; | ||
145 | penv->nVolSwing = pis->rv; | ||
146 | penv->nPanSwing = pis->rp; | ||
147 | penv->nPan = (pis->dfp & 0x7F) << 2; | ||
148 | if (penv->nPan > 256) penv->nPan = 128; | ||
149 | if (pis->dfp < 0x80) penv->dwFlags |= ENV_SETPANNING; | ||
150 | } | ||
151 | if ((penv->nVolLoopStart >= 25) || (penv->nVolLoopEnd >= 25)) penv->dwFlags &= ~ENV_VOLLOOP; | ||
152 | if ((penv->nVolSustainBegin >= 25) || (penv->nVolSustainEnd >= 25)) penv->dwFlags &= ~ENV_VOLSUSTAIN; | ||
153 | return TRUE; | ||
154 | } | ||
155 | |||
156 | |||
157 | BOOL CSoundFile::ReadIT(const BYTE *lpStream, DWORD dwMemLength) | ||
158 | //-------------------------------------------------------------- | ||
159 | { | ||
160 | ITFILEHEADER pifh = *(ITFILEHEADER *)lpStream; | ||
161 | DWORD dwMemPos = sizeof(ITFILEHEADER); | ||
162 | DWORD inspos[MAX_INSTRUMENTS]; | ||
163 | DWORD smppos[MAX_SAMPLES]; | ||
164 | DWORD patpos[MAX_PATTERNS]; | ||
165 | BYTE chnmask[64], channels_used[64]; | ||
166 | MODCOMMAND lastvalue[64]; | ||
167 | |||
168 | pifh.id = bswapLE32(pifh.id); | ||
169 | pifh.reserved1 = bswapLE16(pifh.reserved1); | ||
170 | pifh.ordnum = bswapLE16(pifh.ordnum); | ||
171 | pifh.insnum = bswapLE16(pifh.insnum); | ||
172 | pifh.smpnum = bswapLE16(pifh.smpnum); | ||
173 | pifh.patnum = bswapLE16(pifh.patnum); | ||
174 | pifh.cwtv = bswapLE16(pifh.cwtv); | ||
175 | pifh.cmwt = bswapLE16(pifh.cmwt); | ||
176 | pifh.flags = bswapLE16(pifh.flags); | ||
177 | pifh.special = bswapLE16(pifh.special); | ||
178 | pifh.msglength = bswapLE16(pifh.msglength); | ||
179 | pifh.msgoffset = bswapLE32(pifh.msgoffset); | ||
180 | pifh.reserved2 = bswapLE32(pifh.reserved2); | ||
181 | |||
182 | if ((!lpStream) || (dwMemLength < 0x100)) return FALSE; | ||
183 | if ((pifh.id != 0x4D504D49) || (pifh.insnum >= MAX_INSTRUMENTS) | ||
184 | || (!pifh.smpnum) || (pifh.smpnum >= MAX_INSTRUMENTS) || (!pifh.ordnum)) return FALSE; | ||
185 | if (dwMemPos + pifh.ordnum + pifh.insnum*4 | ||
186 | + pifh.smpnum*4 + pifh.patnum*4 > dwMemLength) return FALSE; | ||
187 | m_nType = MOD_TYPE_IT; | ||
188 | if (pifh.flags & 0x08) m_dwSongFlags |= SONG_LINEARSLIDES; | ||
189 | if (pifh.flags & 0x10) m_dwSongFlags |= SONG_ITOLDEFFECTS; | ||
190 | if (pifh.flags & 0x20) m_dwSongFlags |= SONG_ITCOMPATMODE; | ||
191 | if (pifh.flags & 0x80) m_dwSongFlags |= SONG_EMBEDMIDICFG; | ||
192 | if (pifh.flags & 0x1000) m_dwSongFlags |= SONG_EXFILTERRANGE; | ||
193 | memcpy(m_szNames[0], pifh.songname, 26); | ||
194 | m_szNames[0][26] = 0; | ||
195 | // Global Volume | ||
196 | if (pifh.globalvol) | ||
197 | { | ||
198 | m_nDefaultGlobalVolume = pifh.globalvol << 1; | ||
199 | if (!m_nDefaultGlobalVolume) m_nDefaultGlobalVolume = 256; | ||
200 | if (m_nDefaultGlobalVolume > 256) m_nDefaultGlobalVolume = 256; | ||
201 | } | ||
202 | if (pifh.speed) m_nDefaultSpeed = pifh.speed; | ||
203 | if (pifh.tempo) m_nDefaultTempo = pifh.tempo; | ||
204 | m_nSongPreAmp = pifh.mv & 0x7F; | ||
205 | // Reading Channels Pan Positions | ||
206 | for (int ipan=0; ipan<64; ipan++) if (pifh.chnpan[ipan] != 0xFF) | ||
207 | { | ||
208 | ChnSettings[ipan].nVolume = pifh.chnvol[ipan]; | ||
209 | ChnSettings[ipan].nPan = 128; | ||
210 | if (pifh.chnpan[ipan] & 0x80) ChnSettings[ipan].dwFlags |= CHN_MUTE; | ||
211 | UINT n = pifh.chnpan[ipan] & 0x7F; | ||
212 | if (n <= 64) ChnSettings[ipan].nPan = n << 2; | ||
213 | if (n == 100) ChnSettings[ipan].dwFlags |= CHN_SURROUND; | ||
214 | } | ||
215 | if (m_nChannels < 4) m_nChannels = 4; | ||
216 | // Reading Song Message | ||
217 | if ((pifh.special & 0x01) && (pifh.msglength) && (pifh.msgoffset + pifh.msglength < dwMemLength)) | ||
218 | { | ||
219 | m_lpszSongComments = new char[pifh.msglength+1]; | ||
220 | if (m_lpszSongComments) | ||
221 | { | ||
222 | memcpy(m_lpszSongComments, lpStream+pifh.msgoffset, pifh.msglength); | ||
223 | m_lpszSongComments[pifh.msglength] = 0; | ||
224 | } | ||
225 | } | ||
226 | // Reading orders | ||
227 | UINT nordsize = pifh.ordnum; | ||
228 | if (nordsize > MAX_ORDERS) nordsize = MAX_ORDERS; | ||
229 | memcpy(Order, lpStream+dwMemPos, nordsize); | ||
230 | dwMemPos += pifh.ordnum; | ||
231 | // Reading Instrument Offsets | ||
232 | memset(inspos, 0, sizeof(inspos)); | ||
233 | UINT inspossize = pifh.insnum; | ||
234 | if (inspossize > MAX_INSTRUMENTS) inspossize = MAX_INSTRUMENTS; | ||
235 | inspossize <<= 2; | ||
236 | memcpy(inspos, lpStream+dwMemPos, inspossize); | ||
237 | for (UINT j=0; j < (inspossize>>2); j++) | ||
238 | { | ||
239 | inspos[j] = bswapLE32(inspos[j]); | ||
240 | } | ||
241 | dwMemPos += pifh.insnum * 4; | ||
242 | // Reading Samples Offsets | ||
243 | memset(smppos, 0, sizeof(smppos)); | ||
244 | UINT smppossize = pifh.smpnum; | ||
245 | if (smppossize > MAX_SAMPLES) smppossize = MAX_SAMPLES; | ||
246 | smppossize <<= 2; | ||
247 | memcpy(smppos, lpStream+dwMemPos, smppossize); | ||
248 | for (UINT j=0; j < (smppossize>>2); j++) | ||
249 | { | ||
250 | smppos[j] = bswapLE32(smppos[j]); | ||
251 | } | ||
252 | dwMemPos += pifh.smpnum * 4; | ||
253 | // Reading Patterns Offsets | ||
254 | memset(patpos, 0, sizeof(patpos)); | ||
255 | UINT patpossize = pifh.patnum; | ||
256 | if (patpossize > MAX_PATTERNS) patpossize = MAX_PATTERNS; | ||
257 | patpossize <<= 2; | ||
258 | memcpy(patpos, lpStream+dwMemPos, patpossize); | ||
259 | for (UINT j=0; j < (patpossize>>2); j++) | ||
260 | { | ||
261 | patpos[j] = bswapLE32(patpos[j]); | ||
262 | } | ||
263 | dwMemPos += pifh.patnum * 4; | ||
264 | // Reading IT Extra Info | ||
265 | if (dwMemPos + 2 < dwMemLength) | ||
266 | { | ||
267 | UINT nflt = bswapLE16(*((WORD *)(lpStream + dwMemPos))); | ||
268 | dwMemPos += 2; | ||
269 | if (dwMemPos + nflt * 8 < dwMemLength) dwMemPos += nflt * 8; | ||
270 | } | ||
271 | // Reading Midi Output & Macros | ||
272 | if (m_dwSongFlags & SONG_EMBEDMIDICFG) | ||
273 | { | ||
274 | if (dwMemPos + sizeof(MODMIDICFG) < dwMemLength) | ||
275 | { | ||
276 | memcpy(&m_MidiCfg, lpStream+dwMemPos, sizeof(MODMIDICFG)); | ||
277 | dwMemPos += sizeof(MODMIDICFG); | ||
278 | } | ||
279 | } | ||
280 | // Read pattern names: "PNAM" | ||
281 | if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e50)) | ||
282 | { | ||
283 | UINT len = bswapLE32(*((DWORD *)(lpStream+dwMemPos+4))); | ||
284 | dwMemPos += 8; | ||
285 | if ((dwMemPos + len <= dwMemLength) && (len <= MAX_PATTERNS*MAX_PATTERNNAME) && (len >= MAX_PATTERNNAME)) | ||
286 | { | ||
287 | m_lpszPatternNames = new char[len]; | ||
288 | if (m_lpszPatternNames) | ||
289 | { | ||
290 | m_nPatternNames = len / MAX_PATTERNNAME; | ||
291 | memcpy(m_lpszPatternNames, lpStream+dwMemPos, len); | ||
292 | } | ||
293 | dwMemPos += len; | ||
294 | } | ||
295 | } | ||
296 | // 4-channels minimum | ||
297 | m_nChannels = 4; | ||
298 | // Read channel names: "CNAM" | ||
299 | if ((dwMemPos + 8 < dwMemLength) && (bswapLE32(*((DWORD *)(lpStream+dwMemPos))) == 0x4d414e43)) | ||
300 | { | ||
301 | UINT len = bswapLE32(*((DWORD *)(lpStream+dwMemPos+4))); | ||
302 | dwMemPos += 8; | ||
303 | if ((dwMemPos + len <= dwMemLength) && (len <= 64*MAX_CHANNELNAME)) | ||
304 | { | ||
305 | UINT n = len / MAX_CHANNELNAME; | ||
306 | if (n > m_nChannels) m_nChannels = n; | ||
307 | for (UINT i=0; i<n; i++) | ||
308 | { | ||
309 | memcpy(ChnSettings[i].szName, (lpStream+dwMemPos+i*MAX_CHANNELNAME), MAX_CHANNELNAME); | ||
310 | ChnSettings[i].szName[MAX_CHANNELNAME-1] = 0; | ||
311 | } | ||
312 | dwMemPos += len; | ||
313 | } | ||
314 | } | ||
315 | // Read mix plugins information | ||
316 | if (dwMemPos + 8 < dwMemLength) | ||
317 | { | ||
318 | dwMemPos += LoadMixPlugins(lpStream+dwMemPos, dwMemLength-dwMemPos); | ||
319 | } | ||
320 | // Checking for unused channels | ||
321 | UINT npatterns = pifh.patnum; | ||
322 | if (npatterns > MAX_PATTERNS) npatterns = MAX_PATTERNS; | ||
323 | for (UINT patchk=0; patchk<npatterns; patchk++) | ||
324 | { | ||
325 | memset(chnmask, 0, sizeof(chnmask)); | ||
326 | if ((!patpos[patchk]) || ((DWORD)patpos[patchk] + 4 >= dwMemLength)) continue; | ||
327 | UINT len = bswapLE16(*((WORD *)(lpStream+patpos[patchk]))); | ||
328 | UINT rows = bswapLE16(*((WORD *)(lpStream+patpos[patchk]+2))); | ||
329 | if ((rows < 4) || (rows > 256)) continue; | ||
330 | if (patpos[patchk]+8+len > dwMemLength) continue; | ||
331 | UINT i = 0; | ||
332 | const BYTE *p = lpStream+patpos[patchk]+8; | ||
333 | UINT nrow = 0; | ||
334 | while (nrow<rows) | ||
335 | { | ||
336 | if (i >= len) break; | ||
337 | BYTE b = p[i++]; | ||
338 | if (!b) | ||
339 | { | ||
340 | nrow++; | ||
341 | continue; | ||
342 | } | ||
343 | UINT ch = b & 0x7F; | ||
344 | if (ch) ch = (ch - 1) & 0x3F; | ||
345 | if (b & 0x80) | ||
346 | { | ||
347 | if (i >= len) break; | ||
348 | chnmask[ch] = p[i++]; | ||
349 | } | ||
350 | // Channel used | ||
351 | if (chnmask[ch] & 0x0F) | ||
352 | { | ||
353 | if ((ch >= m_nChannels) && (ch < 64)) m_nChannels = ch+1; | ||
354 | } | ||
355 | // Note | ||
356 | if (chnmask[ch] & 1) i++; | ||
357 | // Instrument | ||
358 | if (chnmask[ch] & 2) i++; | ||
359 | // Volume | ||
360 | if (chnmask[ch] & 4) i++; | ||
361 | // Effect | ||
362 | if (chnmask[ch] & 8) i += 2; | ||
363 | if (i >= len) break; | ||
364 | } | ||
365 | } | ||
366 | // Reading Instruments | ||
367 | m_nInstruments = 0; | ||
368 | if (pifh.flags & 0x04) m_nInstruments = pifh.insnum; | ||
369 | if (m_nInstruments >= MAX_INSTRUMENTS) m_nInstruments = MAX_INSTRUMENTS-1; | ||
370 | for (UINT nins=0; nins<m_nInstruments; nins++) | ||
371 | { | ||
372 | if ((inspos[nins] > 0) && (inspos[nins] < dwMemLength - sizeof(ITOLDINSTRUMENT))) | ||
373 | { | ||
374 | INSTRUMENTHEADER *penv = new INSTRUMENTHEADER; | ||
375 | if (!penv) continue; | ||
376 | Headers[nins+1] = penv; | ||
377 | memset(penv, 0, sizeof(INSTRUMENTHEADER)); | ||
378 | ITInstrToMPT(lpStream + inspos[nins], penv, pifh.cmwt); | ||
379 | } | ||
380 | } | ||
381 | // Reading Samples | ||
382 | m_nSamples = pifh.smpnum; | ||
383 | if (m_nSamples >= MAX_SAMPLES) m_nSamples = MAX_SAMPLES-1; | ||
384 | for (UINT nsmp=0; nsmp<pifh.smpnum; nsmp++) if ((smppos[nsmp]) && (smppos[nsmp] + sizeof(ITSAMPLESTRUCT) <= dwMemLength)) | ||
385 | { | ||
386 | ITSAMPLESTRUCT pis = *(ITSAMPLESTRUCT *)(lpStream+smppos[nsmp]); | ||
387 | pis.id = bswapLE32(pis.id); | ||
388 | pis.length = bswapLE32(pis.length); | ||
389 | pis.loopbegin = bswapLE32(pis.loopbegin); | ||
390 | pis.loopend = bswapLE32(pis.loopend); | ||
391 | pis.C5Speed = bswapLE32(pis.C5Speed); | ||
392 | pis.susloopbegin = bswapLE32(pis.susloopbegin); | ||
393 | pis.susloopend = bswapLE32(pis.susloopend); | ||
394 | pis.samplepointer = bswapLE32(pis.samplepointer); | ||
395 | |||
396 | if (pis.id == 0x53504D49) | ||
397 | { | ||
398 | MODINSTRUMENT *pins = &Ins[nsmp+1]; | ||
399 | memcpy(pins->name, pis.filename, 12); | ||
400 | pins->uFlags = 0; | ||
401 | pins->nLength = 0; | ||
402 | pins->nLoopStart = pis.loopbegin; | ||
403 | pins->nLoopEnd = pis.loopend; | ||
404 | pins->nSustainStart = pis.susloopbegin; | ||
405 | pins->nSustainEnd = pis.susloopend; | ||
406 | pins->nC4Speed = pis.C5Speed; | ||
407 | if (!pins->nC4Speed) pins->nC4Speed = 8363; | ||
408 | if (pis.C5Speed < 256) pins->nC4Speed = 256; | ||
409 | pins->nVolume = pis.vol << 2; | ||
410 | if (pins->nVolume > 256) pins->nVolume = 256; | ||
411 | pins->nGlobalVol = pis.gvl; | ||
412 | if (pins->nGlobalVol > 64) pins->nGlobalVol = 64; | ||
413 | if (pis.flags & 0x10) pins->uFlags |= CHN_LOOP; | ||
414 | if (pis.flags & 0x20) pins->uFlags |= CHN_SUSTAINLOOP; | ||
415 | if (pis.flags & 0x40) pins->uFlags |= CHN_PINGPONGLOOP; | ||
416 | if (pis.flags & 0x80) pins->uFlags |= CHN_PINGPONGSUSTAIN; | ||
417 | pins->nPan = (pis.dfp & 0x7F) << 2; | ||
418 | if (pins->nPan > 256) pins->nPan = 256; | ||
419 | if (pis.dfp & 0x80) pins->uFlags |= CHN_PANNING; | ||
420 | pins->nVibType = autovibit2xm[pis.vit & 7]; | ||
421 | pins->nVibRate = pis.vis; | ||
422 | pins->nVibDepth = pis.vid & 0x7F; | ||
423 | pins->nVibSweep = (pis.vir + 3) / 4; | ||
424 | if ((pis.samplepointer) && (pis.samplepointer < dwMemLength) && (pis.length)) | ||
425 | { | ||
426 | pins->nLength = pis.length; | ||
427 | if (pins->nLength > MAX_SAMPLE_LENGTH) pins->nLength = MAX_SAMPLE_LENGTH; | ||
428 | UINT flags = (pis.cvt & 1) ? RS_PCM8S : RS_PCM8U; | ||
429 | if (pis.flags & 2) | ||
430 | { | ||
431 | flags += 5; | ||
432 | if (pis.flags & 4) flags |= RSF_STEREO; | ||
433 | pins->uFlags |= CHN_16BIT; | ||
434 | // IT 2.14 16-bit packed sample ? | ||
435 | if (pis.flags & 8) flags = ((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT21516 : RS_IT21416; | ||
436 | } else | ||
437 | { | ||
438 | if (pis.flags & 4) flags |= RSF_STEREO; | ||
439 | if (pis.cvt == 0xFF) flags = RS_ADPCM4; else | ||
440 | // IT 2.14 8-bit packed sample ? | ||
441 | if (pis.flags & 8) flags =((pifh.cmwt >= 0x215) && (pis.cvt & 4)) ? RS_IT2158 : RS_IT2148; | ||
442 | } | ||
443 | ReadSample(&Ins[nsmp+1], flags, (LPSTR)(lpStream+pis.samplepointer), dwMemLength - pis.samplepointer); | ||
444 | } | ||
445 | } | ||
446 | memcpy(m_szNames[nsmp+1], pis.name, 26); | ||
447 | } | ||
448 | // Reading Patterns | ||
449 | for (UINT npat=0; npat<npatterns; npat++) | ||
450 | { | ||
451 | if ((!patpos[npat]) || ((DWORD)patpos[npat] + 4 >= dwMemLength)) | ||
452 | { | ||
453 | PatternSize[npat] = 64; | ||
454 | Patterns[npat] = AllocatePattern(64, m_nChannels); | ||
455 | continue; | ||
456 | } | ||
457 | |||
458 | UINT len = bswapLE16(*((WORD *)(lpStream+patpos[npat]))); | ||
459 | UINT rows = bswapLE16(*((WORD *)(lpStream+patpos[npat]+2))); | ||
460 | if ((rows < 4) || (rows > 256)) continue; | ||
461 | if (patpos[npat]+8+len > dwMemLength) continue; | ||
462 | PatternSize[npat] = rows; | ||
463 | if ((Patterns[npat] = AllocatePattern(rows, m_nChannels)) == NULL) continue; | ||
464 | memset(lastvalue, 0, sizeof(lastvalue)); | ||
465 | memset(chnmask, 0, sizeof(chnmask)); | ||
466 | MODCOMMAND *m = Patterns[npat]; | ||
467 | UINT i = 0; | ||
468 | const BYTE *p = lpStream+patpos[npat]+8; | ||
469 | UINT nrow = 0; | ||
470 | while (nrow<rows) | ||
471 | { | ||
472 | if (i >= len) break; | ||
473 | BYTE b = p[i++]; | ||
474 | if (!b) | ||
475 | { | ||
476 | nrow++; | ||
477 | m+=m_nChannels; | ||
478 | continue; | ||
479 | } | ||
480 | UINT ch = b & 0x7F; | ||
481 | if (ch) ch = (ch - 1) & 0x3F; | ||
482 | if (b & 0x80) | ||
483 | { | ||
484 | if (i >= len) break; | ||
485 | chnmask[ch] = p[i++]; | ||
486 | } | ||
487 | if ((chnmask[ch] & 0x10) && (ch < m_nChannels)) | ||
488 | { | ||
489 | m[ch].note = lastvalue[ch].note; | ||
490 | } | ||
491 | if ((chnmask[ch] & 0x20) && (ch < m_nChannels)) | ||
492 | { | ||
493 | m[ch].instr = lastvalue[ch].instr; | ||
494 | } | ||
495 | if ((chnmask[ch] & 0x40) && (ch < m_nChannels)) | ||
496 | { | ||
497 | m[ch].volcmd = lastvalue[ch].volcmd; | ||
498 | m[ch].vol = lastvalue[ch].vol; | ||
499 | } | ||
500 | if ((chnmask[ch] & 0x80) && (ch < m_nChannels)) | ||
501 | { | ||
502 | m[ch].command = lastvalue[ch].command; | ||
503 | m[ch].param = lastvalue[ch].param; | ||
504 | } | ||
505 | if (chnmask[ch] & 1)// Note | ||
506 | { | ||
507 | if (i >= len) break; | ||
508 | UINT note = p[i++]; | ||
509 | if (ch < m_nChannels) | ||
510 | { | ||
511 | if (note < 0x80) note++; | ||
512 | m[ch].note = note; | ||
513 | lastvalue[ch].note = note; | ||
514 | channels_used[ch] = TRUE; | ||
515 | } | ||
516 | } | ||
517 | if (chnmask[ch] & 2) | ||
518 | { | ||
519 | if (i >= len) break; | ||
520 | UINT instr = p[i++]; | ||
521 | if (ch < m_nChannels) | ||
522 | { | ||
523 | m[ch].instr = instr; | ||
524 | lastvalue[ch].instr = instr; | ||
525 | } | ||
526 | } | ||
527 | if (chnmask[ch] & 4) | ||
528 | { | ||
529 | if (i >= len) break; | ||
530 | UINT vol = p[i++]; | ||
531 | if (ch < m_nChannels) | ||
532 | { | ||
533 | // 0-64: Set Volume | ||
534 | if (vol <= 64) { m[ch].volcmd = VOLCMD_VOLUME; m[ch].vol = vol; } else | ||
535 | // 128-192: Set Panning | ||
536 | if ((vol >= 128) && (vol <= 192)) { m[ch].volcmd = VOLCMD_PANNING; m[ch].vol = vol - 128; } else | ||
537 | // 65-74: Fine Volume Up | ||
538 | if (vol < 75) { m[ch].volcmd = VOLCMD_FINEVOLUP; m[ch].vol = vol - 65; } else | ||
539 | // 75-84: Fine Volume Down | ||
540 | if (vol < 85) { m[ch].volcmd = VOLCMD_FINEVOLDOWN; m[ch].vol = vol - 75; } else | ||
541 | // 85-94: Volume Slide Up | ||
542 | if (vol < 95) { m[ch].volcmd = VOLCMD_VOLSLIDEUP; m[ch].vol = vol - 85; } else | ||
543 | // 95-104: Volume Slide Down | ||
544 | if (vol < 105) { m[ch].volcmd = VOLCMD_VOLSLIDEDOWN; m[ch].vol = vol - 95; } else | ||
545 | // 105-114: Pitch Slide Up | ||
546 | if (vol < 115) { m[ch].volcmd = VOLCMD_PORTADOWN; m[ch].vol = vol - 105; } else | ||
547 | // 115-124: Pitch Slide Down | ||
548 | if (vol < 125) { m[ch].volcmd = VOLCMD_PORTAUP; m[ch].vol = vol - 115; } else | ||
549 | // 193-202: Portamento To | ||
550 | if ((vol >= 193) && (vol <= 202)) { m[ch].volcmd = VOLCMD_TONEPORTAMENTO; m[ch].vol = vol - 193; } else | ||
551 | // 203-212: Vibrato | ||
552 | if ((vol >= 203) && (vol <= 212)) { m[ch].volcmd = VOLCMD_VIBRATOSPEED; m[ch].vol = vol - 203; } | ||
553 | lastvalue[ch].volcmd = m[ch].volcmd; | ||
554 | lastvalue[ch].vol = m[ch].vol; | ||
555 | } | ||
556 | } | ||
557 | // Reading command/param | ||
558 | if (chnmask[ch] & 8) | ||
559 | { | ||
560 | if (i > len - 2) break; | ||
561 | UINT cmd = p[i++]; | ||
562 | UINT param = p[i++]; | ||
563 | if (ch < m_nChannels) | ||
564 | { | ||
565 | if (cmd) | ||
566 | { | ||
567 | m[ch].command = cmd; | ||
568 | m[ch].param = param; | ||
569 | S3MConvert(&m[ch], TRUE); | ||
570 | lastvalue[ch].command = m[ch].command; | ||
571 | lastvalue[ch].param = m[ch].param; | ||
572 | } | ||
573 | } | ||
574 | } | ||
575 | } | ||
576 | } | ||
577 | for (UINT ncu=0; ncu<MAX_BASECHANNELS; ncu++) | ||
578 | { | ||
579 | if (ncu>=m_nChannels) | ||
580 | { | ||
581 | ChnSettings[ncu].nVolume = 64; | ||
582 | ChnSettings[ncu].dwFlags &= ~CHN_MUTE; | ||
583 | } | ||
584 | } | ||
585 | m_nMinPeriod = 8; | ||
586 | m_nMaxPeriod = 0xF000; | ||
587 | return TRUE; | ||
588 | } | ||
589 | |||
590 | |||
591 | #ifndef MODPLUG_NO_FILESAVE | ||
592 | //#define SAVEITTIMESTAMP | ||
593 | #pragma warning(disable:4100) | ||
594 | |||
595 | BOOL CSoundFile::SaveIT(LPCSTR lpszFileName, UINT nPacking) | ||
596 | //--------------------------------------------------------- | ||
597 | { | ||
598 | DWORD dwPatNamLen, dwChnNamLen; | ||
599 | ITFILEHEADER header; | ||
600 | ITINSTRUMENT iti; | ||
601 | ITSAMPLESTRUCT itss; | ||
602 | BYTE smpcount[MAX_SAMPLES]; | ||
603 | DWORD inspos[MAX_INSTRUMENTS]; | ||
604 | DWORD patpos[MAX_PATTERNS]; | ||
605 | DWORD smppos[MAX_SAMPLES]; | ||
606 | DWORD dwPos = 0, dwHdrPos = 0, dwExtra = 2; | ||
607 | WORD patinfo[4]; | ||
608 | BYTE chnmask[64]; | ||
609 | BYTE buf[512]; | ||
610 | MODCOMMAND lastvalue[64]; | ||
611 | FILE *f; | ||
612 | |||
613 | |||
614 | if ((!lpszFileName) || ((f = fopen(lpszFileName, "wb")) == NULL)) return FALSE; | ||
615 | memset(inspos, 0, sizeof(inspos)); | ||
616 | memset(patpos, 0, sizeof(patpos)); | ||
617 | memset(smppos, 0, sizeof(smppos)); | ||
618 | // Writing Header | ||
619 | memset(&header, 0, sizeof(header)); | ||
620 | dwPatNamLen = 0; | ||
621 | dwChnNamLen = 0; | ||
622 | header.id = 0x4D504D49; | ||
623 | lstrcpyn(header.songname, m_szNames[0], 27); | ||
624 | header.reserved1 = 0x1004; | ||
625 | header.ordnum = 0; | ||
626 | while ((header.ordnum < MAX_ORDERS) && (Order[header.ordnum] < 0xFF)) header.ordnum++; | ||
627 | if (header.ordnum < MAX_ORDERS) Order[header.ordnum++] = 0xFF; | ||
628 | header.insnum = m_nInstruments; | ||
629 | header.smpnum = m_nSamples; | ||
630 | header.patnum = MAX_PATTERNS; | ||
631 | while ((header.patnum > 0) && (!Patterns[header.patnum-1])) header.patnum--; | ||
632 | header.cwtv = 0x217; | ||
633 | header.cmwt = 0x200; | ||
634 | header.flags = 0x0001; | ||
635 | header.special = 0x0006; | ||
636 | if (m_nInstruments) header.flags |= 0x04; | ||
637 | if (m_dwSongFlags & SONG_LINEARSLIDES) header.flags |= 0x08; | ||
638 | if (m_dwSongFlags & SONG_ITOLDEFFECTS) header.flags |= 0x10; | ||
639 | if (m_dwSongFlags & SONG_ITCOMPATMODE) header.flags |= 0x20; | ||
640 | if (m_dwSongFlags & SONG_EXFILTERRANGE) header.flags |= 0x1000; | ||
641 | header.globalvol = m_nDefaultGlobalVolume >> 1; | ||
642 | header.mv = m_nSongPreAmp; | ||
643 | if (header.mv < 0x20) header.mv = 0x20; | ||
644 | if (header.mv > 0x7F) header.mv = 0x7F; | ||
645 | header.speed = m_nDefaultSpeed; | ||
646 | header.tempo = m_nDefaultTempo; | ||
647 | header.sep = 128; | ||
648 | dwHdrPos = sizeof(header) + header.ordnum; | ||
649 | // Channel Pan and Volume | ||
650 | memset(header.chnpan, 0xFF, 64); | ||
651 | memset(header.chnvol, 64, 64); | ||
652 | for (UINT ich=0; ich<m_nChannels; ich++) | ||
653 | { | ||
654 | header.chnpan[ich] = ChnSettings[ich].nPan >> 2; | ||
655 | if (ChnSettings[ich].dwFlags & CHN_SURROUND) header.chnpan[ich] = 100; | ||
656 | header.chnvol[ich] = ChnSettings[ich].nVolume; | ||
657 | if (ChnSettings[ich].dwFlags & CHN_MUTE) header.chnpan[ich] |= 0x80; | ||
658 | if (ChnSettings[ich].szName[0]) | ||
659 | { | ||
660 | dwChnNamLen = (ich+1) * MAX_CHANNELNAME; | ||
661 | } | ||
662 | } | ||
663 | if (dwChnNamLen) dwExtra += dwChnNamLen + 8; | ||
664 | #ifdef SAVEITTIMESTAMP | ||
665 | dwExtra += 8; // Time Stamp | ||
666 | #endif | ||
667 | if (m_dwSongFlags & SONG_EMBEDMIDICFG) | ||
668 | { | ||
669 | header.flags |= 0x80; | ||
670 | header.special |= 0x08; | ||
671 | dwExtra += sizeof(MODMIDICFG); | ||
672 | } | ||
673 | // Pattern Names | ||
674 | if ((m_nPatternNames) && (m_lpszPatternNames)) | ||
675 | { | ||
676 | dwPatNamLen = m_nPatternNames * MAX_PATTERNNAME; | ||
677 | while ((dwPatNamLen >= MAX_PATTERNNAME) && (!m_lpszPatternNames[dwPatNamLen-MAX_PATTERNNAME])) dwPatNamLen -= MAX_PATTERNNAME; | ||
678 | if (dwPatNamLen < MAX_PATTERNNAME) dwPatNamLen = 0; | ||
679 | if (dwPatNamLen) dwExtra += dwPatNamLen + 8; | ||
680 | } | ||
681 | // Mix Plugins | ||
682 | dwExtra += SaveMixPlugins(NULL, TRUE); | ||
683 | // Comments | ||
684 | if (m_lpszSongComments) | ||
685 | { | ||
686 | header.special |= 1; | ||
687 | header.msglength = strlen(m_lpszSongComments)+1; | ||
688 | header.msgoffset = dwHdrPos + dwExtra + header.insnum*4 + header.patnum*4 + header.smpnum*4; | ||
689 | } | ||
690 | // Write file header | ||
691 | fwrite(&header, 1, sizeof(header), f); | ||
692 | fwrite(Order, 1, header.ordnum, f); | ||
693 | if (header.insnum) fwrite(inspos, 4, header.insnum, f); | ||
694 | if (header.smpnum) fwrite(smppos, 4, header.smpnum, f); | ||
695 | if (header.patnum) fwrite(patpos, 4, header.patnum, f); | ||
696 | // Writing editor history information | ||
697 | { | ||
698 | #ifdef SAVEITTIMESTAMP | ||
699 | SYSTEMTIME systime; | ||
700 | FILETIME filetime; | ||
701 | WORD timestamp[4]; | ||
702 | WORD nInfoEx = 1; | ||
703 | memset(timestamp, 0, sizeof(timestamp)); | ||
704 | fwrite(&nInfoEx, 1, 2, f); | ||
705 | GetSystemTime(&systime); | ||
706 | SystemTimeToFileTime(&systime, &filetime); | ||
707 | FileTimeToDosDateTime(&filetime, ×tamp[0], ×tamp[1]); | ||
708 | fwrite(timestamp, 1, 8, f); | ||
709 | #else | ||
710 | WORD nInfoEx = 0; | ||
711 | fwrite(&nInfoEx, 1, 2, f); | ||
712 | #endif | ||
713 | } | ||
714 | // Writing midi cfg | ||
715 | if (header.flags & 0x80) | ||
716 | { | ||
717 | fwrite(&m_MidiCfg, 1, sizeof(MODMIDICFG), f); | ||
718 | } | ||
719 | // Writing pattern names | ||
720 | if (dwPatNamLen) | ||
721 | { | ||
722 | DWORD d = 0x4d414e50; | ||
723 | fwrite(&d, 1, 4, f); | ||
724 | fwrite(&dwPatNamLen, 1, 4, f); | ||
725 | fwrite(m_lpszPatternNames, 1, dwPatNamLen, f); | ||
726 | } | ||
727 | // Writing channel Names | ||
728 | if (dwChnNamLen) | ||
729 | { | ||
730 | DWORD d = 0x4d414e43; | ||
731 | fwrite(&d, 1, 4, f); | ||
732 | fwrite(&dwChnNamLen, 1, 4, f); | ||
733 | UINT nChnNames = dwChnNamLen / MAX_CHANNELNAME; | ||
734 | for (UINT inam=0; inam<nChnNames; inam++) | ||
735 | { | ||
736 | fwrite(ChnSettings[inam].szName, 1, MAX_CHANNELNAME, f); | ||
737 | } | ||
738 | } | ||
739 | // Writing mix plugins info | ||
740 | SaveMixPlugins(f, FALSE); | ||
741 | // Writing song message | ||
742 | dwPos = dwHdrPos + dwExtra + (header.insnum + header.smpnum + header.patnum) * 4; | ||
743 | if (header.special & 1) | ||
744 | { | ||
745 | dwPos += strlen(m_lpszSongComments) + 1; | ||
746 | fwrite(m_lpszSongComments, 1, strlen(m_lpszSongComments)+1, f); | ||
747 | } | ||
748 | // Writing instruments | ||
749 | for (UINT nins=1; nins<=header.insnum; nins++) | ||
750 | { | ||
751 | memset(&iti, 0, sizeof(iti)); | ||
752 | iti.id = 0x49504D49;// "IMPI" | ||
753 | iti.trkvers = 0x211; | ||
754 | if (Headers[nins]) | ||
755 | { | ||
756 | INSTRUMENTHEADER *penv = Headers[nins]; | ||
757 | memset(smpcount, 0, sizeof(smpcount)); | ||
758 | memcpy(iti.filename, penv->filename, 12); | ||
759 | memcpy(iti.name, penv->name, 26); | ||
760 | iti.mbank = penv->wMidiBank; | ||
761 | iti.mpr = penv->nMidiProgram; | ||
762 | iti.mch = penv->nMidiChannel; | ||
763 | iti.nna = penv->nNNA; | ||
764 | iti.dct = penv->nDCT; | ||
765 | iti.dca = penv->nDNA; | ||
766 | iti.fadeout = penv->nFadeOut >> 5; | ||
767 | iti.pps = penv->nPPS; | ||
768 | iti.ppc = penv->nPPC; | ||
769 | iti.gbv = (BYTE)(penv->nGlobalVol << 1); | ||
770 | iti.dfp = (BYTE)penv->nPan >> 2; | ||
771 | if (!(penv->dwFlags & ENV_SETPANNING)) iti.dfp |= 0x80; | ||
772 | iti.rv = penv->nVolSwing; | ||
773 | iti.rp = penv->nPanSwing; | ||
774 | iti.ifc = penv->nIFC; | ||
775 | iti.ifr = penv->nIFR; | ||
776 | iti.nos = 0; | ||
777 | for (UINT i=0; i<120; i++) if (penv->Keyboard[i] < MAX_SAMPLES) | ||
778 | { | ||
779 | UINT smp = penv->Keyboard[i]; | ||
780 | if ((smp) && (!smpcount[smp])) | ||
781 | { | ||
782 | smpcount[smp] = 1; | ||
783 | iti.nos++; | ||
784 | } | ||
785 | iti.keyboard[i*2] = penv->NoteMap[i] - 1; | ||
786 | iti.keyboard[i*2+1] = smp; | ||
787 | } | ||
788 | // Writing Volume envelope | ||
789 | if (penv->dwFlags & ENV_VOLUME) iti.volenv.flags |= 0x01; | ||
790 | if (penv->dwFlags & ENV_VOLLOOP) iti.volenv.flags |= 0x02; | ||
791 | if (penv->dwFlags & ENV_VOLSUSTAIN) iti.volenv.flags |= 0x04; | ||
792 | if (penv->dwFlags & ENV_VOLCARRY) iti.volenv.flags |= 0x08; | ||
793 | iti.volenv.num = (BYTE)penv->nVolEnv; | ||
794 | iti.volenv.lpb = (BYTE)penv->nVolLoopStart; | ||
795 | iti.volenv.lpe = (BYTE)penv->nVolLoopEnd; | ||
796 | iti.volenv.slb = penv->nVolSustainBegin; | ||
797 | iti.volenv.sle = penv->nVolSustainEnd; | ||
798 | // Writing Panning envelope | ||
799 | if (penv->dwFlags & ENV_PANNING) iti.panenv.flags |= 0x01; | ||
800 | if (penv->dwFlags & ENV_PANLOOP) iti.panenv.flags |= 0x02; | ||
801 | if (penv->dwFlags & ENV_PANSUSTAIN) iti.panenv.flags |= 0x04; | ||
802 | if (penv->dwFlags & ENV_PANCARRY) iti.panenv.flags |= 0x08; | ||
803 | iti.panenv.num = (BYTE)penv->nPanEnv; | ||
804 | iti.panenv.lpb = (BYTE)penv->nPanLoopStart; | ||
805 | iti.panenv.lpe = (BYTE)penv->nPanLoopEnd; | ||
806 | iti.panenv.slb = penv->nPanSustainBegin; | ||
807 | iti.panenv.sle = penv->nPanSustainEnd; | ||
808 | // Writing Pitch Envelope | ||
809 | if (penv->dwFlags & ENV_PITCH) iti.pitchenv.flags |= 0x01; | ||
810 | if (penv->dwFlags & ENV_PITCHLOOP) iti.pitchenv.flags |= 0x02; | ||
811 | if (penv->dwFlags & ENV_PITCHSUSTAIN) iti.pitchenv.flags |= 0x04; | ||
812 | if (penv->dwFlags & ENV_PITCHCARRY) iti.pitchenv.flags |= 0x08; | ||
813 | if (penv->dwFlags & ENV_FILTER) iti.pitchenv.flags |= 0x80; | ||
814 | iti.pitchenv.num = (BYTE)penv->nPitchEnv; | ||
815 | iti.pitchenv.lpb = (BYTE)penv->nPitchLoopStart; | ||
816 | iti.pitchenv.lpe = (BYTE)penv->nPitchLoopEnd; | ||
817 | iti.pitchenv.slb = (BYTE)penv->nPitchSustainBegin; | ||
818 | iti.pitchenv.sle = (BYTE)penv->nPitchSustainEnd; | ||
819 | // Writing Envelopes data | ||
820 | for (UINT ev=0; ev<25; ev++) | ||
821 | { | ||
822 | iti.volenv.data[ev*3] = penv->VolEnv[ev]; | ||
823 | iti.volenv.data[ev*3+1] = penv->VolPoints[ev] & 0xFF; | ||
824 | iti.volenv.data[ev*3+2] = penv->VolPoints[ev] >> 8; | ||
825 | iti.panenv.data[ev*3] = penv->PanEnv[ev] - 32; | ||
826 | iti.panenv.data[ev*3+1] = penv->PanPoints[ev] & 0xFF; | ||
827 | iti.panenv.data[ev*3+2] = penv->PanPoints[ev] >> 8; | ||
828 | iti.pitchenv.data[ev*3] = penv->PitchEnv[ev] - 32; | ||
829 | iti.pitchenv.data[ev*3+1] = penv->PitchPoints[ev] & 0xFF; | ||
830 | iti.pitchenv.data[ev*3+2] = penv->PitchPoints[ev] >> 8; | ||
831 | } | ||
832 | } else | ||
833 | // Save Empty Instrument | ||
834 | { | ||
835 | for (UINT i=0; i<120; i++) iti.keyboard[i*2] = i; | ||
836 | iti.ppc = 5*12; | ||
837 | iti.gbv = 128; | ||
838 | iti.dfp = 0x20; | ||
839 | iti.ifc = 0xFF; | ||
840 | } | ||
841 | if (!iti.nos) iti.trkvers = 0; | ||
842 | // Writing instrument | ||
843 | inspos[nins-1] = dwPos; | ||
844 | dwPos += sizeof(ITINSTRUMENT); | ||
845 | fwrite(&iti, 1, sizeof(ITINSTRUMENT), f); | ||
846 | } | ||
847 | // Writing sample headers | ||
848 | memset(&itss, 0, sizeof(itss)); | ||
849 | for (UINT hsmp=0; hsmp<header.smpnum; hsmp++) | ||
850 | { | ||
851 | smppos[hsmp] = dwPos; | ||
852 | dwPos += sizeof(ITSAMPLESTRUCT); | ||
853 | fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f); | ||
854 | } | ||
855 | // Writing Patterns | ||
856 | for (UINT npat=0; npat<header.patnum; npat++) | ||
857 | { | ||
858 | DWORD dwPatPos = dwPos; | ||
859 | UINT len; | ||
860 | if (!Patterns[npat]) continue; | ||
861 | patpos[npat] = dwPos; | ||
862 | patinfo[0] = 0; | ||
863 | patinfo[1] = PatternSize[npat]; | ||
864 | patinfo[2] = 0; | ||
865 | patinfo[3] = 0; | ||
866 | // Check for empty pattern | ||
867 | if (PatternSize[npat] == 64) | ||
868 | { | ||
869 | MODCOMMAND *pzc = Patterns[npat]; | ||
870 | UINT nz = PatternSize[npat] * m_nChannels; | ||
871 | for (UINT iz=0; iz<nz; iz++) | ||
872 | { | ||
873 | if ((pzc[iz].note) || (pzc[iz].instr) | ||
874 | || (pzc[iz].volcmd) || (pzc[iz].command)) break; | ||
875 | } | ||
876 | if (iz == nz) | ||
877 | { | ||
878 | patpos[npat] = 0; | ||
879 | continue; | ||
880 | } | ||
881 | } | ||
882 | fwrite(patinfo, 8, 1, f); | ||
883 | dwPos += 8; | ||
884 | memset(chnmask, 0xFF, sizeof(chnmask)); | ||
885 | memset(lastvalue, 0, sizeof(lastvalue)); | ||
886 | MODCOMMAND *m = Patterns[npat]; | ||
887 | for (UINT row=0; row<PatternSize[npat]; row++) | ||
888 | { | ||
889 | len = 0; | ||
890 | for (UINT ch=0; ch<m_nChannels; ch++, m++) | ||
891 | { | ||
892 | BYTE b = 0; | ||
893 | UINT command = m->command; | ||
894 | UINT param = m->param; | ||
895 | UINT vol = 0xFF; | ||
896 | UINT note = m->note; | ||
897 | if (note) b |= 1; | ||
898 | if ((note) && (note < 0xFE)) note--; | ||
899 | if (m->instr) b |= 2; | ||
900 | if (m->volcmd) | ||
901 | { | ||
902 | UINT volcmd = m->volcmd; | ||
903 | switch(volcmd) | ||
904 | { | ||
905 | case VOLCMD_VOLUME: vol = m->vol; if (vol > 64) vol = 64; break; | ||
906 | case VOLCMD_PANNING: vol = m->vol + 128; if (vol > 192) vol = 192; break; | ||
907 | case VOLCMD_VOLSLIDEUP: vol = 85 + ConvertVolParam(m->vol); break; | ||
908 | case VOLCMD_VOLSLIDEDOWN:vol = 95 + ConvertVolParam(m->vol); break; | ||
909 | case VOLCMD_FINEVOLUP: vol = 65 + ConvertVolParam(m->vol); break; | ||
910 | case VOLCMD_FINEVOLDOWN:vol = 75 + ConvertVolParam(m->vol); break; | ||
911 | case VOLCMD_VIBRATO: vol = 203; break; | ||
912 | case VOLCMD_VIBRATOSPEED:vol = 203 + ConvertVolParam(m->vol); break; | ||
913 | case VOLCMD_TONEPORTAMENTO:vol = 193 + ConvertVolParam(m->vol); break; | ||
914 | case VOLCMD_PORTADOWN: vol = 105 + ConvertVolParam(m->vol); break; | ||
915 | case VOLCMD_PORTAUP: vol = 115 + ConvertVolParam(m->vol); break; | ||
916 | default: vol = 0xFF; | ||
917 | } | ||
918 | } | ||
919 | if (vol != 0xFF) b |= 4; | ||
920 | if (command) | ||
921 | { | ||
922 | S3MSaveConvert(&command, ¶m, TRUE); | ||
923 | if (command) b |= 8; | ||
924 | } | ||
925 | // Packing information | ||
926 | if (b) | ||
927 | { | ||
928 | // Same note ? | ||
929 | if (b & 1) | ||
930 | { | ||
931 | if ((note == lastvalue[ch].note) && (lastvalue[ch].volcmd & 1)) | ||
932 | { | ||
933 | b &= ~1; | ||
934 | b |= 0x10; | ||
935 | } else | ||
936 | { | ||
937 | lastvalue[ch].note = note; | ||
938 | lastvalue[ch].volcmd |= 1; | ||
939 | } | ||
940 | } | ||
941 | // Same instrument ? | ||
942 | if (b & 2) | ||
943 | { | ||
944 | if ((m->instr == lastvalue[ch].instr) && (lastvalue[ch].volcmd & 2)) | ||
945 | { | ||
946 | b &= ~2; | ||
947 | b |= 0x20; | ||
948 | } else | ||
949 | { | ||
950 | lastvalue[ch].instr = m->instr; | ||
951 | lastvalue[ch].volcmd |= 2; | ||
952 | } | ||
953 | } | ||
954 | // Same volume column byte ? | ||
955 | if (b & 4) | ||
956 | { | ||
957 | if ((vol == lastvalue[ch].vol) && (lastvalue[ch].volcmd & 4)) | ||
958 | { | ||
959 | b &= ~4; | ||
960 | b |= 0x40; | ||
961 | } else | ||
962 | { | ||
963 | lastvalue[ch].vol = vol; | ||
964 | lastvalue[ch].volcmd |= 4; | ||
965 | } | ||
966 | } | ||
967 | // Same command / param ? | ||
968 | if (b & 8) | ||
969 | { | ||
970 | if ((command == lastvalue[ch].command) && (param == lastvalue[ch].param) && (lastvalue[ch].volcmd & 8)) | ||
971 | { | ||
972 | b &= ~8; | ||
973 | b |= 0x80; | ||
974 | } else | ||
975 | { | ||
976 | lastvalue[ch].command = command; | ||
977 | lastvalue[ch].param = param; | ||
978 | lastvalue[ch].volcmd |= 8; | ||
979 | } | ||
980 | } | ||
981 | if (b != chnmask[ch]) | ||
982 | { | ||
983 | chnmask[ch] = b; | ||
984 | buf[len++] = (ch+1) | 0x80; | ||
985 | buf[len++] = b; | ||
986 | } else | ||
987 | { | ||
988 | buf[len++] = ch+1; | ||
989 | } | ||
990 | if (b & 1) buf[len++] = note; | ||
991 | if (b & 2) buf[len++] = m->instr; | ||
992 | if (b & 4) buf[len++] = vol; | ||
993 | if (b & 8) | ||
994 | { | ||
995 | buf[len++] = command; | ||
996 | buf[len++] = param; | ||
997 | } | ||
998 | } | ||
999 | } | ||
1000 | buf[len++] = 0; | ||
1001 | dwPos += len; | ||
1002 | patinfo[0] += len; | ||
1003 | fwrite(buf, 1, len, f); | ||
1004 | } | ||
1005 | fseek(f, dwPatPos, SEEK_SET); | ||
1006 | fwrite(patinfo, 8, 1, f); | ||
1007 | fseek(f, dwPos, SEEK_SET); | ||
1008 | } | ||
1009 | // Writing Sample Data | ||
1010 | for (UINT nsmp=1; nsmp<=header.smpnum; nsmp++) | ||
1011 | { | ||
1012 | MODINSTRUMENT *psmp = &Ins[nsmp]; | ||
1013 | memset(&itss, 0, sizeof(itss)); | ||
1014 | memcpy(itss.filename, psmp->name, 12); | ||
1015 | memcpy(itss.name, m_szNames[nsmp], 26); | ||
1016 | itss.id = 0x53504D49; | ||
1017 | itss.gvl = (BYTE)psmp->nGlobalVol; | ||
1018 | if (m_nInstruments) | ||
1019 | { | ||
1020 | for (UINT iu=1; iu<=m_nInstruments; iu++) if (Headers[iu]) | ||
1021 | { | ||
1022 | INSTRUMENTHEADER *penv = Headers[iu]; | ||
1023 | for (UINT ju=0; ju<128; ju++) if (penv->Keyboard[ju] == nsmp) | ||
1024 | { | ||
1025 | itss.flags = 0x01; | ||
1026 | break; | ||
1027 | } | ||
1028 | } | ||
1029 | } else | ||
1030 | { | ||
1031 | itss.flags = 0x01; | ||
1032 | } | ||
1033 | if (psmp->uFlags & CHN_LOOP) itss.flags |= 0x10; | ||
1034 | if (psmp->uFlags & CHN_SUSTAINLOOP) itss.flags |= 0x20; | ||
1035 | if (psmp->uFlags & CHN_PINGPONGLOOP) itss.flags |= 0x40; | ||
1036 | if (psmp->uFlags & CHN_PINGPONGSUSTAIN) itss.flags |= 0x80; | ||
1037 | itss.C5Speed = psmp->nC4Speed; | ||
1038 | if (!itss.C5Speed) itss.C5Speed = 8363; | ||
1039 | itss.length = psmp->nLength; | ||
1040 | itss.loopbegin = psmp->nLoopStart; | ||
1041 | itss.loopend = psmp->nLoopEnd; | ||
1042 | itss.susloopbegin = psmp->nSustainStart; | ||
1043 | itss.susloopend = psmp->nSustainEnd; | ||
1044 | itss.vol = psmp->nVolume >> 2; | ||
1045 | itss.dfp = psmp->nPan >> 2; | ||
1046 | itss.vit = autovibxm2it[psmp->nVibType & 7]; | ||
1047 | itss.vis = psmp->nVibRate; | ||
1048 | itss.vid = psmp->nVibDepth; | ||
1049 | itss.vir = (psmp->nVibSweep < 64) ? psmp->nVibSweep * 4 : 255; | ||
1050 | if (psmp->uFlags & CHN_PANNING) itss.dfp |= 0x80; | ||
1051 | if ((psmp->pSample) && (psmp->nLength)) itss.cvt = 0x01; | ||
1052 | UINT flags = RS_PCM8S; | ||
1053 | #ifndef NO_PACKING | ||
1054 | if (nPacking) | ||
1055 | { | ||
1056 | if ((!(psmp->uFlags & (CHN_16BIT|CHN_STEREO))) | ||
1057 | && (CanPackSample(psmp->pSample, psmp->nLength, nPacking))) | ||
1058 | { | ||
1059 | flags = RS_ADPCM4; | ||
1060 | itss.cvt = 0xFF; | ||
1061 | } | ||
1062 | } else | ||
1063 | #endif // NO_PACKING | ||
1064 | { | ||
1065 | if (psmp->uFlags & CHN_STEREO) | ||
1066 | { | ||
1067 | flags = RS_STPCM8S; | ||
1068 | itss.flags |= 0x04; | ||
1069 | } | ||
1070 | if (psmp->uFlags & CHN_16BIT) | ||
1071 | { | ||
1072 | itss.flags |= 0x02; | ||
1073 | flags = (psmp->uFlags & CHN_STEREO) ? RS_STPCM16S : RS_PCM16S; | ||
1074 | } | ||
1075 | } | ||
1076 | itss.samplepointer = dwPos; | ||
1077 | fseek(f, smppos[nsmp-1], SEEK_SET); | ||
1078 | fwrite(&itss, 1, sizeof(ITSAMPLESTRUCT), f); | ||
1079 | fseek(f, dwPos, SEEK_SET); | ||
1080 | if ((psmp->pSample) && (psmp->nLength)) | ||
1081 | { | ||
1082 | dwPos += WriteSample(f, psmp, flags); | ||
1083 | } | ||
1084 | } | ||
1085 | // Updating offsets | ||
1086 | fseek(f, dwHdrPos, SEEK_SET); | ||
1087 | if (header.insnum) fwrite(inspos, 4, header.insnum, f); | ||
1088 | if (header.smpnum) fwrite(smppos, 4, header.smpnum, f); | ||
1089 | if (header.patnum) fwrite(patpos, 4, header.patnum, f); | ||
1090 | fclose(f); | ||
1091 | return TRUE; | ||
1092 | } | ||
1093 | |||
1094 | #pragma warning(default:4100) | ||
1095 | #endif // MODPLUG_NO_FILESAVE | ||
1096 | |||
1097 | ////////////////////////////////////////////////////////////////////////////// | ||
1098 | // IT 2.14 compression | ||
1099 | |||
1100 | DWORD ITReadBits(DWORD &bitbuf, UINT &bitnum, LPBYTE &ibuf, CHAR n) | ||
1101 | //----------------------------------------------------------------- | ||
1102 | { | ||
1103 | DWORD retval = 0; | ||
1104 | UINT i = n; | ||
1105 | |||
1106 | if (n > 0) | ||
1107 | { | ||
1108 | do | ||
1109 | { | ||
1110 | if (!bitnum) | ||
1111 | { | ||
1112 | bitbuf = *ibuf++; | ||
1113 | bitnum = 8; | ||
1114 | } | ||
1115 | retval >>= 1; | ||
1116 | retval |= bitbuf << 31; | ||
1117 | bitbuf >>= 1; | ||
1118 | bitnum--; | ||
1119 | i--; | ||
1120 | } while (i); | ||
1121 | i = n; | ||
1122 | } | ||
1123 | return (retval >> (32-i)); | ||
1124 | } | ||
1125 | |||
1126 | #define IT215_SUPPORT | ||
1127 | void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215) | ||
1128 | //------------------------------------------------------------------------------------------- | ||
1129 | { | ||
1130 | signed char *pDst = pSample; | ||
1131 | LPBYTE pSrc = lpMemFile; | ||
1132 | DWORD wHdr = 0; | ||
1133 | DWORD wCount = 0; | ||
1134 | DWORD bitbuf = 0; | ||
1135 | UINT bitnum = 0; | ||
1136 | BYTE bLeft = 0, bTemp = 0, bTemp2 = 0; | ||
1137 | |||
1138 | while (dwLen) | ||
1139 | { | ||
1140 | if (!wCount) | ||
1141 | { | ||
1142 | wCount = 0x8000; | ||
1143 | wHdr = bswapLE16(*((LPWORD)pSrc)); | ||
1144 | pSrc += 2; | ||
1145 | bLeft = 9; | ||
1146 | bTemp = bTemp2 = 0; | ||
1147 | bitbuf = bitnum = 0; | ||
1148 | } | ||
1149 | DWORD d = wCount; | ||
1150 | if (d > dwLen) d = dwLen; | ||
1151 | // Unpacking | ||
1152 | DWORD dwPos = 0; | ||
1153 | do | ||
1154 | { | ||
1155 | WORD wBits = (WORD)ITReadBits(bitbuf, bitnum, pSrc, bLeft); | ||
1156 | if (bLeft < 7) | ||
1157 | { | ||
1158 | DWORD i = 1 << (bLeft-1); | ||
1159 | DWORD j = wBits & 0xFFFF; | ||
1160 | if (i != j) goto UnpackByte; | ||
1161 | wBits = (WORD)(ITReadBits(bitbuf, bitnum, pSrc, 3) + 1) & 0xFF; | ||
1162 | bLeft = ((BYTE)wBits < bLeft) ? (BYTE)wBits : (BYTE)((wBits+1) & 0xFF); | ||
1163 | goto Next; | ||
1164 | } | ||
1165 | if (bLeft < 9) | ||
1166 | { | ||
1167 | WORD i = (0xFF >> (9 - bLeft)) + 4; | ||
1168 | WORD j = i - 8; | ||
1169 | if ((wBits <= j) || (wBits > i)) goto UnpackByte; | ||
1170 | wBits -= j; | ||
1171 | bLeft = ((BYTE)(wBits & 0xFF) < bLeft) ? (BYTE)(wBits & 0xFF) : (BYTE)((wBits+1) & 0xFF); | ||
1172 | goto Next; | ||
1173 | } | ||
1174 | if (bLeft >= 10) goto SkipByte; | ||
1175 | if (wBits >= 256) | ||
1176 | { | ||
1177 | bLeft = (BYTE)(wBits + 1) & 0xFF; | ||
1178 | goto Next; | ||
1179 | } | ||
1180 | UnpackByte: | ||
1181 | if (bLeft < 8) | ||
1182 | { | ||
1183 | BYTE shift = 8 - bLeft; | ||
1184 | signed char c = (signed char)(wBits << shift); | ||
1185 | c >>= shift; | ||
1186 | wBits = (WORD)c; | ||
1187 | } | ||
1188 | wBits += bTemp; | ||
1189 | bTemp = (BYTE)wBits; | ||
1190 | bTemp2 += bTemp; | ||
1191 | #ifdef IT215_SUPPORT | ||
1192 | pDst[dwPos] = (b215) ? bTemp2 : bTemp; | ||
1193 | #else | ||
1194 | pDst[dwPos] = bTemp; | ||
1195 | #endif | ||
1196 | SkipByte: | ||
1197 | dwPos++; | ||
1198 | Next: | ||
1199 | if (pSrc >= lpMemFile+dwMemLength+1) return; | ||
1200 | } while (dwPos < d); | ||
1201 | // Move On | ||
1202 | wCount -= d; | ||
1203 | dwLen -= d; | ||
1204 | pDst += d; | ||
1205 | } | ||
1206 | } | ||
1207 | |||
1208 | |||
1209 | void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215) | ||
1210 | //-------------------------------------------------------------------------------------------- | ||
1211 | { | ||
1212 | signed short *pDst = (signed short *)pSample; | ||
1213 | LPBYTE pSrc = lpMemFile; | ||
1214 | DWORD wHdr = 0; | ||
1215 | DWORD wCount = 0; | ||
1216 | DWORD bitbuf = 0; | ||
1217 | UINT bitnum = 0; | ||
1218 | BYTE bLeft = 0; | ||
1219 | signed short wTemp = 0, wTemp2 = 0; | ||
1220 | |||
1221 | while (dwLen) | ||
1222 | { | ||
1223 | if (!wCount) | ||
1224 | { | ||
1225 | wCount = 0x4000; | ||
1226 | wHdr = bswapLE16(*((LPWORD)pSrc)); | ||
1227 | pSrc += 2; | ||
1228 | bLeft = 17; | ||
1229 | wTemp = wTemp2 = 0; | ||
1230 | bitbuf = bitnum = 0; | ||
1231 | } | ||
1232 | DWORD d = wCount; | ||
1233 | if (d > dwLen) d = dwLen; | ||
1234 | // Unpacking | ||
1235 | DWORD dwPos = 0; | ||
1236 | do | ||
1237 | { | ||
1238 | DWORD dwBits = ITReadBits(bitbuf, bitnum, pSrc, bLeft); | ||
1239 | if (bLeft < 7) | ||
1240 | { | ||
1241 | DWORD i = 1 << (bLeft-1); | ||
1242 | DWORD j = dwBits; | ||
1243 | if (i != j) goto UnpackByte; | ||
1244 | dwBits = ITReadBits(bitbuf, bitnum, pSrc, 4) + 1; | ||
1245 | bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF); | ||
1246 | goto Next; | ||
1247 | } | ||
1248 | if (bLeft < 17) | ||
1249 | { | ||
1250 | DWORD i = (0xFFFF >> (17 - bLeft)) + 8; | ||
1251 | DWORD j = (i - 16) & 0xFFFF; | ||
1252 | if ((dwBits <= j) || (dwBits > (i & 0xFFFF))) goto UnpackByte; | ||
1253 | dwBits -= j; | ||
1254 | bLeft = ((BYTE)(dwBits & 0xFF) < bLeft) ? (BYTE)(dwBits & 0xFF) : (BYTE)((dwBits+1) & 0xFF); | ||
1255 | goto Next; | ||
1256 | } | ||
1257 | if (bLeft >= 18) goto SkipByte; | ||
1258 | if (dwBits >= 0x10000) | ||
1259 | { | ||
1260 | bLeft = (BYTE)(dwBits + 1) & 0xFF; | ||
1261 | goto Next; | ||
1262 | } | ||
1263 | UnpackByte: | ||
1264 | if (bLeft < 16) | ||
1265 | { | ||
1266 | BYTE shift = 16 - bLeft; | ||
1267 | signed short c = (signed short)(dwBits << shift); | ||
1268 | c >>= shift; | ||
1269 | dwBits = (DWORD)c; | ||
1270 | } | ||
1271 | dwBits += wTemp; | ||
1272 | wTemp = (signed short)dwBits; | ||
1273 | wTemp2 += wTemp; | ||
1274 | #ifdef IT215_SUPPORT | ||
1275 | pDst[dwPos] = (b215) ? wTemp2 : wTemp; | ||
1276 | #else | ||
1277 | pDst[dwPos] = wTemp; | ||
1278 | #endif | ||
1279 | SkipByte: | ||
1280 | dwPos++; | ||
1281 | Next: | ||
1282 | if (pSrc >= lpMemFile+dwMemLength+1) return; | ||
1283 | } while (dwPos < d); | ||
1284 | // Move On | ||
1285 | wCount -= d; | ||
1286 | dwLen -= d; | ||
1287 | pDst += d; | ||
1288 | if (pSrc >= lpMemFile+dwMemLength) break; | ||
1289 | } | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | UINT CSoundFile::SaveMixPlugins(FILE *f, BOOL bUpdate) | ||
1294 | //---------------------------------------------------- | ||
1295 | { | ||
1296 | DWORD chinfo[64]; | ||
1297 | CHAR s[32]; | ||
1298 | DWORD nPluginSize; | ||
1299 | UINT nTotalSize = 0; | ||
1300 | UINT nChInfo = 0; | ||
1301 | |||
1302 | for (UINT i=0; i<MAX_MIXPLUGINS; i++) | ||
1303 | { | ||
1304 | PSNDMIXPLUGIN p = &m_MixPlugins[i]; | ||
1305 | if ((p->Info.dwPluginId1) || (p->Info.dwPluginId2)) | ||
1306 | { | ||
1307 | nPluginSize = sizeof(SNDMIXPLUGININFO)+4; // plugininfo+4 (datalen) | ||
1308 | if ((p->pMixPlugin) && (bUpdate)) | ||
1309 | { | ||
1310 | p->pMixPlugin->SaveAllParameters(); | ||
1311 | } | ||
1312 | if (p->pPluginData) | ||
1313 | { | ||
1314 | nPluginSize += p->nPluginDataSize; | ||
1315 | } | ||
1316 | if (f) | ||
1317 | { | ||
1318 | s[0] = 'F'; | ||
1319 | s[1] = 'X'; | ||
1320 | s[2] = '0' + (i/10); | ||
1321 | s[3] = '0' + (i%10); | ||
1322 | fwrite(s, 1, 4, f); | ||
1323 | fwrite(&nPluginSize, 1, 4, f); | ||
1324 | fwrite(&p->Info, 1, sizeof(SNDMIXPLUGININFO), f); | ||
1325 | fwrite(&m_MixPlugins[i].nPluginDataSize, 1, 4, f); | ||
1326 | if (m_MixPlugins[i].pPluginData) | ||
1327 | { | ||
1328 | fwrite(m_MixPlugins[i].pPluginData, 1, m_MixPlugins[i].nPluginDataSize, f); | ||
1329 | } | ||
1330 | } | ||
1331 | nTotalSize += nPluginSize + 8; | ||
1332 | } | ||
1333 | } | ||
1334 | for (UINT j=0; j<m_nChannels; j++) | ||
1335 | { | ||
1336 | if (j < 64) | ||
1337 | { | ||
1338 | if ((chinfo[j] = ChnSettings[j].nMixPlugin) != 0) | ||
1339 | { | ||
1340 | nChInfo = j+1; | ||
1341 | } | ||
1342 | } | ||
1343 | } | ||
1344 | if (nChInfo) | ||
1345 | { | ||
1346 | if (f) | ||
1347 | { | ||
1348 | nPluginSize = 0x58464843; | ||
1349 | fwrite(&nPluginSize, 1, 4, f); | ||
1350 | nPluginSize = nChInfo*4; | ||
1351 | fwrite(&nPluginSize, 1, 4, f); | ||
1352 | fwrite(chinfo, 1, nPluginSize, f); | ||
1353 | } | ||
1354 | nTotalSize += nChInfo*4 + 8; | ||
1355 | } | ||
1356 | return nTotalSize; | ||
1357 | } | ||
1358 | |||
1359 | |||
1360 | UINT CSoundFile::LoadMixPlugins(const void *pData, UINT nLen) | ||
1361 | //----------------------------------------------------------- | ||
1362 | { | ||
1363 | const BYTE *p = (const BYTE *)pData; | ||
1364 | UINT nPos = 0; | ||
1365 | |||
1366 | while (nPos+8 < nLen) | ||
1367 | { | ||
1368 | DWORD nPluginSize; | ||
1369 | UINT nPlugin; | ||
1370 | |||
1371 | nPluginSize = bswapLE32(*(DWORD *)(p+nPos+4)); | ||
1372 | if (nPluginSize > nLen-nPos-8) break;; | ||
1373 | if ((bswapLE32(*(DWORD *)(p+nPos))) == 0x58464843) | ||
1374 | { | ||
1375 | for (UINT ch=0; ch<64; ch++) if (ch*4 < nPluginSize) | ||
1376 | { | ||
1377 | ChnSettings[ch].nMixPlugin = bswapLE32(*(DWORD *)(p+nPos+8+ch*4)); | ||
1378 | } | ||
1379 | } else | ||
1380 | { | ||
1381 | if ((p[nPos] != 'F') || (p[nPos+1] != 'X') | ||
1382 | || (p[nPos+2] < '0') || (p[nPos+3] < '0')) | ||
1383 | { | ||
1384 | break; | ||
1385 | } | ||
1386 | nPlugin = (p[nPos+2]-'0')*10 + (p[nPos+3]-'0'); | ||
1387 | if ((nPlugin < MAX_MIXPLUGINS) && (nPluginSize >= sizeof(SNDMIXPLUGININFO)+4)) | ||
1388 | { | ||
1389 | DWORD dwExtra = bswapLE32(*(DWORD *)(p+nPos+8+sizeof(SNDMIXPLUGININFO))); | ||
1390 | m_MixPlugins[nPlugin].Info = *(const SNDMIXPLUGININFO *)(p+nPos+8); | ||
1391 | m_MixPlugins[nPlugin].Info.dwPluginId1 = bswapLE32(m_MixPlugins[nPlugin].Info.dwPluginId1); | ||
1392 | m_MixPlugins[nPlugin].Info.dwPluginId2 = bswapLE32(m_MixPlugins[nPlugin].Info.dwPluginId2); | ||
1393 | m_MixPlugins[nPlugin].Info.dwInputRouting = bswapLE32(m_MixPlugins[nPlugin].Info.dwInputRouting); | ||
1394 | m_MixPlugins[nPlugin].Info.dwOutputRouting = bswapLE32(m_MixPlugins[nPlugin].Info.dwOutputRouting); | ||
1395 | for (UINT j=0; j<4; j++) | ||
1396 | { | ||
1397 | m_MixPlugins[nPlugin].Info.dwReserved[j] = bswapLE32(m_MixPlugins[nPlugin].Info.dwReserved[j]); | ||
1398 | } | ||
1399 | if ((dwExtra) && (dwExtra <= nPluginSize-sizeof(SNDMIXPLUGININFO)-4)) | ||
1400 | { | ||
1401 | m_MixPlugins[nPlugin].nPluginDataSize = 0; | ||
1402 | m_MixPlugins[nPlugin].pPluginData = new signed char [dwExtra]; | ||
1403 | if (m_MixPlugins[nPlugin].pPluginData) | ||
1404 | { | ||
1405 | m_MixPlugins[nPlugin].nPluginDataSize = dwExtra; | ||
1406 | memcpy(m_MixPlugins[nPlugin].pPluginData, p+nPos+8+sizeof(SNDMIXPLUGININFO)+4, dwExtra); | ||
1407 | } | ||
1408 | } | ||
1409 | } | ||
1410 | } | ||
1411 | nPos += nPluginSize + 8; | ||
1412 | } | ||
1413 | return nPos; | ||
1414 | } | ||
1415 | |||