Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

load_med.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is  free software; you can redistribute it  and modify it
00003  * under the terms of the GNU  General Public License as published by the
00004  * Free Software Foundation; either version 2  of the license or (at your
00005  * option) any later version.
00006  *
00007  * Authors: Olivier Lapicque <olivierl@jps.net>,
00008  *          Adam Goode       <adam@evdebs.org> (endian and char fixes for PPC)
00009 */
00010 
00011 #include "stdafx.h"
00012 #include "sndfile.h"
00013 
00014 //#define MED_LOG
00015 
00016 #ifdef MED_LOG
00017 extern void Log(LPCSTR s, ...);
00018 #endif
00019 
00021 // OctaMed MED file support (import only)
00022 
00023 // flags
00024 #define MMD_FLAG_FILTERON       0x1
00025 #define MMD_FLAG_JUMPINGON      0x2
00026 #define MMD_FLAG_JUMP8TH        0x4
00027 #define MMD_FLAG_INSTRSATT      0x8 // instruments are attached (this is a module)
00028 #define MMD_FLAG_VOLHEX         0x10
00029 #define MMD_FLAG_STSLIDE        0x20 // SoundTracker mode for slides
00030 #define MMD_FLAG_8CHANNEL       0x40 // OctaMED 8 channel song
00031 #define MMD_FLAG_SLOWHQ         0x80 // HQ slows playing speed (V2-V4 compatibility)
00032 // flags2
00033 #define MMD_FLAG2_BMASK         0x1F
00034 #define MMD_FLAG2_BPM           0x20
00035 #define MMD_FLAG2_MIX           0x80 // uses Mixing (V7+)
00036 // flags3:
00037 #define MMD_FLAG3_STEREO        0x1     // mixing in Stereo mode
00038 #define MMD_FLAG3_FREEPAN       0x2     // free panning
00039 #define MMD_FLAG3_GM            0x4 // module designed for GM/XG compatibility
00040 
00041 
00042 // generic MMD tags
00043 #define MMDTAG_END              0
00044 #define MMDTAG_PTR              0x80000000      // data needs relocation
00045 #define MMDTAG_MUSTKNOW 0x40000000      // loader must fail if this isn't recognized
00046 #define MMDTAG_MUSTWARN 0x20000000      // loader must warn if this isn't recognized
00047 
00048 // ExpData tags
00049 // # of effect groups, including the global group (will
00050 // override settings in MMDSong struct), default = 1
00051 #define MMDTAG_EXP_NUMFXGROUPS  1
00052 #define MMDTAG_TRK_NAME         (MMDTAG_PTR|1)  // trackinfo tags
00053 #define MMDTAG_TRK_NAMELEN      2                               // namelen includes zero term.
00054 #define MMDTAG_TRK_FXGROUP      3
00055 // effectinfo tags
00056 #define MMDTAG_FX_ECHOTYPE      1
00057 #define MMDTAG_FX_ECHOLEN       2
00058 #define MMDTAG_FX_ECHODEPTH     3
00059 #define MMDTAG_FX_STEREOSEP     4
00060 #define MMDTAG_FX_GROUPNAME     (MMDTAG_PTR|5)  // the Global Effects group shouldn't have name saved!
00061 #define MMDTAG_FX_GRPNAMELEN 6  // namelen includes zero term.
00062 
00063 #pragma pack(1)
00064 
00065 typedef struct tagMEDMODULEHEADER
00066 {
00067         DWORD id;               // MMD1-MMD3
00068         DWORD modlen;   // Size of file
00069         DWORD song;             // Position in file for this song
00070         WORD psecnum;
00071         WORD pseq;
00072         DWORD blockarr; // Position in file for blocks
00073         DWORD mmdflags;
00074         DWORD smplarr;  // Position in file for samples
00075         DWORD reserved;
00076         DWORD expdata;  // Absolute offset in file for ExpData (0 if not present)
00077         DWORD reserved2;
00078         WORD pstate;
00079         WORD pblock;
00080         WORD pline;
00081         WORD pseqnum;
00082         WORD actplayline;
00083         BYTE counter;
00084         BYTE extra_songs;       // # of songs - 1
00085 } Q_PACKED MEDMODULEHEADER;
00086 
00087 
00088 typedef struct tagMMD0SAMPLE
00089 {
00090         WORD rep, replen;
00091         BYTE midich;
00092         BYTE midipreset;
00093         BYTE svol;
00094         signed char strans;
00095 } Q_PACKED MMD0SAMPLE;
00096 
00097 
00098 // Sample header is immediately followed by sample data...
00099 typedef struct tagMMDSAMPLEHEADER
00100 {
00101         DWORD length;     // length of *one* *unpacked* channel in *bytes*
00102         WORD type;   
00103                                 // if non-negative
00104                                         // bits 0-3 reserved for multi-octave instruments, not supported on the PC
00105                                         // 0x10: 16 bit (otherwise 8 bit)
00106                                         // 0x20: Stereo (otherwise mono)
00107                                         // 0x40: Uses DeltaCode
00108                                         // 0x80: Packed data
00109                                 // -1: Synth
00110                                 // -2: Hybrid
00111         // if type indicates packed data, these fields follow, otherwise we go right to the data
00112         WORD packtype;  // Only 1 = ADPCM is supported
00113         WORD subtype;   // Packing subtype
00114                 // ADPCM subtype
00115                 // 1: g723_40
00116                 // 2: g721
00117                 // 3: g723_24
00118         BYTE commonflags;       // flags common to all packtypes (none defined so far)
00119         BYTE packerflags;       // flags for the specific packtype
00120         ULONG leftchlen;        // packed length of left channel in bytes
00121         ULONG rightchlen;       // packed length of right channel in bytes (ONLY PRESENT IN STEREO SAMPLES)
00122         BYTE SampleData[1];     // Sample Data
00123 } Q_PACKED MMDSAMPLEHEADER;
00124 
00125 
00126 // MMD0/MMD1 song header
00127 typedef struct tagMMD0SONGHEADER
00128 {
00129         MMD0SAMPLE sample[63];
00130         WORD numblocks;         // # of blocks
00131         WORD songlen;           // # of entries used in playseq
00132         BYTE playseq[256];      // Play sequence
00133         WORD deftempo;          // BPM tempo
00134         signed char playtransp; // Play transpose
00135         BYTE flags;                     // 0x10: Hex Volumes | 0x20: ST/NT/PT Slides | 0x40: 8 Channels song
00136         BYTE flags2;            // [b4-b0]+1: Tempo LPB, 0x20: tempo mode, 0x80: mix_conv=on
00137         BYTE tempo2;            // tempo TPL
00138         BYTE trkvol[16];        // track volumes
00139         BYTE mastervol;         // master volume
00140         BYTE numsamples;        // # of samples (max=63)
00141 } Q_PACKED MMD0SONGHEADER;
00142 
00143 
00144 // MMD2/MMD3 song header
00145 typedef struct tagMMD2SONGHEADER
00146 {
00147         MMD0SAMPLE sample[63];
00148         WORD numblocks;         // # of blocks
00149         WORD numsections;       // # of sections
00150         DWORD playseqtable;     // filepos of play sequence
00151         DWORD sectiontable;     // filepos of sections table (WORD array)
00152         DWORD trackvols;        // filepos of tracks volume (BYTE array)
00153         WORD numtracks;         // # of tracks (max 64)
00154         WORD numpseqs;          // # of play sequences
00155         DWORD trackpans;        // filepos of tracks pan values (BYTE array)
00156         LONG flags3;            // 0x1:stereo_mix, 0x2:free_panning, 0x4:GM/XG compatibility
00157         WORD voladj;            // vol_adjust (set to 100 if 0)
00158         WORD channels;          // # of channels (4 if =0)
00159         BYTE mix_echotype;      // 1:normal,2:xecho
00160         BYTE mix_echodepth;     // 1..6
00161         WORD mix_echolen;       // > 0
00162         signed char mix_stereosep;      // -4..4
00163         BYTE pad0[223];
00164         WORD deftempo;          // BPM tempo
00165         signed char playtransp; // play transpose
00166         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
00167         BYTE flags2;            // 0x80:mix_conv=on, [b4-b0]+1:tempo LPB, 0x20:tempo_mode
00168         BYTE tempo2;            // tempo TPL
00169         BYTE pad1[16];
00170         BYTE mastervol;         // master volume
00171         BYTE numsamples;        // # of samples (max 63)
00172 } Q_PACKED MMD2SONGHEADER;
00173 
00174 // For MMD0 the note information is held in 3 bytes, byte0, byte1, byte2.  For reference we 
00175 // number the bits in each byte 0..7, where 0 is the low bit.
00176 // The note is held as bits 5..0 of byte0
00177 // The instrument is encoded in 6 bits,  bits 7 and 6 of byte0 and bits 7,6,5,4 of byte1
00178 // The command number is bits 3,2,1,0 of byte1, command data is in byte2:
00179 // For command 0, byte2 represents the second data byte, otherwise byte2
00180 // represents the first data byte.
00181 typedef struct tagMMD0BLOCK
00182 {
00183         BYTE numtracks;
00184         BYTE lines;             // File value is 1 less than actual, so 0 -> 1 line
00185 } Q_PACKED MMD0BLOCK;           // BYTE data[lines+1][tracks][3];
00186 
00187 
00188 // For MMD1,MMD2,MMD3 the note information is carried in 4 bytes, byte0, byte1,
00189 // byte2 and byte3
00190 // The note is held as byte0 (values above 0x84 are ignored)
00191 // The instrument is held as byte1
00192 // The command number is held as byte2, command data is in byte3
00193 // For commands 0 and 0x19 byte3 represents the second data byte,
00194 // otherwise byte2 represents the first data byte.
00195 typedef struct tagMMD1BLOCK
00196 {
00197         WORD numtracks; // Number of tracks, may be > 64, but then that data is skipped.
00198         WORD lines;             // Stored value is 1 less than actual, so 0 -> 1 line
00199         DWORD info;             // Offset of BlockInfo (if 0, no block_info is present)
00200 } Q_PACKED MMD1BLOCK;
00201 
00202 
00203 typedef struct tagMMD1BLOCKINFO
00204 {
00205         DWORD hlmask;           // Unimplemented - ignore
00206         DWORD blockname;        // file offset of block name
00207         DWORD blocknamelen;     // length of block name (including term. 0)
00208         DWORD pagetable;        // file offset of command page table
00209         DWORD cmdexttable;      // file offset of command extension table
00210         DWORD reserved[4];      // future expansion
00211 } Q_PACKED MMD1BLOCKINFO;
00212 
00213 
00214 // A set of play sequences is stored as an array of ULONG files offsets
00215 // Each offset points to the play sequence itself.
00216 typedef struct tagMMD2PLAYSEQ
00217 {
00218         CHAR name[32];
00219         DWORD command_offs;     // filepos of command table
00220         DWORD reserved;
00221         WORD length;
00222         WORD seq[512];  // skip if > 0x8000
00223 } Q_PACKED MMD2PLAYSEQ;
00224 
00225 
00226 // A command table contains commands that effect a particular play sequence
00227 // entry.  The only commands read in are STOP or POSJUMP, all others are ignored
00228 // POSJUMP is presumed to have extra bytes containing a WORD for the position
00229 typedef struct tagMMDCOMMAND
00230 {
00231         WORD offset;            // Offset within current sequence entry
00232         BYTE cmdnumber;         // STOP (537) or POSJUMP (538) (others skipped)
00233         BYTE extra_count;
00234         BYTE extra_bytes[4];// [extra_count];
00235 } Q_PACKED MMDCOMMAND;  // Last entry has offset == 0xFFFF, cmd_number == 0 and 0 extrabytes
00236 
00237 
00238 typedef struct tagMMD0EXP
00239 {
00240         DWORD nextmod;                  // File offset of next Hdr
00241         DWORD exp_smp;                  // Pointer to extra instrument data
00242         WORD s_ext_entries;             // Number of extra instrument entries
00243         WORD s_ext_entrsz;              // Size of extra instrument data
00244         DWORD annotxt;
00245         DWORD annolen;
00246         DWORD iinfo;                    // Instrument names
00247         WORD i_ext_entries;     
00248         WORD i_ext_entrsz;
00249         DWORD jumpmask;
00250         DWORD rgbtable;
00251         BYTE channelsplit[4];   // Only used if 8ch_conv (extra channel for every nonzero entry)
00252         DWORD n_info;
00253         DWORD songname;                 // Song name
00254         DWORD songnamelen;
00255         DWORD dumps;
00256         DWORD mmdinfo;
00257         DWORD mmdrexx;
00258         DWORD mmdcmd3x;
00259         DWORD trackinfo_ofs;    // ptr to song->numtracks ptrs to tag lists
00260         DWORD effectinfo_ofs;   // ptr to group ptrs
00261         DWORD tag_end;
00262 } Q_PACKED MMD0EXP;
00263 
00264 #pragma pack()
00265 
00266 
00267 
00268 static void MedConvert(MODCOMMAND *p, const MMD0SONGHEADER *pmsh)
00269 //---------------------------------------------------------------
00270 {
00271         const BYTE bpmvals[9] = { 179,164,152,141,131,123,116,110,104};
00272 
00273         UINT command = p->command;
00274         UINT param = p->param;
00275         switch(command)
00276         {
00277         case 0x00:      if (param) command = CMD_ARPEGGIO; else command = 0; break;
00278         case 0x01:      command = CMD_PORTAMENTOUP; break;
00279         case 0x02:      command = CMD_PORTAMENTODOWN; break;
00280         case 0x03:      command = CMD_TONEPORTAMENTO; break;
00281         case 0x04:      command = CMD_VIBRATO; break;
00282         case 0x05:      command = CMD_TONEPORTAVOL; break;
00283         case 0x06:      command = CMD_VIBRATOVOL; break;
00284         case 0x07:      command = CMD_TREMOLO; break;
00285         case 0x0A:      if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break;
00286         case 0x0B:      command = CMD_POSITIONJUMP; break;
00287         case 0x0C:      command = CMD_VOLUME;
00288                                 if (pmsh->flags & MMD_FLAG_VOLHEX)
00289                                 {
00290                                         if (param < 0x80)
00291                                         {
00292                                                 param = (param+1) / 2;
00293                                         } else command = 0;
00294                                 } else
00295                                 {
00296                                         if (param <= 0x99)
00297                                         {
00298                                                 param = (param >> 4)*10+((param & 0x0F) % 10);
00299                                                 if (param > 64) param = 64;
00300                                         } else command = 0;
00301                                 }
00302                                 break;
00303         case 0x09:      command = (param < 0x20) ? CMD_SPEED : CMD_TEMPO; break;
00304         case 0x0D:      if (param & 0xF0) param &= 0xF0; command = CMD_VOLUMESLIDE; if (!param) command = 0; break;
00305         case 0x0F:      // Set Tempo / Special
00306                 // F.00 = Pattern Break
00307                 if (!param)     command = CMD_PATTERNBREAK;     else
00308                 // F.01 - F.F0: Set tempo/speed
00309                 if (param <= 0xF0)
00310                 {
00311                         if (pmsh->flags & MMD_FLAG_8CHANNEL)
00312                         {
00313                                 param = (param > 10) ? 99 : bpmvals[param-1];
00314                         } else
00315                         // F.01 - F.0A: Set Speed
00316                         if (param <= 0x0A)
00317                         {
00318                                 command = CMD_SPEED;
00319                         } else
00320                         // Old tempo
00321                         if (!(pmsh->flags2 & MMD_FLAG2_BPM))
00322                         {
00323                                 param = _muldiv(param, 5*715909, 2*474326);
00324                         }
00325                         // F.0B - F.F0: Set Tempo (assumes LPB=4)
00326                         if (param > 0x0A)
00327                         {
00328                                 command = CMD_TEMPO;
00329                                 if (param < 0x21) param = 0x21;
00330                                 if (param > 240) param = 240;
00331                         }
00332                 } else
00333                 switch(param)
00334                 {
00335                 // F.F1: Retrig 2x
00336                 case 0xF1:
00337                         command = CMD_MODCMDEX;
00338                         param = 0x93;
00339                         break;
00340                 // F.F2: Note Delay 2x
00341                 case 0xF2:
00342                         command = CMD_MODCMDEX;
00343                         param = 0xD3;
00344                         break;
00345                 // F.F3: Retrig 3x
00346                 case 0xF3:
00347                         command = CMD_MODCMDEX;
00348                         param = 0x92;
00349                         break;
00350                 // F.F4: Note Delay 1/3
00351                 case 0xF4:
00352                         command = CMD_MODCMDEX;
00353                         param = 0xD2;
00354                         break;
00355                 // F.F5: Note Delay 2/3
00356                 case 0xF5:
00357                         command = CMD_MODCMDEX;
00358                         param = 0xD4;
00359                         break;
00360                 // F.F8: Filter Off
00361                 case 0xF8:
00362                         command = CMD_MODCMDEX;
00363                         param = 0x00;
00364                         break;
00365                 // F.F9: Filter On
00366                 case 0xF9:
00367                         command = CMD_MODCMDEX;
00368                         param = 0x01;
00369                         break;
00370                 // F.FD: Very fast tone-portamento
00371                 case 0xFD:
00372                         command = CMD_TONEPORTAMENTO;
00373                         param = 0xFF;
00374                         break;
00375                 // F.FE: End Song
00376                 case 0xFE:
00377                         command = CMD_SPEED;
00378                         param = 0;
00379                         break;
00380                 // F.FF: Note Cut
00381                 case 0xFF:
00382                         command = CMD_MODCMDEX;
00383                         param = 0xC0;
00384                         break;
00385                 default:
00386 #ifdef MED_LOG
00387                         Log("Unknown Fxx command: cmd=0x%02X param=0x%02X\n", command, param);
00388 #endif
00389                         param = command = 0;
00390                 }
00391                 break;
00392         // 11.0x: Fine Slide Up
00393         case 0x11:
00394                 command = CMD_MODCMDEX;
00395                 if (param > 0x0F) param = 0x0F;
00396                 param |= 0x10;
00397                 break;
00398         // 12.0x: Fine Slide Down
00399         case 0x12:
00400                 command = CMD_MODCMDEX;
00401                 if (param > 0x0F) param = 0x0F;
00402                 param |= 0x20;
00403                 break;
00404         // 14.xx: Vibrato
00405         case 0x14:
00406                 command = CMD_VIBRATO;
00407                 break;
00408         // 15.xx: FineTune
00409         case 0x15:
00410                 command = CMD_MODCMDEX;
00411                 param &= 0x0F;
00412                 param |= 0x50;
00413                 break;
00414         // 16.xx: Pattern Loop
00415         case 0x16:
00416                 command = CMD_MODCMDEX;
00417                 if (param > 0x0F) param = 0x0F;
00418                 param |= 0x60;
00419                 break;
00420         // 18.xx: Note Cut
00421         case 0x18:
00422                 command = CMD_MODCMDEX;
00423                 if (param > 0x0F) param = 0x0F;
00424                 param |= 0xC0;
00425                 break;
00426         // 19.xx: Sample Offset
00427         case 0x19:
00428                 command = CMD_OFFSET;
00429                 break;
00430         // 1A.0x: Fine Volume Up
00431         case 0x1A:
00432                 command = CMD_MODCMDEX;
00433                 if (param > 0x0F) param = 0x0F;
00434                 param |= 0xA0;
00435                 break;
00436         // 1B.0x: Fine Volume Down
00437         case 0x1B:
00438                 command = CMD_MODCMDEX;
00439                 if (param > 0x0F) param = 0x0F;
00440                 param |= 0xB0;
00441                 break;
00442         // 1D.xx: Pattern Break
00443         case 0x1D:
00444                 command = CMD_PATTERNBREAK;
00445                 break;
00446         // 1E.0x: Pattern Delay
00447         case 0x1E:
00448                 command = CMD_MODCMDEX;
00449                 if (param > 0x0F) param = 0x0F;
00450                 param |= 0xE0;
00451                 break;
00452         // 1F.xy: Retrig
00453         case 0x1F:
00454                 command = CMD_RETRIG;
00455                 param &= 0x0F;
00456                 break;
00457         // 2E.xx: set panning
00458         case 0x2E:
00459                 command = CMD_MODCMDEX;
00460                 param = ((param + 0x10) & 0xFF) >> 1;
00461                 if (param > 0x0F) param = 0x0F;
00462                 param |= 0x80;
00463                 break;
00464         default:
00465 #ifdef MED_LOG
00466                 // 0x2E ?
00467                 Log("Unknown command: cmd=0x%02X param=0x%02X\n", command, param);
00468 #endif
00469                 command = param = 0;
00470         }
00471         p->command = command;
00472         p->param = param;
00473 }
00474 
00475 
00476 BOOL CSoundFile::ReadMed(const BYTE *lpStream, DWORD dwMemLength)
00477 //---------------------------------------------------------------
00478 {
00479         const MEDMODULEHEADER *pmmh;
00480         const MMD0SONGHEADER *pmsh;
00481         const MMD2SONGHEADER *pmsh2;
00482         const MMD0EXP *pmex;
00483         DWORD dwBlockArr, dwSmplArr, dwExpData, wNumBlocks;
00484         LPDWORD pdwTable;
00485         CHAR version;
00486         UINT deftempo;
00487         int playtransp = 0;
00488 
00489         if ((!lpStream) || (dwMemLength < 0x200)) return FALSE;
00490         pmmh = (MEDMODULEHEADER *)lpStream;
00491         if (((pmmh->id & 0x00FFFFFF) != 0x444D4D) || (!pmmh->song)) return FALSE;
00492         // Check for 'MMDx'
00493         DWORD dwSong = bswapBE32(pmmh->song);
00494         if ((dwSong >= dwMemLength) || (dwSong + sizeof(MMD0SONGHEADER) >= dwMemLength)) return FALSE;
00495         version = (signed char)((pmmh->id >> 24) & 0xFF);
00496         if ((version < '0') || (version > '3')) return FALSE;
00497 #ifdef MED_LOG
00498         Log("\nLoading MMD%c module (flags=0x%02X)...\n", version, bswapBE32(pmmh->mmdflags));
00499         Log("  modlen   = %d\n", bswapBE32(pmmh->modlen));
00500         Log("  song     = 0x%08X\n", bswapBE32(pmmh->song));
00501         Log("  psecnum  = %d\n", bswapBE16(pmmh->psecnum));
00502         Log("  pseq     = %d\n", bswapBE16(pmmh->pseq));
00503         Log("  blockarr = 0x%08X\n", bswapBE32(pmmh->blockarr));
00504         Log("  mmdflags = 0x%08X\n", bswapBE32(pmmh->mmdflags));
00505         Log("  smplarr  = 0x%08X\n", bswapBE32(pmmh->smplarr));
00506         Log("  reserved = 0x%08X\n", bswapBE32(pmmh->reserved));
00507         Log("  expdata  = 0x%08X\n", bswapBE32(pmmh->expdata));
00508         Log("  reserved2= 0x%08X\n", bswapBE32(pmmh->reserved2));
00509         Log("  pstate   = %d\n", bswapBE16(pmmh->pstate));
00510         Log("  pblock   = %d\n", bswapBE16(pmmh->pblock));
00511         Log("  pline    = %d\n", bswapBE16(pmmh->pline));
00512         Log("  pseqnum  = %d\n", bswapBE16(pmmh->pseqnum));
00513         Log("  actplayline=%d\n", bswapBE16(pmmh->actplayline));
00514         Log("  counter  = %d\n", pmmh->counter);
00515         Log("  extra_songs = %d\n", pmmh->extra_songs);
00516         Log("\n");
00517 #endif
00518         m_nType = MOD_TYPE_MED;
00519         m_nSongPreAmp = 0x20;
00520         dwBlockArr = bswapBE32(pmmh->blockarr);
00521         dwSmplArr = bswapBE32(pmmh->smplarr);
00522         dwExpData = bswapBE32(pmmh->expdata);
00523         if ((dwExpData) && (dwExpData+sizeof(MMD0EXP) < dwMemLength))
00524                 pmex = (MMD0EXP *)(lpStream+dwExpData);
00525         else
00526                 pmex = NULL;
00527         pmsh = (MMD0SONGHEADER *)(lpStream + dwSong);
00528         pmsh2 = (MMD2SONGHEADER *)pmsh;
00529 #ifdef MED_LOG
00530         if (version < '2')
00531         {
00532                 Log("MMD0 Header:\n");
00533                 Log("  numblocks  = %d\n", bswapBE16(pmsh->numblocks));
00534                 Log("  songlen    = %d\n", bswapBE16(pmsh->songlen));
00535                 Log("  playseq    = ");
00536                 for (UINT idbg1=0; idbg1<16; idbg1++) Log("%2d, ", pmsh->playseq[idbg1]);
00537                 Log("...\n");
00538                 Log("  deftempo   = 0x%04X\n", bswapBE16(pmsh->deftempo));
00539                 Log("  playtransp = %d\n", (signed char)pmsh->playtransp);
00540                 Log("  flags(1,2) = 0x%02X, 0x%02X\n", pmsh->flags, pmsh->flags2);
00541                 Log("  tempo2     = %d\n", pmsh->tempo2);
00542                 Log("  trkvol     = ");
00543                 for (UINT idbg2=0; idbg2<16; idbg2++) Log("0x%02X, ", pmsh->trkvol[idbg2]);
00544                 Log("...\n");
00545                 Log("  mastervol  = 0x%02X\n", pmsh->mastervol);
00546                 Log("  numsamples = %d\n", pmsh->numsamples);
00547         } else
00548         {
00549                 Log("MMD2 Header:\n");
00550                 Log("  numblocks  = %d\n", bswapBE16(pmsh2->numblocks));
00551                 Log("  numsections= %d\n", bswapBE16(pmsh2->numsections));
00552                 Log("  playseqptr = 0x%04X\n", bswapBE32(pmsh2->playseqtable));
00553                 Log("  sectionptr = 0x%04X\n", bswapBE32(pmsh2->sectiontable));
00554                 Log("  trackvols  = 0x%04X\n", bswapBE32(pmsh2->trackvols));
00555                 Log("  numtracks  = %d\n", bswapBE16(pmsh2->numtracks));
00556                 Log("  numpseqs   = %d\n", bswapBE16(pmsh2->numpseqs));
00557                 Log("  trackpans  = 0x%04X\n", bswapBE32(pmsh2->trackpans));
00558                 Log("  flags3     = 0x%08X\n", bswapBE32(pmsh2->flags3));
00559                 Log("  voladj     = %d\n", bswapBE16(pmsh2->voladj));
00560                 Log("  channels   = %d\n", bswapBE16(pmsh2->channels));
00561                 Log("  echotype   = %d\n", pmsh2->mix_echotype);
00562                 Log("  echodepth  = %d\n", pmsh2->mix_echodepth);
00563                 Log("  echolen    = %d\n", bswapBE16(pmsh2->mix_echolen));
00564                 Log("  stereosep  = %d\n", (signed char)pmsh2->mix_stereosep);
00565                 Log("  deftempo   = 0x%04X\n", bswapBE16(pmsh2->deftempo));
00566                 Log("  playtransp = %d\n", (signed char)pmsh2->playtransp);
00567                 Log("  flags(1,2) = 0x%02X, 0x%02X\n", pmsh2->flags, pmsh2->flags2);
00568                 Log("  tempo2     = %d\n", pmsh2->tempo2);
00569                 Log("  mastervol  = 0x%02X\n", pmsh2->mastervol);
00570                 Log("  numsamples = %d\n", pmsh->numsamples);
00571         }
00572         Log("\n");
00573 #endif
00574         wNumBlocks = bswapBE16(pmsh->numblocks);
00575         m_nChannels = 4;
00576         m_nSamples = pmsh->numsamples;
00577         if (m_nSamples > 63) m_nSamples = 63;
00578         // Tempo
00579         m_nDefaultTempo = 125;
00580         deftempo = bswapBE16(pmsh->deftempo);
00581         if (!deftempo) deftempo = 125;
00582         if (pmsh->flags2 & MMD_FLAG2_BPM)
00583         {
00584                 UINT tempo_tpl = (pmsh->flags2 & MMD_FLAG2_BMASK) + 1;
00585                 if (!tempo_tpl) tempo_tpl = 4;
00586                 deftempo *= tempo_tpl;
00587                 deftempo /= 4;
00588         #ifdef MED_LOG
00589                 Log("newtempo: %3d bpm (bpm=%3d lpb=%2d)\n", deftempo, bswapBE16(pmsh->deftempo), (pmsh->flags2 & MMD_FLAG2_BMASK)+1);
00590         #endif
00591         } else
00592         {
00593                 deftempo = _muldiv(deftempo, 5*715909, 2*474326);
00594         #ifdef MED_LOG
00595                 Log("oldtempo: %3d bpm (bpm=%3d)\n", deftempo, bswapBE16(pmsh->deftempo));
00596         #endif
00597         }
00598         // Speed
00599         m_nDefaultSpeed = pmsh->tempo2;
00600         if (!m_nDefaultSpeed) m_nDefaultSpeed = 6;
00601         if (deftempo < 0x21) deftempo = 0x21;
00602         if (deftempo > 255)
00603         {
00604                 while ((m_nDefaultSpeed > 3) && (deftempo > 260))
00605                 {
00606                         deftempo = (deftempo * (m_nDefaultSpeed - 1)) / m_nDefaultSpeed;
00607                         m_nDefaultSpeed--;
00608                 }
00609                 if (deftempo > 255) deftempo = 255;
00610         }
00611         m_nDefaultTempo = deftempo;
00612         // Reading Samples
00613         for (UINT iSHdr=0; iSHdr<m_nSamples; iSHdr++)
00614         {
00615                 MODINSTRUMENT *pins = &Ins[iSHdr+1];
00616                 pins->nLoopStart = bswapBE16(pmsh->sample[iSHdr].rep) << 1;
00617                 pins->nLoopEnd = pins->nLoopStart + (bswapBE16(pmsh->sample[iSHdr].replen) << 1);
00618                 pins->nVolume = (pmsh->sample[iSHdr].svol << 2);
00619                 pins->nGlobalVol = 64;
00620                 if (pins->nVolume > 256) pins->nVolume = 256;
00621                 pins->RelativeTone = -12 * pmsh->sample[iSHdr].strans;
00622                 pins->nPan = 128;
00623                 if (pins->nLoopEnd) pins->uFlags |= CHN_LOOP;
00624         }
00625         // Common Flags
00626         if (!(pmsh->flags & 0x20)) m_dwSongFlags |= SONG_FASTVOLSLIDES;
00627         // Reading play sequence
00628         if (version < '2')
00629         {
00630                 UINT nbo = pmsh->songlen >> 8;
00631                 if (nbo >= MAX_ORDERS) nbo = MAX_ORDERS-1;
00632                 if (!nbo) nbo = 1;
00633                 memcpy(Order, pmsh->playseq, nbo);
00634                 playtransp = pmsh->playtransp;
00635         } else
00636         {
00637                 UINT nOrders, nSections;
00638                 UINT nTrks = bswapBE16(pmsh2->numtracks);
00639                 if ((nTrks >= 4) && (nTrks <= 32)) m_nChannels = nTrks;
00640                 DWORD playseqtable = bswapBE32(pmsh2->playseqtable);
00641                 UINT numplayseqs = bswapBE16(pmsh2->numpseqs);
00642                 if (!numplayseqs) numplayseqs = 1;
00643                 nOrders = 0;
00644                 nSections = bswapBE16(pmsh2->numsections);
00645                 DWORD sectiontable = bswapBE32(pmsh2->sectiontable);
00646                 if ((!nSections) || (!sectiontable) || (sectiontable >= dwMemLength-2)) nSections = 1;
00647                 nOrders = 0;
00648                 for (UINT iSection=0; iSection<nSections; iSection++)
00649                 {
00650                         UINT nplayseq = 0;
00651                         if ((sectiontable) && (sectiontable < dwMemLength-2))
00652                         {
00653                                 nplayseq = lpStream[sectiontable+1];
00654                                 sectiontable += 2; // WORDs
00655                         } else
00656                         {
00657                                 nSections = 0;
00658                         }
00659                         UINT pseq = 0;
00660                         
00661                         if ((playseqtable) && (playseqtable + nplayseq*4 < dwMemLength))
00662                         {
00663                                 pseq = bswapBE32(((LPDWORD)(lpStream+playseqtable))[nplayseq]);
00664                         }
00665                         if ((pseq) && (pseq < dwMemLength - sizeof(MMD2PLAYSEQ)))
00666                         {
00667                                 MMD2PLAYSEQ *pmps = (MMD2PLAYSEQ *)(lpStream + pseq);
00668                                 if (!m_szNames[0][0]) memcpy(m_szNames[0], pmps->name, 31);
00669                                 UINT n = bswapBE16(pmps->length);
00670                                 if (pseq+n <= dwMemLength)
00671                                 {
00672                                         for (UINT i=0; i<n; i++)
00673                                         {
00674                                                 UINT seqval = pmps->seq[i] >> 8;
00675                                                 if ((seqval < wNumBlocks) && (nOrders < MAX_ORDERS-1))
00676                                                 {
00677                                                         Order[nOrders++] = seqval;
00678                                                 }
00679                                         }
00680                                 }
00681                         }
00682                 }
00683                 playtransp = pmsh2->playtransp;
00684                 while (nOrders < MAX_ORDERS) Order[nOrders++] = 0xFF;
00685         }
00686         // Reading Expansion structure
00687         if (pmex)
00688         {
00689                 // Channel Split
00690                 if ((m_nChannels == 4) && (pmsh->flags & 0x40))
00691                 {
00692                         for (UINT i8ch=0; i8ch<4; i8ch++)
00693                         {
00694                                 if (pmex->channelsplit[i8ch]) m_nChannels++;
00695                         }
00696                 }
00697                 // Song Comments
00698                 UINT annotxt = bswapBE32(pmex->annotxt);
00699                 UINT annolen = bswapBE32(pmex->annolen);
00700                 if ((annotxt) && (annolen) && (annotxt+annolen <= dwMemLength))
00701                 {
00702                         m_lpszSongComments = new char[annolen+1];
00703                         memcpy(m_lpszSongComments, lpStream+annotxt, annolen);
00704                         m_lpszSongComments[annolen] = 0;
00705                 }
00706                 // Song Name
00707                 UINT songname = bswapBE32(pmex->songname);
00708                 UINT songnamelen = bswapBE32(pmex->songnamelen);
00709                 if ((songname) && (songnamelen) && (songname+songnamelen <= dwMemLength))
00710                 {
00711                         if (songnamelen > 31) songnamelen = 31;
00712                         memcpy(m_szNames[0], lpStream+songname, songnamelen);
00713                 }
00714                 // Sample Names
00715                 DWORD smpinfoex = bswapBE32(pmex->iinfo);
00716                 if (smpinfoex)
00717                 {
00718                         DWORD iinfoptr = bswapBE32(pmex->iinfo);
00719                         UINT ientries = bswapBE16(pmex->i_ext_entries);
00720                         UINT ientrysz = bswapBE16(pmex->i_ext_entrsz);
00721 
00722                         if ((iinfoptr) && (ientrysz < 256) && (iinfoptr + ientries*ientrysz < dwMemLength))
00723                         {
00724                                 LPCSTR psznames = (LPCSTR)(lpStream + iinfoptr);
00725                                 UINT maxnamelen = ientrysz;
00726                                 if (maxnamelen > 32) maxnamelen = 32;
00727                                 for (UINT i=0; i<ientries; i++) if (i < m_nSamples)
00728                                 {
00729                                         lstrcpyn(m_szNames[i+1], psznames + i*ientrysz, maxnamelen);
00730                                 }
00731                         }
00732                 }
00733                 // Track Names
00734                 DWORD trackinfo_ofs = bswapBE32(pmex->trackinfo_ofs);
00735                 if ((trackinfo_ofs) && (trackinfo_ofs + m_nChannels * 4 < dwMemLength))
00736                 {
00737                         DWORD *ptrktags = (DWORD *)(lpStream + trackinfo_ofs);
00738                         for (UINT i=0; i<m_nChannels; i++)
00739                         {
00740                                 DWORD trknameofs = 0, trknamelen = 0;
00741                                 DWORD trktagofs = bswapBE32(ptrktags[i]);
00742                                 if (trktagofs)
00743                                 {
00744                                         while (trktagofs+8 < dwMemLength)
00745                                         {
00746                                                 DWORD ntag = bswapBE32(*(DWORD *)(lpStream + trktagofs));
00747                                                 if (ntag == MMDTAG_END) break;
00748                                                 DWORD tagdata = bswapBE32(*(DWORD *)(lpStream + trktagofs + 4));
00749                                                 switch(ntag)
00750                                                 {
00751                                                 case MMDTAG_TRK_NAMELEN:        trknamelen = tagdata; break;
00752                                                 case MMDTAG_TRK_NAME:           trknameofs = tagdata; break;
00753                                                 }
00754                                                 trktagofs += 8;
00755                                         }
00756                                         if (trknamelen > MAX_CHANNELNAME) trknamelen = MAX_CHANNELNAME;
00757                                         if ((trknameofs) && (trknameofs + trknamelen < dwMemLength))
00758                                         {
00759                                                 lstrcpyn(ChnSettings[i].szName, (LPCSTR)(lpStream+trknameofs), MAX_CHANNELNAME);
00760                                         }
00761                                 }
00762                         }
00763                 }
00764         }
00765         // Reading samples
00766         if (dwSmplArr > dwMemLength - 4*m_nSamples) return TRUE;
00767         pdwTable = (LPDWORD)(lpStream + dwSmplArr);
00768         for (UINT iSmp=0; iSmp<m_nSamples; iSmp++) if (pdwTable[iSmp])
00769         {
00770                 UINT dwPos = bswapBE32(pdwTable[iSmp]);
00771                 if ((dwPos >= dwMemLength) || (dwPos + sizeof(MMDSAMPLEHEADER) >= dwMemLength)) continue;
00772                 MMDSAMPLEHEADER *psdh = (MMDSAMPLEHEADER *)(lpStream + dwPos);
00773                 UINT len = bswapBE32(psdh->length);
00774         #ifdef MED_LOG
00775                 Log("SampleData %d: stype=0x%02X len=%d\n", iSmp, bswapBE16(psdh->type), len);
00776         #endif
00777                 if ((len > MAX_SAMPLE_LENGTH) || (dwPos + len + 6 > dwMemLength)) len = 0;
00778                 UINT flags = RS_PCM8S, stype = bswapBE16(psdh->type);
00779                 LPSTR psdata = (LPSTR)(lpStream + dwPos + 6);
00780                 if (stype & 0x80)
00781                 {
00782                         psdata += (stype & 0x20) ? 14 : 6;
00783                 } else
00784                 {
00785                         if (stype & 0x10)
00786                         {
00787                                 Ins[iSmp+1].uFlags |= CHN_16BIT;
00788                                 len /= 2;
00789                                 flags = (stype & 0x20) ? RS_STPCM16M : RS_PCM16M;
00790                         } else
00791                         {
00792                                 flags = (stype & 0x20) ? RS_STPCM8S : RS_PCM8S;
00793                         }
00794                         if (stype & 0x20) len /= 2;
00795                 }
00796                 Ins[iSmp+1].nLength = len;
00797                 ReadSample(&Ins[iSmp+1], flags, psdata, dwMemLength - dwPos - 6);
00798         }
00799         // Reading patterns (blocks)
00800         if (wNumBlocks > MAX_PATTERNS) wNumBlocks = MAX_PATTERNS;
00801         if ((!dwBlockArr) || (dwBlockArr > dwMemLength - 4*wNumBlocks)) return TRUE;
00802         pdwTable = (LPDWORD)(lpStream + dwBlockArr);
00803         playtransp += (version == '3') ? 24 : 48;
00804         for (UINT iBlk=0; iBlk<wNumBlocks; iBlk++)
00805         {
00806                 UINT dwPos = bswapBE32(pdwTable[iBlk]);
00807                 if ((!dwPos) || (dwPos >= dwMemLength) || (dwPos >= dwMemLength - 8)) continue;
00808                 UINT lines = 64, tracks = 4;
00809                 if (version == '0')
00810                 {
00811                         const MMD0BLOCK *pmb = (const MMD0BLOCK *)(lpStream + dwPos);
00812                         lines = pmb->lines + 1;
00813                         tracks = pmb->numtracks;
00814                         if (!tracks) tracks = m_nChannels;
00815                         if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue;
00816                         PatternSize[iBlk] = lines;
00817                         MODCOMMAND *p = Patterns[iBlk];
00818                         LPBYTE s = (LPBYTE)(lpStream + dwPos + 2);
00819                         UINT maxlen = tracks*lines*3;
00820                         if (maxlen + dwPos > dwMemLength - 2) break;
00821                         for (UINT y=0; y<lines; y++)
00822                         {
00823                                 for (UINT x=0; x<tracks; x++, s+=3) if (x < m_nChannels)
00824                                 {
00825                                         BYTE note = s[0] & 0x3F;
00826                                         BYTE instr = s[1] >> 4;
00827                                         if (s[0] & 0x80) instr |= 0x10;
00828                                         if (s[0] & 0x40) instr |= 0x20;
00829                                         if ((note) && (note <= 132)) p->note = note + playtransp;
00830                                         p->instr = instr;
00831                                         p->command = s[1] & 0x0F;
00832                                         p->param = s[2];
00833                                         // if (!iBlk) Log("%02X.%02X.%02X | ", s[0], s[1], s[2]);
00834                                         MedConvert(p, pmsh);
00835                                         p++;
00836                                 }
00837                                 //if (!iBlk) Log("\n");
00838                         }
00839                 } else
00840                 {
00841                         MMD1BLOCK *pmb = (MMD1BLOCK *)(lpStream + dwPos);
00842                 #ifdef MED_LOG
00843                         Log("MMD1BLOCK:   lines=%2d, tracks=%2d, offset=0x%04X\n",
00844                                 bswapBE16(pmb->lines), bswapBE16(pmb->numtracks), bswapBE32(pmb->info));
00845                 #endif
00846                         MMD1BLOCKINFO *pbi = NULL;
00847                         BYTE *pcmdext = NULL;
00848                         lines = (pmb->lines >> 8) + 1;
00849                         tracks = pmb->numtracks >> 8;
00850                         if (!tracks) tracks = m_nChannels;
00851                         if ((Patterns[iBlk] = AllocatePattern(lines, m_nChannels)) == NULL) continue;
00852                         PatternSize[iBlk] = (WORD)lines;
00853                         DWORD dwBlockInfo = bswapBE32(pmb->info);
00854                         if ((dwBlockInfo) && (dwBlockInfo < dwMemLength - sizeof(MMD1BLOCKINFO)))
00855                         {
00856                                 pbi = (MMD1BLOCKINFO *)(lpStream + dwBlockInfo);
00857                         #ifdef MED_LOG
00858                                 Log("  BLOCKINFO: blockname=0x%04X namelen=%d pagetable=0x%04X &cmdexttable=0x%04X\n",
00859                                         bswapBE32(pbi->blockname), bswapBE32(pbi->blocknamelen), bswapBE32(pbi->pagetable), bswapBE32(pbi->cmdexttable));
00860                         #endif
00861                                 if ((pbi->blockname) && (pbi->blocknamelen))
00862                                 {
00863                                         DWORD nameofs = bswapBE32(pbi->blockname);
00864                                         UINT namelen = bswapBE32(pbi->blocknamelen);
00865                                         if ((nameofs < dwMemLength) && (nameofs+namelen < dwMemLength))
00866                                         {
00867                                                 SetPatternName(iBlk, (LPCSTR)(lpStream+nameofs));
00868                                         }
00869                                 }
00870                                 if (pbi->cmdexttable)
00871                                 {
00872                                         DWORD cmdexttable = bswapBE32(pbi->cmdexttable);
00873                                         if (cmdexttable < dwMemLength - 4)
00874                                         {
00875                                                 cmdexttable = bswapBE32(*(DWORD *)(lpStream + cmdexttable));
00876                                                 if ((cmdexttable) && (cmdexttable <= dwMemLength - lines*tracks))
00877                                                 {
00878                                                         pcmdext = (BYTE *)(lpStream + cmdexttable);
00879                                                 }
00880                                         }
00881                                 }
00882                         }
00883                         MODCOMMAND *p = Patterns[iBlk];
00884                         LPBYTE s = (LPBYTE)(lpStream + dwPos + 8);
00885                         UINT maxlen = tracks*lines*4;
00886                         if (maxlen + dwPos > dwMemLength - 8) break;
00887                         for (UINT y=0; y<lines; y++)
00888                         {
00889                                 for (UINT x=0; x<tracks; x++, s+=4) if (x < m_nChannels)
00890                                 {
00891                                         BYTE note = s[0];
00892                                         if ((note) && (note <= 132))
00893                                         {
00894                                                 int rnote = note + playtransp;
00895                                                 if (rnote < 1) rnote = 1;
00896                                                 if (rnote > 120) rnote = 120;
00897                                                 p->note = (BYTE)rnote;
00898                                         }
00899                                         p->instr = s[1];
00900                                         p->command = s[2];
00901                                         p->param = s[3];
00902                                         if (pcmdext) p->vol = pcmdext[x];
00903                                         MedConvert(p, pmsh);
00904                                         p++;
00905                                 }
00906                                 if (pcmdext) pcmdext += tracks;
00907                         }
00908                 }
00909         }
00910         // Setup channel pan positions
00911         for (UINT iCh=0; iCh<m_nChannels; iCh++)
00912         {
00913                 ChnSettings[iCh].nPan = (((iCh&3) == 1) || ((iCh&3) == 2)) ? 0xC0 : 0x40;
00914                 ChnSettings[iCh].nVolume = 64;
00915         }
00916         return TRUE;
00917 }
00918 
00919 

Generated on Sat Nov 5 16:15:39 2005 for OPIE by  doxygen 1.4.2