From: <sag...@us...> - 2013-02-16 15:06:59
|
Revision: 1532 http://sourceforge.net/p/modplug/code/1532 Author: saga-games Date: 2013-02-16 15:06:45 +0000 (Sat, 16 Feb 2013) Log Message: ----------- [Imp] OpenMPT doesn't request exclusive file reading rights anymore, so it is now possible to open files that are being read by another application at the same time (http://bugs.openmpt.org/view.php?id=352). [Ref] Rewrote IMF loader to use the FileReader class. Modified Paths: -------------- trunk/OpenMPT/mptrack/Mptrack.cpp trunk/OpenMPT/soundlib/Load_imf.cpp trunk/OpenMPT/soundlib/ModSequence.cpp trunk/OpenMPT/soundlib/ModSequence.h trunk/OpenMPT/soundlib/Sndfile.cpp trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/patternContainer.cpp Modified: trunk/OpenMPT/mptrack/Mptrack.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mptrack.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/mptrack/Mptrack.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -1629,6 +1629,8 @@ "http://zlib.net/|" "Josh Coalson for libFLAC|" "http://flac.sourceforge.net/|" + "The mpg123 project for libmpg123|" + "http://mpg123.de/|" "Storlek for all the IT compatibility hints and testcases|" "as well as the IMF, OKT and ULT loaders|" "http://schismtracker.org/|" @@ -2101,7 +2103,7 @@ BOOL CMappedFile::Open(LPCSTR lpszFileName) //----------------------------------------- { - return m_File.Open(lpszFileName, CFile::modeRead|CFile::typeBinary); + return m_File.Open(lpszFileName, CFile::modeRead | CFile::typeBinary | CFile::shareDenyWrite); } Modified: trunk/OpenMPT/soundlib/Load_imf.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_imf.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/Load_imf.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -17,85 +17,216 @@ #pragma pack(push, 1) -struct IMFCHANNEL +struct IMFChannel { - char name[12]; // Channel name (ASCIIZ-String, max 11 chars) + char name[12]; // Channel name (ASCIIZ-String, max 11 chars) uint8 chorus; // Default chorus uint8 reverb; // Default reverb uint8 panning; // Pan positions 00-FF uint8 status; // Channel status: 0 = enabled, 1 = mute, 2 = disabled (ignore effects!) }; -struct IMFHEADER +struct IMFFileHeader { - char title[32]; // Songname (ASCIIZ-String, max. 31 chars) - uint16 ordnum; // Number of orders saved - uint16 patnum; // Number of patterns saved - uint16 insnum; // Number of instruments saved - uint16 flags; // Module flags (&1 => linear) - uint8 unused1[8]; - uint8 tempo; // Default tempo (Axx, 1..255) - uint8 bpm; // Default beats per minute (BPM) (Txx, 32..255) - uint8 master; // Default mastervolume (Vxx, 0..64) - uint8 amp; // Amplification factor (mixing volume, 4..127) - uint8 unused2[8]; - char im10[4]; // 'IM10' - IMFCHANNEL channels[32]; // Channel settings + enum SongFlags + { + lineSlides = 0x01, + }; + + char title[32]; // Songname (ASCIIZ-String, max. 31 chars) + uint16 ordNum; // Number of orders saved + uint16 patNum; // Number of patterns saved + uint16 insNum; // Number of instruments saved + uint16 flags; // See SongFlags + uint8 unused1[8]; + uint8 tempo; // Default tempo (Axx, 1...255) + uint8 bpm; // Default beats per minute (BPM) (Txx, 32...255) + uint8 master; // Default master volume (Vxx, 0...64) + uint8 amp; // Amplification factor (mixing volume, 4...127) + uint8 unused2[8]; + char im10[4]; // 'IM10' + IMFChannel channels[32]; // Channel settings uint8 orderlist[256]; // Order list (0xFF = +++; blank out anything beyond ordnum) + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(ordNum); + SwapBytesLE(patNum); + SwapBytesLE(insNum); + SwapBytesLE(flags); + } }; -enum +struct IMFEnvelope { - IMF_ENV_VOL = 0, - IMF_ENV_PAN = 1, - IMF_ENV_FILTER = 2, -}; + enum EnvFlags + { + envEnabled = 0x01, + envSustain = 0x02, + envLoop = 0x04, + }; -struct IMFENVELOPE -{ uint8 points; // Number of envelope points uint8 sustain; // Envelope sustain point uint8 loop_start; // Envelope loop start point uint8 loop_end; // Envelope loop end point - uint8 flags; // Envelope flags + uint8 flags; // See EnvFlags uint8 unused[3]; }; -struct IMFENVNODES +struct IMFEnvNode { uint16 tick; uint16 value; }; -struct IMFINSTRUMENT +struct IMFInstrument { - char name[32]; // Inst. name (ASCIIZ-String, max. 31 chars) + enum EnvTypes + { + volEnv = 0, + panEnv = 1, + filterEnv = 2, + }; + + char name[32]; // Inst. name (ASCIIZ-String, max. 31 chars) uint8 map[120]; // Multisample settings uint8 unused[8]; - IMFENVNODES nodes[3][16]; - IMFENVELOPE env[3]; + IMFEnvNode nodes[3][16]; + IMFEnvelope env[3]; uint16 fadeout; // Fadeout rate (0...0FFFH) - uint16 smpnum; // Number of samples in instrument - char ii10[4]; // 'II10' + uint16 smpNum; // Number of samples in instrument + char ii10[4]; // 'II10' + + void ConvertEnvelope(InstrumentEnvelope &mptEnv, EnvTypes e) const + { + const int shift = (e == volEnv) ? 0 : 2; + + mptEnv.dwFlags.set(ENV_ENABLED, (env[e].flags & 1) != 0); + mptEnv.dwFlags.set(ENV_SUSTAIN, (env[e].flags & 2) != 0); + mptEnv.dwFlags.set(ENV_LOOP, (env[e].flags & 4) != 0); + + mptEnv.nNodes = env[e].points; + Limit(mptEnv.nNodes, 2u, 16u); + mptEnv.nLoopStart = env[e].loop_start; + mptEnv.nLoopEnd = env[e].loop_end; + mptEnv.nSustainStart = mptEnv.nSustainEnd = env[e].sustain; + + uint16 minTick = 0; // minimum tick value for next node + for(uint32 n = 0; n < mptEnv.nNodes; n++) + { + minTick = mptEnv.Ticks[n] = Util::Max(minTick, nodes[e][n].tick); + minTick++; + mptEnv.Values[n] = static_cast<uint8>(Util::Min(nodes[e][n].value >> shift, ENVELOPE_MAX)); + } + } + + // Convert an IMFInstrument to OpenMPT's internal instrument representation. + void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX firstSample) const + { + StringFixer::ReadString<StringFixer::nullTerminated>(mptIns.name, name); + + if(smpNum) + { + STATIC_ASSERT(CountOf(mptIns.Keyboard) >= CountOf(map)); + for(size_t note = 0; note < CountOf(map); note++) + { + mptIns.Keyboard[note] = firstSample + map[note]; + } + } + + mptIns.nFadeOut = fadeout; + + ConvertEnvelope(mptIns.VolEnv, volEnv); + ConvertEnvelope(mptIns.PanEnv, panEnv); + ConvertEnvelope(mptIns.PitchEnv, filterEnv); + if(mptIns.PitchEnv.dwFlags[ENV_ENABLED]) + mptIns.PitchEnv.dwFlags.set(ENV_FILTER); + + // hack to get === to stop notes (from modplug's xm loader) + if(!mptIns.VolEnv.dwFlags[ENV_ENABLED] && !mptIns.nFadeOut) + mptIns.nFadeOut = 8192; + } + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + for(size_t e = 0; e < CountOf(nodes); e++) + { + for(size_t n = 0; n < CountOf(nodes[0]); n++) + { + SwapBytesLE(nodes[e][n].tick); + SwapBytesLE(nodes[e][n].value); + } + } + SwapBytesLE(fadeout); + SwapBytesLE(smpNum); + } }; -struct IMFSAMPLE +struct IMFSample { - char filename[13]; // Sample filename (12345678.ABC) */ - uint8 unused1[3]; - uint32 length; // Length (in bytes) - uint32 loop_start; // Loop start (in bytes) - uint32 loop_end; // Loop end (in bytes) - uint32 C5Speed; // Samplerate - uint8 volume; // Default volume (0...64) - uint8 panning; // Default pan (0...255) - uint8 unused2[14]; - uint8 flags; // Sample flags - uint8 unused3[5]; - uint16 ems; // Reserved for internal usage - uint32 dram; // Reserved for internal usage - char is10[4]; // 'IS10' + enum SampleFlags + { + smpLoop = 0x01, + smpPingPongLoop = 0x02, + smp16Bit = 0x04, + smpPanning = 0x08, + }; + + char filename[13]; // Sample filename (12345678.ABC) */ + uint8 unused1[3]; + uint32 length; // Length (in bytes) + uint32 loopStart; // Loop start (in bytes) + uint32 loopEnd; // Loop end (in bytes) + uint32 c5Speed; // Samplerate + uint8 volume; // Default volume (0...64) + uint8 panning; // Default pan (0...255) + uint8 unused2[14]; + uint8 flags; // Sample flags + uint8 unused3[5]; + uint16 ems; // Reserved for internal usage + uint32 dram; // Reserved for internal usage + char is10[4]; // 'IS10' + + // Convert an IMFSample to OpenMPT's internal sample representation. + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(); + StringFixer::ReadString<StringFixer::nullTerminated>(mptSmp.filename, filename); + + mptSmp.nLength = length; + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopEnd; + mptSmp.nC5Speed = c5Speed; + mptSmp.nVolume = volume * 4; + mptSmp.nPan = panning; + if(flags & smpLoop) + mptSmp.uFlags.set(CHN_LOOP); + if(flags & smpPingPongLoop) + mptSmp.uFlags.set(CHN_PINGPONGLOOP); + if(flags & smp16Bit) + { + mptSmp.uFlags.set(CHN_16BIT); + mptSmp.nLength /= 2; + mptSmp.nLoopStart /= 2; + mptSmp.nLoopEnd /= 2; + } + if(flags & smpPanning) + mptSmp.uFlags.set(CHN_PANNING); + } + + // Convert all multi-byte numeric values to current platform's endianness or vice versa. + void ConvertEndianness() + { + SwapBytesLE(length); + SwapBytesLE(loopStart); + SwapBytesLE(loopEnd); + SwapBytesLE(c5Speed); + } }; + #pragma pack(pop) static const uint8 imfEffects[] = @@ -148,47 +279,47 @@ CMD_NONE, // 0x23 Zxx Reverb - XXX }; -static void ImportIMFEffect(ModCommand *note) -//------------------------------------------- +static void ImportIMFEffect(ModCommand &m) +//---------------------------------------- { uint8 n; // fix some of them - switch (note->command) + switch (m.command) { case 0xE: // fine volslide // hackaround to get almost-right behavior for fine slides (i think!) - if(note->param == 0) + if(m.param == 0) /* nothing */; - else if(note->param == 0xF0) - note->param = 0xEF; - else if(note->param == 0x0F) - note->param = 0xFE; - else if(note->param & 0xF0) - note->param |= 0x0F; + else if(m.param == 0xF0) + m.param = 0xEF; + else if(m.param == 0x0F) + m.param = 0xFE; + else if(m.param & 0xF0) + m.param |= 0x0F; else - note->param |= 0xF0; + m.param |= 0xF0; break; case 0xF: // set finetune // we don't implement this, but let's at least import the value - note->param = 0x20 | min(note->param >> 4, 0xf); + m.param = 0x20 | min(m.param >> 4, 0x0F); break; case 0x14: // fine slide up case 0x15: // fine slide down // this is about as close as we can do... - if(note->param >> 4) - note->param = 0xf0 | min(note->param >> 4, 0xf); + if(m.param >> 4) + m.param = 0xF0 | min(m.param >> 4, 0x0F); else - note->param |= 0xe0; + m.param |= 0xE0; break; case 0x16: // cutoff - note->param >>= 1; + m.param >>= 1; break; case 0x1F: // set global volume - note->param = min(note->param << 1, 0xff); + m.param = min(m.param << 1, 0xFF); break; case 0x21: n = 0; - switch (note->param >> 4) + switch (m.param >> 4) { case 0: /* undefined, but since S0x does nothing in IT anyway, we won't care. @@ -198,7 +329,7 @@ default: // undefined case 0x1: // set filter case 0xF: // invert loop - note->command = CMD_NONE; + m.command = CMD_NONE; break; case 0x3: // glissando n = 0x20; @@ -223,111 +354,62 @@ /* predicament: we can only disable one envelope at a time. volume is probably most noticeable, so let's go with that. (... actually, orpheus doesn't even seem to implement this at all) */ - note->param = 0x77; + m.param = 0x77; break; case 0x18: // sample offset // O00 doesn't pick up the previous value - if(!note->param) - note->command = CMD_NONE; + if(!m.param) + m.command = CMD_NONE; break; } if(n) - note->param = n | (note->param & 0x0F); + m.param = n | (m.param & 0x0F); break; } - note->command = (note->command < CountOf(imfEffects)) ? imfEffects[note->command] : CMD_NONE; - if(note->command == CMD_VOLUME && note->volcmd == VOLCMD_NONE) + m.command = (m.command < CountOf(imfEffects)) ? imfEffects[m.command] : CMD_NONE; + if(m.command == CMD_VOLUME && m.volcmd == VOLCMD_NONE) { - note->volcmd = VOLCMD_VOLUME; - note->vol = note->param; - note->command = CMD_NONE; - note->param = 0; + m.volcmd = VOLCMD_VOLUME; + m.vol = m.param; + m.command = CMD_NONE; + m.param = 0; } } -static void LoadIMFEnvelope(InstrumentEnvelope *env, const IMFINSTRUMENT *imfins, const int e) -//-------------------------------------------------------------------------------------------- +bool CSoundFile::ReadIMF(FileReader &file) +//---------------------------------------- { - const int shift = (e == IMF_ENV_VOL) ? 0 : 2; - - env->dwFlags.set(ENV_ENABLED, (imfins->env[e].flags & 1) != 0); - env->dwFlags.set(ENV_SUSTAIN, (imfins->env[e].flags & 2) != 0); - env->dwFlags.set(ENV_LOOP, (imfins->env[e].flags & 4) != 0); - - env->nNodes = imfins->env[e].points; - Limit(env->nNodes, 2u, 16u); - env->nLoopStart = imfins->env[e].loop_start; - env->nLoopEnd = imfins->env[e].loop_end; - env->nSustainStart = env->nSustainEnd = imfins->env[e].sustain; - - uint16 min = 0; // minimum tick value for next node - for(uint32 n = 0; n < env->nNodes; n++) + IMFFileHeader fileHeader; + file.Rewind(); + if(!file.ReadConvertEndianness(fileHeader) + || memcmp(fileHeader.im10, "IM10", 4)) { - uint16 nTick, nValue; - nTick = LittleEndianW(imfins->nodes[e][n].tick); - nValue = LittleEndianW(imfins->nodes[e][n].value) >> shift; - env->Ticks[n] = (uint16)max(min, nTick); - env->Values[n] = (uint8)min(nValue, ENVELOPE_MAX); - min = nTick + 1; + return false; } -} -bool CSoundFile::ReadIMF(const LPCBYTE lpStream, const DWORD dwMemLength) -//----------------------------------------------------------------------- -{ - DWORD dwMemPos = 0; + // Read channel configuration vector<bool> ignoreChannels(32, false); // bit set for each channel that's completely disabled - - ASSERT_CAN_READ(sizeof(IMFHEADER)); - IMFHEADER hdr; - memcpy(&hdr, lpStream, sizeof(IMFHEADER)); - dwMemPos = sizeof(IMFHEADER); - - hdr.ordnum = LittleEndianW(hdr.ordnum); - hdr.patnum = LittleEndianW(hdr.patnum); - hdr.insnum = LittleEndianW(hdr.insnum); - hdr.flags = LittleEndianW(hdr.flags); - - if(memcmp(hdr.im10, "IM10", 4) != 0) - return false; - - m_nType = MOD_TYPE_IMF; - SetModFlag(MSF_COMPATIBLE_PLAY, true); - - // song name - MemsetZero(m_szNames); - StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[0], hdr.title); - - m_SongFlags = (hdr.flags & 1) ? SONG_LINEARSLIDES : SongFlags(0); - m_nDefaultSpeed = hdr.tempo; - m_nDefaultTempo = hdr.bpm; - m_nDefaultGlobalVolume = CLAMP(hdr.master, 0, 64) << 2; - m_nSamplePreAmp = CLAMP(hdr.amp, 4, 127); - - m_nSamples = 0; // Will be incremented later - m_nInstruments = 0; - m_nChannels = 0; - for(CHANNELINDEX nChn = 0; nChn < 32; nChn++) + for(CHANNELINDEX chn = 0; chn < 32; chn++) { - ChnSettings[nChn].nPan = hdr.channels[nChn].panning * 64 / 255; - ChnSettings[nChn].nPan *= 4; + ChnSettings[chn].Reset(); + ChnSettings[chn].nPan = fileHeader.channels[chn].panning * 256 / 255; - StringFixer::ReadString<StringFixer::nullTerminated>(ChnSettings[nChn].szName, hdr.channels[nChn].name); + StringFixer::ReadString<StringFixer::nullTerminated>(ChnSettings[chn].szName, fileHeader.channels[chn].name); // TODO: reverb/chorus? - switch(hdr.channels[nChn].status) + switch(fileHeader.channels[chn].status) { case 0: // enabled; don't worry about it - m_nChannels = nChn + 1; + m_nChannels = chn + 1; break; case 1: // mute - ChnSettings[nChn].dwFlags = CHN_MUTE; - m_nChannels = nChn + 1; + ChnSettings[chn].dwFlags = CHN_MUTE; + m_nChannels = chn + 1; break; case 2: // disabled - ChnSettings[nChn].dwFlags = CHN_MUTE; - ignoreChannels[nChn] = true; + ChnSettings[chn].dwFlags = CHN_MUTE; + ignoreChannels[chn] = true; break; default: // uhhhh.... freak out //fprintf(stderr, "imf: channel %d has unknown status %d\n", n, hdr.channels[n].status); @@ -337,245 +419,179 @@ if(!m_nChannels) return false; //From mikmod: work around an Orpheus bug - if(hdr.channels[0].status == 0) + if(fileHeader.channels[0].status == 0) { - CHANNELINDEX nChn; - for(nChn = 1; nChn < 16; nChn++) - if(hdr.channels[nChn].status != 1) + CHANNELINDEX chn; + for(chn = 1; chn < 16; chn++) + if(fileHeader.channels[chn].status != 1) break; - if(nChn == 16) - for(nChn = 1; nChn < 16; nChn++) - ChnSettings[nChn].dwFlags.reset(CHN_MUTE); + if(chn == 16) + for(chn = 1; chn < 16; chn++) + ChnSettings[chn].dwFlags.reset(CHN_MUTE); } - Order.resize(hdr.ordnum); - for(ORDERINDEX nOrd = 0; nOrd < hdr.ordnum; nOrd++) - Order[nOrd] = ((hdr.orderlist[nOrd] == 0xFF) ? Order.GetIgnoreIndex() : (PATTERNINDEX)hdr.orderlist[nOrd]); + m_nType = MOD_TYPE_IMF; + SetModFlag(MSF_COMPATIBLE_PLAY, true); - // read patterns - for(PATTERNINDEX nPat = 0; nPat < hdr.patnum; nPat++) - { - uint16 length, nrows; - uint8 mask, channel; - int row; - unsigned int lostfx = 0; - ModCommand *note, junk_note; + // Song Name + StringFixer::ReadString<StringFixer::nullTerminated>(m_szNames[0], fileHeader.title); - ASSERT_CAN_READ(4); - length = LittleEndianW(*((uint16 *)(lpStream + dwMemPos))); - nrows = LittleEndianW(*((uint16 *)(lpStream + dwMemPos + 2))); - dwMemPos += 4; + m_SongFlags = (fileHeader.flags & IMFFileHeader::lineSlides) ? SONG_LINEARSLIDES : SongFlags(0); + m_nDefaultSpeed = fileHeader.tempo; + m_nDefaultTempo = fileHeader.bpm; + m_nDefaultGlobalVolume = Clamp(fileHeader.master, uint8(0), uint8(64)) * 4; + m_nSamplePreAmp = Clamp(fileHeader.amp, uint8(4), uint8(127)); - if(Patterns.Insert(nPat, nrows)) - break; + m_nInstruments = fileHeader.insNum; + m_nSamples = 0; // Will be incremented later - row = 0; - while(row < nrows) + Order.resize(fileHeader.ordNum); + for(ORDERINDEX ord = 0; ord < fileHeader.ordNum; ord++) + Order[ord] = ((fileHeader.orderlist[ord] == 0xFF) ? Order.GetIgnoreIndex() : (PATTERNINDEX)fileHeader.orderlist[ord]); + + // Read patterns + for(PATTERNINDEX pat = 0; pat < fileHeader.patNum; pat++) + { + const uint16 length = file.ReadUint16LE(), numRows = file.ReadUint16LE(); + FileReader patternChunk = file.GetChunk(length - 4); + + if(Patterns.Insert(pat, numRows)) { - ASSERT_CAN_READ(1); - mask = *((uint8 *)(lpStream + dwMemPos)); - dwMemPos += 1; + continue; + } + + ModCommand junkNote; + ROWINDEX row = 0; + while(row < numRows) + { + uint8 mask = patternChunk.ReadUint8(); if(mask == 0) { row++; continue; } - channel = mask & 0x1F; + uint8 channel = mask & 0x1F; + ModCommand &m = ignoreChannels[channel] ? junkNote : *Patterns[pat].GetpModCommand(row, channel); - if(ignoreChannels[channel]) - { - /* should do this better, i.e. not go through the whole process of deciding - what to do with the effects since they're just being thrown out */ - //printf("disabled channel %d contains data\n", channel + 1); - note = &junk_note; - } else - { - note = Patterns[nPat].GetpModCommand(row, channel); - } - if(mask & 0x20) { - // read note/instrument - ASSERT_CAN_READ(2); - note->note = *((BYTE *)(lpStream + dwMemPos)); - note->instr = *((BYTE *)(lpStream + dwMemPos + 1)); - dwMemPos += 2; + // Read note/instrument + m.note = patternChunk.ReadUint8(); + m.instr = patternChunk.ReadUint8(); - if(note->note == 160) + if(m.note == 160) { - note->note = NOTE_KEYOFF; /* ??? */ - } else if(note->note == 255) + m.note = NOTE_KEYOFF; + } else if(m.note == 255) { - note->note = NOTE_NONE; /* ??? */ + m.note = NOTE_NONE; } else { - note->note = (note->note >> 4) * 12 + (note->note & 0x0F) + 12 + 1; - if(note->note > NOTE_MAX) + m.note = (m.note >> 4) * 12 + (m.note & 0x0F) + 12 + 1; + if(!m.IsNoteOrEmpty()) { - /*printf("%d.%d.%d: funny note 0x%02x\n", - nPat, row, channel, fp->data[fp->pos - 1]);*/ - note->note = NOTE_NONE; + m.note = NOTE_NONE; } } } - if((mask & 0xc0) == 0xC0) + if((mask & 0xC0) == 0xC0) { - // read both effects and figure out what to do with them - ASSERT_CAN_READ(4); - uint8 e1c = *((uint8 *)(lpStream + dwMemPos)); // Command 1 - uint8 e1d = *((uint8 *)(lpStream + dwMemPos + 1)); // Data 1 - uint8 e2c = *((uint8 *)(lpStream + dwMemPos + 2)); // Command 2 - uint8 e2d = *((uint8 *)(lpStream + dwMemPos + 3)); // Data 2 - dwMemPos += 4; + // Read both effects and figure out what to do with them + uint8 e1c = patternChunk.ReadUint8(); // Command 1 + uint8 e1d = patternChunk.ReadUint8(); // Data 1 + uint8 e2c = patternChunk.ReadUint8(); // Command 2 + uint8 e2d = patternChunk.ReadUint8(); // Data 2 if(e1c == 0x0C) { - note->vol = min(e1d, 0x40); - note->volcmd = VOLCMD_VOLUME; - note->command = e2c; - note->param = e2d; + m.vol = min(e1d, 0x40); + m.volcmd = VOLCMD_VOLUME; + m.command = e2c; + m.param = e2d; } else if(e2c == 0x0C) { - note->vol = min(e2d, 0x40); - note->volcmd = VOLCMD_VOLUME; - note->command = e1c; - note->param = e1d; + m.vol = min(e2d, 0x40); + m.volcmd = VOLCMD_VOLUME; + m.command = e1c; + m.param = e1d; } else if(e1c == 0x0A) { - note->vol = e1d * 64 / 255; - note->volcmd = VOLCMD_PANNING; - note->command = e2c; - note->param = e2d; + m.vol = e1d * 64 / 255; + m.volcmd = VOLCMD_PANNING; + m.command = e2c; + m.param = e2d; } else if(e2c == 0x0A) { - note->vol = e2d * 64 / 255; - note->volcmd = VOLCMD_PANNING; - note->command = e1c; - note->param = e1d; + m.vol = e2d * 64 / 255; + m.volcmd = VOLCMD_PANNING; + m.command = e1c; + m.param = e1d; } else { /* check if one of the effects is a 'global' effect -- if so, put it in some unused channel instead. otherwise pick the most important effect. */ - lostfx++; - note->command = e2c; - note->param = e2d; + m.command = e2c; + m.param = e2d; } } else if(mask & 0xC0) { - // there's one effect, just stick it in the effect column - ASSERT_CAN_READ(2); - note->command = *((BYTE *)(lpStream + dwMemPos)); - note->param = *((BYTE *)(lpStream + dwMemPos + 1)); - dwMemPos += 2; + // There's one effect, just stick it in the effect column + m.command = patternChunk.ReadUint8(); + m.param = patternChunk.ReadUint8(); } - if(note->command) - ImportIMFEffect(note); + if(m.command) + ImportIMFEffect(m); } } - SAMPLEINDEX firstsample = 1; // first sample index of the current instrument + SAMPLEINDEX firstSample = 1; // first sample index of the current instrument // read instruments - for(INSTRUMENTINDEX nIns = 0; nIns < hdr.insnum; nIns++) + for(INSTRUMENTINDEX ins = 0; ins < GetNumInstruments(); ins++) { - IMFINSTRUMENT imfins; - ModInstrument *pIns; - ASSERT_CAN_READ(sizeof(IMFINSTRUMENT)); - memcpy(&imfins, lpStream + dwMemPos, sizeof(IMFINSTRUMENT)); - dwMemPos += sizeof(IMFINSTRUMENT); - m_nInstruments++; + ModInstrument *instr = AllocateInstrument(ins + 1); + IMFInstrument instrumentHeader; + if(!file.ReadConvertEndianness(instrumentHeader) || instr == nullptr) + { + continue; + } - imfins.smpnum = LittleEndianW(imfins.smpnum); - imfins.fadeout = LittleEndianW(imfins.fadeout); - // Orpheus does not check this! - //if(memcmp(imfins.ii10, "II10", 4) != 0) + //if(memcmp(instrumentHeader.ii10, "II10", 4) != 0) // return false; + instrumentHeader.ConvertToMPT(*instr, firstSample); - pIns = AllocateInstrument(nIns + 1); - if(pIns == nullptr) + // Read this instrument's samples + for(SAMPLEINDEX smp = 0; smp < instrumentHeader.smpNum; smp++) { - continue; - } + IMFSample sampleHeader; + file.ReadConvertEndianness(sampleHeader); + m_nSamples++; - StringFixer::ReadString<StringFixer::nullTerminated>(pIns->name, imfins.name); - - if(imfins.smpnum) - { - STATIC_ASSERT(CountOf(pIns->Keyboard) >= CountOf(imfins.map)); - for(size_t cNote = 0; cNote < CountOf(imfins.map); cNote++) + if(memcmp(sampleHeader.is10, "IS10", 4) || m_nSamples >= MAX_SAMPLES) { - pIns->Keyboard[cNote] = firstsample + imfins.map[cNote]; + continue; } - } - pIns->nFadeOut = imfins.fadeout; + ModSample &sample = Samples[firstSample + smp]; - LoadIMFEnvelope(&pIns->VolEnv, &imfins, IMF_ENV_VOL); - LoadIMFEnvelope(&pIns->PanEnv, &imfins, IMF_ENV_PAN); - LoadIMFEnvelope(&pIns->PitchEnv, &imfins, IMF_ENV_FILTER); - if((pIns->PitchEnv.dwFlags & ENV_ENABLED) != 0) - pIns->PitchEnv.dwFlags |= ENV_FILTER; - - // hack to get === to stop notes (from modplug's xm loader) - if(!pIns->VolEnv.dwFlags[ENV_ENABLED] && !pIns->nFadeOut) - pIns->nFadeOut = 8192; - - // read this instrument's samples - for(SAMPLEINDEX nSmp = 0; nSmp < imfins.smpnum; nSmp++) - { - ASSERT_CAN_READ(sizeof(IMFSAMPLE)); - IMFSAMPLE imfsmp; - memcpy(&imfsmp, lpStream + dwMemPos, sizeof(IMFSAMPLE)); - dwMemPos += sizeof(IMFSAMPLE); - m_nSamples++; - - if(memcmp(imfsmp.is10, "IS10", 4) != 0) - return false; - - ModSample &sample = Samples[firstsample + nSmp]; - - sample.Initialize(); - StringFixer::ReadString<StringFixer::nullTerminated>(sample.filename, imfsmp.filename); + sampleHeader.ConvertToMPT(sample); strcpy(m_szNames[m_nSamples], sample.filename); - uint32 byteLen = sample.nLength = LittleEndian(imfsmp.length); - sample.nLoopStart = LittleEndian(imfsmp.loop_start); - sample.nLoopEnd = LittleEndian(imfsmp.loop_end); - sample.nC5Speed = LittleEndian(imfsmp.C5Speed); - sample.nVolume = imfsmp.volume * 4; - sample.nPan = imfsmp.panning; - if(imfsmp.flags & 1) - sample.uFlags |= CHN_LOOP; - if(imfsmp.flags & 2) - sample.uFlags |= CHN_PINGPONGLOOP; - if(imfsmp.flags & 4) + if(sampleHeader.length) { - sample.uFlags |= CHN_16BIT; - sample.nLength /= 2; - sample.nLoopStart /= 2; - sample.nLoopEnd /= 2; - } - if(imfsmp.flags & 8) - sample.uFlags |= CHN_PANNING; - - if(byteLen) - { - ASSERT_CAN_READ(byteLen); - + FileReader sampleChunk = file.GetChunk(sampleHeader.length); SampleIO( - (imfsmp.flags & 4) ? SampleIO::_16bit : SampleIO::_8bit, + sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::signedPCM) - .ReadSample(sample, reinterpret_cast<LPCSTR>(lpStream + dwMemPos), byteLen); + .ReadSample(sample, sampleChunk); } - - dwMemPos += byteLen; } - firstsample += imfins.smpnum; + firstSample += instrumentHeader.smpNum; } return true; Modified: trunk/OpenMPT/soundlib/ModSequence.cpp =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/ModSequence.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -28,7 +28,7 @@ PATTERNINDEX* pArray, ORDERINDEX nSize, ORDERINDEX nCapacity, - const bool bDeletableArray) : + const bool bDeletableArray) : m_pSndFile(&rSf), m_pArray(pArray), m_nSize(nSize), @@ -40,7 +40,7 @@ {} -ModSequence::ModSequence(CSoundFile& rSf, ORDERINDEX nSize) : +ModSequence::ModSequence(CSoundFile& rSf, ORDERINDEX nSize) : m_pSndFile(&rSf), m_bDeletableArray(true), m_nInvalidIndex(GetInvalidPatIndex(MOD_TYPE_MPT)), @@ -121,7 +121,7 @@ if(GetLengthTailTrimmed() > specs.ordersMax) { #ifdef MODPLUG_TRACKER - if (m_pSndFile->GetpModDoc()) + if(m_pSndFile->GetpModDoc()) m_pSndFile->GetpModDoc()->AddToLog("WARNING: Order list has been trimmed!\n"); #endif // MODPLUG_TRACKER } @@ -159,7 +159,7 @@ { const ORDERINDEX nLength = GetLength(); if(nLength == 0) return 0; - ORDERINDEX next = min(nLength-1, start+1); + ORDERINDEX next = Util::Min(ORDERINDEX(nLength - 1), ORDERINDEX(start + 1)); while(next+1 < nLength && (*this)[next] == GetIgnoreIndex()) next++; return next; } @@ -170,7 +170,7 @@ { const ORDERINDEX nLength = GetLength(); if(start == 0 || nLength == 0) return 0; - ORDERINDEX prev = min(start-1, nLength-1); + ORDERINDEX prev = Util::Min(ORDERINDEX(start - 1), ORDERINDEX(nLength - 1)); while(prev > 0 && (*this)[prev] == GetIgnoreIndex()) prev--; return prev; } @@ -311,9 +311,9 @@ ModSequenceSet::ModSequenceSet(CSoundFile& sndFile) - : ModSequence(sndFile, m_Cache, s_nCacheSize, s_nCacheSize, NoArrayDelete), + : ModSequence(sndFile, m_Cache, s_nCacheSize, s_nCacheSize, false), m_nCurrentSeq(0) -//------------------------------------------------------------------- +//-------------------------------------------------------------- { m_Sequences.push_back(ModSequence(sndFile, s_nCacheSize)); } @@ -322,7 +322,7 @@ const ModSequence& ModSequenceSet::GetSequence(SEQUENCEINDEX nSeq) const //---------------------------------------------------------------------- { - if (nSeq == GetCurrentSequenceIndex()) + if(nSeq == GetCurrentSequenceIndex()) return *this; else return m_Sequences[nSeq]; @@ -332,7 +332,7 @@ ModSequence& ModSequenceSet::GetSequence(SEQUENCEINDEX nSeq) //---------------------------------------------------------- { - if (nSeq == GetCurrentSequenceIndex()) + if(nSeq == GetCurrentSequenceIndex()) return *this; else return m_Sequences[nSeq]; @@ -350,7 +350,7 @@ //--------------------------------------- { const ModSequence& rSeq = m_Sequences[m_nCurrentSeq]; - if (rSeq.GetLength() <= s_nCacheSize) + if(rSeq.GetLength() <= s_nCacheSize) { PATTERNINDEX* pOld = m_pArray; m_pArray = m_Cache; @@ -396,13 +396,13 @@ //-------------------------------------------------- { // Do nothing if index is invalid or if there's only one sequence left. - if (i >= m_Sequences.size() || m_Sequences.size() <= 1) + if(i >= m_Sequences.size() || m_Sequences.size() <= 1) return; const bool bSequenceChanges = (i == m_nCurrentSeq); m_Sequences.erase(m_Sequences.begin() + i); - if (i < m_nCurrentSeq || m_nCurrentSeq >= GetNumSequences()) + if(i < m_nCurrentSeq || m_nCurrentSeq >= GetNumSequences()) m_nCurrentSeq--; - if (bSequenceChanges) + if(bSequenceChanges) CopyStorageToCache(); } @@ -417,11 +417,11 @@ GetSequence(n).AdjustToNewModType(oldtype); } // Multisequences not suppported by other formats - if (oldtype != MOD_TYPE_NONE && newtype != MOD_TYPE_MPT) + if(oldtype != MOD_TYPE_NONE && newtype != MOD_TYPE_MPT) MergeSequences(); // Convert sequence with separator patterns into multiple sequences? - if (oldtype != MOD_TYPE_NONE && newtype == MOD_TYPE_MPT && GetNumSequences() == 1) + if(oldtype != MOD_TYPE_NONE && newtype == MOD_TYPE_MPT && GetNumSequences() == 1) ConvertSubsongsToMultipleSequences(); } @@ -430,7 +430,7 @@ //------------------------------------------------------- { // Allow conversion only if there's only one sequence. - if (GetNumSequences() != 1 || m_pSndFile->GetType() != MOD_TYPE_MPT) + if(GetNumSequences() != 1 || m_pSndFile->GetType() != MOD_TYPE_MPT) return false; bool hasSepPatterns = false; @@ -447,7 +447,7 @@ if(hasSepPatterns && Reporting::Confirm("The order list contains separator items.\nThe new format supports multiple sequences, do you want to convert those separate tracks into multiple song sequences?", - "Order list conversion") == cnfYes) + "Order list conversion", false, true) == cnfYes) { SetSequence(0); @@ -488,7 +488,7 @@ if(m_pSndFile->Patterns.IsValidPat(copyPat)) { ModCommand *m = m_pSndFile->Patterns[copyPat]; - for (UINT len = m_pSndFile->Patterns[copyPat].GetNumRows() * m_pSndFile->m_nChannels; len; m++, len--) + for(size_t len = m_pSndFile->Patterns[copyPat].GetNumRows() * m_pSndFile->m_nChannels; len; m++, len--) { if(m->command == CMD_POSITIONJUMP && m->param >= startOrd) { @@ -554,7 +554,7 @@ if(!m_pSndFile->Patterns.IsValidPat(nPat)) continue; ModCommand *m = m_pSndFile->Patterns[nPat]; - for (UINT len = 0; len < m_pSndFile->Patterns[nPat].GetNumRows() * m_pSndFile->m_nChannels; m++, len++) + for(size_t len = 0; len < m_pSndFile->Patterns[nPat].GetNumRows() * m_pSndFile->m_nChannels; m++, len++) { if(m->command == CMD_POSITIONJUMP) { Modified: trunk/OpenMPT/soundlib/ModSequence.h =================================================================== --- trunk/OpenMPT/soundlib/ModSequence.h 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/ModSequence.h 2013-02-16 15:06:45 UTC (rev 1532) @@ -132,8 +132,6 @@ PATTERNINDEX m_nIgnoreIndex; // Ignore pat index. bool m_bDeletableArray; // True if m_pArray points the deletable(with delete[]) array. CSoundFile* m_pSndFile; // Pointer to associated CSoundFile. - - static const bool NoArrayDelete = false; }; Modified: trunk/OpenMPT/soundlib/Sndfile.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -631,7 +631,7 @@ #endif // MODPLUG_TRACKER #endif // MODPLUG_BASIC_SUPPORT && !ReadGDM(file) - && !ReadIMF(lpStream, dwMemLength) + && !ReadIMF(file) && !ReadAM(file) && !ReadJ2B(file) && !ReadMO3(file) Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-02-16 15:06:45 UTC (rev 1532) @@ -415,7 +415,7 @@ bool ReadUMX(FileReader &file); bool ReadMO3(FileReader &file); bool ReadGDM(FileReader &file); - bool ReadIMF(const LPCBYTE lpStream, const DWORD dwMemLength); + bool ReadIMF(FileReader &file); bool ReadAM(FileReader &file); bool ReadJ2B(FileReader &file); bool ReadMID(const LPCBYTE lpStream, DWORD dwMemLength); Modified: trunk/OpenMPT/soundlib/patternContainer.cpp =================================================================== --- trunk/OpenMPT/soundlib/patternContainer.cpp 2013-02-16 01:12:24 UTC (rev 1531) +++ trunk/OpenMPT/soundlib/patternContainer.cpp 2013-02-16 15:06:45 UTC (rev 1532) @@ -52,9 +52,8 @@ bool CPatternContainer::Insert(const PATTERNINDEX index, const ROWINDEX rows) //--------------------------------------------------------------------------- { - ASSERT(rows != 0); const CModSpecifications& specs = m_rSndFile.GetModSpecifications(); - if(index >= specs.patternsMax || index > m_Patterns.size() || rows > specs.patternRowsMax) + if(index >= specs.patternsMax || index > m_Patterns.size() || rows > specs.patternRowsMax || rows == 0) return true; if(index < m_Patterns.size() && m_Patterns[index]) return true; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |