author | llornkcor <llornkcor> | 2002-07-20 22:07:31 (UTC) |
---|---|---|
committer | llornkcor <llornkcor> | 2002-07-20 22:07:31 (UTC) |
commit | 2342d48be31847e7ead9d1cc682452e8f0122351 (patch) (unidiff) | |
tree | 8329bb94e9d429c905a0ef6b881cf1c0f775bf14 /core/multimedia/opieplayer/modplug/load_med.cpp | |
parent | 0f24c1fb86d3bb58d8696358b824c0e01752b10d (diff) | |
download | opie-2342d48be31847e7ead9d1cc682452e8f0122351.zip opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.gz opie-2342d48be31847e7ead9d1cc682452e8f0122351.tar.bz2 |
initial commit of modplugin
Diffstat (limited to 'core/multimedia/opieplayer/modplug/load_med.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | core/multimedia/opieplayer/modplug/load_med.cpp | 919 |
1 files changed, 919 insertions, 0 deletions
diff --git a/core/multimedia/opieplayer/modplug/load_med.cpp b/core/multimedia/opieplayer/modplug/load_med.cpp new file mode 100644 index 0000000..1a4b30c --- a/dev/null +++ b/core/multimedia/opieplayer/modplug/load_med.cpp | |||
@@ -0,0 +1,919 @@ | |||
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 | |||
14 | //#define MED_LOG | ||
15 | |||
16 | #ifdef MED_LOG | ||
17 | extern void Log(LPCSTR s, ...); | ||
18 | #endif | ||
19 | |||
20 | ////////////////////////////////////////////////////////// | ||
21 | // OctaMed MED file support (import only) | ||
22 | |||
23 | // flags | ||
24 | #define MMD_FLAG_FILTERON0x1 | ||
25 | #define MMD_FLAG_JUMPINGON0x2 | ||
26 | #define MMD_FLAG_JUMP8TH0x4 | ||
27 | #define MMD_FLAG_INSTRSATT0x8 // instruments are attached (this is a module) | ||
28 | #define MMD_FLAG_VOLHEX 0x10 | ||
29 | #define MMD_FLAG_STSLIDE0x20 // SoundTracker mode for slides | ||
30 | #define MMD_FLAG_8CHANNEL0x40 // OctaMED 8 channel song | ||
31 | #define MMD_FLAG_SLOWHQ 0x80 // HQ slows playing speed (V2-V4 compatibility) | ||
32 | // flags2 | ||
33 | #define MMD_FLAG2_BMASK 0x1F | ||
34 | #define MMD_FLAG2_BPM 0x20 | ||
35 | #define MMD_FLAG2_MIX 0x80 // uses Mixing (V7+) | ||
36 | // flags3: | ||
37 | #define MMD_FLAG3_STEREO 0x1// mixing in Stereo mode | ||
38 | #define MMD_FLAG3_FREEPAN 0x2// free panning | ||
39 | #define MMD_FLAG3_GM 0x4 // module designed for GM/XG compatibility | ||
40 | |||
41 | |||
42 | // generic MMD tags | ||
43 | #define MMDTAG_END 0 | ||
44 | #define MMDTAG_PTR 0x80000000// data needs relocation | ||
45 | #define MMDTAG_MUSTKNOW 0x40000000// loader must fail if this isn't recognized | ||
46 | #define MMDTAG_MUSTWARN 0x20000000// loader must warn if this isn't recognized | ||
47 | |||
48 | // ExpData tags | ||
49 | // # of effect groups, including the global group (will | ||
50 | // override settings in MMDSong struct), default = 1 | ||
51 | #define MMDTAG_EXP_NUMFXGROUPS1 | ||
52 | #define MMDTAG_TRK_NAME (MMDTAG_PTR|1)// trackinfo tags | ||
53 | #define MMDTAG_TRK_NAMELEN 2 // namelen includes zero term. | ||
54 | #define MMDTAG_TRK_FXGROUP3 | ||
55 | // effectinfo tags | ||
56 | #define MMDTAG_FX_ECHOTYPE1 | ||
57 | #define MMDTAG_FX_ECHOLEN2 | ||
58 | #define MMDTAG_FX_ECHODEPTH3 | ||
59 | #define MMDTAG_FX_STEREOSEP4 | ||
60 | #define MMDTAG_FX_GROUPNAME (MMDTAG_PTR|5)// the Global Effects group shouldn't have name saved! | ||
61 | #define MMDTAG_FX_GRPNAMELEN 6// namelen includes zero term. | ||
62 | |||
63 | #pragma pack(1) | ||
64 | |||
65 | typedef struct tagMEDMODULEHEADER | ||
66 | { | ||
67 | DWORD id; // MMD1-MMD3 | ||
68 | DWORD modlen;// Size of file | ||
69 | DWORD song; // Position in file for this song | ||
70 | WORD psecnum; | ||
71 | WORD pseq; | ||
72 | DWORD blockarr;// Position in file for blocks | ||
73 | DWORD mmdflags; | ||
74 | DWORD smplarr;// Position in file for samples | ||
75 | DWORD reserved; | ||
76 | DWORD expdata;// Absolute offset in file for ExpData (0 if not present) | ||
77 | DWORD reserved2; | ||
78 | WORD pstate; | ||
79 | WORD pblock; | ||
80 | WORD pline; | ||
81 | WORD pseqnum; | ||
82 | WORD actplayline; | ||
83 | BYTE counter; | ||
84 | BYTE extra_songs;// # of songs - 1 | ||
85 | } Q_PACKED MEDMODULEHEADER; | ||
86 | |||
87 | |||
88 | typedef struct tagMMD0SAMPLE | ||
89 | { | ||
90 | WORD rep, replen; | ||
91 | BYTE midich; | ||
92 | BYTE midipreset; | ||
93 | BYTE svol; | ||
94 | signed char strans; | ||
95 | } Q_PACKED MMD0SAMPLE; | ||
96 | |||
97 | |||
98 | // Sample header is immediately followed by sample data... | ||
99 | typedef struct tagMMDSAMPLEHEADER | ||
100 | { | ||
101 | DWORD length; // length of *one* *unpacked* channel in *bytes* | ||
102 | WORD type; | ||
103 | // if non-negative | ||
104 | // bits 0-3 reserved for multi-octave instruments, not supported on the PC | ||
105 | // 0x10: 16 bit (otherwise 8 bit) | ||
106 | // 0x20: Stereo (otherwise mono) | ||
107 | // 0x40: Uses DeltaCode | ||
108 | // 0x80: Packed data | ||
109 | // -1: Synth | ||
110 | // -2: Hybrid | ||
111 | // if type indicates packed data, these fields follow, otherwise we go right to the data | ||
112 | WORD packtype;// Only 1 = ADPCM is supported | ||
113 | WORD subtype;// Packing subtype | ||
114 | // ADPCM subtype | ||
115 | // 1: g723_40 | ||
116 | // 2: g721 | ||
117 | // 3: g723_24 | ||
118 | BYTE commonflags;// flags common to all packtypes (none defined so far) | ||
119 | BYTE packerflags;// flags for the specific packtype | ||
120 | ULONG leftchlen;// packed length of left channel in bytes | ||
121 | ULONG rightchlen;// packed length of right channel in bytes (ONLY PRESENT IN STEREO SAMPLES) | ||
122 | BYTE SampleData[1];// Sample Data | ||
123 | } Q_PACKED MMDSAMPLEHEADER; | ||
124 | |||
125 | |||
126 | // MMD0/MMD1 song header | ||
127 | typedef struct tagMMD0SONGHEADER | ||
128 | { | ||
129 | MMD0SAMPLE sample[63]; | ||
130 | WORD numblocks; // # of blocks | ||
131 | WORD songlen; // # of entries used in playseq | ||
132 | BYTE playseq[256];// Play sequence | ||
133 | WORD deftempo; // BPM tempo | ||
134 | signed char playtransp;// Play transpose | ||
135 | BYTE flags; // 0x10: Hex Volumes | 0x20: ST/NT/PT Slides | 0x40: 8 Channels song | ||
136 | BYTE flags2; // [b4-b0]+1: Tempo LPB, 0x20: tempo mode, 0x80: mix_conv=on | ||
137 | BYTE tempo2; // tempo TPL | ||
138 | BYTE trkvol[16];// track volumes | ||
139 | BYTE mastervol; // master volume | ||
140 | BYTE numsamples;// # of samples (max=63) | ||
141 | } Q_PACKED MMD0SONGHEADER; | ||
142 | |||
143 | |||
144 | // MMD2/MMD3 song header | ||
145 | typedef struct tagMMD2SONGHEADER | ||
146 | { | ||
147 | MMD0SAMPLE sample[63]; | ||
148 | WORD numblocks; // # of blocks | ||
149 | WORD numsections;// # of sections | ||
150 | DWORD playseqtable;// filepos of play sequence | ||
151 | DWORD sectiontable;// filepos of sections table (WORD array) | ||
152 | DWORD trackvols;// filepos of tracks volume (BYTE array) | ||
153 | WORD numtracks; // # of tracks (max 64) | ||
154 | WORD numpseqs; // # of play sequences | ||
155 | DWORD trackpans;// filepos of tracks pan values (BYTE array) | ||
156 | LONG flags3; // 0x1:stereo_mix, 0x2:free_panning, 0x4:GM/XG compatibility | ||
157 | WORD voladj; // vol_adjust (set to 100 if 0) | ||
158 | WORD channels; // # of channels (4 if =0) | ||
159 | BYTE mix_echotype;// 1:normal,2:xecho | ||
160 | BYTE mix_echodepth;// 1..6 | ||
161 | WORD mix_echolen;// > 0 | ||
162 | signed char mix_stereosep;// -4..4 | ||
163 | BYTE pad0[223]; | ||
164 | WORD deftempo; // BPM tempo | ||
165 | signed char playtransp;// play transpose | ||
166 | BYTE flags; // 0x1:filteron, 0x2:jumpingon, 0x4:jump8th, 0x8:instr_attached, 0x10:hex_vol, 0x20:PT_slides, 0x40:8ch_conv,0x80:hq slows playing speed | ||
167 | BYTE flags2; // 0x80:mix_conv=on, [b4-b0]+1:tempo LPB, 0x20:tempo_mode | ||
168 | BYTE tempo2; // tempo TPL | ||
169 | BYTE pad1[16]; | ||
170 | BYTE mastervol; // master volume | ||
171 | BYTE numsamples;// # of samples (max 63) | ||
172 | } Q_PACKED MMD2SONGHEADER; | ||
173 | |||
174 | // For MMD0 the note information is held in 3 bytes, byte0, byte1, byte2. For reference we | ||
175 | // number the bits in each byte 0..7, where 0 is the low bit. | ||
176 | // The note is held as bits 5..0 of byte0 | ||
177 | // The instrument is encoded in 6 bits, bits 7 and 6 of byte0 and bits 7,6,5,4 of byte1 | ||
178 | // The command number is bits 3,2,1,0 of byte1, command data is in byte2: | ||
179 | // For command 0, byte2 represents the second data byte, otherwise byte2 | ||
180 | // represents the first data byte. | ||
181 | typedef struct tagMMD0BLOCK | ||
182 | { | ||
183 | BYTE numtracks; | ||
184 | BYTE lines; // File value is 1 less than actual, so 0 -> 1 line | ||
185 | } Q_PACKED MMD0BLOCK; // BYTE data[lines+1][tracks][3]; | ||
186 | |||
187 | |||
188 | // For MMD1,MMD2,MMD3 the note information is carried in 4 bytes, byte0, byte1, | ||
189 | // byte2 and byte3 | ||
190 | // The note is held as byte0 (values above 0x84 are ignored) | ||
191 | // The instrument is held as byte1 | ||
192 | // The command number is held as byte2, command data is in byte3 | ||
193 | // For commands 0 and 0x19 byte3 represents the second data byte, | ||
194 | // otherwise byte2 represents the first data byte. | ||
195 | typedef struct tagMMD1BLOCK | ||
196 | { | ||
197 | WORD numtracks;// Number of tracks, may be > 64, but then that data is skipped. | ||
198 | WORD lines; // Stored value is 1 less than actual, so 0 -> 1 line | ||
199 | DWORD info; // Offset of BlockInfo (if 0, no block_info is present) | ||
200 | } Q_PACKED MMD1BLOCK; | ||
201 | |||
202 | |||
203 | typedef struct tagMMD1BLOCKINFO | ||
204 | { | ||
205 | DWORD hlmask; // Unimplemented - ignore | ||
206 | DWORD blockname;// file offset of block name | ||
207 | DWORD blocknamelen;// length of block name (including term. 0) | ||
208 | DWORD pagetable;// file offset of command page table | ||
209 | DWORD cmdexttable;// file offset of command extension table | ||
210 | DWORD reserved[4];// future expansion | ||
211 | } Q_PACKED MMD1BLOCKINFO; | ||
212 | |||
213 | |||
214 | // A set of play sequences is stored as an array of ULONG files offsets | ||
215 | // Each offset points to the play sequence itself. | ||
216 | typedef struct tagMMD2PLAYSEQ | ||
217 | { | ||
218 | CHAR name[32]; | ||
219 | DWORD command_offs;// filepos of command table | ||
220 | DWORD reserved; | ||
221 | WORD length; | ||
222 | WORD seq[512];// skip if > 0x8000 | ||
223 | } Q_PACKED MMD2PLAYSEQ; | ||
224 | |||
225 | |||
226 | // A command table contains commands that effect a particular play sequence | ||
227 | // entry. The only commands read in are STOP or POSJUMP, all others are ignored | ||
228 | // POSJUMP is presumed to have extra bytes containing a WORD for the position | ||
229 | typedef struct tagMMDCOMMAND | ||
230 | { | ||
231 | WORD offset; // Offset within current sequence entry | ||
232 | BYTE cmdnumber; // STOP (537) or POSJUMP (538) (others skipped) | ||
233 | BYTE extra_count; | ||
234 | BYTE extra_bytes[4];// [extra_count]; | ||
235 | } Q_PACKED MMDCOMMAND; // Last entry has offset == 0xFFFF, cmd_number == 0 and 0 extrabytes | ||
236 | |||
237 | |||
238 | typedef struct tagMMD0EXP | ||
239 | { | ||
240 | DWORD nextmod; // File offset of next Hdr | ||
241 | DWORD exp_smp; // Pointer to extra instrument data | ||
242 | WORD s_ext_entries; // Number of extra instrument entries | ||
243 | WORD s_ext_entrsz; // Size of extra instrument data | ||
244 | DWORD annotxt; | ||
245 | DWORD annolen; | ||
246 | DWORD iinfo; // Instrument names | ||
247 | WORD i_ext_entries; | ||
248 | WORD i_ext_entrsz; | ||
249 | DWORD jumpmask; | ||
250 | DWORD rgbtable; | ||
251 | BYTE channelsplit[4];// Only used if 8ch_conv (extra channel for every nonzero entry) | ||
252 | DWORD n_info; | ||
253 | DWORD songname; // Song name | ||
254 | DWORD songnamelen; | ||
255 | DWORD dumps; | ||
256 | DWORD mmdinfo; | ||
257 | DWORD mmdrexx; | ||
258 | DWORD mmdcmd3x; | ||
259 | DWORD trackinfo_ofs;// ptr to song->numtracks ptrs to tag lists | ||
260 | DWORD effectinfo_ofs;// ptr to group ptrs | ||
261 | DWORD tag_end; | ||
262 | } Q_PACKED MMD0EXP; | ||
263 | |||
264 | #pragma pack() | ||
265 | |||
266 | |||
267 | |||
268 | static void MedConvert(MODCOMMAND *p, const MMD0SONGHEADER *pmsh) | ||
269 | //--------------------------------------------------------------- | ||
270 | { | ||
271 | const BYTE bpmvals[9] = { 179,164,152,141,131,123,116,110,104}; | ||
272 | |||
273 | UINT command = p->command; | ||
274 | UINT param = p->param; | ||
275 | switch(command) | ||
276 | { | ||
277 | case 0x00:if (param) command = CMD_ARPEGGIO; else command = 0; break; | ||
278 | case 0x01:command = CMD_PORTAMENTOUP; break; | ||
279 | case 0x02:command = CMD_PORTAMENTODOWN; break; | ||
280 | case 0x03:command = CMD_TONEPORTAMENTO; break; | ||
281 | case 0x04:command = CMD_VIBRATO; break; | ||
282 | case 0x05:command = CMD_TONEPORTAVOL; break; | ||
283 | case 0x06:command = CMD_VIBRATOVOL; break; | ||
284 | case 0x07:command = CMD_TREMOLO; break; | ||
285 | case 0x0A:if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break; | ||
286 | case 0x0B:command = CMD_POSITIONJUMP; break; | ||
287 | case 0x0C:command = CMD_VOLUME; | ||
288 | if (pmsh->flags & MMD_FLAG_VOLHEX) | ||
289 | { | ||
290 | if (param < 0x80) | ||
291 | { | ||
292 | param = (param+1) / 2; | ||
293 | } else command = 0; | ||
294 | } else | ||
295 | { | ||
296 | if (param <= 0x99) | ||
297 | { | ||
298 | param = (param >> 4)*10+((param & 0x0F) % 10); | ||
299 | if (param > 64) param = 64; | ||
300 | } else command = 0; | ||
301 | } | ||
302 | break; | ||
303 | case 0x09:command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break; | ||
304 | case 0x0D:if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break; | ||
305 | case 0x0F:// Set Tempo / Special | ||
306 | // F.00 = Pattern Break | ||
307 | if (!param) command = CMD_PATTERNBREAK;else | ||
308 | // F.01 - F.F0: Set tempo/speed | ||
309 | if (param <= 0xF0) | ||
310 | { | ||
311 | if (pmsh->flags & MMD_FLAG_8CHANNEL) | ||
312 | { | ||
313 | param = (param > 10) ? 99 : bpmvals[param-1]; | ||
314 | } else | ||
315 | // F.01 - F.0A: Set Speed | ||
316 | if (param <= 0x0A) | ||
317 | { | ||
318 | command = CMD_SPEED; | ||
319 | } else | ||
320 | // Old tempo | ||
321 | if (!(pmsh->flags2 & MMD_FLAG2_BPM)) | ||
322 | { | ||
323 | param = _muldiv(param, 5*715909, 2*474326); | ||
324 | } | ||
325 | // F.0B - F.F0: Set Tempo (assumes LPB=4) | ||
326 | if (param > 0x0A) | ||
327 | { | ||
328 | command = CMD_TEMPO; | ||
329 | if (param < 0x21) param = 0x21; | ||
330 | if (param > 240) param = 240; | ||
331 | } | ||
332 | } else | ||
333 | switch(param) | ||
334 | { | ||
335 | // F.F1: Retrig 2x | ||
336 | case 0xF1: | ||
337 | command = CMD_MODCMDEX; | ||
338 | param = 0x93; | ||
339 | break; | ||
340 | // F.F2: Note Delay 2x | ||
341 | case 0xF2: | ||
342 | command = CMD_MODCMDEX; | ||
343 | param = 0xD3; | ||
344 | break; | ||
345 | // F.F3: Retrig 3x | ||
346 | case 0xF3: | ||
347 | command = CMD_MODCMDEX; | ||
348 | param = 0x92; | ||
349 | break; | ||
350 | // F.F4: Note Delay 1/3 | ||
351 | case 0xF4: | ||
352 | command = CMD_MODCMDEX; | ||
353 | param = 0xD2; | ||
354 | break; | ||
355 | // F.F5: Note Delay 2/3 | ||
356 | case 0xF5: | ||
357 | command = CMD_MODCMDEX; | ||
358 | param = 0xD4; | ||
359 | break; | ||
360 | // F.F8: Filter Off | ||
361 | case 0xF8: | ||
362 | command = CMD_MODCMDEX; | ||
363 | param = 0x00; | ||
364 | break; | ||
365 | // F.F9: Filter On | ||
366 | case 0xF9: | ||
367 | command = CMD_MODCMDEX; | ||
368 | param = 0x01; | ||
369 | break; | ||
370 | // F.FD: Very fast tone-portamento | ||
371 | case 0xFD: | ||
372 | command = CMD_TONEPORTAMENTO; | ||
373 | param = 0xFF; | ||
374 | break; | ||
375 | // F.FE: End Song | ||
376 | case 0xFE: | ||
377 | command = CMD_SPEED; | ||
378 | param = 0; | ||
379 | break; | ||
380 | // F.FF: Note Cut | ||
381 | case 0xFF: | ||
382 | command = CMD_MODCMDEX; | ||
383 | param = 0xC0; | ||
384 | break; | ||
385 | default: | ||
386 | #ifdef MED_LOG | ||
387 | Log("Unknown Fxx command: cmd=0x%02X param=0x%02X\n", command, param); | ||
388 | #endif | ||
389 | param = command = 0; | ||
390 | } | ||
391 | break; | ||
392 | // 11.0x: Fine Slide Up | ||
393 | case 0x11: | ||
394 | command = CMD_MODCMDEX; | ||
395 | if (param > 0x0F) param = 0x0F; | ||
396 | param |= 0x10; | ||
397 | break; | ||
398 | // 12.0x: Fine Slide Down | ||
399 | case 0x12: | ||
400 | command = CMD_MODCMDEX; | ||
401 | if (param > 0x0F) param = 0x0F; | ||
402 | param |= 0x20; | ||
403 | break; | ||
404 | // 14.xx: Vibrato | ||
405 | case 0x14: | ||
406 | command = CMD_VIBRATO; | ||
407 | break; | ||
408 | // 15.xx: FineTune | ||
409 | case 0x15: | ||
410 | command = CMD_MODCMDEX; | ||
411 | param &= 0x0F; | ||
412 | param |= 0x50; | ||
413 | break; | ||
414 | // 16.xx: Pattern Loop | ||
415 | case 0x16: | ||
416 | command = CMD_MODCMDEX; | ||
417 | if (param > 0x0F) param = 0x0F; | ||
418 | param |= 0x60; | ||
419 | break; | ||
420 | // 18.xx: Note Cut | ||
421 | case 0x18: | ||
422 | command = CMD_MODCMDEX; | ||
423 | if (param > 0x0F) param = 0x0F; | ||
424 | param |= 0xC0; | ||
425 | break; | ||
426 | // 19.xx: Sample Offset | ||
427 | case 0x19: | ||
428 | command = CMD_OFFSET; | ||
429 | break; | ||
430 | // 1A.0x: Fine Volume Up | ||
431 | case 0x1A: | ||
432 | command = CMD_MODCMDEX; | ||
433 | if (param > 0x0F) param = 0x0F; | ||
434 | param |= 0xA0; | ||
435 | break; | ||
436 | // 1B.0x: Fine Volume Down | ||
437 | case 0x1B: | ||
438 | command = CMD_MODCMDEX; | ||
439 | if (param > 0x0F) param = 0x0F; | ||
440 | param |= 0xB0; | ||
441 | break; | ||
442 | // 1D.xx: Pattern Break | ||
443 | case 0x1D: | ||
444 | command = CMD_PATTERNBREAK; | ||
445 | break; | ||
446 | // 1E.0x: Pattern Delay | ||
447 | case 0x1E: | ||
448 | command = CMD_MODCMDEX; | ||
449 | if (param > 0x0F) param = 0x0F; | ||
450 | param |= 0xE0; | ||
451 | break; | ||
452 | // 1F.xy: Retrig | ||
453 | case 0x1F: | ||
454 | command = CMD_RETRIG; | ||
455 | param &= 0x0F; | ||
456 | break; | ||
457 | // 2E.xx: set panning | ||
458 | case 0x2E: | ||
459 | command = CMD_MODCMDEX; | ||
460 | param = ((param + 0x10) & 0xFF) >> 1; | ||
461 | if (param > 0x0F) param = 0x0F; | ||
462 | param |= 0x80; | ||
463 | break; | ||
464 | default: | ||
465 | #ifdef MED_LOG | ||
466 | // 0x2E ? | ||
467 | Log("Unknown command: cmd=0x%02X param=0x%02X\n", command, param); | ||
468 | #endif | ||
469 | command = param = 0; | ||
470 | } | ||
471 | p->command = command; | ||
472 | p->param = param; | ||
473 | } | ||
474 | |||
475 | |||
476 | BOOL CSoundFile::ReadMed(const BYTE *lpStream, DWORD dwMemLength) | ||
477 | //--------------------------------------------------------------- | ||
478 | { | ||
479 | const MEDMODULEHEADER *pmmh; | ||
480 | const MMD0SONGHEADER *pmsh; | ||
481 | const MMD2SONGHEADER *pmsh2; | ||
482 | const MMD0EXP *pmex; | ||
483 | DWORD dwBlockArr, dwSmplArr, dwExpData, wNumBlocks; | ||
484 | LPDWORD pdwTable; | ||
485 | CHAR version; | ||
486 | UINT deftempo; | ||
487 | int playtransp = 0; | ||
488 | |||
489 | if ((!lpStream) || (dwMemLength < 0x200)) return FALSE; | ||
490 | pmmh = (MEDMODULEHEADER *)lpStream; | ||
491 | if (((pmmh->id & 0x00FFFFFF) != 0x444D4D) || (!pmmh->song)) return FALSE; | ||
492 | // Check for 'MMDx' | ||
493 | DWORD dwSong = bswapBE32(pmmh->song); | ||
494 | if ((dwSong >= dwMemLength) || (dwSong + sizeof(MMD0SONGHEADER) >= dwMemLength)) return FALSE; | ||
495 | version = (signed char)((pmmh->id >> 24) & 0xFF); | ||
496 | if ((version < '0') || (version > '3')) return FALSE; | ||
497 | #ifdef MED_LOG | ||
498 | Log("\nLoading MMD%c module (flags=0x%02X)...\n", version, bswapBE32(pmmh->mmdflags)); | ||
499 | Log(" modlen = %d\n", bswapBE32(pmmh->modlen)); | ||
500 | Log(" song = 0x%08X\n", bswapBE32(pmmh->song)); | ||
501 | Log(" psecnum = %d\n", bswapBE16(pmmh->psecnum)); | ||
502 | Log(" pseq = %d\n", bswapBE16(pmmh->pseq)); | ||
503 | Log(" blockarr = 0x%08X\n", bswapBE32(pmmh->blockarr)); | ||
504 | Log(" mmdflags = 0x%08X\n", bswapBE32(pmmh->mmdflags)); | ||
505 | Log(" smplarr = 0x%08X\n", bswapBE32(pmmh->smplarr)); | ||
506 | Log(" reserved = 0x%08X\n", bswapBE32(pmmh->reserved)); | ||
507 | Log(" expdata = 0x%08X\n", bswapBE32(pmmh->expdata)); | ||
508 | Log(" reserved2= 0x%08X\n", bswapBE32(pmmh->reserved2)); | ||
509 | Log(" pstate = %d\n", bswapBE16(pmmh->pstate)); | ||
510 | Log(" pblock = %d\n", bswapBE16(pmmh->pblock)); | ||
511 | Log(" pline = %d\n", bswapBE16(pmmh->pline)); | ||
512 | Log(" pseqnum = %d\n", bswapBE16(pmmh->pseqnum)); | ||
513 | Log(" actplayline=%d\n", bswapBE16(pmmh->actplayline)); | ||
514 | Log(" counter = %d\n", pmmh->counter); | ||
515 | Log(" extra_songs = %d\n", pmmh->extra_songs); | ||
516 | Log("\n"); | ||
517 | #endif | ||
518 | m_nType = MOD_TYPE_MED; | ||
519 | m_nSongPreAmp = 0x20; | ||
520 | dwBlockArr = bswapBE32(pmmh->blockarr); | ||
521 | dwSmplArr = bswapBE32(pmmh->smplarr); | ||
522 | dwExpData = bswapBE32(pmmh->expdata); | ||
523 | if ((dwExpData) && (dwExpData+sizeof(MMD0EXP) < dwMemLength)) | ||
524 | pmex = (MMD0EXP *)(lpStream+dwExpData); | ||
525 | else | ||
526 | pmex = NULL; | ||
527 | pmsh = (MMD0SONGHEADER *)(lpStream + dwSong); | ||
528 | pmsh2 = (MMD2SONGHEADER *)pmsh; | ||
529 | #ifdef MED_LOG | ||
530 | if (version < '2') | ||
531 | { | ||
532 | Log("MMD0 Header:\n"); | ||
533 | Log(" numblocks = %d\n", bswapBE16(pmsh->numblocks)); | ||
534 | Log(" songlen = %d\n", bswapBE16(pmsh->songlen)); | ||
535 | Log(" playseq = "); | ||
536 | for (UINT idbg1=0; idbg1<16; idbg1++) Log("%2d, ", pmsh->playseq[idbg1]); | ||
537 | Log("...\n"); | ||
538 | Log(" deftempo = 0x%04X\n", bswapBE16(pmsh->deftempo)); | ||
539 | Log(" playtransp = %d\n", (signed char)pmsh->playtransp); | ||
540 | Log(" flags(1,2) = 0x%02X, 0x%02X\n", pmsh->flags, pmsh->flags2); | ||
541 | Log(" tempo2 = %d\n", pmsh->tempo2); | ||
542 | Log(" trkvol = "); | ||
543 | for (UINT idbg2=0; idbg2<16; idbg2++) Log("0x%02X, ", pmsh->trkvol[idbg2]); | ||
544 | Log("...\n"); | ||
545 | Log(" mastervol = 0x%02X\n", pmsh->mastervol); | ||
546 | Log(" numsamples = %d\n", pmsh->numsamples); | ||
547 | } else | ||
548 | { | ||
549 | Log("MMD2 Header:\n"); | ||
550 | Log(" numblocks = %d\n", bswapBE16(pmsh2->numblocks)); | ||
551 | Log(" numsections= %d\n", bswapBE16(pmsh2->numsections)); | ||
552 | Log(" playseqptr = 0x%04X\n", bswapBE32(pmsh2->playseqtable)); | ||
553 | Log(" sectionptr = 0x%04X\n", bswapBE32(pmsh2->sectiontable)); | ||
554 | Log(" trackvols = 0x%04X\n", bswapBE32(pmsh2->trackvols)); | ||
555 | Log(" numtracks = %d\n", bswapBE16(pmsh2->numtracks)); | ||
556 | Log(" numpseqs = %d\n", bswapBE16(pmsh2->numpseqs)); | ||
557 | Log(" trackpans = 0x%04X\n", bswapBE32(pmsh2->trackpans)); | ||
558 | Log(" flags3 = 0x%08X\n", bswapBE32(pmsh2->flags3)); | ||
559 | Log(" voladj = %d\n", bswapBE16(pmsh2->voladj)); | ||
560 | Log(" channels = %d\n", bswapBE16(pmsh2->channels)); | ||
561 | Log(" echotype = %d\n", pmsh2->mix_echotype); | ||
562 | Log(" echodepth = %d\n", pmsh2->mix_echodepth); | ||
563 | Log(" echolen = %d\n", bswapBE16(pmsh2->mix_echolen)); | ||
564 | Log(" stereosep = %d\n", (signed char)pmsh2->mix_stereosep); | ||
565 | Log(" deftempo = 0x%04X\n", bswapBE16(pmsh2->deftempo)); | ||
566 | Log(" playtransp = %d\n", (signed char)pmsh2->playtransp); | ||
567 | Log(" flags(1,2) = 0x%02X, 0x%02X\n", pmsh2->flags, pmsh2->flags2); | ||
568 | Log(" tempo2 = %d\n", pmsh2->tempo2); | ||
569 | Log(" mastervol = 0x%02X\n", pmsh2->mastervol); | ||
570 | Log(" numsamples = %d\n", pmsh->numsamples); | ||
571 | } | ||
572 | Log("\n"); | ||
573 | #endif | ||
574 | wNumBlocks = bswapBE16(pmsh->numblocks); | ||
575 | m_nChannels = 4; | ||
576 | m_nSamples = pmsh->numsamples; | ||
577 | if (m_nSamples > 63) m_nSamples = 63; | ||
578 | // Tempo | ||
579 | m_nDefaultTempo = 125; | ||
580 | deftempo = bswapBE16(pmsh->deftempo); | ||
581 | if (!deftempo) deftempo = 125; | ||
582 | if (pmsh->flags2 & MMD_FLAG2_BPM) | ||
583 | { | ||
584 | UINT tempo_tpl = (pmsh->flags2 & MMD_FLAG2_BMASK) + 1; | ||
585 | if (!tempo_tpl) tempo_tpl = 4; | ||
586 | deftempo *= tempo_tpl; | ||
587 | deftempo /= 4; | ||
588 | #ifdef MED_LOG | ||
589 | Log("newtempo: %3d bpm (bpm=%3d lpb=%2d)\n", deftempo, bswapBE16(pmsh->deftempo), (pmsh->flags2 & MMD_FLAG2_BMASK)+1); | ||
590 | #endif | ||
591 | } else | ||
592 | { | ||
593 | deftempo = _muldiv(deftempo, 5*715909, 2*474326); | ||
594 | #ifdef MED_LOG | ||
595 | Log("oldtempo: %3d bpm (bpm=%3d)\n", deftempo, bswapBE16(pmsh->deftempo)); | ||
596 | #endif | ||
597 | } | ||
598 | // Speed | ||
599 | m_nDefaultSpeed = pmsh->tempo2; | ||
600 | if (!m_nDefaultSpeed) m_nDefaultSpeed = 6; | ||
601 | if (deftempo < 0x21) deftempo = 0x21; | ||
602 | if (deftempo > 255) | ||
603 | { | ||
604 | while ((m_nDefaultSpeed > 3) && (deftempo > 260)) | ||
605 | { | ||
606 | deftempo = (deftempo * (m_nDefaultSpeed - 1)) / m_nDefaultSpeed; | ||
607 | m_nDefaultSpeed--; | ||
608 | } | ||
609 | if (deftempo > 255) deftempo = 255; | ||
610 | } | ||
611 | m_nDefaultTempo = deftempo; | ||
612 | // Reading Samples | ||
613 | for (UINT iSHdr=0; iSHdr<m_nSamples; iSHdr++) | ||
614 | { | ||
615 | MODINSTRUMENT *pins = &Ins[iSHdr+1]; | ||
616 | pins->nLoopStart = bswapBE16(pmsh->sample[iSHdr].rep) << 1; | ||
617 | pins->nLoopEnd = pins->nLoopStart + (bswapBE16(pmsh->sample[iSHdr].replen) << 1); | ||
618 | pins->nVolume = (pmsh->sample[iSHdr].svol << 2); | ||
619 | pins->nGlobalVol = 64; | ||
620 | if (pins->nVolume > 256) pins->nVolume = 256; | ||
621 | pins->RelativeTone = -12 * pmsh->sample[iSHdr].strans; | ||
622 | pins->nPan = 128; | ||
623 | if (pins->nLoopEnd) pins->uFlags |= CHN_LOOP; | ||
624 | } | ||
625 | // Common Flags | ||
626 | if (!(pmsh->flags & 0x20)) m_dwSongFlags |= SONG_FASTVOLSLIDES; | ||
627 | // Reading play sequence | ||
628 | if (version < '2') | ||
629 | { | ||
630 | UINT nbo = pmsh->songlen >> 8; | ||
631 | if (nbo >= MAX_ORDERS) nbo = MAX_ORDERS-1; | ||
632 | if (!nbo) nbo = 1; | ||
633 | memcpy(Order, pmsh->playseq, nbo); | ||
634 | playtransp = pmsh->playtransp; | ||
635 | } else | ||
636 | { | ||
637 | UINT nOrders, nSections; | ||
638 | UINT nTrks = bswapBE16(pmsh2->numtracks); | ||
639 | if ((nTrks >= 4) && (nTrks <= 32)) m_nChannels = nTrks; | ||
640 | DWORD playseqtable = bswapBE32(pmsh2->playseqtable); | ||
641 | UINT numplayseqs = bswapBE16(pmsh2->numpseqs); | ||
642 | if (!numplayseqs) numplayseqs = 1; | ||
643 | nOrders = 0; | ||
644 | nSections = bswapBE16(pmsh2->numsections); | ||
645 | DWORD sectiontable = bswapBE32(pmsh2->sectiontable); | ||
646 | if ((!nSections) || (!sectiontable) || (sectiontable >= dwMemLength-2)) nSections = 1; | ||
647 | nOrders = 0; | ||
648 | for (UINT iSection=0; iSection<nSections; iSection++) | ||
649 | { | ||
650 | UINT nplayseq = 0; | ||
651 | if ((sectiontable) && (sectiontable < dwMemLength-2)) | ||
652 | { | ||
653 | nplayseq = lpStream[sectiontable+1]; | ||
654 | sectiontable += 2; // WORDs | ||
655 | } else | ||
656 | { | ||
657 | nSections = 0; | ||
658 | } | ||
659 | UINT pseq = 0; | ||
660 | |||
661 | if ((playseqtable) && (playseqtable + nplayseq*4 < dwMemLength)) | ||
662 | { | ||
663 | pseq = bswapBE32(((LPDWORD)(lpStream+playseqtable))[nplayseq]); | ||
664 | } | ||
665 | if ((pseq) && (pseq < dwMemLength - sizeof(MMD2PLAYSEQ))) | ||
666 | { | ||
667 | MMD2PLAYSEQ *pmps = (MMD2PLAYSEQ *)(lpStream + pseq); | ||
668 | if (!m_szNames[0][0]) memcpy(m_szNames[0], pmps->name, 31); | ||
669 | UINT n = bswapBE16(pmps->length); | ||
670 | if (pseq+n <= dwMemLength) | ||
671 | { | ||
672 | for (UINT i=0; i<n; i++) | ||
673 | { | ||
674 | UINT seqval = pmps->seq[i] >> 8; | ||
675 | if ((seqval < wNumBlocks) && (nOrders < MAX_ORDERS-1)) | ||
676 | { | ||
677 | Order[nOrders++] = seqval; | ||
678 | } | ||
679 | } | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | playtransp = pmsh2->playtransp; | ||
684 | while (nOrders < MAX_ORDERS) Order[nOrders++] = 0xFF; | ||
685 | } | ||
686 | // Reading Expansion structure | ||
687 | if (pmex) | ||
688 | { | ||
689 | // Channel Split | ||
690 | if ((m_nChannels == 4) && (pmsh->flags & 0x40)) | ||
691 | { | ||
692 | for (UINT i8ch=0; i8ch<4; i8ch++) | ||
693 | { | ||
694 | if (pmex->channelsplit[i8ch]) m_nChannels++; | ||
695 | } | ||
696 | } | ||
697 | // Song Comments | ||
698 | UINT annotxt = bswapBE32(pmex->annotxt); | ||
699 | UINT annolen = bswapBE32(pmex->annolen); | ||
700 | if ((annotxt) && (annolen) && (annotxt+annolen <= dwMemLength)) | ||
701 | { | ||
702 | m_lpszSongComments = new char[annolen+1]; | ||
703 | memcpy(m_lpszSongComments, lpStream+annotxt, annolen); | ||
704 | m_lpszSongComments[annolen] = 0; | ||
705 | } | ||
706 | // Song Name | ||
707 | UINT songname = bswapBE32(pmex->songname); | ||
708 | UINT songnamelen = bswapBE32(pmex->songnamelen); | ||
709 | if ((songname) && (songnamelen) && (songname+songnamelen <= dwMemLength)) | ||
710 | { | ||
711 | if (songnamelen > 31) songnamelen = 31; | ||
712 | memcpy(m_szNames[0], lpStream+songname, songnamelen); | ||
713 | } | ||
714 | // Sample Names | ||
715 | DWORD smpinfoex = bswapBE32(pmex->iinfo); | ||
716 | if (smpinfoex) | ||
717 | { | ||
718 | DWORD iinfoptr = bswapBE32(pmex->iinfo); | ||
719 | UINT ientries = bswapBE16(pmex->i_ext_entries); | ||
720 | UINT ientrysz = bswapBE16(pmex->i_ext_entrsz); | ||
721 | |||
722 | if ((iinfoptr) && (ientrysz < 256) && (iinfoptr + ientries*ientrysz < dwMemLength)) | ||
723 | { | ||
724 | LPCSTR psznames = (LPCSTR)(lpStream + iinfoptr); | ||
725 | UINT maxnamelen = ientrysz; | ||
726 | if (maxnamelen > 32) maxnamelen = 32; | ||
727 | for (UINT i=0; i<ientries; i++) if (i < m_nSamples) | ||
728 | { | ||
729 | lstrcpyn(m_szNames[i+1], psznames + i*ientrysz, maxnamelen); | ||
730 | } | ||
731 | } | ||
732 | } | ||
733 | // Track Names | ||
734 | DWORD trackinfo_ofs = bswapBE32(pmex->trackinfo_ofs); | ||
735 | if ((trackinfo_ofs) && (trackinfo_ofs + m_nChannels * 4 < dwMemLength)) | ||
736 | { | ||
737 | DWORD *ptrktags = (DWORD *)(lpStream + trackinfo_ofs); | ||
738 | for (UINT i=0; i<m_nChannels; i++) | ||
739 | { | ||
740 | DWORD trknameofs = 0, trknamelen = 0; | ||
741 | DWORD trktagofs = bswapBE32(ptrktags[i]); | ||
742 | if (trktagofs) | ||
743 | { | ||
744 | while (trktagofs+8 < dwMemLength) | ||
745 | { | ||
746 | DWORD ntag = bswapBE32(*(DWORD *)(lpStream + trktagofs)); | ||
747 | if (ntag == MMDTAG_END) break; | ||
748 | DWORD tagdata = bswapBE32(*(DWORD *)(lpStream + trktagofs + 4)); | ||
749 | switch(ntag) | ||
750 | { | ||
751 | case MMDTAG_TRK_NAMELEN:trknamelen = tagdata; break; | ||
752 | case MMDTAG_TRK_NAME: trknameofs = tagdata; break; | ||
753 | } | ||
754 | trktagofs += 8; | ||
755 | } | ||
756 | if (trknamelen > MAX_CHANNELNAME) trknamelen = MAX_CHANNELNAME; | ||
757 | if ((trknameofs) && (trknameofs + trknamelen < dwMemLength)) | ||
758 | { | ||
759 | lstrcpyn(ChnSettings[i].szName, (LPCSTR)(lpStream+trknameofs), MAX_CHANNELNAME); | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | // Reading samples | ||
766 | if (dwSmplArr > dwMemLength - 4*m_nSamples) return TRUE; | ||
767 | pdwTable = (LPDWORD)(lpStream + dwSmplArr); | ||
768 | for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (pdwTable[iSmp]) | ||
769 | { | ||
770 | UINT dwPos = bswapBE32(pdwTable[iSmp]); | ||
771 | if ((dwPos >= dwMemLength) || (dwPos + sizeof(MMDSAMPLEHEADER) >= dwMemLength)) continue; | ||
772 | MMDSAMPLEHEADER *psdh = (MMDSAMPLEHEADER *)(lpStream + dwPos); | ||
773 | UINT len = bswapBE32(psdh->length); | ||
774 | #ifdef MED_LOG | ||
775 | Log("SampleData %d: stype=0x%02X len=%d\n", iSmp, bswapBE16(psdh->type), len); | ||
776 | #endif | ||
777 | if ((len > MAX_SAMPLE_LENGTH) || (dwPos + len + 6 > dwMemLength)) len = 0; | ||
778 | UINT flags = RS_PCM8S, stype = bswapBE16(psdh->type); | ||
779 | LPSTR psdata = (LPSTR)(lpStream + dwPos + 6); | ||
780 | if (stype & 0x80) | ||
781 | { | ||
782 | psdata += (stype & 0x20) ? 14 : 6; | ||
783 | } else | ||
784 | { | ||
785 | if (stype & 0x10) | ||
786 | { | ||
787 | Ins[iSmp+1].uFlags |= CHN_16BIT; | ||
788 | len /= 2; | ||
789 | flags = (stype & 0x20) ? RS_STPCM16M : RS_PCM16M; | ||
790 | } else | ||
791 | { | ||
792 | flags = (stype & 0x20) ? RS_STPCM8S : RS_PCM8S; | ||
793 | } | ||
794 | if (stype & 0x20) len /= 2; | ||
795 | } | ||
796 | Ins[iSmp+1].nLength = len; | ||
797 | ReadSample(&Ins[iSmp+1], flags, psdata, dwMemLength - dwPos - 6); | ||
798 | } | ||
799 | // Reading patterns (blocks) | ||
800 | if (wNumBlocks > MAX_PATTERNS) wNumBlocks = MAX_PATTERNS; | ||
801 | if ((!dwBlockArr) || (dwBlockArr > dwMemLength - 4*wNumBlocks)) return TRUE; | ||
802 | pdwTable = (LPDWORD)(lpStream + dwBlockArr); | ||
803 | playtransp += (version == '3') ? 24 : 48; | ||
804 | for (UINT iBlk=0; iBlk<wNumBlocks; iBlk++) | ||
805 | { | ||
806 | UINT dwPos = bswapBE32(pdwTable[iBlk]); | ||
807 | if ((!dwPos) || (dwPos >= dwMemLength) || (dwPos >= dwMemLength - 8)) continue; | ||
808 | UINT lines = 64, tracks = 4; | ||
809 | if (version == '0') | ||
810 | { | ||
811 | const MMD0BLOCK *pmb = (const MMD0BLOCK *)(lpStream + dwPos); | ||
812 | lines = pmb->lines + 1; | ||
813 | tracks = pmb->numtracks; | ||
814 | if (!tracks) tracks = m_nChannels; | ||
815 | if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue; | ||
816 | PatternSize[iBlk] = lines; | ||
817 | MODCOMMAND *p = Patterns[iBlk]; | ||
818 | LPBYTE s = (LPBYTE)(lpStream + dwPos + 2); | ||
819 | UINT maxlen = tracks*lines*3; | ||
820 | if (maxlen + dwPos > dwMemLength - 2) break; | ||
821 | for (UINT y=0; y<lines; y++) | ||
822 | { | ||
823 | for (UINT x=0; x<tracks; x++, s+=3) if (x < m_nChannels) | ||
824 | { | ||
825 | BYTE note = s[0] & 0x3F; | ||
826 | BYTE instr = s[1] >> 4; | ||
827 | if (s[0] & 0x80) instr |= 0x10; | ||
828 | if (s[0] & 0x40) instr |= 0x20; | ||
829 | if ((note) && (note <= 132)) p->note = note + playtransp; | ||
830 | p->instr = instr; | ||
831 | p->command = s[1] & 0x0F; | ||
832 | p->param = s[2]; | ||
833 | // if (!iBlk) Log("%02X.%02X.%02X | ", s[0], s[1], s[2]); | ||
834 | MedConvert(p, pmsh); | ||
835 | p++; | ||
836 | } | ||
837 | //if (!iBlk) Log("\n"); | ||
838 | } | ||
839 | } else | ||
840 | { | ||
841 | MMD1BLOCK *pmb = (MMD1BLOCK *)(lpStream + dwPos); | ||
842 | #ifdef MED_LOG | ||
843 | Log("MMD1BLOCK: lines=%2d, tracks=%2d, offset=0x%04X\n", | ||
844 | bswapBE16(pmb->lines), bswapBE16(pmb->numtracks), bswapBE32(pmb->info)); | ||
845 | #endif | ||
846 | MMD1BLOCKINFO *pbi = NULL; | ||
847 | BYTE *pcmdext = NULL; | ||
848 | lines = (pmb->lines >> 8) + 1; | ||
849 | tracks = pmb->numtracks >> 8; | ||
850 | if (!tracks) tracks = m_nChannels; | ||
851 | if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue; | ||
852 | PatternSize[iBlk] = (WORD)lines; | ||
853 | DWORD dwBlockInfo = bswapBE32(pmb->info); | ||
854 | if ((dwBlockInfo) && (dwBlockInfo < dwMemLength - sizeof(MMD1BLOCKINFO))) | ||
855 | { | ||
856 | pbi = (MMD1BLOCKINFO *)(lpStream + dwBlockInfo); | ||
857 | #ifdef MED_LOG | ||
858 | Log(" BLOCKINFO: blockname=0x%04X namelen=%d pagetable=0x%04X &cmdexttable=0x%04X\n", | ||
859 | bswapBE32(pbi->blockname), bswapBE32(pbi->blocknamelen), bswapBE32(pbi->pagetable), bswapBE32(pbi->cmdexttable)); | ||
860 | #endif | ||
861 | if ((pbi->blockname) && (pbi->blocknamelen)) | ||
862 | { | ||
863 | DWORD nameofs = bswapBE32(pbi->blockname); | ||
864 | UINT namelen = bswapBE32(pbi->blocknamelen); | ||
865 | if ((nameofs < dwMemLength) && (nameofs+namelen < dwMemLength)) | ||
866 | { | ||
867 | SetPatternName(iBlk, (LPCSTR)(lpStream+nameofs)); | ||
868 | } | ||
869 | } | ||
870 | if (pbi->cmdexttable) | ||
871 | { | ||
872 | DWORD cmdexttable = bswapBE32(pbi->cmdexttable); | ||
873 | if (cmdexttable < dwMemLength - 4) | ||
874 | { | ||
875 | cmdexttable = bswapBE32(*(DWORD *)(lpStream + cmdexttable)); | ||
876 | if ((cmdexttable) && (cmdexttable <= dwMemLength - lines*tracks)) | ||
877 | { | ||
878 | pcmdext = (BYTE *)(lpStream + cmdexttable); | ||
879 | } | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | MODCOMMAND *p = Patterns[iBlk]; | ||
884 | LPBYTE s = (LPBYTE)(lpStream + dwPos + 8); | ||
885 | UINT maxlen = tracks*lines*4; | ||
886 | if (maxlen + dwPos > dwMemLength - 8) break; | ||
887 | for (UINT y=0; y<lines; y++) | ||
888 | { | ||
889 | for (UINT x=0; x<tracks; x++, s+=4) if (x < m_nChannels) | ||
890 | { | ||
891 | BYTE note = s[0]; | ||
892 | if ((note) && (note <= 132)) | ||
893 | { | ||
894 | int rnote = note + playtransp; | ||
895 | if (rnote < 1) rnote = 1; | ||
896 | if (rnote > 120) rnote = 120; | ||
897 | p->note = (BYTE)rnote; | ||
898 | } | ||
899 | p->instr = s[1]; | ||
900 | p->command = s[2]; | ||
901 | p->param = s[3]; | ||
902 | if (pcmdext) p->vol = pcmdext[x]; | ||
903 | MedConvert(p, pmsh); | ||
904 | p++; | ||
905 | } | ||
906 | if (pcmdext) pcmdext += tracks; | ||
907 | } | ||
908 | } | ||
909 | } | ||
910 | // Setup channel pan positions | ||
911 | for (UINT iCh=0; iCh<m_nChannels; iCh++) | ||
912 | { | ||
913 | ChnSettings[iCh].nPan = (((iCh&3) == 1) || ((iCh&3) == 2)) ? 0xC0 : 0x40; | ||
914 | ChnSettings[iCh].nVolume = 64; | ||
915 | } | ||
916 | return TRUE; | ||
917 | } | ||
918 | |||
919 | |||