|
From: <sag...@us...> - 2013-06-30 22:29:13
|
Revision: 2457
http://sourceforge.net/p/modplug/code/2457
Author: saga-games
Date: 2013-06-30 22:29:04 +0000 (Sun, 30 Jun 2013)
Log Message:
-----------
[Ref] Rewrote PTM loader using FileReader.
[Imp] PTM: Note cut should work better, added support for reversed samples.
Modified Paths:
--------------
trunk/OpenMPT/soundlib/Load_ptm.cpp
trunk/OpenMPT/soundlib/Snd_fx.cpp
trunk/OpenMPT/soundlib/Sndfile.cpp
trunk/OpenMPT/soundlib/Sndfile.h
Modified: trunk/OpenMPT/soundlib/Load_ptm.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Load_ptm.cpp 2013-06-30 20:24:50 UTC (rev 2456)
+++ trunk/OpenMPT/soundlib/Load_ptm.cpp 2013-06-30 22:29:04 UTC (rev 2457)
@@ -4,7 +4,6 @@
* Purpose: PTM (PolyTracker) module loader
* Notes : (currently none)
* Authors: Olivier Lapicque
- * Adam Goode (endian and char fixes for PPC)
* OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
@@ -13,227 +12,259 @@
#include "stdafx.h"
#include "Loaders.h"
-#if MPT_COMPILER_MSVC
-#pragma warning(disable:4244) //"conversion from 'type1' to 'type2', possible loss of data"
-#endif
-
#ifdef NEEDS_PRAGMA_PACK
#pragma pack(push, 1)
#endif
-typedef struct PACKED PTMFILEHEADER
+struct PACKED PTMFileHeader
{
- char songname[28]; // name of song, asciiz string
- CHAR eof; // 26
- BYTE version_lo; // 03 version of file, currently 0203h
- BYTE version_hi; // 02
- BYTE reserved1; // reserved, set to 0
- WORD norders; // number of orders (0..256)
- WORD nsamples; // number of instruments (1..255)
- WORD npatterns; // number of patterns (1..128)
- WORD nchannels; // number of channels (voices) used (1..32)
- WORD fileflags; // set to 0
- WORD reserved2; // reserved, set to 0
- DWORD ptmf_id; // song identification, 'PTMF' or 0x464d5450
- BYTE reserved3[16]; // reserved, set to 0
- BYTE chnpan[32]; // channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right
- BYTE orders[256]; // order list, valid entries 0..nOrders-1
- WORD patseg[128]; // pattern offsets (*16)
-} PTMFILEHEADER, *LPPTMFILEHEADER;
+ char songname[28]; // Name of song, asciiz string
+ uint8 dosEOF; // 26
+ uint8 versionLo; // 03 version of file, currently 0203h
+ uint8 versionHi; // 02
+ uint8 reserved1; // Reserved, set to 0
+ uint16 numOrders; // Number of orders (0..256)
+ uint16 numSamples; // Number of instruments (1..255)
+ uint16 numPatterns; // Number of patterns (1..128)
+ uint16 numChannels; // Number of channels (voices) used (1..32)
+ uint8 flags[2]; // Set to 0
+ uint8 reserved2[2]; // Reserved, set to 0
+ char magic[4]; // Song identification, 'PTMF'
+ uint8 reserved3[16]; // Reserved, set to 0
+ uint8 chnPan[32]; // Channel panning settings, 0..15, 0 = left, 7 = middle, 15 = right
+ uint8 orders[256]; // Order list, valid entries 0..nOrders-1
+ uint16 patOffsets[128]; // Pattern offsets (*16)
-STATIC_ASSERT(sizeof(PTMFILEHEADER) == 608);
+ // Convert all multi-byte numeric values to current platform's endianness or vice versa.
+ void ConvertEndianness()
+ {
+ SwapBytesLE(numOrders);
+ SwapBytesLE(numSamples);
+ SwapBytesLE(numPatterns);
+ SwapBytesLE(numChannels);
+ for(int i = 0; i < CountOf(patOffsets); i++)
+ {
+ SwapBytesLE(patOffsets[i]);
+ }
+ }
+};
-typedef struct PACKED PTMSAMPLE
+STATIC_ASSERT(sizeof(PTMFileHeader) == 608);
+
+struct PACKED PTMSampleHeader
{
- BYTE sampletype; // sample type (bit array)
- char filename[12]; // name of external sample file
- BYTE volume; // default volume
- WORD nC4Spd; // C4 speed
- WORD sampleseg; // sample segment (used internally)
- WORD fileofs[2]; // offset of sample data
- WORD length[2]; // sample size (in bytes)
- WORD loopbeg[2]; // start of loop
- WORD loopend[2]; // end of loop
- WORD gusdata[7];
- char samplename[28]; // name of sample, asciiz
- DWORD ptms_id; // sample identification, 'PTMS' or 0x534d5450
-} PTMSAMPLE;
+ enum SampleFlags
+ {
+ smpTypeMask = 0x03,
+ smpPCM = 0x01,
-STATIC_ASSERT(sizeof(PTMSAMPLE) == 80);
+ smpLoop = 0x04,
+ smpPingPong = 0x08,
+ smp16Bit = 0x10,
+ };
+ uint8 flags; // Sample type (see SampleFlags)
+ char filename[12]; // Name of external sample file
+ uint8 volume; // Default volume
+ uint16 c4speed; // C-4 speed (yep, not C-5)
+ uint8 smpSegment[2]; // Sample segment (used internally)
+ uint32 dataOffset; // Offset of sample data
+ uint32 length; // Sample size (in bytes)
+ uint32 loopStart; // Start of loop
+ uint32 loopEnd; // End of loop
+ uint8 gusdata[14];
+ char samplename[28]; // Name of sample, ASCIIZ
+ char magic[4]; // Sample identification, 'PTMS'
+
+ // Convert all multi-byte numeric values to current platform's endianness or vice versa.
+ void ConvertEndianness()
+ {
+ SwapBytesLE(c4speed);
+ SwapBytesLE(dataOffset);
+ SwapBytesLE(length);
+ SwapBytesLE(loopStart);
+ SwapBytesLE(loopEnd);
+ }
+
+ // Convert an PTM sample header to OpenMPT's internal sample header.
+ SampleIO ConvertToMPT(ModSample &mptSmp) const
+ {
+ mptSmp.Initialize(MOD_TYPE_S3M);
+ mptSmp.nVolume = std::min(volume, uint8(64)) * 4;
+ mptSmp.nC5Speed = c4speed * 2;
+
+ mpt::String::Read<mpt::String::maybeNullTerminated>(mptSmp.filename, filename);
+
+ SampleIO sampleIO(
+ SampleIO::_8bit,
+ SampleIO::mono,
+ SampleIO::littleEndian,
+ SampleIO::deltaPCM);
+
+ if((flags & smpTypeMask) == smpPCM)
+ {
+ mptSmp.nLength = length;
+ mptSmp.nLoopStart = loopStart;
+ mptSmp.nLoopEnd = loopEnd;
+
+ if(flags & smpLoop) mptSmp.uFlags.set(CHN_LOOP);
+ if(flags & smpPingPong) mptSmp.uFlags.set(CHN_PINGPONGLOOP);
+ if(flags & smp16Bit)
+ {
+ sampleIO |= SampleIO::_16bit;
+ sampleIO |= SampleIO::PTM8Dto16;
+
+ mptSmp.nLength /= 2;
+ mptSmp.nLoopStart /= 2;
+ mptSmp.nLoopEnd /= 2;
+ }
+ }
+
+ return sampleIO;
+ }
+};
+
+STATIC_ASSERT(sizeof(PTMSampleHeader) == 80);
+
#ifdef NEEDS_PRAGMA_PACK
#pragma pack(pop)
#endif
-bool CSoundFile::ReadPTM(const BYTE *lpStream, const DWORD dwMemLength, ModLoadingFlags loadFlags)
-//------------------------------------------------------------------------------------------------
+bool CSoundFile::ReadPTM(FileReader &file, ModLoadingFlags loadFlags)
+//-------------------------------------------------------------------
{
- if(lpStream == nullptr || dwMemLength < sizeof(PTMFILEHEADER))
- return false;
+ file.Rewind();
- PTMFILEHEADER pfh = *(LPPTMFILEHEADER)lpStream;
- DWORD dwMemPos;
- UINT nOrders;
-
- pfh.norders = LittleEndianW(pfh.norders);
- pfh.nsamples = LittleEndianW(pfh.nsamples);
- pfh.npatterns = LittleEndianW(pfh.npatterns);
- pfh.nchannels = LittleEndianW(pfh.nchannels);
- pfh.fileflags = LittleEndianW(pfh.fileflags);
- pfh.reserved2 = LittleEndianW(pfh.reserved2);
- pfh.ptmf_id = LittleEndian(pfh.ptmf_id);
- for (size_t j = 0; j < CountOf(pfh.patseg); j++)
+ PTMFileHeader fileHeader;
+ if(!file.ReadConvertEndianness(fileHeader)
+ || memcmp(fileHeader.magic, "PTMF", 4)
+ || !fileHeader.numChannels
+ || fileHeader.numChannels > 32
+ || !fileHeader.numOrders || fileHeader.numOrders > 256
+ || !fileHeader.numSamples || fileHeader.numSamples > 255
+ || !fileHeader.numPatterns || fileHeader.numPatterns > 128
+ || !file.CanRead(fileHeader.numSamples * sizeof(PTMSampleHeader)))
{
- pfh.patseg[j] = LittleEndianW(pfh.patseg[j]);
- }
-
- if ((pfh.ptmf_id != 0x464d5450) || (!pfh.nchannels)
- || (pfh.nchannels > 32)
- || (pfh.norders > 256) || (!pfh.norders)
- || (!pfh.nsamples) || (pfh.nsamples > 255)
- || (!pfh.npatterns) || (pfh.npatterns > 128)
- || (sizeof(PTMFILEHEADER) + pfh.nsamples * sizeof(PTMSAMPLE) >= dwMemLength))
- {
return false;
} else if(loadFlags == onlyVerifyHeader)
{
return true;
}
- mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[0], pfh.songname);
+ mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[0], fileHeader.songname);
InitializeGlobals();
- madeWithTracker = mpt::String::Format("PolyTracker %d.%d", pfh.version_hi, pfh.version_lo);
+ madeWithTracker = mpt::String::Format("PolyTracker %d.%02x", fileHeader.versionHi, fileHeader.versionLo);
m_nType = MOD_TYPE_PTM;
- m_nChannels = pfh.nchannels;
- m_nSamples = MIN(pfh.nsamples, MAX_SAMPLES - 1);
- dwMemPos = sizeof(PTMFILEHEADER);
- nOrders = (pfh.norders < MAX_ORDERS) ? pfh.norders : MAX_ORDERS-1;
- Order.ReadFromArray(pfh.orders, nOrders);
+ m_nChannels = fileHeader.numChannels;
+ m_nSamples = std::min<SAMPLEINDEX>(fileHeader.numSamples, MAX_SAMPLES - 1);
+ Order.ReadFromArray(fileHeader.orders, fileHeader.numOrders);
- for (CHANNELINDEX ipan = 0; ipan < m_nChannels; ipan++)
+ // Reading channel panning
+ for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
{
- ChnSettings[ipan].Reset();
- ChnSettings[ipan].nPan = ((pfh.chnpan[ipan] & 0x0F) << 4) + 4;
+ ChnSettings[chn].Reset();
+ ChnSettings[chn].nPan = ((fileHeader.chnPan[chn] & 0x0F) << 4) + 4;
}
- for (SAMPLEINDEX ismp = 0; ismp < m_nSamples; ismp++, dwMemPos += sizeof(PTMSAMPLE))
+
+ // Reading samples
+ FileReader sampleHeaderChunk = file.GetChunk(fileHeader.numSamples * sizeof(PTMSampleHeader));
+ for(SAMPLEINDEX smp = 0; smp < m_nSamples; smp++)
{
- ModSample &sample = Samples[ismp + 1];
- PTMSAMPLE *psmp = (PTMSAMPLE *)(lpStream+dwMemPos);
+ PTMSampleHeader sampleHeader;
+ sampleHeaderChunk.ReadConvertEndianness(sampleHeader);
- sample.Initialize();
- mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[ismp + 1], psmp->samplename);
- mpt::String::Read<mpt::String::maybeNullTerminated>(sample.filename, psmp->filename);
+ ModSample &sample = Samples[smp + 1];
+ mpt::String::Read<mpt::String::maybeNullTerminated>(m_szNames[smp + 1], sampleHeader.samplename);
+ SampleIO sampleIO = sampleHeader.ConvertToMPT(sample);
- sample.nVolume = psmp->volume * 4;
- sample.nC5Speed = LittleEndianW(psmp->nC4Spd) * 2;
-
- if((psmp->sampletype & 3) == 1)
+ if((loadFlags & loadSampleData) && sample.nLength && sampleHeader.dataOffset && file.Seek(sampleHeader.dataOffset))
{
- SampleIO sampleIO(
- SampleIO::_8bit,
- SampleIO::mono,
- SampleIO::littleEndian,
- SampleIO::deltaPCM);
-
- DWORD samplepos;
- sample.nLength = LittleEndian(*(LPDWORD)(psmp->length));
- sample.nLoopStart = LittleEndian(*(LPDWORD)(psmp->loopbeg));
- sample.nLoopEnd = LittleEndian(*(LPDWORD)(psmp->loopend));
- samplepos = LittleEndian(*(LPDWORD)(&psmp->fileofs));
- if (psmp->sampletype & 4) sample.uFlags |= CHN_LOOP;
- if (psmp->sampletype & 8) sample.uFlags |= CHN_PINGPONGLOOP;
- if (psmp->sampletype & 16)
- {
- sampleIO |= SampleIO::_16bit;
- sampleIO |= SampleIO::PTM8Dto16;
-
- sample.nLength /= 2;
- sample.nLoopStart /= 2;
- sample.nLoopEnd /= 2;
- }
- if(sample.nLength && samplepos && samplepos < dwMemLength && (loadFlags & loadSampleData))
- {
- FileReader chunk(lpStream + samplepos, dwMemLength - samplepos);
- sampleIO.ReadSample(sample, chunk);
- }
+ sampleIO.ReadSample(sample, file);
}
}
+
// Reading Patterns
if(!(loadFlags && loadPatternData))
{
return true;
}
- for (UINT ipat=0; ipat<pfh.npatterns; ipat++)
+
+ for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
{
- dwMemPos = ((UINT)pfh.patseg[ipat]) << 4;
- if ((!dwMemPos) || (dwMemPos >= dwMemLength)) continue;
- if(Patterns.Insert(ipat, 64))
- break;
- //
- ModCommand *m = Patterns[ipat];
- for (UINT row=0; ((row < 64) && (dwMemPos < dwMemLength)); )
+ if(Patterns.Insert(pat, 64)
+ || fileHeader.patOffsets[pat] == 0
+ || !file.Seek(fileHeader.patOffsets[pat] << 4))
{
- UINT b = lpStream[dwMemPos++];
+ continue;
+ }
- if (dwMemPos >= dwMemLength) break;
- if (b)
+ ModCommand *rowBase = Patterns[pat];
+ ROWINDEX row = 0;
+ while(row < 64 && file.AreBytesLeft())
+ {
+ uint8 b = file.ReadUint8();
+
+ if(b == 0)
{
- UINT nChn = b & 0x1F;
+ row++;
+ rowBase += m_nChannels;
+ continue;
+ }
+ CHANNELINDEX chn = (b & 0x1F);
+ ModCommand dummy;
+ ModCommand &m = chn < GetNumChannels() ? rowBase[chn] : dummy;
- if (b & 0x20)
+ if(b & 0x20)
+ {
+ m.note = file.ReadUint8();
+ m.instr = file.ReadUint8();
+ if(m.note == 254)
+ m.note = NOTE_NOTECUT;
+ else if(!m.note || m.note > 120)
+ m.note = NOTE_NONE;
+ }
+ if(b & 0x40)
+ {
+ m.command = file.ReadUint8();
+ m.param = file.ReadUint8();
+ if(m.command < 0x10)
{
- if (dwMemPos + 2 > dwMemLength) break;
- m[nChn].note = lpStream[dwMemPos++];
- m[nChn].instr = lpStream[dwMemPos++];
- }
- if (b & 0x40)
+ // Beware: Effect letters are as in MOD, but portamento and volume slides behave like in S3M (i.e. fine slides share the same effect letters)
+ ConvertModCommand(m);
+ } else
{
- if (dwMemPos + 2 > dwMemLength) break;
- m[nChn].command = lpStream[dwMemPos++];
- m[nChn].param = lpStream[dwMemPos++];
- if (m[nChn].command < 0x10)
+ switch(m.command)
{
- ConvertModCommand(m[nChn]);
- m[nChn].ExtendedMODtoS3MEffect();
- // Note cut does just mute the sample, not cut it. We have to fix that, if possible.
- if(m[nChn].command == CMD_S3MCMDEX && (m[nChn].param & 0xF0) == 0xC0 && m[nChn].volcmd == VOLCMD_NONE)
+ case 0x10:
+ m.command = CMD_GLOBALVOLUME;
+ break;
+ case 0x11:
+ m.command = CMD_RETRIG;
+ break;
+ case 0x12:
+ m.command = CMD_FINEVIBRATO;
+ break;
+ case 0x17:
+ // Reverse sample + offset (start with offset 256 * xx bytes) -- is this an offset from the sample end...?
+ if(m.param)
{
- // SCx => v00 + SDx
- // This is a pretty dumb solution because many (?) PTM files make usage of the volume column + note cut at the same time.
- m[nChn].param = 0xD0 | (m[nChn].param & 0x0F);
- m[nChn].volcmd = VOLCMD_VOLUME;
- m[nChn].vol = 0;
+ m.volcmd = VOLCMD_OFFSET;
+ m.vol = m.param >> 3;
}
- } else
- {
- switch(m[nChn].command)
- {
- case 16:
- m[nChn].command = CMD_GLOBALVOLUME;
- break;
- case 17:
- m[nChn].command = CMD_RETRIG;
- break;
- case 18:
- m[nChn].command = CMD_FINEVIBRATO;
- break;
- default:
- m[nChn].command = 0;
- }
+ m.command = CMD_S3MCMDEX;
+ m.param = 0x9F;
+ break;
+ default:
+ m.command = CMD_NONE;
}
}
- if (b & 0x80)
- {
- if (dwMemPos >= dwMemLength) break;
- m[nChn].volcmd = VOLCMD_VOLUME;
- m[nChn].vol = lpStream[dwMemPos++];
- }
- } else
+ }
+ if(b & 0x80)
{
- row++;
- m += m_nChannels;
+ m.volcmd = VOLCMD_VOLUME;
+ m.vol = file.ReadUint8();
}
}
}
Modified: trunk/OpenMPT/soundlib/Snd_fx.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Snd_fx.cpp 2013-06-30 20:24:50 UTC (rev 2456)
+++ trunk/OpenMPT/soundlib/Snd_fx.cpp 2013-06-30 22:29:04 UTC (rev 2457)
@@ -1676,7 +1676,7 @@
//:xy --> note delay until tick x, note cut at tick x+y
nStartTick = (param & 0xF0) >> 4;
const UINT cutAtTick = nStartTick + (param & 0x0F);
- NoteCut(nChn, cutAtTick);
+ NoteCut(nChn, cutAtTick, IsCompatibleMode(TRK_IMPULSETRACKER | TRK_SCREAMTRACKER));
} else if ((cmd == CMD_MODCMDEX) || (cmd == CMD_S3MCMDEX))
{
if ((!param) && (GetType() & (MOD_TYPE_S3M|MOD_TYPE_IT|MOD_TYPE_MPT))) param = pChn->nOldCmdEx; else pChn->nOldCmdEx = param;
@@ -3457,7 +3457,7 @@
// EBx: Fine Volume Down
case 0xB0: if ((param) || (GetType() & (MOD_TYPE_XM|MOD_TYPE_MT2))) FineVolumeDown(pChn, param, false); break;
// ECx: Note Cut
- case 0xC0: NoteCut(nChn, param); break;
+ case 0xC0: NoteCut(nChn, param, false); break;
// EDx: Note Delay
// EEx: Pattern Delay
case 0xF0:
@@ -3631,7 +3631,9 @@
else if(GetType() == MOD_TYPE_S3M)
return;
}
- NoteCut(nChn, param);
+ // S3M/IT compatibility: Note Cut really cuts notes and does not just mute them (so that following volume commands could restore the sample)
+ // Test case: scx.it
+ NoteCut(nChn, param, IsCompatibleMode(TRK_IMPULSETRACKER | TRK_SCREAMTRACKER));
break;
// SDx: Note Delay
// SEx: Pattern Delay for x rows
@@ -4354,16 +4356,14 @@
}
-void CSoundFile::NoteCut(CHANNELINDEX nChn, UINT nTick)
-//-----------------------------------------------------
+void CSoundFile::NoteCut(CHANNELINDEX nChn, UINT nTick, bool cutSample)
+//---------------------------------------------------------------------
{
if (m_nTickCount == nTick)
{
ModChannel *pChn = &Chn[nChn];
pChn->nVolume = 0;
- // S3M/IT compatibility: Note Cut really cuts notes and does not just mute them (so that following volume commands could restore the sample)
- // Test case: scx.it
- if(IsCompatibleMode(TRK_IMPULSETRACKER|TRK_SCREAMTRACKER))
+ if(cutSample)
{
pChn->nFadeOutVol = 0;
pChn->dwFlags.set(CHN_NOTEFADE);
@@ -4949,7 +4949,7 @@
if(m_nTickCount == 0)
pChn->nOldFinePortaUpDown = 0;
- const int tickParam = (m_nTickCount + 1.0) * param / m_nMusicSpeed;
+ const int tickParam = static_cast<int>((m_nTickCount + 1.0) * param / m_nMusicSpeed);
pChn->m_PortamentoFineSteps += (param >= 0) ? tickParam - pChn->nOldFinePortaUpDown : tickParam + pChn->nOldFinePortaUpDown;
if(m_nTickCount + 1 == m_nMusicSpeed)
pChn->nOldFinePortaUpDown = abs(param);
Modified: trunk/OpenMPT/soundlib/Sndfile.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Sndfile.cpp 2013-06-30 20:24:50 UTC (rev 2456)
+++ trunk/OpenMPT/soundlib/Sndfile.cpp 2013-06-30 22:29:04 UTC (rev 2457)
@@ -590,7 +590,7 @@
// Global variable initializer for loader functions
void CSoundFile::InitializeGlobals()
-//---------------------------
+//----------------------------------
{
// Do not add or change any of these values! And if you do, review each and every loader to check if they require these defaults!
m_nType = MOD_TYPE_NONE;
@@ -707,7 +707,7 @@
&& !ReadAMS(file, loadFlags)
&& !ReadAMS2(file, loadFlags)
&& !ReadOKT(file, loadFlags)
- && !ReadPTM(lpStream, dwMemLength, loadFlags)
+ && !ReadPTM(file, loadFlags)
&& !ReadUlt(file, loadFlags)
&& !ReadDMF(file, loadFlags)
&& !ReadDSM(lpStream, dwMemLength, loadFlags)
@@ -1295,12 +1295,12 @@
void CSoundFile::LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
//------------------------------------------------------------
{
- if ((nPat < 0) || (nPat >= Patterns.Size()) || (!Patterns[nPat]))
+ if(!Patterns.IsValidPat(nPat))
{
m_SongFlags.reset(SONG_PATTERNLOOP);
} else
{
- if ((nRow < 0) || (nRow >= (int)Patterns[nPat].GetNumRows())) nRow = 0;
+ if(nRow >= Patterns[nPat].GetNumRows()) nRow = 0;
m_nPattern = nPat;
m_nRow = m_nNextRow = nRow;
m_nTickCount = m_nMusicSpeed;
@@ -1309,7 +1309,6 @@
m_nBufferCount = 0;
m_nNextPatStartRow = 0;
m_SongFlags.set(SONG_PATTERNLOOP);
- // m_nSeqOverride = 0;
}
}
@@ -1318,8 +1317,8 @@
void CSoundFile::DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
//----------------------------------------------------------------
{
- if ((nPat < 0) || (nPat >= Patterns.Size()) || (!Patterns[nPat])) nPat = 0;
- if ((nRow < 0) || (nRow >= (int)Patterns[nPat].GetNumRows())) nRow = 0;
+ if(!Patterns.IsValidPat(nPat)) nPat = 0;
+ if(nRow >= Patterns[nPat].GetNumRows()) nRow = 0;
m_nPattern = nPat;
m_nRow = m_nNextRow = nRow;
m_nTickCount = m_nMusicSpeed;
@@ -1328,7 +1327,6 @@
m_nBufferCount = 0;
m_nNextPatStartRow = 0;
m_SongFlags.reset(SONG_PATTERNLOOP);
- //m_nSeqOverride = 0;
}
//end rewbs.playSongFromCursor
Modified: trunk/OpenMPT/soundlib/Sndfile.h
===================================================================
--- trunk/OpenMPT/soundlib/Sndfile.h 2013-06-30 20:24:50 UTC (rev 2456)
+++ trunk/OpenMPT/soundlib/Sndfile.h 2013-06-30 22:29:04 UTC (rev 2457)
@@ -574,7 +574,7 @@
bool ReadMDL(const LPCBYTE lpStream, const DWORD dwMemLength, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadOKT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadDMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
- bool ReadPTM(const LPCBYTE lpStream, const DWORD dwMemLength, ModLoadingFlags loadFlags = loadCompleteModule);
+ bool ReadPTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadDBM(const LPCBYTE lpStream, const DWORD dwMemLength, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
@@ -738,7 +738,7 @@
void Panbrello(ModChannel *pChn, UINT param);
void RetrigNote(CHANNELINDEX nChn, int param, UINT offset=0); //rewbs.volOffset: added last param
void SampleOffset(CHANNELINDEX nChn, UINT param);
- void NoteCut(CHANNELINDEX nChn, UINT nTick);
+ void NoteCut(CHANNELINDEX nChn, UINT nTick, bool cutSample);
ROWINDEX PatternLoop(ModChannel *, UINT param);
void ExtendedMODCommands(CHANNELINDEX nChn, UINT param);
void ExtendedS3MCommands(CHANNELINDEX nChn, UINT param);
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|