View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000755 | OpenMPT | File Format Support | public | 2016-03-05 04:15 | 2017-03-31 08:02 |
Reporter | Revenant | Assigned To | Saga Musix | ||
Priority | normal | Severity | minor | Reproducibility | N/A |
Status | resolved | Resolution | fixed | ||
Target Version | OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) | Fixed in Version | OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) | ||
Summary | 0000755: Soundtracker Pro II support | ||||
Description | As mentioned the other day, here's my experimental loader patch for Soundtracker Pro II. Program & documentation: Some notes:
Anyway, let me know what you think. I'd like to be able to find more files to test with than the very few on Modland, but I think all of the ones I have currently get loaded/played back as close as possible to how they sound in the original tracker. | ||||
Tags | No tags attached. | ||||
Attached Files | stpro2.patch (23,636 bytes)
diff --git OpenMPT/libopenmpt/foo_openmpt.cpp OpenMPT/libopenmpt/foo_openmpt.cpp index ac7ce34..8947cdf 100644 --- OpenMPT/libopenmpt/foo_openmpt.cpp +++ OpenMPT/libopenmpt/foo_openmpt.cpp @@ -319,6 +319,7 @@ DECLARE_FILE_TYPE("OpenMPT compatible module files", "*.imf" ";" "*.j2b" ";" "*.plm" ";" + "*.stp" ";" "*.gdm" ";" "*.umx" ";" "*.mo3" ";" diff --git OpenMPT/soundlib/Load_stp.cpp OpenMPT/soundlib/Load_stp.cpp new file mode 100644 index 0000000..457ecdf --- /dev/null +++ OpenMPT/soundlib/Load_stp.cpp @@ -0,0 +1,716 @@ +/* + * Load_stp.cpp + * ------------ + * Purpose: STP (Soundtracker Pro II) module loader + * Notes : doesn't support multiple loops per sample, and various exotic effects. + * fractional speed values and combined auto effects are handled whenever possible, + * but some effects may be omitted (and there may be tempo accuracy issues). + * Authors: Devin Acker + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + * + * Wisdom from the Soundtracker Pro II manual: + * "To create shorter patterns, simply create shorter patterns." + */ + +#include "stdafx.h" +#include "Loaders.h" +#include "Tables.h" + +OPENMPT_NAMESPACE_BEGIN + +#ifdef NEEDS_PRAGMA_PACK +#pragma pack(push, 1) +#endif + +// File header (except for "STP3" magic) +struct PACKED STPFileHeader { + uint16 version; + uint8 numOrders; + uint8 patternLength; + uint8 orderList[128]; + uint16 speed; + uint16 speedFrac; + uint16 timerCount; + uint16 flags; + uint32 reserved; + uint16 midiCount; // always 50 + uint8 midi[50]; + uint16 numSamples; + uint16 sampleStructSize; + + void ConvertEndianness() + { + SwapBytesBE(version); + SwapBytesBE(speed); + SwapBytesBE(speedFrac); + SwapBytesBE(timerCount); + SwapBytesBE(flags); + SwapBytesBE(midiCount); + SwapBytesBE(numSamples); + SwapBytesBE(sampleStructSize); + } +}; + +STATIC_ASSERT(sizeof(STPFileHeader) == 200); + +// Sample header (versions 0 and 1) +struct PACKED STPSampleHeaderOld { + char pathName[31]; + uint8 flags; + char fileName[30]; + uint32 length; + uint8 volume; + uint8 reserved1; + uint32 loopStart; + uint32 loopLength; + uint16 defaultCmd; + uint32 reserved2; + + void ConvertEndianness() + { + SwapBytesBE(length); + SwapBytesBE(loopStart); + SwapBytesBE(loopLength); + SwapBytesBE(defaultCmd); + } + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = length; + mptSmp.nVolume = 4 * MIN(volume, 64); + + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + + if(mptSmp.nLoopStart >= mptSmp.nLength) + { + mptSmp.nLoopStart = mptSmp.nLength - 1; + } + if(mptSmp.nLoopEnd > mptSmp.nLength) + { + mptSmp.nLoopEnd = mptSmp.nLength; + } + + if(mptSmp.nLoopStart > mptSmp.nLoopEnd) + { + mptSmp.nLoopStart = 0; + mptSmp.nLoopEnd = 0; + } + else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) + { + mptSmp.uFlags.set(CHN_LOOP); + } + } + + void Read(FileReader &file) { + file.ReadConvertEndianness(*this); + pathName[30] = '\0'; + } +}; + +STATIC_ASSERT(sizeof(STPSampleHeaderOld) == 82); + +// Sample header (version 2), not packed due to variable string length and alignment in file +struct STPSampleHeader { + char pathName[256]; + uint8 flags; + char fileName[30]; + uint32 length; + uint8 volume; + uint8 reserved1; + uint32 loopStart; + uint32 loopLength; + uint16 defaultCmd; + uint16 defaultPeriod; + uint8 finetune; + uint8 reserved2; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = length; + mptSmp.nFineTune = static_cast<int8>(finetune << 3); + mptSmp.nVolume = 4 * MIN(volume, 64); + + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + + if(mptSmp.nLoopStart >= mptSmp.nLength) + { + mptSmp.nLoopStart = mptSmp.nLength - 1; + } + if(mptSmp.nLoopEnd > mptSmp.nLength) + { + mptSmp.nLoopEnd = mptSmp.nLength; + } + + if(mptSmp.nLoopStart > mptSmp.nLoopEnd) + { + mptSmp.nLoopStart = 0; + mptSmp.nLoopEnd = 0; + } + else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) + { + mptSmp.uFlags.set(CHN_LOOP); + } + } + + void Read(FileReader &file) { + std::string str; + + file.ReadNullString(str, 255); + std::strncpy(pathName, str.c_str(), 255); + pathName[255] = '\0'; + + flags = file.ReadUint8(); + + file.ReadNullString(str, 29); + std::strncpy(fileName, str.c_str(), 29); + pathName[29] = '\0'; + + // seek to even boundary + if(file.GetPosition() & 1) + file.Skip(1); + + length = file.ReadUint32BE(); + volume = file.ReadUint8(); + reserved1 = file.ReadUint8(); + + loopStart = file.ReadUint32BE(); + loopLength = file.ReadUint32BE(); + + defaultCmd = file.ReadUint16BE(); + defaultPeriod = file.ReadUint16BE(); + + finetune = file.ReadUint8(); + reserved2 = file.ReadUint8(); + } +}; + +#ifdef NEEDS_PRAGMA_PACK +#pragma pack(pop) +#endif + +template <typename T> +static void ReadSample(FileReader &file, T &sampleHeader, ModSample &sample, char (&sampleName)[MAX_SAMPLENAME]) +//-------------------------------------------------------------------------------------------------------------- +{ + sampleHeader.Read(file); + sampleHeader.ConvertToMPT(sample); + + mpt::String::Read<mpt::String::spacePadded>(sampleName, sampleHeader.fileName); + // Get rid of weird characters in sample names. + for(size_t i = 0; i < CountOf(sampleName); i++) + { + if(sampleName[i] > 0 && sampleName[i] < ' ') + { + sampleName[i] = ' '; + } + } +} + +static TEMPO ConvertTempo(uint16 ciaSpeed) +//--------------------------------------- +{ + // 3546 is the resulting CIA timer value when using 4F7D (tempo 125 bpm) command in STProII + return TEMPO(125.0 * (3546.0 / ciaSpeed)); +} + +bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags) +//------------------------------------------------------------------- +{ + file.Rewind(); + if(!file.ReadMagic("STP3")) + return false; + + STPFileHeader fileHeader; + file.ReadConvertEndianness(fileHeader); + if(fileHeader.version > 2 || + fileHeader.numOrders > 128 || fileHeader.numSamples > MAX_SAMPLES || + fileHeader.midiCount != 50) + return false; + + if(loadFlags == onlyVerifyHeader) + return true; + + InitializeGlobals(MOD_TYPE_STP); + + m_nChannels = 4; + m_nSamples = 0; + m_nInstruments = 0; + + m_nDefaultSpeed = fileHeader.speed; + m_nDefaultTempo = ConvertTempo(fileHeader.timerCount); + + m_nMinPeriod = 14 * 4; + m_nMaxPeriod = 3424 * 4; + + Order.ReadFromArray(fileHeader.orderList, fileHeader.numOrders); + + // Load sample headers + for(SAMPLEINDEX smp = 1; smp <= fileHeader.numSamples; smp++) + { + // this is 1-based the same as smp + SAMPLEINDEX actualSmp = file.ReadUint16BE(); + if(actualSmp > MAX_SAMPLES) + return false; + + m_nSamples = MAX(m_nSamples, actualSmp); + + if(fileHeader.version == 2) + { + static STPSampleHeader sampleHeader; + uint32 headerSize = file.ReadUint32BE(); + + ReadSample(file, sampleHeader, Samples[actualSmp], m_szNames[actualSmp]); + // TODO: verify string lengths against headerSize? + (void)headerSize; + } + else + { + static STPSampleHeaderOld sampleHeaderOld; + ReadSample(file, sampleHeaderOld, Samples[actualSmp], m_szNames[actualSmp]); + } + + if(fileHeader.version >= 1) + { + uint16 numLoops = file.ReadUint16BE(); + // ignore these + file.Skip(numLoops*8); + } + } + + // Load patterns + uint16 numPatterns = 128; + if (fileHeader.version == 0) + numPatterns = file.ReadUint16BE(); + + uint16 patternLength = fileHeader.patternLength; + uint16 channels = 4; + + uint8 globalVolSlide = 0; + std::vector<uint8> autoFinePorta; + std::vector<uint8> autoPortaUp; + std::vector<uint8> autoPortaDown; + std::vector<uint8> autoVolSlide; + std::vector<uint8> autoVibrato; + std::vector<uint8> vibratoMem; + std::vector<uint8> autoTremolo; + std::vector<uint8> autoTonePorta; + std::vector<uint8> tonePortaMem; + + for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) + { + PATTERNINDEX actualPat = pat; + + if(fileHeader.version > 0) + { + actualPat = file.ReadUint16BE(); + if(actualPat == 0xFFFF) + break; + + patternLength = file.ReadUint16BE(); + channels = file.ReadUint16BE(); + + m_nChannels = MIN(m_nChannels, channels); + } + + if(!(loadFlags & loadPatternData) || !Patterns.Insert(actualPat, patternLength)) + { + file.Skip(channels * patternLength * 4); + continue; + } + + autoFinePorta.resize(channels, 0); + autoPortaUp.resize(channels, 0); + autoPortaDown.resize(channels, 0); + autoVolSlide.resize(channels, 0); + autoVibrato.resize(channels, 0); + vibratoMem.resize(channels, 0); + autoTremolo.resize(channels, 0); + autoTonePorta.resize(channels, 0); + tonePortaMem.resize(channels, 0); + + for(ROWINDEX row = 0; row < patternLength; row++) + { + PatternRow rowBase = Patterns[actualPat].GetpModCommand(row, 0); + + bool didGlobalVolSlide = false; + bool shouldDelay = false; + + // if a fractional speed value is in use then determine if we should stick a fine pattern delay somewhere + switch(fileHeader.speedFrac & 3) + { + // 1/4 + case 1: shouldDelay = (row & 3) == 0; break; + // 1/2 + case 2: shouldDelay = (row & 1) == 0; break; + // 3/4 + case 3: shouldDelay = (row & 3) != 3; break; + } + + for(CHANNELINDEX chn = 0; chn < channels; chn++) + { + ModCommand &m = rowBase[chn]; + + m.instr = file.ReadUint8(); + m.note = file.ReadUint8(); + m.command = file.ReadUint8(); + m.param = file.ReadUint8(); + + if(m.note) + { + m.note += 25; + + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoVolSlide[chn] = 0; + autoVibrato[chn] = vibratoMem[chn] = 0; + autoTremolo[chn] = 0; + autoTonePorta[chn] = tonePortaMem[chn] = 0; + } + + uint8 swap = (m.param >> 4) | (m.param << 4); + + if((m.command & 0xF0) == 0xF0) + { + m.param = Util::Round<uint8>(ConvertTempo(m.param | (((uint16)m.command & 0xF) << 8)).ToDouble()); + m.command = CMD_TEMPO; + } else switch(m.command) + { + case 0x00: // arpeggio + if(m.param) + m.command = CMD_ARPEGGIO; + break; + + case 0x01: // portamento up + m.command = CMD_PORTAMENTOUP; + break; + + case 0x02: // portamento down + m.command = CMD_PORTAMENTODOWN; + break; + + case 0x03: // auto fine portamento up + autoFinePorta[chn] = 0x10 | MIN(m.param, 15); + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x04: // auto fine portamento down + autoFinePorta[chn] = 0x20 | MIN(m.param, 15); + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x05: // auto portamento up + autoFinePorta[chn] = 0; + autoPortaUp[chn] = m.param; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x06: // auto portamento down + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = m.param; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x07: // set global volume + m.command = CMD_GLOBALVOLUME; + globalVolSlide = 0; + break; + + case 0x08: // auto global volume slide + globalVolSlide = swap; + m.command = m.param = 0; + break; + + case 0x09: // fine portamento up + m.command = CMD_MODCMDEX; + m.param = 0x10 | MIN(m.param, 15); + break; + + case 0x0A: // fine portamento down + m.command = CMD_MODCMDEX; + m.param = 0x20 | MIN(m.param, 15); + break; + + case 0x0B: // auto volume slide + autoVolSlide[chn] = swap; + m.command = m.param = 0; + break; + + case 0x0C: // set volume + m.volcmd = VOLCMD_VOLUME; + m.vol = m.param; + autoVolSlide[chn] = 0; + m.command = m.param = 0; + break; + + case 0x0D: // volume slide (param is swapped compared to .mod) + if(m.param & 0xF0) + { + m.volcmd = VOLCMD_VOLSLIDEDOWN; + m.vol = m.param >> 4; + } else if(m.param & 0x0F) + { + m.volcmd = VOLCMD_VOLSLIDEUP; + m.vol = m.param & 0xF; + } + autoVolSlide[chn] = 0; + m.command = m.param = 0; + break; + + case 0x0E: // set filter (also uses opposite value compared to .mod) + m.command = CMD_MODCMDEX; + m.param = 1 ^ MIN(m.param, 1); + break; + + case 0x0F: // set speed + m.command = CMD_SPEED; + fileHeader.speedFrac = m.param & 0xF; + m.param >>= 4; + break; + + case 0x10: // auto vibrato + autoVibrato[chn] = m.param; + vibratoMem[chn] = 0; + m.command = m.param = 0; + break; + + case 0x11: // auto tremolo + if(m.param & 0xF) + autoTremolo[chn] = m.param; + else + autoTremolo[chn] = 0; + m.command = m.param = 0; + break; + + case 0x12: // pattern break + m.command = CMD_PATTERNBREAK; + break; + + case 0x13: // auto tone portamento + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = m.param; + + tonePortaMem[chn] = 0; + m.command = m.param = 0; + break; + + case 0x14: // position jump + m.command = CMD_POSITIONJUMP; + break; + + case 0x1D: // fine volume slide + m.command = CMD_MODCMDEX; + if(m.param & 0xF0) + m.param = 0xB0 | (m.param >> 4); + else if(m.param & 0x0F) + m.param = 0xA0 | (m.param & 0xF); + break; + + case 0x20: // "delayed fade" + // just behave like either a normal fade or a notecut + // depending on the speed + if(m.param & 0xF0) + { + autoVolSlide[chn] = m.param >> 4; + m.command = m.param = 0; + } else { + m.command = CMD_MODCMDEX; + m.param = 0xC0 | (m.param & 0xF); + } + break; + + case 0x21: // note delay + m.command = CMD_MODCMDEX; + m.param = 0xD0 | MIN(m.param, 15); + break; + + case 0x22: // retrigger note + m.command = CMD_RETRIG; + break; + + case 0x49: // set sample offset + m.command = CMD_OFFSET; + break; + + case 0x4E: // other protracker commands (pattern loop / delay) + if((m.param & 0xF0) == 0x60 || (m.param & 0xF0) == 0xE0) + m.command = CMD_MODCMDEX; + else + m.command = m.param = 0; + break; + + case 0x4F: // set speed/tempo + if(m.param < 0x20) + { + m.command = CMD_SPEED; + fileHeader.speedFrac = 0; + } else + { + m.command = CMD_TEMPO; + } + break; + + default: + m.command = m.param = 0; + break; + } + + bool didVolSlide = false; + + // try to put volume slide in volume command + if(autoVolSlide[chn] && !m.volcmd) + { + if(autoVolSlide[chn] & 0xF0) + { + m.volcmd = VOLCMD_VOLSLIDEDOWN; + m.vol = autoVolSlide[chn] >> 4; + } else + { + m.volcmd = VOLCMD_VOLSLIDEUP; + m.vol = autoVolSlide[chn] & 0xF; + } + didVolSlide = true; + } + + // try to place/combine all remaining running effects. + if(!m.command) + { + if(autoPortaUp[chn]) + { + m.command = CMD_PORTAMENTOUP; + m.param = autoPortaUp[chn]; + + } else if(autoPortaDown[chn]) + { + m.command = CMD_PORTAMENTODOWN; + m.param = autoPortaDown[chn]; + + } else if(autoFinePorta[chn]) + { + m.command = CMD_MODCMDEX; + m.param = autoFinePorta[chn]; + + } else if(autoTonePorta[chn]) + { + // try a volslide+portamento + if (!didVolSlide && autoVolSlide[chn] && tonePortaMem[chn]) + { + m.command = CMD_TONEPORTAVOL; + m.param = autoVolSlide[chn]; + didVolSlide = true; + } else + { + m.command = CMD_TONEPORTAMENTO; + m.param = tonePortaMem[chn] = autoTonePorta[chn]; + } + + } else if(autoVibrato[chn]) + { + // try a volslide+vibrato + if (!didVolSlide && autoVolSlide[chn] && vibratoMem[chn]) + { + m.command = CMD_VIBRATOVOL; + m.param = autoVolSlide[chn]; + didVolSlide = true; + } else + { + m.command = CMD_VIBRATO; + m.param = vibratoMem[chn] = autoVibrato[chn]; + } + + } else if(!didVolSlide && autoVolSlide[chn]) + { + m.command = CMD_VOLUMESLIDE; + m.param = autoVolSlide[chn]; + didVolSlide = true; + + } else if(autoTremolo[chn]) + { + m.command = CMD_TREMOLO; + m.param = autoTremolo[chn]; + + } else if(shouldDelay) + { + // insert a fine pattern delay here + m.command = CMD_S3MCMDEX; + m.param = 0x61; + shouldDelay = false; + + } else if(!didGlobalVolSlide && globalVolSlide) + { + m.command = CMD_GLOBALVOLSLIDE; + m.param = globalVolSlide; + didGlobalVolSlide = true; + } + } + } + + // TODO: create/use extra channels for global volslide/delay if needed + } + } + + // after we know how many channels there really are... + m_nSamplePreAmp = 256 / m_nChannels; + // Setup channel pan positions and volume + SetupMODPanning(true); + + // Skip over scripts and drumpad info + if(fileHeader.version > 0) + { + uint16 scriptNum; + uint32 length; + + while(file.CanRead(2)) + { + scriptNum = file.ReadUint16BE(); + if(scriptNum == 0xFFFF) + break; + + file.Skip(2); + length = file.ReadUint32BE(); + file.Skip(length); + } + + // skip drumpad stuff + file.Skip(17*2); + } + + // Reading samples + if(loadFlags & loadSampleData) + { + for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++) if(Samples[smp].nLength) + { + SampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM) + .ReadSample(Samples[smp], file); + } + } + + return true; +} + +OPENMPT_NAMESPACE_END diff --git OpenMPT/soundlib/Snd_defs.h OpenMPT/soundlib/Snd_defs.h index 4499f0b..23eeb62 100644 --- OpenMPT/soundlib/Snd_defs.h +++ OpenMPT/soundlib/Snd_defs.h @@ -97,6 +97,7 @@ enum MODTYPE MOD_TYPE_DIGI = 0x8000000, MOD_TYPE_UAX = 0x10000000, // sampleset as module MOD_TYPE_PLM = 0x20000000, + MOD_TYPE_STP = 0x40000000, }; DECLARE_FLAGSET(MODTYPE) diff --git OpenMPT/soundlib/Snd_fx.cpp OpenMPT/soundlib/Snd_fx.cpp index 1631620..80bcb87 100644 --- OpenMPT/soundlib/Snd_fx.cpp +++ OpenMPT/soundlib/Snd_fx.cpp @@ -3358,7 +3358,7 @@ void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const else param = pChn->nOldPortaUpDown; - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI)); + const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP)); // Process MIDI pitch bend for instrument plugins MidiPortamento(nChn, param, doFineSlides); @@ -3417,7 +3417,7 @@ void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, cons else param = pChn->nOldPortaUpDown; - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI)); + const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP)); // Process MIDI pitch bend for instrument plugins MidiPortamento(nChn, -static_cast<int>(param), doFineSlides); @@ -3889,7 +3889,7 @@ void CSoundFile::VolumeSlide(ModChannel *pChn, ModCommand::PARAM param) else param = pChn->nOldVolumeSlide; - if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI))) + if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP))) { // MOD / XM nibble priority if((param & 0xF0) != 0) @@ -3902,7 +3902,7 @@ void CSoundFile::VolumeSlide(ModChannel *pChn, ModCommand::PARAM param) } int newvolume = pChn->nVolume; - if(!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MED))) + if(!(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_STP))) { if ((param & 0x0F) == 0x0F) //Fine upslide or slide -15 { @@ -5445,7 +5445,7 @@ uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPerio //------------------------------------------------------------------------------------------ { if (!period) return 0; - if (GetType() & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_DIGI|MOD_TYPE_MTM|MOD_TYPE_AMF0)) + if (GetType() & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_DIGI|MOD_TYPE_MTM|MOD_TYPE_AMF0|MOD_TYPE_STP)) { return ((3546895L * 4) << FREQ_FRACBITS) / period; } else if (GetType() == MOD_TYPE_XM) diff --git OpenMPT/soundlib/Sndfile.cpp OpenMPT/soundlib/Sndfile.cpp index 006d046..39e4a03 100644 --- OpenMPT/soundlib/Sndfile.cpp +++ OpenMPT/soundlib/Sndfile.cpp @@ -317,7 +317,8 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags) && !ReadMod(file, loadFlags) && !Read669(file, loadFlags) && !ReadICE(file, loadFlags) - && !ReadM15(file, loadFlags)) + && !ReadM15(file, loadFlags) + && !ReadSTP(file, loadFlags)) { m_nType = MOD_TYPE_NONE; m_ContainerType = MOD_CONTAINERTYPE_NONE; @@ -1046,6 +1047,8 @@ MODTYPE CSoundFile::GetBestSaveFormat() const case MOD_TYPE_AMF0: case MOD_TYPE_DIGI: return MOD_TYPE_MOD; + case MOD_TYPE_STP: + return MOD_TYPE_XM; case MOD_TYPE_MED: if(m_nDefaultTempo == TEMPO(125, 0) && m_nDefaultSpeed == 6 && !m_nInstruments) { diff --git OpenMPT/soundlib/Sndfile.h OpenMPT/soundlib/Sndfile.h index 1ea882a..1c03f2a 100644 --- OpenMPT/soundlib/Sndfile.h +++ OpenMPT/soundlib/Sndfile.h @@ -659,6 +659,7 @@ public: bool ReadDIGI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadPLM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); static std::vector<const char *> GetSupportedExtensions(bool otherFormats); static mpt::Charset GetCharsetFromModType(MODTYPE modtype); diff --git OpenMPT/soundlib/Tables.cpp OpenMPT/soundlib/Tables.cpp index abf91a9..06250bd 100644 --- OpenMPT/soundlib/Tables.cpp +++ OpenMPT/soundlib/Tables.cpp @@ -87,6 +87,7 @@ static const ModFormatInfo modFormatInfo[] = { MOD_TYPE_IMF, "Imago Orpheus", "imf" }, { MOD_TYPE_J2B, "Galaxy Sound System", "j2b" }, { MOD_TYPE_PLM, "Disorder Tracker 2", "plm" }, + { MOD_TYPE_STP, "Soundtracker Pro II", "stp" }, #ifndef NO_ARCHIVE_SUPPORT // Compressed modules @@ -147,6 +148,7 @@ static const ModCharsetInfo ModCharsetInfos[] = { MOD_TYPE_OKT , mpt::CharsetISO8859_1 }, { MOD_TYPE_DBM , mpt::CharsetISO8859_1 }, { MOD_TYPE_DIGI, mpt::CharsetISO8859_1 }, + { MOD_TYPE_STP, mpt::CharsetISO8859_1 }, // Amiga // DOS { MOD_TYPE_MOD , mpt::CharsetISO8859_1 }, { MOD_TYPE_MED , mpt::CharsetISO8859_1 }, stpro2_r2.patch (32,311 bytes)
diff --git a/OpenMPT/build/android_ndk/Android-minimp3-stbvorbis.mk b/OpenMPT/build/android_ndk/Android-minimp3-stbvorbis.mk index 7ec6552..05ad6fb 100644 --- a/OpenMPT/build/android_ndk/Android-minimp3-stbvorbis.mk +++ b/OpenMPT/build/android_ndk/Android-minimp3-stbvorbis.mk @@ -74,6 +74,7 @@ LOCAL_SRC_FILES := \ soundlib/Load_ptm.cpp \ soundlib/Load_s3m.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ diff --git a/OpenMPT/build/android_ndk/Android-mpg123-vorbis.mk b/OpenMPT/build/android_ndk/Android-mpg123-vorbis.mk index 0c09b5e..456aa21 100644 --- a/OpenMPT/build/android_ndk/Android-mpg123-vorbis.mk +++ b/OpenMPT/build/android_ndk/Android-mpg123-vorbis.mk @@ -72,6 +72,7 @@ LOCAL_SRC_FILES := \ soundlib/Load_ptm.cpp \ soundlib/Load_s3m.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ diff --git a/OpenMPT/build/android_ndk/Android-unmo3.mk b/OpenMPT/build/android_ndk/Android-unmo3.mk index f28d829..aa56d61 100644 --- a/OpenMPT/build/android_ndk/Android-unmo3.mk +++ b/OpenMPT/build/android_ndk/Android-unmo3.mk @@ -105,6 +105,7 @@ LOCAL_SRC_FILES := \ soundlib/Load_ptm.cpp \ soundlib/Load_s3m.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ diff --git a/OpenMPT/build/android_ndk/Android.mk b/OpenMPT/build/android_ndk/Android.mk index 6ef628b..6643057 100644 --- a/OpenMPT/build/android_ndk/Android.mk +++ b/OpenMPT/build/android_ndk/Android.mk @@ -73,6 +73,7 @@ LOCAL_SRC_FILES := \ soundlib/Load_ptm.cpp \ soundlib/Load_s3m.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ diff --git a/OpenMPT/build/autotools/Makefile.am b/OpenMPT/build/autotools/Makefile.am index 86dbdd2..ea60f94 100644 --- a/OpenMPT/build/autotools/Makefile.am +++ b/OpenMPT/build/autotools/Makefile.am @@ -185,6 +185,7 @@ libopenmpt_la_SOURCES += soundlib/Load_psm.cpp libopenmpt_la_SOURCES += soundlib/Load_ptm.cpp libopenmpt_la_SOURCES += soundlib/Load_s3m.cpp libopenmpt_la_SOURCES += soundlib/Load_stm.cpp +libopenmpt_la_SOURCES += soundlib/Load_stp.cpp libopenmpt_la_SOURCES += soundlib/Load_ult.cpp libopenmpt_la_SOURCES += soundlib/Load_umx.cpp libopenmpt_la_SOURCES += soundlib/Load_wav.cpp @@ -418,6 +419,7 @@ libopenmpttest_SOURCES += soundlib/Load_psm.cpp libopenmpttest_SOURCES += soundlib/Load_ptm.cpp libopenmpttest_SOURCES += soundlib/Load_s3m.cpp libopenmpttest_SOURCES += soundlib/Load_stm.cpp +libopenmpttest_SOURCES += soundlib/Load_stp.cpp libopenmpttest_SOURCES += soundlib/Load_ult.cpp libopenmpttest_SOURCES += soundlib/Load_umx.cpp libopenmpttest_SOURCES += soundlib/Load_wav.cpp diff --git a/OpenMPT/libopenmpt/foo_openmpt.cpp b/OpenMPT/libopenmpt/foo_openmpt.cpp index ac7ce34..8947cdf 100644 --- a/OpenMPT/libopenmpt/foo_openmpt.cpp +++ b/OpenMPT/libopenmpt/foo_openmpt.cpp @@ -319,6 +319,7 @@ DECLARE_FILE_TYPE("OpenMPT compatible module files", "*.imf" ";" "*.j2b" ";" "*.plm" ";" + "*.stp" ";" "*.gdm" ";" "*.umx" ";" "*.mo3" ";" diff --git a/OpenMPT/soundlib/Load_stp.cpp b/OpenMPT/soundlib/Load_stp.cpp new file mode 100644 index 0000000..2a054ee --- /dev/null +++ b/OpenMPT/soundlib/Load_stp.cpp @@ -0,0 +1,945 @@ +/* + * Load_stp.cpp + * ------------ + * Purpose: STP (Soundtracker Pro II) module loader + * Notes : a few exotic effects aren't supported. + * multiple sample loops are supported, but only the first 10 can be used as cue points + * (with 16xx and 18xx). + * fractional speed values and combined auto effects are handled whenever possible, + * but some effects may be omitted (and there may be tempo accuracy issues). + * Authors: Devin Acker + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + * + * Wisdom from the Soundtracker Pro II manual: + * "To create shorter patterns, simply create shorter patterns." + */ + +#include "stdafx.h" +#include "Loaders.h" +#include "Tables.h" + +OPENMPT_NAMESPACE_BEGIN + +#ifdef NEEDS_PRAGMA_PACK +#pragma pack(push, 1) +#endif + +// File header (except for "STP3" magic) +struct PACKED STPFileHeader { + uint16 version; + uint8 numOrders; + uint8 patternLength; + uint8 orderList[128]; + uint16 speed; + uint16 speedFrac; + uint16 timerCount; + uint16 flags; + uint32 reserved; + uint16 midiCount; // always 50 + uint8 midi[50]; + uint16 numSamples; + uint16 sampleStructSize; + + void ConvertEndianness() + { + SwapBytesBE(version); + SwapBytesBE(speed); + SwapBytesBE(speedFrac); + SwapBytesBE(timerCount); + SwapBytesBE(flags); + SwapBytesBE(midiCount); + SwapBytesBE(numSamples); + SwapBytesBE(sampleStructSize); + } +}; + +STATIC_ASSERT(sizeof(STPFileHeader) == 200); + +// Sample header (versions 0 and 1) +struct PACKED STPSampleHeaderOld { + char pathName[31]; + uint8 flags; + char fileName[30]; + uint32 length; + uint8 volume; + uint8 reserved1; + uint32 loopStart; + uint32 loopLength; + uint16 defaultCmd; + uint32 reserved2; + + void ConvertEndianness() + { + SwapBytesBE(length); + SwapBytesBE(loopStart); + SwapBytesBE(loopLength); + SwapBytesBE(defaultCmd); + } + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = length; + mptSmp.nVolume = 4 * MIN(volume, 64); + + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + + if(mptSmp.nLoopStart >= mptSmp.nLength) + { + mptSmp.nLoopStart = mptSmp.nLength - 1; + } + if(mptSmp.nLoopEnd > mptSmp.nLength) + { + mptSmp.nLoopEnd = mptSmp.nLength; + } + + if(mptSmp.nLoopStart > mptSmp.nLoopEnd) + { + mptSmp.nLoopStart = 0; + mptSmp.nLoopEnd = 0; + } + else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) + { + mptSmp.uFlags.set(CHN_LOOP); + } + } + + void Read(FileReader &file) { + file.ReadConvertEndianness(*this); + pathName[30] = '\0'; + } +}; + +STATIC_ASSERT(sizeof(STPSampleHeaderOld) == 82); + +#ifdef NEEDS_PRAGMA_PACK +#pragma pack(pop) +#endif + +// Sample header (version 2), not packed due to variable string length and alignment in file +struct STPSampleHeader { + char pathName[256]; + uint8 flags; + char fileName[30]; + uint32 length; + uint8 volume; + uint8 reserved1; + uint32 loopStart; + uint32 loopLength; + uint16 defaultCmd; + uint16 defaultPeriod; + uint8 finetune; + uint8 reserved2; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = length; + mptSmp.nFineTune = static_cast<int8>(finetune << 3); + mptSmp.nVolume = 4 * MIN(volume, 64); + + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + + if(mptSmp.nLoopStart >= mptSmp.nLength) + { + mptSmp.nLoopStart = mptSmp.nLength - 1; + } + if(mptSmp.nLoopEnd > mptSmp.nLength) + { + mptSmp.nLoopEnd = mptSmp.nLength; + } + + if(mptSmp.nLoopStart > mptSmp.nLoopEnd) + { + mptSmp.nLoopStart = 0; + mptSmp.nLoopEnd = 0; + } + else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) + { + mptSmp.cues[0] = mptSmp.nLoopStart; + mptSmp.uFlags.set(CHN_LOOP); + } + } + + void Read(FileReader &file) { + std::string str; + + file.ReadNullString(str, 255); + std::strncpy(pathName, str.c_str(), 255); + pathName[255] = '\0'; + + flags = file.ReadUint8(); + + file.ReadNullString(str, 29); + std::strncpy(fileName, str.c_str(), 29); + pathName[29] = '\0'; + + // seek to even boundary + if(file.GetPosition() & 1) + file.Skip(1); + + length = file.ReadUint32BE(); + volume = file.ReadUint8(); + reserved1 = file.ReadUint8(); + + loopStart = file.ReadUint32BE(); + loopLength = file.ReadUint32BE(); + + defaultCmd = file.ReadUint16BE(); + defaultPeriod = file.ReadUint16BE(); + + finetune = file.ReadUint8(); + reserved2 = file.ReadUint8(); + } +}; + +struct STPLoopInfo { + SmpLength loopStart; + SmpLength loopLength; + SAMPLEINDEX looped; + SAMPLEINDEX nonLooped; +}; + +typedef std::vector<STPLoopInfo> STPLoopList; + +template <typename T> +static void ReadSample(FileReader &file, T &sampleHeader, ModSample &sample, char (&sampleName)[MAX_SAMPLENAME]) +//-------------------------------------------------------------------------------------------------------------- +{ + sampleHeader.Read(file); + sampleHeader.ConvertToMPT(sample); + + mpt::String::Read<mpt::String::spacePadded>(sampleName, sampleHeader.fileName); + // Get rid of weird characters in sample names. + for(size_t i = 0; i < CountOf(sampleName); i++) + { + if(sampleName[i] > 0 && sampleName[i] < ' ') + { + sampleName[i] = ' '; + } + } +} + +static TEMPO ConvertTempo(uint16 ciaSpeed) +//---------------------------------------- +{ + // 3546 is the resulting CIA timer value when using 4F7D (tempo 125 bpm) command in STProII + return TEMPO(125.0 * (3546.0 / ciaSpeed)); +} + +static void ConvertLoopSlice(ModSample &src, ModSample &dest, SmpLength start, SmpLength len, bool loop) +//------------------------------------------------------------------------------------------------------ +{ + if(!src.HasSampleData()) return; + + dest.FreeSample(); + + dest = src; + dest.nLength = len; + dest.pSample = nullptr; + + if(dest.AllocateSample() != len) + { + dest.FreeSample(); + return; + } + + // only preserve cue points if the target sample length is the same + if(len != src.nLength) + memset(dest.cues, 0, sizeof(dest.cues)); + + memcpy(dest.pSample8, src.pSample8 + start, len); + if(loop) + { + dest.nLoopStart = 0; + dest.nLoopEnd = len; + dest.uFlags.set(CHN_LOOP); + } else + { + dest.nLoopStart = 0; + dest.nLoopEnd = 0; + dest.uFlags.reset(CHN_LOOP); + } +} + +static void ConvertLoopSequence(ModSample &smp, STPLoopList &loopList) +//-------------------------------------------------------------------- +{ + // This should only modify a sample if it has more than one loop + // (otherwise, it behaves like a normal sample loop) + if(!smp.HasSampleData() || loopList.size() < 2) return; + + ModSample newSmp = smp; + newSmp.nLength = 0; + newSmp.pSample = nullptr; + + SAMPLEINDEX numLoops = loopList.size(); + + // get the total length of the sample after combining all looped sections + for(int i = 0; i < numLoops; i++) + { + STPLoopInfo &info = loopList[i]; + + // if adding this loop would cause the sample length to exceed maximum, + // then limit and bail out + if((newSmp.nLength + info.loopLength > MAX_SAMPLE_LENGTH) || + (info.loopLength > MAX_SAMPLE_LENGTH) || + (info.loopStart + info.loopLength > smp.nLength)) + { + numLoops = i; + break; + } + + newSmp.nLength += info.loopLength; + } + + if(newSmp.AllocateSample() != newSmp.nLength) + { + newSmp.FreeSample(); + return; + } + + // start copying the looped sample data parts + SmpLength start = 0; + + for(int i = 0; i < numLoops; i++) + { + STPLoopInfo &info = loopList[i]; + + memcpy(newSmp.pSample8 + start, smp.pSample8 + info.loopStart, info.loopLength); + + // update loop info based on position in edited sample + info.loopStart = start; + if(i > 0 && i < 10) + { + newSmp.cues[i-1] = start; + } + start += info.loopLength; + } + + // replace old sample with new one + smp.FreeSample(); + smp = newSmp; + + smp.nLoopStart = 0; + smp.nLoopEnd = smp.nLength; + smp.uFlags.set(CHN_LOOP); +} + +bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags) +//------------------------------------------------------------------- +{ + file.Rewind(); + if(!file.ReadMagic("STP3")) + return false; + + STPFileHeader fileHeader; + file.ReadConvertEndianness(fileHeader); + if(fileHeader.version > 2 || + fileHeader.numOrders > 128 || fileHeader.numSamples > MAX_SAMPLES || + fileHeader.midiCount != 50) + return false; + + if(loadFlags == onlyVerifyHeader) + return true; + + InitializeGlobals(MOD_TYPE_STP); + + m_nChannels = 4; + m_nSamples = 0; + m_nInstruments = 0; + + m_nDefaultSpeed = fileHeader.speed; + m_nDefaultTempo = ConvertTempo(fileHeader.timerCount); + + m_nMinPeriod = 14 * 4; + m_nMaxPeriod = 3424 * 4; + + Order.ReadFromArray(fileHeader.orderList, fileHeader.numOrders); + + std::vector<STPLoopList> loopInfo; + // non-looped versions of samples with loopes (when needed) + std::vector<SAMPLEINDEX> nonLooped; + + // Load sample headers + SAMPLEINDEX samplesInFile = 0; + + for(SAMPLEINDEX smp = 1; smp <= fileHeader.numSamples; smp++) + { + // this is 1-based the same as smp + SAMPLEINDEX actualSmp = file.ReadUint16BE(); + if(actualSmp > MAX_SAMPLES) + return false; + + samplesInFile = m_nSamples = MAX(m_nSamples, actualSmp); + + ModSample &thisSmp = Samples[actualSmp]; + + if(fileHeader.version == 2) + { + STPSampleHeader sampleHeader; + uint32 headerSize = file.ReadUint32BE(); + + ReadSample(file, sampleHeader, thisSmp, m_szNames[actualSmp]); + // TODO: verify string lengths against headerSize? + (void)headerSize; + } else + { + STPSampleHeaderOld sampleHeaderOld; + ReadSample(file, sampleHeaderOld, thisSmp, m_szNames[actualSmp]); + } + + STPLoopList loopList; + + if(fileHeader.version >= 1) + { + uint16 numLoops = file.ReadUint16BE(); + + STPLoopInfo loop; + loop.looped = loop.nonLooped = 0; + + if(numLoops == 0 && thisSmp.uFlags[CHN_LOOP]) + { + loop.loopStart = thisSmp.nLoopStart; + loop.loopLength = thisSmp.nLoopEnd - thisSmp.nLoopStart; + loopList.push_back(loop); + + } else for(SAMPLEINDEX i = 0; i < numLoops; i++) + { + loop.loopStart = file.ReadUint32BE(); + loop.loopLength = file.ReadUint32BE(); + loopList.push_back(loop); + } + } + + nonLooped.resize(actualSmp); + loopInfo.resize(actualSmp); + loopInfo[actualSmp - 1] = loopList; + } + + // Load patterns + uint16 numPatterns = 128; + if (fileHeader.version == 0) + numPatterns = file.ReadUint16BE(); + + uint16 patternLength = fileHeader.patternLength; + uint16 channels = 4; + + uint8 globalVolSlide = 0; + std::vector<uint8> autoFinePorta; + std::vector<uint8> autoPortaUp; + std::vector<uint8> autoPortaDown; + std::vector<uint8> autoVolSlide; + std::vector<uint8> autoVibrato; + std::vector<uint8> vibratoMem; + std::vector<uint8> autoTremolo; + std::vector<uint8> autoTonePorta; + std::vector<uint8> tonePortaMem; + + for(PATTERNINDEX pat = 0; pat < numPatterns; pat++) + { + PATTERNINDEX actualPat = pat; + + if(fileHeader.version > 0) + { + actualPat = file.ReadUint16BE(); + if(actualPat == 0xFFFF) + break; + + patternLength = file.ReadUint16BE(); + channels = file.ReadUint16BE(); + + m_nChannels = MIN(m_nChannels, channels); + } + + if(!(loadFlags & loadPatternData) || !Patterns.Insert(actualPat, patternLength)) + { + file.Skip(channels * patternLength * 4); + continue; + } + + autoFinePorta.resize(channels, 0); + autoPortaUp.resize(channels, 0); + autoPortaDown.resize(channels, 0); + autoVolSlide.resize(channels, 0); + autoVibrato.resize(channels, 0); + vibratoMem.resize(channels, 0); + autoTremolo.resize(channels, 0); + autoTonePorta.resize(channels, 0); + tonePortaMem.resize(channels, 0); + + for(ROWINDEX row = 0; row < patternLength; row++) + { + PatternRow rowBase = Patterns[actualPat].GetpModCommand(row, 0); + + bool didGlobalVolSlide = false; + bool shouldDelay = false; + + // if a fractional speed value is in use then determine if we should stick a fine pattern delay somewhere + switch(fileHeader.speedFrac & 3) + { + // 1/4 + case 1: shouldDelay = (row & 3) == 0; break; + // 1/2 + case 2: shouldDelay = (row & 1) == 0; break; + // 3/4 + case 3: shouldDelay = (row & 3) != 3; break; + } + + for(CHANNELINDEX chn = 0; chn < channels; chn++) + { + ModCommand &m = rowBase[chn]; + + m.instr = file.ReadUint8(); + m.note = file.ReadUint8(); + m.command = file.ReadUint8(); + m.param = file.ReadUint8(); + + if(m.note) + { + m.note += 25; + + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoVolSlide[chn] = 0; + autoVibrato[chn] = vibratoMem[chn] = 0; + autoTremolo[chn] = 0; + autoTonePorta[chn] = tonePortaMem[chn] = 0; + } + + // this is a nibble-swapped param value used for auto fine volside + // and auto global fine volside + uint8 swap = (m.param >> 4) | (m.param << 4); + + if((m.command & 0xF0) == 0xF0) + { + m.param = Util::Round<uint8>(ConvertTempo(m.param | (((uint16)m.command & 0xF) << 8)).ToDouble()); + m.command = CMD_TEMPO; + } else switch(m.command) + { + case 0x00: // arpeggio + if(m.param) + m.command = CMD_ARPEGGIO; + break; + + case 0x01: // portamento up + m.command = CMD_PORTAMENTOUP; + break; + + case 0x02: // portamento down + m.command = CMD_PORTAMENTODOWN; + break; + + case 0x03: // auto fine portamento up + autoFinePorta[chn] = 0x10 | MIN(m.param, 15); + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x04: // auto fine portamento down + autoFinePorta[chn] = 0x20 | MIN(m.param, 15); + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x05: // auto portamento up + autoFinePorta[chn] = 0; + autoPortaUp[chn] = m.param; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x06: // auto portamento down + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = m.param; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x07: // set global volume + m.command = CMD_GLOBALVOLUME; + globalVolSlide = 0; + break; + + case 0x08: // auto global fine volume slide + globalVolSlide = swap; + m.command = m.param = 0; + break; + + case 0x09: // fine portamento up + m.command = CMD_MODCMDEX; + m.param = 0x10 | MIN(m.param, 15); + break; + + case 0x0A: // fine portamento down + m.command = CMD_MODCMDEX; + m.param = 0x20 | MIN(m.param, 15); + break; + + case 0x0B: // auto fine volume slide + autoVolSlide[chn] = swap; + m.command = m.param = 0; + break; + + case 0x0C: // set volume + m.volcmd = VOLCMD_VOLUME; + m.vol = m.param; + autoVolSlide[chn] = 0; + m.command = m.param = 0; + break; + + case 0x0D: // volume slide (param is swapped compared to .mod) + if(m.param & 0xF0) + { + m.volcmd = VOLCMD_VOLSLIDEDOWN; + m.vol = m.param >> 4; + } else if(m.param & 0x0F) + { + m.volcmd = VOLCMD_VOLSLIDEUP; + m.vol = m.param & 0xF; + } + autoVolSlide[chn] = 0; + m.command = m.param = 0; + break; + + case 0x0E: // set filter (also uses opposite value compared to .mod) + m.command = CMD_MODCMDEX; + m.param = 1 ^ MIN(m.param, 1); + break; + + case 0x0F: // set speed + m.command = CMD_SPEED; + fileHeader.speedFrac = m.param & 0xF; + m.param >>= 4; + break; + + case 0x10: // auto vibrato + autoVibrato[chn] = m.param; + vibratoMem[chn] = 0; + m.command = m.param = 0; + break; + + case 0x11: // auto tremolo + if(m.param & 0xF) + autoTremolo[chn] = m.param; + else + autoTremolo[chn] = 0; + m.command = m.param = 0; + break; + + case 0x12: // pattern break + m.command = CMD_PATTERNBREAK; + break; + + case 0x13: // auto tone portamento + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = m.param; + + tonePortaMem[chn] = 0; + m.command = m.param = 0; + break; + + case 0x14: // position jump + m.command = CMD_POSITIONJUMP; + break; + + case 0x16: // start loop sequence + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList& loopList = loopInfo[m.instr-1]; + + m.param--; + if(m.param < MIN(9u, loopList.size())) + { + m.volcmd = VOLCMD_OFFSET; + m.vol = m.param; + } + } + + m.command = m.param = 0; + break; + + case 0x17: // play only loop nn + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList& loopList = loopInfo[m.instr-1]; + + m.param--; + if (m.param < loopList.size()) + { + if (!loopList[m.param].looped && m_nSamples < MAX_SAMPLES-1) + loopList[m.param].looped = ++m_nSamples; + m.instr = loopList[m.param].looped; + } + } + + m.command = m.param = 0; + break; + + case 0x18: // play sequence without loop + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList& loopList = loopInfo[m.instr-1]; + + m.param--; + if(m.param < MIN(9u, loopList.size())) + { + m.volcmd = VOLCMD_OFFSET; + m.vol = m.param; + } + // switch to non-looped version of sample and create it if needed + if (!nonLooped[m.instr-1] && m_nSamples < MAX_SAMPLES-1) + nonLooped[m.instr-1] = ++m_nSamples; + m.instr = nonLooped[m.instr-1]; + } + + m.command = m.param = 0; + break; + + case 0x19: // play only loop nn without loop + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList& loopList = loopInfo[m.instr-1]; + + m.param--; + if (m.param < loopList.size()) + { + if (!loopList[m.param].nonLooped && m_nSamples < MAX_SAMPLES-1) + loopList[m.param].nonLooped = ++m_nSamples; + m.instr = loopList[m.param].nonLooped; + } + } + + m.command = m.param = 0; + break; + + case 0x1D: // fine volume slide (nibble order also swapped) + m.command = CMD_VOLUMESLIDE; + m.param = swap; + if(m.param & 0xF0) // slide down + m.param |= 0x0F; + else if(m.param & 0x0F) + m.param |= 0xF0; + break; + + case 0x20: // "delayed fade" + // just behave like either a normal fade or a notecut + // depending on the speed + if(m.param & 0xF0) + { + autoVolSlide[chn] = m.param >> 4; + m.command = m.param = 0; + } else + { + m.command = CMD_MODCMDEX; + m.param = 0xC0 | (m.param & 0xF); + } + break; + + case 0x21: // note delay + m.command = CMD_MODCMDEX; + m.param = 0xD0 | MIN(m.param, 15); + break; + + case 0x22: // retrigger note + m.command = CMD_RETRIG; + m.param = MIN(m.param, 15); + break; + + case 0x49: // set sample offset + m.command = CMD_OFFSET; + break; + + case 0x4E: // other protracker commands (pattern loop / delay) + if((m.param & 0xF0) == 0x60 || (m.param & 0xF0) == 0xE0) + m.command = CMD_MODCMDEX; + else + m.command = m.param = 0; + break; + + case 0x4F: // set speed/tempo + if(m.param < 0x20) + { + m.command = CMD_SPEED; + fileHeader.speedFrac = 0; + } else + { + m.command = CMD_TEMPO; + } + break; + + default: + m.command = m.param = 0; + break; + } + + bool didVolSlide = false; + + // try to put volume slide in volume command + if(autoVolSlide[chn] && !m.volcmd) + { + if(autoVolSlide[chn] & 0xF0) + { + m.volcmd = VOLCMD_FINEVOLUP; + m.vol = autoVolSlide[chn] >> 4; + } else + { + m.volcmd = VOLCMD_FINEVOLDOWN; + m.vol = autoVolSlide[chn] & 0xF; + } + didVolSlide = true; + } + + // try to place/combine all remaining running effects. + if(!m.command) + { + if(autoPortaUp[chn]) + { + m.command = CMD_PORTAMENTOUP; + m.param = autoPortaUp[chn]; + + } else if(autoPortaDown[chn]) + { + m.command = CMD_PORTAMENTODOWN; + m.param = autoPortaDown[chn]; + + } else if(autoFinePorta[chn]) + { + m.command = CMD_MODCMDEX; + m.param = autoFinePorta[chn]; + + } else if(autoTonePorta[chn]) + { + m.command = CMD_TONEPORTAMENTO; + m.param = tonePortaMem[chn] = autoTonePorta[chn]; + + } else if(autoVibrato[chn]) + { + m.command = CMD_VIBRATO; + m.param = vibratoMem[chn] = autoVibrato[chn]; + + } else if(!didVolSlide && autoVolSlide[chn]) + { + m.command = CMD_VOLUMESLIDE; + m.param = autoVolSlide[chn]; + // convert to a "fine" value by setting the other nibble to 0xF + if(m.param & 0x0F) + m.param |= 0xF0; + else if(m.param & 0xF0) + m.param |= 0x0F; + didVolSlide = true; + + } else if(autoTremolo[chn]) + { + m.command = CMD_TREMOLO; + m.param = autoTremolo[chn]; + + } else if(shouldDelay) + { + // insert a fine pattern delay here + m.command = CMD_S3MCMDEX; + m.param = 0x61; + shouldDelay = false; + + } else if(!didGlobalVolSlide && globalVolSlide) + { + m.command = CMD_GLOBALVOLSLIDE; + m.param = globalVolSlide; + // convert to a "fine" value by setting the other nibble to 0xF + if(m.param & 0x0F) + m.param |= 0xF0; + else if(m.param & 0xF0) + m.param |= 0x0F; + + didGlobalVolSlide = true; + } + } + } + + // TODO: create/use extra channels for global volslide/delay if needed + } + } + + // after we know how many channels there really are... + m_nSamplePreAmp = 256 / m_nChannels; + // Setup channel pan positions and volume + SetupMODPanning(true); + + // Skip over scripts and drumpad info + if(fileHeader.version > 0) + { + uint16 scriptNum; + uint32 length; + + while(file.CanRead(2)) + { + scriptNum = file.ReadUint16BE(); + if(scriptNum == 0xFFFF) + break; + + file.Skip(2); + length = file.ReadUint32BE(); + file.Skip(length); + } + + // skip drumpad stuff + file.Skip(17*2); + } + + // Reading samples + if(loadFlags & loadSampleData) + { + for(SAMPLEINDEX smp = 1; smp <= samplesInFile; smp++) if(Samples[smp].nLength) + { + SampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM) + .ReadSample(Samples[smp], file); + + ConvertLoopSequence(Samples[smp], loopInfo[smp-1]); + + // make a non-looping duplicate of this sample if needed + if(nonLooped[smp-1]) + { + ConvertLoopSlice(Samples[smp], Samples[nonLooped[smp-1]], 0, Samples[smp].nLength, false); + } + + for(SAMPLEINDEX loop = 0; loop < loopInfo[smp-1].size(); loop++) + { + STPLoopInfo &info = loopInfo[smp-1][loop]; + + // make duplicate samples for this individual section if needed + if(info.looped) + { + ConvertLoopSlice(Samples[smp], Samples[info.looped], info.loopStart, info.loopLength, true); + } + if(info.nonLooped) + { + ConvertLoopSlice(Samples[smp], Samples[info.nonLooped], info.loopStart, info.loopLength, false); + } + } + } + } + + return true; +} + +OPENMPT_NAMESPACE_END diff --git a/OpenMPT/soundlib/Snd_defs.h b/OpenMPT/soundlib/Snd_defs.h index 687b0e8..ce5fa00 100644 --- a/OpenMPT/soundlib/Snd_defs.h +++ b/OpenMPT/soundlib/Snd_defs.h @@ -97,6 +97,7 @@ enum MODTYPE MOD_TYPE_DIGI = 0x8000000, MOD_TYPE_UAX = 0x10000000, // sampleset as module MOD_TYPE_PLM = 0x20000000, + MOD_TYPE_STP = 0x40000000, }; DECLARE_FLAGSET(MODTYPE) diff --git a/OpenMPT/soundlib/Snd_fx.cpp b/OpenMPT/soundlib/Snd_fx.cpp index 3542afb..7a482bc 100644 --- a/OpenMPT/soundlib/Snd_fx.cpp +++ b/OpenMPT/soundlib/Snd_fx.cpp @@ -3363,7 +3363,7 @@ void CSoundFile::PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const else param = pChn->nOldPortaUpDown; - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI)); + const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP)); // Process MIDI pitch bend for instrument plugins MidiPortamento(nChn, param, doFineSlides); @@ -3422,7 +3422,7 @@ void CSoundFile::PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, cons else param = pChn->nOldPortaUpDown; - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI)); + const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP)); // Process MIDI pitch bend for instrument plugins MidiPortamento(nChn, -static_cast<int>(param), doFineSlides); @@ -3894,7 +3894,7 @@ void CSoundFile::VolumeSlide(ModChannel *pChn, ModCommand::PARAM param) else param = pChn->nOldVolumeSlide; - if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI))) + if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP))) { // MOD / XM nibble priority if((param & 0xF0) != 0) @@ -5458,7 +5458,7 @@ uint32 CSoundFile::GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPerio //------------------------------------------------------------------------------------------ { if (!period) return 0; - if (GetType() & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_DIGI|MOD_TYPE_MTM|MOD_TYPE_AMF0)) + if (GetType() & (MOD_TYPE_MED|MOD_TYPE_MOD|MOD_TYPE_DIGI|MOD_TYPE_MTM|MOD_TYPE_AMF0|MOD_TYPE_STP)) { return ((3546895L * 4) << FREQ_FRACBITS) / period; } else if (GetType() == MOD_TYPE_XM) diff --git a/OpenMPT/soundlib/Sndfile.cpp b/OpenMPT/soundlib/Sndfile.cpp index c463551..30df0c8 100644 --- a/OpenMPT/soundlib/Sndfile.cpp +++ b/OpenMPT/soundlib/Sndfile.cpp @@ -310,6 +310,7 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags) && !ReadJ2B(file, loadFlags) && !ReadMO3(file, loadFlags) && !ReadPT36(file, loadFlags) + && !ReadSTP(file, loadFlags) && !ReadMod(file, loadFlags) && !Read669(file, loadFlags) && !ReadICE(file, loadFlags) @@ -1043,6 +1044,8 @@ MODTYPE CSoundFile::GetBestSaveFormat() const case MOD_TYPE_AMF0: case MOD_TYPE_DIGI: return MOD_TYPE_MOD; + case MOD_TYPE_STP: + return MOD_TYPE_XM; case MOD_TYPE_MED: if(m_nDefaultTempo == TEMPO(125, 0) && m_nDefaultSpeed == 6 && !m_nInstruments) { diff --git a/OpenMPT/soundlib/Sndfile.h b/OpenMPT/soundlib/Sndfile.h index 5b1f4d1..c3f8dee 100644 --- a/OpenMPT/soundlib/Sndfile.h +++ b/OpenMPT/soundlib/Sndfile.h @@ -670,6 +670,7 @@ public: bool ReadDIGI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadPLM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); static std::vector<const char *> GetSupportedExtensions(bool otherFormats); static mpt::Charset GetCharsetFromModType(MODTYPE modtype); diff --git a/OpenMPT/soundlib/Tables.cpp b/OpenMPT/soundlib/Tables.cpp index abf91a9..06250bd 100644 --- a/OpenMPT/soundlib/Tables.cpp +++ b/OpenMPT/soundlib/Tables.cpp @@ -87,6 +87,7 @@ static const ModFormatInfo modFormatInfo[] = { MOD_TYPE_IMF, "Imago Orpheus", "imf" }, { MOD_TYPE_J2B, "Galaxy Sound System", "j2b" }, { MOD_TYPE_PLM, "Disorder Tracker 2", "plm" }, + { MOD_TYPE_STP, "Soundtracker Pro II", "stp" }, #ifndef NO_ARCHIVE_SUPPORT // Compressed modules @@ -147,6 +148,7 @@ static const ModCharsetInfo ModCharsetInfos[] = { MOD_TYPE_OKT , mpt::CharsetISO8859_1 }, { MOD_TYPE_DBM , mpt::CharsetISO8859_1 }, { MOD_TYPE_DIGI, mpt::CharsetISO8859_1 }, + { MOD_TYPE_STP, mpt::CharsetISO8859_1 }, // Amiga // DOS { MOD_TYPE_MOD , mpt::CharsetISO8859_1 }, { MOD_TYPE_MED , mpt::CharsetISO8859_1 }, stpro2_r3.patch (33,845 bytes)
Index: build/android_ndk/Android-minimp3-stbvorbis.mk =================================================================== --- build/android_ndk/Android-minimp3-stbvorbis.mk (revision 6473) +++ build/android_ndk/Android-minimp3-stbvorbis.mk (working copy) @@ -75,6 +75,7 @@ soundlib/Load_s3m.cpp \ soundlib/Load_sfx.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ Index: build/android_ndk/Android-mpg123-vorbis.mk =================================================================== --- build/android_ndk/Android-mpg123-vorbis.mk (revision 6473) +++ build/android_ndk/Android-mpg123-vorbis.mk (working copy) @@ -73,6 +73,7 @@ soundlib/Load_s3m.cpp \ soundlib/Load_sfx.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ Index: build/android_ndk/Android-unmo3.mk =================================================================== --- build/android_ndk/Android-unmo3.mk (revision 6473) +++ build/android_ndk/Android-unmo3.mk (working copy) @@ -106,6 +106,7 @@ soundlib/Load_s3m.cpp \ soundlib/Load_sfx.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ Index: build/android_ndk/Android.mk =================================================================== --- build/android_ndk/Android.mk (revision 6473) +++ build/android_ndk/Android.mk (working copy) @@ -74,6 +74,7 @@ soundlib/Load_s3m.cpp \ soundlib/Load_sfx.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ Index: build/autotools/Makefile.am =================================================================== --- build/autotools/Makefile.am (revision 6473) +++ build/autotools/Makefile.am (working copy) @@ -186,6 +186,7 @@ libopenmpt_la_SOURCES += soundlib/Load_s3m.cpp libopenmpt_la_SOURCES += soundlib/Load_sfx.cpp libopenmpt_la_SOURCES += soundlib/Load_stm.cpp +libopenmpt_la_SOURCES += soundlib/Load_stp.cpp libopenmpt_la_SOURCES += soundlib/Load_ult.cpp libopenmpt_la_SOURCES += soundlib/Load_umx.cpp libopenmpt_la_SOURCES += soundlib/Load_wav.cpp @@ -432,6 +433,7 @@ libopenmpttest_SOURCES += soundlib/Load_s3m.cpp libopenmpttest_SOURCES += soundlib/Load_sfx.cpp libopenmpttest_SOURCES += soundlib/Load_stm.cpp +libopenmpttest_SOURCES += soundlib/Load_stp.cpp libopenmpttest_SOURCES += soundlib/Load_ult.cpp libopenmpttest_SOURCES += soundlib/Load_umx.cpp libopenmpttest_SOURCES += soundlib/Load_wav.cpp Index: libopenmpt/foo_openmpt.cpp =================================================================== --- libopenmpt/foo_openmpt.cpp (revision 6473) +++ libopenmpt/foo_openmpt.cpp (working copy) @@ -319,6 +319,7 @@ "*.imf" ";" "*.j2b" ";" "*.plm" ";" + "*.stp" ";" "*.sfx" ";" "*.sfx2" ";" "*.mms" ";" Index: mptrack/Mptrack.cpp =================================================================== --- mptrack/Mptrack.cpp (revision 6473) +++ mptrack/Mptrack.cpp (working copy) @@ -1412,7 +1412,7 @@ "FastTracker Modules (*.xm)|*.xm;*.xmz|" "Impulse Tracker Modules (*.it)|*.it;*.itz|" "OpenMPT Modules (*.mptm)|*.mptm;*.mptmz|" - "Other Modules (mtm,okt,mdl,669,far,...)|*.mtm;*.669;*.ult;*.wow;*.far;*.mdl;*.okt;*.dmf;*.ptm;*.med;*.ams;*.dbm;*.digi;*.dsm;*.umx;*.amf;*.psm;*.mt2;*.gdm;*.imf;*.itp;*.j2b;*.ice;*.st26;*.plm;*.sfx;*.sfx2;*.mms|" + "Other Modules (mtm,okt,mdl,669,far,...)|*.mtm;*.669;*.ult;*.wow;*.far;*.mdl;*.okt;*.dmf;*.ptm;*.med;*.ams;*.dbm;*.digi;*.dsm;*.umx;*.amf;*.psm;*.mt2;*.gdm;*.imf;*.itp;*.j2b;*.ice;*.st26;*.plm;*.stp;*.sfx;*.sfx2;*.mms|" "Wave Files (*.wav)|*.wav|" "MIDI Files (*.mid,*.rmi)|*.mid;*.rmi;*.smf|" "All Files (*.*)|*.*||") Index: mptrack/mptrack_10.vcxproj =================================================================== --- mptrack/mptrack_10.vcxproj (revision 6473) +++ mptrack/mptrack_10.vcxproj (working copy) @@ -785,6 +785,7 @@ <ClCompile Include="..\soundlib\Load_digi.cpp" /> <ClCompile Include="..\soundlib\Load_plm.cpp" /> <ClCompile Include="..\soundlib\Load_sfx.cpp" /> + <ClCompile Include="..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\soundlib\Message.cpp" /> <ClCompile Include="..\soundlib\MIDIEvents.cpp" /> <ClCompile Include="..\soundlib\MIDIMacros.cpp" /> Index: mptrack/mptrack_10.vcxproj.filters =================================================================== --- mptrack/mptrack_10.vcxproj.filters (revision 6473) +++ mptrack/mptrack_10.vcxproj.filters (working copy) @@ -643,6 +643,9 @@ <ClCompile Include="..\soundlib\Load_sfx.cpp"> <Filter>Source Files\soundlib\Module Loaders</Filter> </ClCompile> + <ClCompile Include="..\soundlib\Load_stp.cpp"> + <Filter>Source Files\soundlib\Module Loaders</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\soundlib\Loaders.h"> Index: soundlib/Load_stp.cpp =================================================================== --- soundlib/Load_stp.cpp (nonexistent) +++ soundlib/Load_stp.cpp (working copy) @@ -0,0 +1,951 @@ +/* + * Load_stp.cpp + * ------------ + * Purpose: STP (Soundtracker Pro II) module loader + * Notes : a few exotic effects aren't supported. + * multiple sample loops are supported, but only the first 10 can be used as cue points + * (with 16xx and 18xx). + * fractional speed values and combined auto effects are handled whenever possible, + * but some effects may be omitted (and there may be tempo accuracy issues). + * Authors: Devin Acker + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + * + * Wisdom from the Soundtracker Pro II manual: + * "To create shorter patterns, simply create shorter patterns." + */ + +#include "stdafx.h" +#include "Loaders.h" +#include "Tables.h" + +OPENMPT_NAMESPACE_BEGIN + +#ifdef NEEDS_PRAGMA_PACK +#pragma pack(push, 1) +#endif + +// File header (except for "STP3" magic) +struct PACKED STPFileHeader +{ + uint16 version; + uint8 numOrders; + uint8 patternLength; + uint8 orderList[128]; + uint16 speed; + uint16 speedFrac; + uint16 timerCount; + uint16 flags; + uint32 reserved; + uint16 midiCount; // always 50 + uint8 midi[50]; + uint16 numSamples; + uint16 sampleStructSize; + + void ConvertEndianness() + { + SwapBytesBE(version); + SwapBytesBE(speed); + SwapBytesBE(speedFrac); + SwapBytesBE(timerCount); + SwapBytesBE(flags); + SwapBytesBE(midiCount); + SwapBytesBE(numSamples); + SwapBytesBE(sampleStructSize); + } +}; + +STATIC_ASSERT(sizeof(STPFileHeader) == 200); + + +// Sample header (versions 0 and 1) +struct PACKED STPSampleHeaderOld +{ + char pathName[31]; + uint8 flags; + char fileName[30]; + uint32 length; + uint8 volume; + uint8 reserved1; + uint32 loopStart; + uint32 loopLength; + uint16 defaultCmd; + uint32 reserved2; + + void ConvertEndianness() + { + SwapBytesBE(length); + SwapBytesBE(loopStart); + SwapBytesBE(loopLength); + SwapBytesBE(defaultCmd); + } + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = length; + mptSmp.nVolume = 4u * std::min<uint16>(volume, 64); + + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + + if(mptSmp.nLoopStart >= mptSmp.nLength) + { + mptSmp.nLoopStart = mptSmp.nLength - 1; + } + if(mptSmp.nLoopEnd > mptSmp.nLength) + { + mptSmp.nLoopEnd = mptSmp.nLength; + } + + if(mptSmp.nLoopStart > mptSmp.nLoopEnd) + { + mptSmp.nLoopStart = 0; + mptSmp.nLoopEnd = 0; + } + else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) + { + mptSmp.uFlags.set(CHN_LOOP); + } + } + + void Read(FileReader &file) + { + file.ReadConvertEndianness(*this); + } +}; + +STATIC_ASSERT(sizeof(STPSampleHeaderOld) == 82); + +#ifdef NEEDS_PRAGMA_PACK +#pragma pack(pop) +#endif + +// Sample header (version 2), not packed due to variable string length and alignment in file +struct STPSampleHeader +{ + //char pathName[256]; + uint8 flags; + char fileName[30]; + uint32 length; + uint8 volume; + uint8 reserved1; + uint32 loopStart; + uint32 loopLength; + uint16 defaultCmd; + uint16 defaultPeriod; + uint8 finetune; + uint8 reserved2; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = length; + mptSmp.nFineTune = static_cast<int8>(finetune << 3); + mptSmp.nVolume = 4 * MIN(volume, 64); + + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + + if(mptSmp.nLoopStart >= mptSmp.nLength) + { + mptSmp.nLoopStart = mptSmp.nLength - 1; + } + if(mptSmp.nLoopEnd > mptSmp.nLength) + { + mptSmp.nLoopEnd = mptSmp.nLength; + } + + if(mptSmp.nLoopStart > mptSmp.nLoopEnd) + { + mptSmp.nLoopStart = 0; + mptSmp.nLoopEnd = 0; + } else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) + { + mptSmp.cues[0] = mptSmp.nLoopStart; + mptSmp.uFlags.set(CHN_LOOP); + } + } + + void Read(FileReader &file) + { + std::string str; + + file.ReadNullString(str, 255); + //mpt::String::Copy(pathName, str); + + flags = file.ReadUint8(); + + file.ReadNullString(str, 29); + mpt::String::Copy(fileName, str); + + // seek to even boundary + if(file.GetPosition() % 2u) + file.Skip(1); + + length = file.ReadUint32BE(); + volume = file.ReadUint8(); + reserved1 = file.ReadUint8(); + + loopStart = file.ReadUint32BE(); + loopLength = file.ReadUint32BE(); + + defaultCmd = file.ReadUint16BE(); + defaultPeriod = file.ReadUint16BE(); + + finetune = file.ReadUint8(); + reserved2 = file.ReadUint8(); + } +}; + +struct STPLoopInfo +{ + SmpLength loopStart; + SmpLength loopLength; + SAMPLEINDEX looped; + SAMPLEINDEX nonLooped; +}; + +typedef std::vector<STPLoopInfo> STPLoopList; + +template <typename T> +static void ReadSample(FileReader &file, T &sampleHeader, ModSample &sample, char (&sampleName)[MAX_SAMPLENAME]) +//-------------------------------------------------------------------------------------------------------------- +{ + sampleHeader.Read(file); + sampleHeader.ConvertToMPT(sample); + + mpt::String::Read<mpt::String::maybeNullTerminated>(sampleName, sampleHeader.fileName); +} + + +static TEMPO ConvertTempo(uint16 ciaSpeed) +//---------------------------------------- +{ + // 3546 is the resulting CIA timer value when using 4F7D (tempo 125 bpm) command in STProII + return TEMPO((125.0 * 3546.0) / ciaSpeed); +} + + +static void ConvertLoopSlice(ModSample &src, ModSample &dest, SmpLength start, SmpLength len, bool loop) +//------------------------------------------------------------------------------------------------------ +{ + if(!src.HasSampleData()) return; + + dest.FreeSample(); + + dest = src; + dest.nLength = len; + dest.pSample = nullptr; + + if(!dest.AllocateSample()) + { + return; + } + + // only preserve cue points if the target sample length is the same + if(len != src.nLength) + MemsetZero(dest.cues); + + memcpy(dest.pSample8, src.pSample8 + start, len); + if(loop) + { + dest.nLoopStart = 0; + dest.nLoopEnd = len; + dest.uFlags.set(CHN_LOOP); + } else + { + dest.nLoopStart = 0; + dest.nLoopEnd = 0; + dest.uFlags.reset(CHN_LOOP); + } +} + +static void ConvertLoopSequence(ModSample &smp, STPLoopList &loopList) +//-------------------------------------------------------------------- +{ + // This should only modify a sample if it has more than one loop + // (otherwise, it behaves like a normal sample loop) + if(!smp.HasSampleData() || loopList.size() < 2) return; + + ModSample newSmp = smp; + newSmp.nLength = 0; + newSmp.pSample = nullptr; + + size_t numLoops = loopList.size(); + + // get the total length of the sample after combining all looped sections + for(size_t i = 0; i < numLoops; i++) + { + STPLoopInfo &info = loopList[i]; + + // if adding this loop would cause the sample length to exceed maximum, + // then limit and bail out + if((newSmp.nLength + info.loopLength > MAX_SAMPLE_LENGTH) || + (info.loopLength > MAX_SAMPLE_LENGTH) || + (info.loopStart + info.loopLength > smp.nLength)) + { + numLoops = i; + break; + } + + newSmp.nLength += info.loopLength; + } + + if(!newSmp.AllocateSample()) + { + return; + } + + // start copying the looped sample data parts + SmpLength start = 0; + + for(size_t i = 0; i < numLoops; i++) + { + STPLoopInfo &info = loopList[i]; + + memcpy(newSmp.pSample8 + start, smp.pSample8 + info.loopStart, info.loopLength); + + // update loop info based on position in edited sample + info.loopStart = start; + if(i > 0 && i <= CountOf(newSmp.cues)) + { + newSmp.cues[i - 1] = start; + } + start += info.loopLength; + } + + // replace old sample with new one + smp.FreeSample(); + smp = newSmp; + + smp.nLoopStart = 0; + smp.nLoopEnd = smp.nLength; + smp.uFlags.set(CHN_LOOP); +} + + +bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags) +//------------------------------------------------------------------- +{ + file.Rewind(); + if(!file.ReadMagic("STP3")) + return false; + + STPFileHeader fileHeader; + file.ReadConvertEndianness(fileHeader); + if(fileHeader.version > 2 || + fileHeader.numOrders > 128 || fileHeader.numSamples >= MAX_SAMPLES || + fileHeader.midiCount != 50) + return false; + + if(loadFlags == onlyVerifyHeader) + return true; + + InitializeGlobals(MOD_TYPE_STP); + + m_nChannels = 4; + m_nSamples = 0; + m_nInstruments = 0; + + m_nDefaultSpeed = fileHeader.speed; + m_nDefaultTempo = ConvertTempo(fileHeader.timerCount); + + m_nMinPeriod = 14 * 4; + m_nMaxPeriod = 3424 * 4; + + Order.ReadFromArray(fileHeader.orderList, fileHeader.numOrders); + + std::vector<STPLoopList> loopInfo; + // non-looped versions of samples with loopes (when needed) + std::vector<SAMPLEINDEX> nonLooped; + + // Load sample headers + SAMPLEINDEX samplesInFile = 0; + + for(SAMPLEINDEX smp = 1; smp <= fileHeader.numSamples; smp++) + { + // this is 1-based the same as smp + SAMPLEINDEX actualSmp = file.ReadUint16BE(); + if(actualSmp >= MAX_SAMPLES) + return false; + + samplesInFile = m_nSamples = MAX(m_nSamples, actualSmp); + + ModSample &thisSmp = Samples[actualSmp]; + + if(fileHeader.version == 2) + { + STPSampleHeader sampleHeader; + uint32 headerSize = file.ReadUint32BE(); + + ReadSample(file, sampleHeader, thisSmp, m_szNames[actualSmp]); + // TODO: verify string lengths against headerSize? + MPT_UNUSED_VARIABLE(headerSize); + } else + { + STPSampleHeaderOld sampleHeaderOld; + ReadSample(file, sampleHeaderOld, thisSmp, m_szNames[actualSmp]); + } + + STPLoopList loopList; + + if(fileHeader.version >= 1) + { + uint16 numLoops = file.ReadUint16BE(); + + STPLoopInfo loop; + loop.looped = loop.nonLooped = 0; + + if(numLoops == 0 && thisSmp.uFlags[CHN_LOOP]) + { + loop.loopStart = thisSmp.nLoopStart; + loop.loopLength = thisSmp.nLoopEnd - thisSmp.nLoopStart; + loopList.push_back(loop); + + } else for(SAMPLEINDEX i = 0; i < numLoops; i++) + { + loop.loopStart = file.ReadUint32BE(); + loop.loopLength = file.ReadUint32BE(); + loopList.push_back(loop); + } + } + + nonLooped.resize(actualSmp); + loopInfo.resize(actualSmp); + loopInfo[actualSmp - 1] = loopList; + } + + // Load patterns + uint16 numPatterns = 128; + if (fileHeader.version == 0) + numPatterns = file.ReadUint16BE(); + + uint16 patternLength = fileHeader.patternLength; + CHANNELINDEX channels = 4; + if(fileHeader.version > 0) + { + // Scan for total number of channels + FileReader::off_t patOffset = file.GetPosition(); + for(uint16 pat = 0; pat < numPatterns; pat++) + { + PATTERNINDEX actualPat = file.ReadUint16BE(); + if(actualPat == 0xFFFF) + break; + + patternLength = file.ReadUint16BE(); + channels = file.ReadUint16BE(); + m_nChannels = std::max(m_nChannels, channels); + + file.Skip(channels * patternLength * 4u); + } + file.Seek(patOffset); + if(m_nChannels > MAX_BASECHANNELS) + return false; + } + + uint8 globalVolSlide = 0; + std::vector<uint8> autoFinePorta(channels, 0); + std::vector<uint8> autoPortaUp(channels, 0); + std::vector<uint8> autoPortaDown(channels, 0); + std::vector<uint8> autoVolSlide(channels, 0); + std::vector<uint8> autoVibrato(channels, 0); + std::vector<uint8> vibratoMem(channels, 0); + std::vector<uint8> autoTremolo(channels, 0); + std::vector<uint8> autoTonePorta(channels, 0); + std::vector<uint8> tonePortaMem(channels, 0); + + for(uint16 pat = 0; pat < numPatterns; pat++) + { + PATTERNINDEX actualPat = pat; + + if(fileHeader.version > 0) + { + actualPat = file.ReadUint16BE(); + if(actualPat == 0xFFFF) + break; + + patternLength = file.ReadUint16BE(); + channels = file.ReadUint16BE(); + } + + if(!(loadFlags & loadPatternData) || !Patterns.Insert(actualPat, patternLength)) + { + file.Skip(channels * patternLength * 4u); + continue; + } + + for(ROWINDEX row = 0; row < patternLength; row++) + { + PatternRow rowBase = Patterns[actualPat].GetpModCommand(row, 0); + + bool didGlobalVolSlide = false; + bool shouldDelay = false; + + // if a fractional speed value is in use then determine if we should stick a fine pattern delay somewhere + switch(fileHeader.speedFrac & 3) + { + // 1/4 + case 1: shouldDelay = (row & 3) == 0; break; + // 1/2 + case 2: shouldDelay = (row & 1) == 0; break; + // 3/4 + case 3: shouldDelay = (row & 3) != 3; break; + } + + for(CHANNELINDEX chn = 0; chn < channels; chn++) + { + ModCommand &m = rowBase[chn]; + uint8 data[4]; + file.ReadArray(data); + + m.instr = data[0]; + m.note = data[1]; + m.command = data[2]; + m.param = data[3]; + + if(m.note) + { + m.note += 24 + NOTE_MIN; + + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoVolSlide[chn] = 0; + autoVibrato[chn] = vibratoMem[chn] = 0; + autoTremolo[chn] = 0; + autoTonePorta[chn] = tonePortaMem[chn] = 0; + } + + // this is a nibble-swapped param value used for auto fine volside + // and auto global fine volside + uint8 swap = (m.param >> 4) | (m.param << 4); + + if((m.command & 0xF0) == 0xF0) + { + m.param = mpt::saturate_cast<uint8>(Util::Round(ConvertTempo(m.param | (((uint16)m.command & 0xF) << 8)).ToDouble())); + m.command = CMD_TEMPO; + } else switch(m.command) + { + case 0x00: // arpeggio + if(m.param) + m.command = CMD_ARPEGGIO; + break; + + case 0x01: // portamento up + m.command = CMD_PORTAMENTOUP; + break; + + case 0x02: // portamento down + m.command = CMD_PORTAMENTODOWN; + break; + + case 0x03: // auto fine portamento up + autoFinePorta[chn] = 0x10 | std::min(m.param, ModCommand::PARAM(15)); + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x04: // auto fine portamento down + autoFinePorta[chn] = 0x20 | std::min(m.param, ModCommand::PARAM(15)); + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x05: // auto portamento up + autoFinePorta[chn] = 0; + autoPortaUp[chn] = m.param; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x06: // auto portamento down + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = m.param; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x07: // set global volume + m.command = CMD_GLOBALVOLUME; + globalVolSlide = 0; + break; + + case 0x08: // auto global fine volume slide + globalVolSlide = swap; + m.command = m.param = 0; + break; + + case 0x09: // fine portamento up + m.command = CMD_MODCMDEX; + m.param = 0x10 | std::min(m.param, ModCommand::PARAM(15)); + break; + + case 0x0A: // fine portamento down + m.command = CMD_MODCMDEX; + m.param = 0x20 | std::min(m.param, ModCommand::PARAM(15)); + break; + + case 0x0B: // auto fine volume slide + autoVolSlide[chn] = swap; + m.command = m.param = 0; + break; + + case 0x0C: // set volume + m.volcmd = VOLCMD_VOLUME; + m.vol = m.param; + autoVolSlide[chn] = 0; + m.command = m.param = 0; + break; + + case 0x0D: // volume slide (param is swapped compared to .mod) + if(m.param & 0xF0) + { + m.volcmd = VOLCMD_VOLSLIDEDOWN; + m.vol = m.param >> 4; + } else if(m.param & 0x0F) + { + m.volcmd = VOLCMD_VOLSLIDEUP; + m.vol = m.param & 0xF; + } + autoVolSlide[chn] = 0; + m.command = m.param = 0; + break; + + case 0x0E: // set filter (also uses opposite value compared to .mod) + m.command = CMD_MODCMDEX; + m.param = 1 ^ (m.param ? 1 : 0); + break; + + case 0x0F: // set speed + m.command = CMD_SPEED; + fileHeader.speedFrac = m.param & 0xF; + m.param >>= 4; + break; + + case 0x10: // auto vibrato + autoVibrato[chn] = m.param; + vibratoMem[chn] = 0; + m.command = m.param = 0; + break; + + case 0x11: // auto tremolo + if(m.param & 0xF) + autoTremolo[chn] = m.param; + else + autoTremolo[chn] = 0; + m.command = m.param = 0; + break; + + case 0x12: // pattern break + m.command = CMD_PATTERNBREAK; + break; + + case 0x13: // auto tone portamento + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = m.param; + + tonePortaMem[chn] = 0; + m.command = m.param = 0; + break; + + case 0x14: // position jump + m.command = CMD_POSITIONJUMP; + break; + + case 0x16: // start loop sequence + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList& loopList = loopInfo[m.instr-1]; + + m.param--; + if(m.param < std::min(CountOf(ModSample().cues), loopList.size())) + { + m.volcmd = VOLCMD_OFFSET; + m.vol = m.param; + } + } + + m.command = m.param = 0; + break; + + case 0x17: // play only loop nn + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList& loopList = loopInfo[m.instr-1]; + + m.param--; + if (m.param < loopList.size()) + { + if (!loopList[m.param].looped && m_nSamples < MAX_SAMPLES - 1) + loopList[m.param].looped = ++m_nSamples; + m.instr = static_cast<ModCommand::INSTR>(loopList[m.param].looped); + } + } + + m.command = m.param = 0; + break; + + case 0x18: // play sequence without loop + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList& loopList = loopInfo[m.instr-1]; + + m.param--; + if(m.param < std::min(CountOf(ModSample().cues), loopList.size())) + { + m.volcmd = VOLCMD_OFFSET; + m.vol = m.param; + } + // switch to non-looped version of sample and create it if needed + if (!nonLooped[m.instr - 1] && m_nSamples < MAX_SAMPLES - 1) + nonLooped[m.instr - 1] = ++m_nSamples; + m.instr = static_cast<ModCommand::INSTR>(nonLooped[m.instr - 1]); + } + + m.command = m.param = 0; + break; + + case 0x19: // play only loop nn without loop + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList& loopList = loopInfo[m.instr-1]; + + m.param--; + if (m.param < loopList.size()) + { + if (!loopList[m.param].nonLooped && m_nSamples < MAX_SAMPLES-1) + loopList[m.param].nonLooped = ++m_nSamples; + m.instr = static_cast<ModCommand::INSTR>(loopList[m.param].nonLooped); + } + } + + m.command = m.param = 0; + break; + + case 0x1D: // fine volume slide (nibble order also swapped) + m.command = CMD_VOLUMESLIDE; + m.param = swap; + if(m.param & 0xF0) // slide down + m.param |= 0x0F; + else if(m.param & 0x0F) + m.param |= 0xF0; + break; + + case 0x20: // "delayed fade" + // just behave like either a normal fade or a notecut + // depending on the speed + if(m.param & 0xF0) + { + autoVolSlide[chn] = m.param >> 4; + m.command = m.param = 0; + } else + { + m.command = CMD_MODCMDEX; + m.param = 0xC0 | (m.param & 0xF); + } + break; + + case 0x21: // note delay + m.command = CMD_MODCMDEX; + m.param = 0xD0 | MIN(m.param, 15); + break; + + case 0x22: // retrigger note + m.command = CMD_RETRIG; + m.param = MIN(m.param, 15); + break; + + case 0x49: // set sample offset + m.command = CMD_OFFSET; + break; + + case 0x4E: // other protracker commands (pattern loop / delay) + if((m.param & 0xF0) == 0x60 || (m.param & 0xF0) == 0xE0) + m.command = CMD_MODCMDEX; + else + m.command = m.param = 0; + break; + + case 0x4F: // set speed/tempo + if(m.param < 0x20) + { + m.command = CMD_SPEED; + fileHeader.speedFrac = 0; + } else + { + m.command = CMD_TEMPO; + } + break; + + default: + m.command = CMD_NONE; + break; + } + + bool didVolSlide = false; + + // try to put volume slide in volume command + if(autoVolSlide[chn] && !m.volcmd) + { + if(autoVolSlide[chn] & 0xF0) + { + m.volcmd = VOLCMD_FINEVOLUP; + m.vol = autoVolSlide[chn] >> 4; + } else + { + m.volcmd = VOLCMD_FINEVOLDOWN; + m.vol = autoVolSlide[chn] & 0xF; + } + didVolSlide = true; + } + + // try to place/combine all remaining running effects. + if(!m.command) + { + if(autoPortaUp[chn]) + { + m.command = CMD_PORTAMENTOUP; + m.param = autoPortaUp[chn]; + + } else if(autoPortaDown[chn]) + { + m.command = CMD_PORTAMENTODOWN; + m.param = autoPortaDown[chn]; + + } else if(autoFinePorta[chn]) + { + m.command = CMD_MODCMDEX; + m.param = autoFinePorta[chn]; + + } else if(autoTonePorta[chn]) + { + m.command = CMD_TONEPORTAMENTO; + m.param = tonePortaMem[chn] = autoTonePorta[chn]; + + } else if(autoVibrato[chn]) + { + m.command = CMD_VIBRATO; + m.param = vibratoMem[chn] = autoVibrato[chn]; + + } else if(!didVolSlide && autoVolSlide[chn]) + { + m.command = CMD_VOLUMESLIDE; + m.param = autoVolSlide[chn]; + // convert to a "fine" value by setting the other nibble to 0xF + if(m.param & 0x0F) + m.param |= 0xF0; + else if(m.param & 0xF0) + m.param |= 0x0F; + didVolSlide = true; + + } else if(autoTremolo[chn]) + { + m.command = CMD_TREMOLO; + m.param = autoTremolo[chn]; + + } else if(shouldDelay) + { + // insert a fine pattern delay here + m.command = CMD_S3MCMDEX; + m.param = 0x61; + shouldDelay = false; + + } else if(!didGlobalVolSlide && globalVolSlide) + { + m.command = CMD_GLOBALVOLSLIDE; + m.param = globalVolSlide; + // convert to a "fine" value by setting the other nibble to 0xF + if(m.param & 0x0F) + m.param |= 0xF0; + else if(m.param & 0xF0) + m.param |= 0x0F; + + didGlobalVolSlide = true; + } + } + } + + // TODO: create/use extra channels for global volslide/delay if needed + } + } + + // after we know how many channels there really are... + m_nSamplePreAmp = 256 / m_nChannels; + // Setup channel pan positions and volume + SetupMODPanning(true); + + // Skip over scripts and drumpad info + if(fileHeader.version > 0) + { + uint16 scriptNum; + uint32 length; + + while(file.CanRead(2)) + { + scriptNum = file.ReadUint16BE(); + if(scriptNum == 0xFFFF) + break; + + file.Skip(2); + length = file.ReadUint32BE(); + file.Skip(length); + } + + // skip drumpad stuff + file.Skip(17*2); + } + + // Reading samples + if(loadFlags & loadSampleData) + { + for(SAMPLEINDEX smp = 1; smp <= samplesInFile; smp++) if(Samples[smp].nLength) + { + SampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM) + .ReadSample(Samples[smp], file); + + ConvertLoopSequence(Samples[smp], loopInfo[smp-1]); + + // make a non-looping duplicate of this sample if needed + if(nonLooped[smp-1]) + { + ConvertLoopSlice(Samples[smp], Samples[nonLooped[smp-1]], 0, Samples[smp].nLength, false); + } + + for(SAMPLEINDEX loop = 0; loop < loopInfo[smp-1].size(); loop++) + { + STPLoopInfo &info = loopInfo[smp-1][loop]; + + // make duplicate samples for this individual section if needed + if(info.looped) + { + ConvertLoopSlice(Samples[smp], Samples[info.looped], info.loopStart, info.loopLength, true); + } + if(info.nonLooped) + { + ConvertLoopSlice(Samples[smp], Samples[info.nonLooped], info.loopStart, info.loopLength, false); + } + } + } + } + + return true; +} + +OPENMPT_NAMESPACE_END Property changes on: soundlib/Load_stp.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/x-c++src \ No newline at end of property Index: soundlib/Snd_defs.h =================================================================== --- soundlib/Snd_defs.h (revision 6473) +++ soundlib/Snd_defs.h (working copy) @@ -98,6 +98,7 @@ MOD_TYPE_UAX = 0x10000000, // sampleset as module MOD_TYPE_PLM = 0x20000000, MOD_TYPE_SFX = 0x40000000, + MOD_TYPE_STP = 0x80000000, }; DECLARE_FLAGSET(MODTYPE) Index: soundlib/Snd_fx.cpp =================================================================== --- soundlib/Snd_fx.cpp (revision 6473) +++ soundlib/Snd_fx.cpp (working copy) @@ -3358,7 +3358,7 @@ else param = pChn->nOldPortaUpDown; - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI)); + const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP)); // Process MIDI pitch bend for instrument plugins MidiPortamento(nChn, param, doFineSlides); @@ -3417,7 +3417,7 @@ else param = pChn->nOldPortaUpDown; - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI)); + const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP)); // Process MIDI pitch bend for instrument plugins MidiPortamento(nChn, -static_cast<int>(param), doFineSlides); @@ -3895,7 +3895,7 @@ else param = pChn->nOldVolumeSlide; - if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI))) + if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP))) { // MOD / XM nibble priority if((param & 0xF0) != 0) @@ -5468,7 +5468,7 @@ //------------------------------------------------------------------------------------------ { if (!period) return 0; - if (GetType() & (MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_DIGI | MOD_TYPE_MTM | MOD_TYPE_AMF0 | MOD_TYPE_SFX)) + if (GetType() & (MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_DIGI | MOD_TYPE_MTM | MOD_TYPE_AMF0 | MOD_TYPE_SFX | MOD_TYPE_STP)) { return ((3546895L * 4) << FREQ_FRACBITS) / period; } else if (GetType() == MOD_TYPE_XM) Index: soundlib/Sndfile.cpp =================================================================== --- soundlib/Sndfile.cpp (revision 6473) +++ soundlib/Sndfile.cpp (working copy) @@ -312,6 +312,7 @@ && !ReadJ2B(file, loadFlags) && !ReadPT36(file, loadFlags) && !ReadSFX(file, loadFlags) + && !ReadSTP(file, loadFlags) && !ReadMod(file, loadFlags) && !ReadICE(file, loadFlags) && !Read669(file, loadFlags) @@ -1058,6 +1059,7 @@ case MOD_TYPE_AMF0: case MOD_TYPE_DIGI: case MOD_TYPE_SFX: + case MOD_TYPE_STP: return MOD_TYPE_MOD; case MOD_TYPE_MED: if(m_nDefaultTempo == TEMPO(125, 0) && m_nDefaultSpeed == 6 && !m_nInstruments) Index: soundlib/Sndfile.h =================================================================== --- soundlib/Sndfile.h (revision 6473) +++ soundlib/Sndfile.h (working copy) @@ -668,6 +668,7 @@ bool ReadPLM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSFX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); static std::vector<const char *> GetSupportedExtensions(bool otherFormats); static mpt::Charset GetCharsetFromModType(MODTYPE modtype); Index: soundlib/Tables.cpp =================================================================== --- soundlib/Tables.cpp (revision 6473) +++ soundlib/Tables.cpp (working copy) @@ -90,6 +90,7 @@ { MOD_TYPE_SFX, "SoundFX", "sfx" }, { MOD_TYPE_SFX, "SoundFX", "sfx2" }, { MOD_TYPE_SFX, "MultiMedia Sound", "mms" }, + { MOD_TYPE_STP, "Soundtracker Pro II", "stp" }, #ifndef NO_ARCHIVE_SUPPORT // Compressed modules @@ -151,6 +152,7 @@ { MOD_TYPE_DBM , mpt::CharsetISO8859_1 }, { MOD_TYPE_DIGI, mpt::CharsetISO8859_1 }, { MOD_TYPE_SFX , mpt::CharsetISO8859_1 }, + { MOD_TYPE_STP, mpt::CharsetISO8859_1 }, // Amiga // DOS { MOD_TYPE_MOD , mpt::CharsetISO8859_1 }, { MOD_TYPE_MED , mpt::CharsetISO8859_1 }, stpro2_r4.patch (43,295 bytes)
Index: android_ndk/Android.mk =================================================================== --- android_ndk/Android.mk (revision 6938) +++ android_ndk/Android.mk (working copy) @@ -187,6 +187,7 @@ soundlib/Load_s3m.cpp \ soundlib/Load_sfx.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ Index: autotools/Makefile.am =================================================================== --- autotools/Makefile.am (revision 6938) +++ autotools/Makefile.am (working copy) @@ -194,6 +194,7 @@ libopenmpt_la_SOURCES += soundlib/Load_s3m.cpp libopenmpt_la_SOURCES += soundlib/Load_sfx.cpp libopenmpt_la_SOURCES += soundlib/Load_stm.cpp +libopenmpt_la_SOURCES += soundlib/Load_stp.cpp libopenmpt_la_SOURCES += soundlib/Load_ult.cpp libopenmpt_la_SOURCES += soundlib/Load_umx.cpp libopenmpt_la_SOURCES += soundlib/Load_wav.cpp @@ -444,6 +445,7 @@ libopenmpttest_SOURCES += soundlib/Load_s3m.cpp libopenmpttest_SOURCES += soundlib/Load_sfx.cpp libopenmpttest_SOURCES += soundlib/Load_stm.cpp +libopenmpttest_SOURCES += soundlib/Load_stp.cpp libopenmpttest_SOURCES += soundlib/Load_ult.cpp libopenmpttest_SOURCES += soundlib/Load_umx.cpp libopenmpttest_SOURCES += soundlib/Load_wav.cpp Index: vs2008/libopenmpt-small.vcproj =================================================================== --- vs2008/libopenmpt-small.vcproj (revision 6938) +++ vs2008/libopenmpt-small.vcproj (working copy) @@ -1075,6 +1075,10 @@ > </File> <File + RelativePath="..\..\soundlib\Load_stp.cpp" + > + </File> + <File RelativePath="..\..\soundlib\Load_ult.cpp" > </File> Index: vs2008/libopenmpt.vcproj =================================================================== --- vs2008/libopenmpt.vcproj (revision 6938) +++ vs2008/libopenmpt.vcproj (working copy) @@ -1079,6 +1079,10 @@ > </File> <File + RelativePath="..\..\soundlib\Load_stp.cpp" + > + </File> + <File RelativePath="..\..\soundlib\Load_ult.cpp" > </File> Index: vs2008/libopenmpt_test.vcproj =================================================================== --- vs2008/libopenmpt_test.vcproj (revision 6938) +++ vs2008/libopenmpt_test.vcproj (working copy) @@ -807,6 +807,10 @@ > </File> <File + RelativePath="..\..\soundlib\Load_stp.cpp" + > + </File> + <File RelativePath="..\..\soundlib\Load_ult.cpp" > </File> Index: vs2008/OpenMPT.vcproj =================================================================== --- vs2008/OpenMPT.vcproj (revision 6938) +++ vs2008/OpenMPT.vcproj (working copy) @@ -2553,6 +2553,10 @@ > </File> <File + RelativePath="..\..\soundlib\Load_stp.cpp" + > + </File> + <File RelativePath="..\..\soundlib\Load_ult.cpp" > </File> Index: vs2008w2k/libopenmpt-small.vcproj =================================================================== --- vs2008w2k/libopenmpt-small.vcproj (revision 6938) +++ vs2008w2k/libopenmpt-small.vcproj (working copy) @@ -1075,6 +1075,10 @@ > </File> <File + RelativePath="..\..\soundlib\Load_stp.cpp" + > + </File> + <File RelativePath="..\..\soundlib\Load_ult.cpp" > </File> Index: vs2008w2k/libopenmpt.vcproj =================================================================== --- vs2008w2k/libopenmpt.vcproj (revision 6938) +++ vs2008w2k/libopenmpt.vcproj (working copy) @@ -1079,6 +1079,10 @@ > </File> <File + RelativePath="..\..\soundlib\Load_stp.cpp" + > + </File> + <File RelativePath="..\..\soundlib\Load_ult.cpp" > </File> Index: vs2008w2k/libopenmpt_test.vcproj =================================================================== --- vs2008w2k/libopenmpt_test.vcproj (revision 6938) +++ vs2008w2k/libopenmpt_test.vcproj (working copy) @@ -807,6 +807,10 @@ > </File> <File + RelativePath="..\..\soundlib\Load_stp.cpp" + > + </File> + <File RelativePath="..\..\soundlib\Load_ult.cpp" > </File> Index: vs2008w2k/OpenMPT.vcproj =================================================================== --- vs2008w2k/OpenMPT.vcproj (revision 6938) +++ vs2008w2k/OpenMPT.vcproj (working copy) @@ -2553,6 +2553,10 @@ > </File> <File + RelativePath="..\..\soundlib\Load_stp.cpp" + > + </File> + <File RelativePath="..\..\soundlib\Load_ult.cpp" > </File> Index: vs2010/libopenmpt-small.vcxproj =================================================================== --- vs2010/libopenmpt-small.vcxproj (revision 6938) +++ vs2010/libopenmpt-small.vcxproj (working copy) @@ -510,6 +510,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2010/libopenmpt-small.vcxproj.filters =================================================================== --- vs2010/libopenmpt-small.vcxproj.filters (revision 6938) +++ vs2010/libopenmpt-small.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2010/libopenmpt.vcxproj =================================================================== --- vs2010/libopenmpt.vcxproj (revision 6938) +++ vs2010/libopenmpt.vcxproj (working copy) @@ -510,6 +510,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2010/libopenmpt.vcxproj.filters =================================================================== --- vs2010/libopenmpt.vcxproj.filters (revision 6938) +++ vs2010/libopenmpt.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2010/libopenmpt_test.vcxproj =================================================================== --- vs2010/libopenmpt_test.vcxproj (revision 6938) +++ vs2010/libopenmpt_test.vcxproj (working copy) @@ -358,6 +358,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2010/libopenmpt_test.vcxproj.filters =================================================================== --- vs2010/libopenmpt_test.vcxproj.filters (revision 6938) +++ vs2010/libopenmpt_test.vcxproj.filters (working copy) @@ -521,6 +521,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2010/OpenMPT.vcxproj =================================================================== --- vs2010/OpenMPT.vcxproj (revision 6938) +++ vs2010/OpenMPT.vcxproj (working copy) @@ -1047,6 +1047,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2010/OpenMPT.vcxproj.filters =================================================================== --- vs2010/OpenMPT.vcxproj.filters (revision 6938) +++ vs2010/OpenMPT.vcxproj.filters (working copy) @@ -1160,6 +1160,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2010xp/libopenmpt-small.vcxproj =================================================================== --- vs2010xp/libopenmpt-small.vcxproj (revision 6938) +++ vs2010xp/libopenmpt-small.vcxproj (working copy) @@ -508,6 +508,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2010xp/libopenmpt-small.vcxproj.filters =================================================================== --- vs2010xp/libopenmpt-small.vcxproj.filters (revision 6938) +++ vs2010xp/libopenmpt-small.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2010xp/libopenmpt.vcxproj =================================================================== --- vs2010xp/libopenmpt.vcxproj (revision 6938) +++ vs2010xp/libopenmpt.vcxproj (working copy) @@ -508,6 +508,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2010xp/libopenmpt.vcxproj.filters =================================================================== --- vs2010xp/libopenmpt.vcxproj.filters (revision 6938) +++ vs2010xp/libopenmpt.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2010xp/libopenmpt_test.vcxproj =================================================================== --- vs2010xp/libopenmpt_test.vcxproj (revision 6938) +++ vs2010xp/libopenmpt_test.vcxproj (working copy) @@ -357,6 +357,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2010xp/libopenmpt_test.vcxproj.filters =================================================================== --- vs2010xp/libopenmpt_test.vcxproj.filters (revision 6938) +++ vs2010xp/libopenmpt_test.vcxproj.filters (working copy) @@ -521,6 +521,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2010xp/OpenMPT.vcxproj =================================================================== --- vs2010xp/OpenMPT.vcxproj (revision 6938) +++ vs2010xp/OpenMPT.vcxproj (working copy) @@ -1044,6 +1044,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2010xp/OpenMPT.vcxproj.filters =================================================================== --- vs2010xp/OpenMPT.vcxproj.filters (revision 6938) +++ vs2010xp/OpenMPT.vcxproj.filters (working copy) @@ -1160,6 +1160,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2012/libopenmpt-small.vcxproj =================================================================== --- vs2012/libopenmpt-small.vcxproj (revision 6938) +++ vs2012/libopenmpt-small.vcxproj (working copy) @@ -518,6 +518,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2012/libopenmpt-small.vcxproj.filters =================================================================== --- vs2012/libopenmpt-small.vcxproj.filters (revision 6938) +++ vs2012/libopenmpt-small.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2012/libopenmpt.vcxproj =================================================================== --- vs2012/libopenmpt.vcxproj (revision 6938) +++ vs2012/libopenmpt.vcxproj (working copy) @@ -518,6 +518,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2012/libopenmpt.vcxproj.filters =================================================================== --- vs2012/libopenmpt.vcxproj.filters (revision 6938) +++ vs2012/libopenmpt.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2012/libopenmpt_test.vcxproj =================================================================== --- vs2012/libopenmpt_test.vcxproj (revision 6938) +++ vs2012/libopenmpt_test.vcxproj (working copy) @@ -362,6 +362,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2012/libopenmpt_test.vcxproj.filters =================================================================== --- vs2012/libopenmpt_test.vcxproj.filters (revision 6938) +++ vs2012/libopenmpt_test.vcxproj.filters (working copy) @@ -521,6 +521,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2012/OpenMPT.vcxproj =================================================================== --- vs2012/OpenMPT.vcxproj (revision 6938) +++ vs2012/OpenMPT.vcxproj (working copy) @@ -1059,6 +1059,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2012/OpenMPT.vcxproj.filters =================================================================== --- vs2012/OpenMPT.vcxproj.filters (revision 6938) +++ vs2012/OpenMPT.vcxproj.filters (working copy) @@ -1160,6 +1160,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2012xp/libopenmpt-small.vcxproj =================================================================== --- vs2012xp/libopenmpt-small.vcxproj (revision 6938) +++ vs2012xp/libopenmpt-small.vcxproj (working copy) @@ -518,6 +518,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2012xp/libopenmpt-small.vcxproj.filters =================================================================== --- vs2012xp/libopenmpt-small.vcxproj.filters (revision 6938) +++ vs2012xp/libopenmpt-small.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2012xp/libopenmpt.vcxproj =================================================================== --- vs2012xp/libopenmpt.vcxproj (revision 6938) +++ vs2012xp/libopenmpt.vcxproj (working copy) @@ -518,6 +518,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2012xp/libopenmpt.vcxproj.filters =================================================================== --- vs2012xp/libopenmpt.vcxproj.filters (revision 6938) +++ vs2012xp/libopenmpt.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2012xp/libopenmpt_test.vcxproj =================================================================== --- vs2012xp/libopenmpt_test.vcxproj (revision 6938) +++ vs2012xp/libopenmpt_test.vcxproj (working copy) @@ -362,6 +362,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2012xp/libopenmpt_test.vcxproj.filters =================================================================== --- vs2012xp/libopenmpt_test.vcxproj.filters (revision 6938) +++ vs2012xp/libopenmpt_test.vcxproj.filters (working copy) @@ -521,6 +521,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2012xp/OpenMPT.vcxproj =================================================================== --- vs2012xp/OpenMPT.vcxproj (revision 6938) +++ vs2012xp/OpenMPT.vcxproj (working copy) @@ -1059,6 +1059,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2012xp/OpenMPT.vcxproj.filters =================================================================== --- vs2012xp/OpenMPT.vcxproj.filters (revision 6938) +++ vs2012xp/OpenMPT.vcxproj.filters (working copy) @@ -1160,6 +1160,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2013/libopenmpt-small.vcxproj =================================================================== --- vs2013/libopenmpt-small.vcxproj (revision 6938) +++ vs2013/libopenmpt-small.vcxproj (working copy) @@ -519,6 +519,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2013/libopenmpt-small.vcxproj.filters =================================================================== --- vs2013/libopenmpt-small.vcxproj.filters (revision 6938) +++ vs2013/libopenmpt-small.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2013/libopenmpt.vcxproj =================================================================== --- vs2013/libopenmpt.vcxproj (revision 6938) +++ vs2013/libopenmpt.vcxproj (working copy) @@ -519,6 +519,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2013/libopenmpt.vcxproj.filters =================================================================== --- vs2013/libopenmpt.vcxproj.filters (revision 6938) +++ vs2013/libopenmpt.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2013/libopenmpt_test.vcxproj =================================================================== --- vs2013/libopenmpt_test.vcxproj (revision 6938) +++ vs2013/libopenmpt_test.vcxproj (working copy) @@ -363,6 +363,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2013/libopenmpt_test.vcxproj.filters =================================================================== --- vs2013/libopenmpt_test.vcxproj.filters (revision 6938) +++ vs2013/libopenmpt_test.vcxproj.filters (working copy) @@ -521,6 +521,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2013/OpenMPT.vcxproj =================================================================== --- vs2013/OpenMPT.vcxproj (revision 6938) +++ vs2013/OpenMPT.vcxproj (working copy) @@ -1060,6 +1060,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2013/OpenMPT.vcxproj.filters =================================================================== --- vs2013/OpenMPT.vcxproj.filters (revision 6938) +++ vs2013/OpenMPT.vcxproj.filters (working copy) @@ -1160,6 +1160,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2013xp/libopenmpt-small.vcxproj =================================================================== --- vs2013xp/libopenmpt-small.vcxproj (revision 6938) +++ vs2013xp/libopenmpt-small.vcxproj (working copy) @@ -519,6 +519,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2013xp/libopenmpt-small.vcxproj.filters =================================================================== --- vs2013xp/libopenmpt-small.vcxproj.filters (revision 6938) +++ vs2013xp/libopenmpt-small.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2013xp/libopenmpt.vcxproj =================================================================== --- vs2013xp/libopenmpt.vcxproj (revision 6938) +++ vs2013xp/libopenmpt.vcxproj (working copy) @@ -519,6 +519,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2013xp/libopenmpt.vcxproj.filters =================================================================== --- vs2013xp/libopenmpt.vcxproj.filters (revision 6938) +++ vs2013xp/libopenmpt.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2013xp/libopenmpt_test.vcxproj =================================================================== --- vs2013xp/libopenmpt_test.vcxproj (revision 6938) +++ vs2013xp/libopenmpt_test.vcxproj (working copy) @@ -363,6 +363,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2013xp/libopenmpt_test.vcxproj.filters =================================================================== --- vs2013xp/libopenmpt_test.vcxproj.filters (revision 6938) +++ vs2013xp/libopenmpt_test.vcxproj.filters (working copy) @@ -521,6 +521,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2013xp/OpenMPT.vcxproj =================================================================== --- vs2013xp/OpenMPT.vcxproj (revision 6938) +++ vs2013xp/OpenMPT.vcxproj (working copy) @@ -1060,6 +1060,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2013xp/OpenMPT.vcxproj.filters =================================================================== --- vs2013xp/OpenMPT.vcxproj.filters (revision 6938) +++ vs2013xp/OpenMPT.vcxproj.filters (working copy) @@ -1160,6 +1160,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2015/libopenmpt-small.vcxproj =================================================================== --- vs2015/libopenmpt-small.vcxproj (revision 6938) +++ vs2015/libopenmpt-small.vcxproj (working copy) @@ -519,6 +519,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2015/libopenmpt-small.vcxproj.filters =================================================================== --- vs2015/libopenmpt-small.vcxproj.filters (revision 6938) +++ vs2015/libopenmpt-small.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2015/libopenmpt.vcxproj =================================================================== --- vs2015/libopenmpt.vcxproj (revision 6938) +++ vs2015/libopenmpt.vcxproj (working copy) @@ -519,6 +519,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2015/libopenmpt.vcxproj.filters =================================================================== --- vs2015/libopenmpt.vcxproj.filters (revision 6938) +++ vs2015/libopenmpt.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2015/libopenmpt_test.vcxproj =================================================================== --- vs2015/libopenmpt_test.vcxproj (revision 6938) +++ vs2015/libopenmpt_test.vcxproj (working copy) @@ -363,6 +363,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2015/libopenmpt_test.vcxproj.filters =================================================================== --- vs2015/libopenmpt_test.vcxproj.filters (revision 6938) +++ vs2015/libopenmpt_test.vcxproj.filters (working copy) @@ -521,6 +521,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2015/OpenMPT.vcxproj =================================================================== --- vs2015/OpenMPT.vcxproj (revision 6938) +++ vs2015/OpenMPT.vcxproj (working copy) @@ -1060,6 +1060,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2015/OpenMPT.vcxproj.filters =================================================================== --- vs2015/OpenMPT.vcxproj.filters (revision 6938) +++ vs2015/OpenMPT.vcxproj.filters (working copy) @@ -1169,6 +1169,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2015xp/libopenmpt-small.vcxproj =================================================================== --- vs2015xp/libopenmpt-small.vcxproj (revision 6938) +++ vs2015xp/libopenmpt-small.vcxproj (working copy) @@ -519,6 +519,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2015xp/libopenmpt-small.vcxproj.filters =================================================================== --- vs2015xp/libopenmpt-small.vcxproj.filters (revision 6938) +++ vs2015xp/libopenmpt-small.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2015xp/libopenmpt.vcxproj =================================================================== --- vs2015xp/libopenmpt.vcxproj (revision 6938) +++ vs2015xp/libopenmpt.vcxproj (working copy) @@ -519,6 +519,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2015xp/libopenmpt.vcxproj.filters =================================================================== --- vs2015xp/libopenmpt.vcxproj.filters (revision 6938) +++ vs2015xp/libopenmpt.vcxproj.filters (working copy) @@ -503,6 +503,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2015xp/libopenmpt_test.vcxproj =================================================================== --- vs2015xp/libopenmpt_test.vcxproj (revision 6938) +++ vs2015xp/libopenmpt_test.vcxproj (working copy) @@ -363,6 +363,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2015xp/libopenmpt_test.vcxproj.filters =================================================================== --- vs2015xp/libopenmpt_test.vcxproj.filters (revision 6938) +++ vs2015xp/libopenmpt_test.vcxproj.filters (working copy) @@ -521,6 +521,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: vs2015xp/OpenMPT.vcxproj =================================================================== --- vs2015xp/OpenMPT.vcxproj (revision 6938) +++ vs2015xp/OpenMPT.vcxproj (working copy) @@ -1060,6 +1060,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: vs2015xp/OpenMPT.vcxproj.filters =================================================================== --- vs2015xp/OpenMPT.vcxproj.filters (revision 6938) +++ vs2015xp/OpenMPT.vcxproj.filters (working copy) @@ -1169,6 +1169,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> | ||||
Has the bug occurred in previous versions? | |||||
Tested code revision (in case you know it) | |||||
A few comments (I did not check the whole patch yet and I'm not the expert on various file formats):
|
|
I'll attach a newer patch later, pending any other feedback you guys have. |
|
Regarding 4, it's a mixture between "most used" and "how sane are the magic bytes". For example, M15 needs to be the last because it has no magic bytes at all, and 669 should be one of the last because its magic bytes are "if" (which could conflict with song titles in various module formats). |
|
Do you know how relevant the missing features are for most modules? It's always nice to add support for new formats of course, but I would like to not repeat errors of the past and add support for tons of only partially-supported formats when there are already good players out there. For example, would there be many modules that require multiple sample loops? Can this feature maybe be faked using sustain loops or duplicating sample slots? |
|
It's hard to say, since there don't seem to be a lot of publicly-available modules in the format to begin with and none of the few available on Modland use any "weird" features other than fractional speed values. Faking some of the features like multiple loops would probably be doable but I think I'd have to make up some example modules myself just to see exactly how the tracker itself handles them. |
|
Ok, after actually checking out the feature in the tracker, here's a basic summary. If a sample has just one loop, it's handled as normal; otherwise, all the looped sections are played one after another, starting from the first loop's start point instead of the beginning of the sample (basically, automatic beat slicing). Normally each looped section is played once at a time, in order, returning to the first one after playing the final one. This can be faked easily by just messing with the sample data at load time. The not-so-easy part is the effects, which make different behavior: 16xx: start sample at loop-start number xx (can easily be done with "set offset" command but probably with some loss of precision) (The params are decimal numbers 01-99, out of range values (including 00) are the same as using 01) Effects 17/18/19 could be handled by just making duplicate samples as needed, although the implementation might get a little hairy. I'd love to be able to get my hands on some modules that actually use this feature (or any other modules in this format at all, really), but for now all I have is the very small/simple selection on Modland. I might try to contact the author of the tracker at some point in search of some more, though. (On that note, there's also of course a Soundtracker Pro 1, which seems to essentially be Ultimate Soundtracker with the same fractional-speed feature and variable pattern lengths. But I can't find any modules for it online and I can't get it to recognize keyboard input in WinUAE, so I doubt I'll bother trying to handle that one...) |
|
16xx: start sample at loop-start number xx (can easily be done with "set offset" command but probably with some loss of precision) The MPTM volume command VOLCMD_OFFSET can be used for that, as you get 9 freely definable offset positions. Given the number of trackers in the 90s, it's very much possible that ModLand's representation is accurate that noone just ever used the feature. |
|
Yeah, unfortunately I've had pretty much the same assumption. It's a pretty interesting and fairly sophisticated tracker, but I guess by 1996 anyone interested in the concept of a "pro" Amiga tracker was probably already using OctaMED instead. Anyway, if you're still interested in actually supporting the format, I can at least add basic loop sequence support and the 16xx effect and post a new patch. |
|
Sure, go ahead. :) |
|
Uploaded a second patch which handles all four of the "loop sequence" effects using cue points and sample duplication. I also fixed some other effect behavior (auto volume slide / auto global volume slide should be treated as fine slides, not normal ones). Crappy loop test file that I made in about five minutes: There are probably still some weird effect quirks that I'm totally unaware of, but... |
|
I've now finally started looking into this loader a bit more, and it's a bit brittle, so I'm not sure if it will make it into the next release (it will require a big review). Problems fixed so far:
I hope this list helps with implementing future loaders. ;) By now it might make sense to introduce auto-slide commands in OpenMPT since they are used in several formats. |
|
I'm also not quite sure if this module plays as intended - see samples 10 and 11: |
|
I've attached the current status of the code to this issue (stpro2_r3.patch). I haven't had a look at it in a while now, but I'm still hesistant to add it in its current shape. Given the whopping amount of five modules on ModLand, I guess it's not too urgent to support this format. |
|
No functional changes, but I updated the patch to make use of the recent endianness-related code changes. |
|
I've uploaded some mod files, see link bellow. https://drive.google.com/file/d/0B1qzOm-C-64iZ1ktLUd4aHM2UXM/view?usp=sharing Thanks for all the effort! |
|
Hey Revenant, I hope you're still around. I am now finally ready to merge this patch after a few remaining modifications. |
|
For the reference, here's the current state of the loader. stpro2_r5.patch (70,513 bytes)
Index: build/android_ndk/Android.mk =================================================================== --- build/android_ndk/Android.mk (revision 7555) +++ build/android_ndk/Android.mk (working copy) @@ -187,6 +187,7 @@ soundlib/Load_s3m.cpp \ soundlib/Load_sfx.cpp \ soundlib/Load_stm.cpp \ + soundlib/Load_stp.cpp \ soundlib/Load_ult.cpp \ soundlib/Load_umx.cpp \ soundlib/Load_wav.cpp \ Index: build/autotools/Makefile.am =================================================================== --- build/autotools/Makefile.am (revision 7555) +++ build/autotools/Makefile.am (working copy) @@ -205,6 +205,7 @@ libopenmpt_la_SOURCES += soundlib/Load_s3m.cpp libopenmpt_la_SOURCES += soundlib/Load_sfx.cpp libopenmpt_la_SOURCES += soundlib/Load_stm.cpp +libopenmpt_la_SOURCES += soundlib/Load_stp.cpp libopenmpt_la_SOURCES += soundlib/Load_ult.cpp libopenmpt_la_SOURCES += soundlib/Load_umx.cpp libopenmpt_la_SOURCES += soundlib/Load_wav.cpp @@ -463,6 +464,7 @@ libopenmpttest_SOURCES += soundlib/Load_s3m.cpp libopenmpttest_SOURCES += soundlib/Load_sfx.cpp libopenmpttest_SOURCES += soundlib/Load_stm.cpp +libopenmpttest_SOURCES += soundlib/Load_stp.cpp libopenmpttest_SOURCES += soundlib/Load_ult.cpp libopenmpttest_SOURCES += soundlib/Load_umx.cpp libopenmpttest_SOURCES += soundlib/Load_wav.cpp Index: build/vs2010/libopenmpt-small.vcxproj =================================================================== --- build/vs2010/libopenmpt-small.vcxproj (revision 7555) +++ build/vs2010/libopenmpt-small.vcxproj (working copy) @@ -529,6 +529,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2010/libopenmpt-small.vcxproj.filters =================================================================== --- build/vs2010/libopenmpt-small.vcxproj.filters (revision 7555) +++ build/vs2010/libopenmpt-small.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2010/libopenmpt.vcxproj =================================================================== --- build/vs2010/libopenmpt.vcxproj (revision 7555) +++ build/vs2010/libopenmpt.vcxproj (working copy) @@ -529,6 +529,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2010/libopenmpt.vcxproj.filters =================================================================== --- build/vs2010/libopenmpt.vcxproj.filters (revision 7555) +++ build/vs2010/libopenmpt.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2010/libopenmpt_test.vcxproj =================================================================== --- build/vs2010/libopenmpt_test.vcxproj (revision 7555) +++ build/vs2010/libopenmpt_test.vcxproj (working copy) @@ -361,6 +361,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2010/libopenmpt_test.vcxproj.filters =================================================================== --- build/vs2010/libopenmpt_test.vcxproj.filters (revision 7555) +++ build/vs2010/libopenmpt_test.vcxproj.filters (working copy) @@ -533,6 +533,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2010xp/libopenmpt-small.vcxproj =================================================================== --- build/vs2010xp/libopenmpt-small.vcxproj (revision 7555) +++ build/vs2010xp/libopenmpt-small.vcxproj (working copy) @@ -527,6 +527,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2010xp/libopenmpt-small.vcxproj.filters =================================================================== --- build/vs2010xp/libopenmpt-small.vcxproj.filters (revision 7555) +++ build/vs2010xp/libopenmpt-small.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2010xp/libopenmpt.vcxproj =================================================================== --- build/vs2010xp/libopenmpt.vcxproj (revision 7555) +++ build/vs2010xp/libopenmpt.vcxproj (working copy) @@ -527,6 +527,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2010xp/libopenmpt.vcxproj.filters =================================================================== --- build/vs2010xp/libopenmpt.vcxproj.filters (revision 7555) +++ build/vs2010xp/libopenmpt.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2010xp/libopenmpt_test.vcxproj =================================================================== --- build/vs2010xp/libopenmpt_test.vcxproj (revision 7555) +++ build/vs2010xp/libopenmpt_test.vcxproj (working copy) @@ -360,6 +360,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2010xp/libopenmpt_test.vcxproj.filters =================================================================== --- build/vs2010xp/libopenmpt_test.vcxproj.filters (revision 7555) +++ build/vs2010xp/libopenmpt_test.vcxproj.filters (working copy) @@ -533,6 +533,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2012/libopenmpt-small.vcxproj =================================================================== --- build/vs2012/libopenmpt-small.vcxproj (revision 7555) +++ build/vs2012/libopenmpt-small.vcxproj (working copy) @@ -537,6 +537,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2012/libopenmpt-small.vcxproj.filters =================================================================== --- build/vs2012/libopenmpt-small.vcxproj.filters (revision 7555) +++ build/vs2012/libopenmpt-small.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2012/libopenmpt.vcxproj =================================================================== --- build/vs2012/libopenmpt.vcxproj (revision 7555) +++ build/vs2012/libopenmpt.vcxproj (working copy) @@ -537,6 +537,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2012/libopenmpt.vcxproj.filters =================================================================== --- build/vs2012/libopenmpt.vcxproj.filters (revision 7555) +++ build/vs2012/libopenmpt.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2012/libopenmpt_test.vcxproj =================================================================== --- build/vs2012/libopenmpt_test.vcxproj (revision 7555) +++ build/vs2012/libopenmpt_test.vcxproj (working copy) @@ -365,6 +365,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2012/libopenmpt_test.vcxproj.filters =================================================================== --- build/vs2012/libopenmpt_test.vcxproj.filters (revision 7555) +++ build/vs2012/libopenmpt_test.vcxproj.filters (working copy) @@ -533,6 +533,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2012xp/libopenmpt-small.vcxproj =================================================================== --- build/vs2012xp/libopenmpt-small.vcxproj (revision 7555) +++ build/vs2012xp/libopenmpt-small.vcxproj (working copy) @@ -537,6 +537,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2012xp/libopenmpt-small.vcxproj.filters =================================================================== --- build/vs2012xp/libopenmpt-small.vcxproj.filters (revision 7555) +++ build/vs2012xp/libopenmpt-small.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2012xp/libopenmpt.vcxproj =================================================================== --- build/vs2012xp/libopenmpt.vcxproj (revision 7555) +++ build/vs2012xp/libopenmpt.vcxproj (working copy) @@ -537,6 +537,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2012xp/libopenmpt.vcxproj.filters =================================================================== --- build/vs2012xp/libopenmpt.vcxproj.filters (revision 7555) +++ build/vs2012xp/libopenmpt.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2012xp/libopenmpt_test.vcxproj =================================================================== --- build/vs2012xp/libopenmpt_test.vcxproj (revision 7555) +++ build/vs2012xp/libopenmpt_test.vcxproj (working copy) @@ -365,6 +365,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2012xp/libopenmpt_test.vcxproj.filters =================================================================== --- build/vs2012xp/libopenmpt_test.vcxproj.filters (revision 7555) +++ build/vs2012xp/libopenmpt_test.vcxproj.filters (working copy) @@ -533,6 +533,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2013/libopenmpt-small.vcxproj =================================================================== --- build/vs2013/libopenmpt-small.vcxproj (revision 7555) +++ build/vs2013/libopenmpt-small.vcxproj (working copy) @@ -538,6 +538,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2013/libopenmpt-small.vcxproj.filters =================================================================== --- build/vs2013/libopenmpt-small.vcxproj.filters (revision 7555) +++ build/vs2013/libopenmpt-small.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2013/libopenmpt.vcxproj =================================================================== --- build/vs2013/libopenmpt.vcxproj (revision 7555) +++ build/vs2013/libopenmpt.vcxproj (working copy) @@ -538,6 +538,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2013/libopenmpt.vcxproj.filters =================================================================== --- build/vs2013/libopenmpt.vcxproj.filters (revision 7555) +++ build/vs2013/libopenmpt.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2013/libopenmpt_test.vcxproj =================================================================== --- build/vs2013/libopenmpt_test.vcxproj (revision 7555) +++ build/vs2013/libopenmpt_test.vcxproj (working copy) @@ -366,6 +366,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2013/libopenmpt_test.vcxproj.filters =================================================================== --- build/vs2013/libopenmpt_test.vcxproj.filters (revision 7555) +++ build/vs2013/libopenmpt_test.vcxproj.filters (working copy) @@ -533,6 +533,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2013/OpenMPT.vcxproj =================================================================== --- build/vs2013/OpenMPT.vcxproj (revision 7555) +++ build/vs2013/OpenMPT.vcxproj (working copy) @@ -1062,6 +1062,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2013/OpenMPT.vcxproj.filters =================================================================== --- build/vs2013/OpenMPT.vcxproj.filters (revision 7555) +++ build/vs2013/OpenMPT.vcxproj.filters (working copy) @@ -1169,6 +1169,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2013xp/libopenmpt-small.vcxproj =================================================================== --- build/vs2013xp/libopenmpt-small.vcxproj (revision 7555) +++ build/vs2013xp/libopenmpt-small.vcxproj (working copy) @@ -538,6 +538,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2013xp/libopenmpt-small.vcxproj.filters =================================================================== --- build/vs2013xp/libopenmpt-small.vcxproj.filters (revision 7555) +++ build/vs2013xp/libopenmpt-small.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2013xp/libopenmpt.vcxproj =================================================================== --- build/vs2013xp/libopenmpt.vcxproj (revision 7555) +++ build/vs2013xp/libopenmpt.vcxproj (working copy) @@ -538,6 +538,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2013xp/libopenmpt.vcxproj.filters =================================================================== --- build/vs2013xp/libopenmpt.vcxproj.filters (revision 7555) +++ build/vs2013xp/libopenmpt.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2013xp/libopenmpt_test.vcxproj =================================================================== --- build/vs2013xp/libopenmpt_test.vcxproj (revision 7555) +++ build/vs2013xp/libopenmpt_test.vcxproj (working copy) @@ -366,6 +366,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2013xp/libopenmpt_test.vcxproj.filters =================================================================== --- build/vs2013xp/libopenmpt_test.vcxproj.filters (revision 7555) +++ build/vs2013xp/libopenmpt_test.vcxproj.filters (working copy) @@ -533,6 +533,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2013xp/OpenMPT.vcxproj =================================================================== --- build/vs2013xp/OpenMPT.vcxproj (revision 7555) +++ build/vs2013xp/OpenMPT.vcxproj (working copy) @@ -1062,6 +1062,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2013xp/OpenMPT.vcxproj.filters =================================================================== --- build/vs2013xp/OpenMPT.vcxproj.filters (revision 7555) +++ build/vs2013xp/OpenMPT.vcxproj.filters (working copy) @@ -1169,6 +1169,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2015/libopenmpt-small.vcxproj =================================================================== --- build/vs2015/libopenmpt-small.vcxproj (revision 7555) +++ build/vs2015/libopenmpt-small.vcxproj (working copy) @@ -538,6 +538,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2015/libopenmpt-small.vcxproj.filters =================================================================== --- build/vs2015/libopenmpt-small.vcxproj.filters (revision 7555) +++ build/vs2015/libopenmpt-small.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2015/libopenmpt.vcxproj =================================================================== --- build/vs2015/libopenmpt.vcxproj (revision 7555) +++ build/vs2015/libopenmpt.vcxproj (working copy) @@ -538,6 +538,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2015/libopenmpt.vcxproj.filters =================================================================== --- build/vs2015/libopenmpt.vcxproj.filters (revision 7555) +++ build/vs2015/libopenmpt.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2015/libopenmpt_test.vcxproj =================================================================== --- build/vs2015/libopenmpt_test.vcxproj (revision 7555) +++ build/vs2015/libopenmpt_test.vcxproj (working copy) @@ -366,6 +366,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2015/libopenmpt_test.vcxproj.filters =================================================================== --- build/vs2015/libopenmpt_test.vcxproj.filters (revision 7555) +++ build/vs2015/libopenmpt_test.vcxproj.filters (working copy) @@ -533,6 +533,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2015/OpenMPT.vcxproj =================================================================== --- build/vs2015/OpenMPT.vcxproj (revision 7555) +++ build/vs2015/OpenMPT.vcxproj (working copy) @@ -1062,6 +1062,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2015/OpenMPT.vcxproj.filters =================================================================== --- build/vs2015/OpenMPT.vcxproj.filters (revision 7555) +++ build/vs2015/OpenMPT.vcxproj.filters (working copy) @@ -1178,6 +1178,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2015xp/libopenmpt-small.vcxproj =================================================================== --- build/vs2015xp/libopenmpt-small.vcxproj (revision 7555) +++ build/vs2015xp/libopenmpt-small.vcxproj (working copy) @@ -538,6 +538,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2015xp/libopenmpt-small.vcxproj.filters =================================================================== --- build/vs2015xp/libopenmpt-small.vcxproj.filters (revision 7555) +++ build/vs2015xp/libopenmpt-small.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2015xp/libopenmpt.vcxproj =================================================================== --- build/vs2015xp/libopenmpt.vcxproj (revision 7555) +++ build/vs2015xp/libopenmpt.vcxproj (working copy) @@ -538,6 +538,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2015xp/libopenmpt.vcxproj.filters =================================================================== --- build/vs2015xp/libopenmpt.vcxproj.filters (revision 7555) +++ build/vs2015xp/libopenmpt.vcxproj.filters (working copy) @@ -515,6 +515,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2015xp/libopenmpt_test.vcxproj =================================================================== --- build/vs2015xp/libopenmpt_test.vcxproj (revision 7555) +++ build/vs2015xp/libopenmpt_test.vcxproj (working copy) @@ -366,6 +366,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2015xp/libopenmpt_test.vcxproj.filters =================================================================== --- build/vs2015xp/libopenmpt_test.vcxproj.filters (revision 7555) +++ build/vs2015xp/libopenmpt_test.vcxproj.filters (working copy) @@ -533,6 +533,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: build/vs2015xp/OpenMPT.vcxproj =================================================================== --- build/vs2015xp/OpenMPT.vcxproj (revision 7555) +++ build/vs2015xp/OpenMPT.vcxproj (working copy) @@ -1062,6 +1062,7 @@ <ClCompile Include="..\..\soundlib\Load_s3m.cpp" /> <ClCompile Include="..\..\soundlib\Load_sfx.cpp" /> <ClCompile Include="..\..\soundlib\Load_stm.cpp" /> + <ClCompile Include="..\..\soundlib\Load_stp.cpp" /> <ClCompile Include="..\..\soundlib\Load_ult.cpp" /> <ClCompile Include="..\..\soundlib\Load_umx.cpp" /> <ClCompile Include="..\..\soundlib\Load_wav.cpp" /> Index: build/vs2015xp/OpenMPT.vcxproj.filters =================================================================== --- build/vs2015xp/OpenMPT.vcxproj.filters (revision 7555) +++ build/vs2015xp/OpenMPT.vcxproj.filters (working copy) @@ -1178,6 +1178,9 @@ <ClCompile Include="..\..\soundlib\Load_stm.cpp"> <Filter>soundlib</Filter> </ClCompile> + <ClCompile Include="..\..\soundlib\Load_stp.cpp"> + <Filter>soundlib</Filter> + </ClCompile> <ClCompile Include="..\..\soundlib\Load_ult.cpp"> <Filter>soundlib</Filter> </ClCompile> Index: installer/filetypes.iss =================================================================== --- installer/filetypes.iss (revision 7555) +++ installer/filetypes.iss (working copy) @@ -47,6 +47,7 @@ Name: "associate_exotic\sfx2"; Description: "SoundFX 2 (SFX2)"; Name: "associate_exotic\st26"; Description: "SoundTracker 2.6 (ST26)"; Name: "associate_exotic\stm"; Description: "Scream Tracker 2 (STM)"; +Name: "associate_exotic\stp"; Description: "Soundtracker Pro II (STP)"; Name: "associate_exotic\ult"; Description: "UltraTracker (ULT)"; Name: "associate_exotic\umx"; Description: "Unreal Music (UMX)"; Name: "associate_exotic\wow"; Description: "Grave Composer (WOW)"; @@ -95,6 +96,7 @@ Root: HKCR; Subkey: ".sfx2"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\sfx2 Root: HKCR; Subkey: ".st26"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\st26 Root: HKCR; Subkey: ".stm"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\stm +Root: HKCR; Subkey: ".stp"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\stp Root: HKCR; Subkey: ".ult"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\ult Root: HKCR; Subkey: ".umx"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\umx Root: HKCR; Subkey: ".wow"; ValueType: string; ValueName: ""; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: associate_exotic\wow @@ -165,6 +167,7 @@ Root: HKLM; Subkey: "Software\Clients\Media\OpenMPT\Capabilities\FileAssociations"; ValueType: string; ValueName: ".sfx2"; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Clients\Media\OpenMPT\Capabilities\FileAssociations"; ValueType: string; ValueName: ".st26"; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Clients\Media\OpenMPT\Capabilities\FileAssociations"; ValueType: string; ValueName: ".stm"; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: not portable +Root: HKLM; Subkey: "Software\Clients\Media\OpenMPT\Capabilities\FileAssociations"; ValueType: string; ValueName: ".stp"; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Clients\Media\OpenMPT\Capabilities\FileAssociations"; ValueType: string; ValueName: ".ult"; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Clients\Media\OpenMPT\Capabilities\FileAssociations"; ValueType: string; ValueName: ".umx"; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Clients\Media\OpenMPT\Capabilities\FileAssociations"; ValueType: string; ValueName: ".wow"; ValueData: "OpenMPTFile"; Flags: uninsdeletevalue; Tasks: not portable @@ -211,6 +214,7 @@ Root: HKLM; Subkey: "Software\Classes\Applications\mptrack.exe\SupportedTypes"; ValueType: string; ValueName: ".sfx2"; ValueData: ""; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Classes\Applications\mptrack.exe\SupportedTypes"; ValueType: string; ValueName: ".st26"; ValueData: ""; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Classes\Applications\mptrack.exe\SupportedTypes"; ValueType: string; ValueName: ".stm"; ValueData: ""; Flags: uninsdeletevalue; Tasks: not portable +Root: HKLM; Subkey: "Software\Classes\Applications\mptrack.exe\SupportedTypes"; ValueType: string; ValueName: ".stp"; ValueData: ""; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Classes\Applications\mptrack.exe\SupportedTypes"; ValueType: string; ValueName: ".ult"; ValueData: ""; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Classes\Applications\mptrack.exe\SupportedTypes"; ValueType: string; ValueName: ".umx"; ValueData: ""; Flags: uninsdeletevalue; Tasks: not portable Root: HKLM; Subkey: "Software\Classes\Applications\mptrack.exe\SupportedTypes"; ValueType: string; ValueName: ".wow"; ValueData: ""; Flags: uninsdeletevalue; Tasks: not portable Index: libopenmpt/foo_openmpt.cpp =================================================================== --- libopenmpt/foo_openmpt.cpp (revision 7555) +++ libopenmpt/foo_openmpt.cpp (working copy) @@ -319,6 +319,7 @@ "*.imf" ";" "*.j2b" ";" "*.plm" ";" + "*.stp" ";" "*.sfx" ";" "*.sfx2" ";" "*.mms" ";" Index: mptrack/Mptrack.cpp =================================================================== --- mptrack/Mptrack.cpp (revision 7555) +++ mptrack/Mptrack.cpp (working copy) @@ -1431,7 +1431,7 @@ "FastTracker Modules (*.xm)|*.xm;*.xmz|" "Impulse Tracker Modules (*.it)|*.it;*.itz|" "OpenMPT Modules (*.mptm)|*.mptm;*.mptmz|" - "Other Modules (mtm,okt,mdl,669,far,...)|*.mtm;*.669;*.ult;*.wow;*.far;*.mdl;*.okt;*.dmf;*.ptm;*.med;*.ams;*.dbm;*.digi;*.dsm;*.umx;*.amf;*.psm;*.mt2;*.gdm;*.imf;*.itp;*.j2b;*.ice;*.st26;*.plm;*.sfx;*.sfx2;*.mms|" + "Other Modules (mtm,okt,mdl,669,far,...)|*.mtm;*.669;*.ult;*.wow;*.far;*.mdl;*.okt;*.dmf;*.ptm;*.med;*.ams;*.dbm;*.digi;*.dsm;*.umx;*.amf;*.psm;*.mt2;*.gdm;*.imf;*.itp;*.j2b;*.ice;*.st26;*.plm;*.stp;*.sfx;*.sfx2;*.mms|" "Wave Files (*.wav)|*.wav|" "MIDI Files (*.mid,*.rmi)|*.mid;*.rmi;*.smf|" "All Files (*.*)|*.*||") Index: soundlib/Load_stp.cpp =================================================================== --- soundlib/Load_stp.cpp (nonexistent) +++ soundlib/Load_stp.cpp (working copy) @@ -0,0 +1,923 @@ +/* + * Load_stp.cpp + * ------------ + * Purpose: STP (Soundtracker Pro II) module loader + * Notes : A few exotic effects aren't supported. + * Multiple sample loops are supported, but only the first 10 can be used as cue points + * (with 16xx and 18xx). + * Fractional speed values and combined auto effects are handled whenever possible, + * but some effects may be omitted (and there may be tempo accuracy issues). + * Authors: Devin Acker + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + * + * Wisdom from the Soundtracker Pro II manual: + * "To create shorter patterns, simply create shorter patterns." + */ + +#include "stdafx.h" +#include "Loaders.h" + +OPENMPT_NAMESPACE_BEGIN + +// File header (except for "STP3" magic) +struct STPFileHeader +{ + uint16be version; + uint8be numOrders; + uint8be patternLength; + uint8be orderList[128]; + uint16be speed; + uint16be speedFrac; + uint16be timerCount; + uint16be flags; + uint32be reserved; + uint16be midiCount; // always 50 + uint8be midi[50]; + uint16be numSamples; + uint16be sampleStructSize; +}; + +MPT_BINARY_STRUCT(STPFileHeader, 200); + + +// Sample header (versions 0 and 1) +struct STPSampleHeaderOld +{ + char pathName[31]; + uint8be flags; + char fileName[30]; + uint32be length; + uint8be volume; + uint8be reserved1; + uint32be loopStart; + uint32be loopLength; + uint16be defaultCmd; + uint32be reserved2; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = length; + mptSmp.nVolume = 4u * std::min<uint16>(volume, 64); + + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + + if(mptSmp.nLoopStart >= mptSmp.nLength) + { + mptSmp.nLoopStart = mptSmp.nLength - 1; + } + if(mptSmp.nLoopEnd > mptSmp.nLength) + { + mptSmp.nLoopEnd = mptSmp.nLength; + } + + if(mptSmp.nLoopStart > mptSmp.nLoopEnd) + { + mptSmp.nLoopStart = 0; + mptSmp.nLoopEnd = 0; + } + else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) + { + mptSmp.uFlags.set(CHN_LOOP); + } + } + + void Read(FileReader &file) + { + file.ReadStruct(*this); + } +}; + +MPT_BINARY_STRUCT(STPSampleHeaderOld, 82); + + +// Sample header (version 2), no endian-defined integers due to variable string length and alignment in file (we read the fields manually) +struct STPSampleHeader +{ + //char pathName[256]; + uint8 flags; + char fileName[30]; + uint32 length; + uint8 volume; + uint8 reserved1; + uint32 loopStart; + uint32 loopLength; + uint16 defaultCmd; + uint16 defaultPeriod; + uint8 finetune; + uint8 reserved2; + + void ConvertToMPT(ModSample &mptSmp) const + { + mptSmp.Initialize(MOD_TYPE_MOD); + mptSmp.nLength = length; + mptSmp.nFineTune = static_cast<int8>(finetune << 3); + mptSmp.nVolume = 4 * std::min<uint8>(volume, 64); + + mptSmp.nLoopStart = loopStart; + mptSmp.nLoopEnd = loopStart + loopLength; + + if(mptSmp.nLoopStart >= mptSmp.nLength) + { + mptSmp.nLoopStart = mptSmp.nLength - 1; + } + if(mptSmp.nLoopEnd > mptSmp.nLength) + { + mptSmp.nLoopEnd = mptSmp.nLength; + } + + if(mptSmp.nLoopStart > mptSmp.nLoopEnd) + { + mptSmp.nLoopStart = 0; + mptSmp.nLoopEnd = 0; + } else if(mptSmp.nLoopEnd > mptSmp.nLoopStart) + { + mptSmp.cues[0] = mptSmp.nLoopStart; + mptSmp.uFlags.set(CHN_LOOP); + } + } + + void Read(FileReader &file) + { + std::string str; + + file.ReadNullString(str, 255); + //mpt::String::Copy(pathName, str); + + flags = file.ReadUint8(); + + file.ReadNullString(str, 29); + mpt::String::Copy(fileName, str); + + // seek to even boundary + if(file.GetPosition() % 2u) + file.Skip(1); + + length = file.ReadUint32BE(); + volume = file.ReadUint8(); + reserved1 = file.ReadUint8(); + + loopStart = file.ReadUint32BE(); + loopLength = file.ReadUint32BE(); + + defaultCmd = file.ReadUint16BE(); + defaultPeriod = file.ReadUint16BE(); + + finetune = file.ReadUint8(); + reserved2 = file.ReadUint8(); + } +}; + +struct STPLoopInfo +{ + SmpLength loopStart; + SmpLength loopLength; + SAMPLEINDEX looped; + SAMPLEINDEX nonLooped; +}; + +typedef std::vector<STPLoopInfo> STPLoopList; + +template <typename T> +static void ReadSample(FileReader &file, T &sampleHeader, ModSample &sample, char (&sampleName)[MAX_SAMPLENAME]) +//-------------------------------------------------------------------------------------------------------------- +{ + sampleHeader.Read(file); + sampleHeader.ConvertToMPT(sample); + + mpt::String::Read<mpt::String::maybeNullTerminated>(sampleName, sampleHeader.fileName); +} + + +static TEMPO ConvertTempo(uint16 ciaSpeed) +//---------------------------------------- +{ + // 3546 is the resulting CIA timer value when using 4F7D (tempo 125 bpm) command in STProII + return TEMPO((125.0 * 3546.0) / ciaSpeed); +} + + +static void ConvertLoopSlice(ModSample &src, ModSample &dest, SmpLength start, SmpLength len, bool loop) +//------------------------------------------------------------------------------------------------------ +{ + if(!src.HasSampleData()) return; + + dest.FreeSample(); + + dest = src; + dest.nLength = len; + dest.pSample = nullptr; + + if(!dest.AllocateSample()) + { + return; + } + + // only preserve cue points if the target sample length is the same + if(len != src.nLength) + MemsetZero(dest.cues); + + std::memcpy(dest.pSample8, src.pSample8 + start, len); + if(loop) + { + dest.nLoopStart = 0; + dest.nLoopEnd = len; + dest.uFlags.set(CHN_LOOP); + } else + { + dest.nLoopStart = 0; + dest.nLoopEnd = 0; + dest.uFlags.reset(CHN_LOOP); + } +} + +static void ConvertLoopSequence(ModSample &smp, STPLoopList &loopList) +//-------------------------------------------------------------------- +{ + // This should only modify a sample if it has more than one loop + // (otherwise, it behaves like a normal sample loop) + if(!smp.HasSampleData() || loopList.size() < 2) return; + + ModSample newSmp = smp; + newSmp.nLength = 0; + newSmp.pSample = nullptr; + + size_t numLoops = loopList.size(); + + // get the total length of the sample after combining all looped sections + for(size_t i = 0; i < numLoops; i++) + { + STPLoopInfo &info = loopList[i]; + + // if adding this loop would cause the sample length to exceed maximum, + // then limit and bail out + if((newSmp.nLength + info.loopLength > MAX_SAMPLE_LENGTH) || + (info.loopLength > MAX_SAMPLE_LENGTH) || + (info.loopStart + info.loopLength > smp.nLength)) + { + numLoops = i; + break; + } + + newSmp.nLength += info.loopLength; + } + + if(!newSmp.AllocateSample()) + { + return; + } + + // start copying the looped sample data parts + SmpLength start = 0; + + for(size_t i = 0; i < numLoops; i++) + { + STPLoopInfo &info = loopList[i]; + + memcpy(newSmp.pSample8 + start, smp.pSample8 + info.loopStart, info.loopLength); + + // update loop info based on position in edited sample + info.loopStart = start; + if(i > 0 && i <= CountOf(newSmp.cues)) + { + newSmp.cues[i - 1] = start; + } + start += info.loopLength; + } + + // replace old sample with new one + smp.FreeSample(); + smp = newSmp; + + smp.nLoopStart = 0; + smp.nLoopEnd = smp.nLength; + smp.uFlags.set(CHN_LOOP); +} + + +bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags) +//------------------------------------------------------------------- +{ + file.Rewind(); + if(!file.ReadMagic("STP3")) + return false; + + STPFileHeader fileHeader; + file.ReadStruct(fileHeader); + if(fileHeader.version > 2 + || fileHeader.numOrders > 128 + || fileHeader.numSamples >= MAX_SAMPLES + || fileHeader.midiCount != 50) + return false; + + if(loadFlags == onlyVerifyHeader) + return true; + + InitializeGlobals(MOD_TYPE_STP); + + m_nChannels = 4; + m_nSamples = 0; + m_nInstruments = 0; + + m_nDefaultSpeed = fileHeader.speed; + m_nDefaultTempo = ConvertTempo(fileHeader.timerCount); + + m_nMinPeriod = 14 * 4; + m_nMaxPeriod = 3424 * 4; + + Order.ReadFromArray(fileHeader.orderList, fileHeader.numOrders); + + std::vector<STPLoopList> loopInfo; + // non-looped versions of samples with loops (when needed) + std::vector<SAMPLEINDEX> nonLooped; + + // Load sample headers + SAMPLEINDEX samplesInFile = 0; + + for(SAMPLEINDEX smp = 1; smp <= fileHeader.numSamples; smp++) + { + // this is 1-based the same as smp + SAMPLEINDEX actualSmp = file.ReadUint16BE(); + if(actualSmp >= MAX_SAMPLES) + return false; + + samplesInFile = m_nSamples = std::max(m_nSamples, actualSmp); + + ModSample &thisSmp = Samples[actualSmp]; + + if(fileHeader.version == 2) + { + STPSampleHeader sampleHeader; + uint32 headerSize = file.ReadUint32BE(); + + ReadSample(file, sampleHeader, thisSmp, m_szNames[actualSmp]); + // TODO: verify string lengths against headerSize? + MPT_UNUSED_VARIABLE(headerSize); + } else + { + STPSampleHeaderOld sampleHeaderOld; + ReadSample(file, sampleHeaderOld, thisSmp, m_szNames[actualSmp]); + } + + STPLoopList loopList; + + if(fileHeader.version >= 1) + { + uint16 numLoops = file.ReadUint16BE(); + + STPLoopInfo loop; + loop.looped = loop.nonLooped = 0; + + if(numLoops == 0 && thisSmp.uFlags[CHN_LOOP]) + { + loop.loopStart = thisSmp.nLoopStart; + loop.loopLength = thisSmp.nLoopEnd - thisSmp.nLoopStart; + loopList.push_back(loop); + } else for(SAMPLEINDEX i = 0; i < numLoops; i++) + { + loop.loopStart = file.ReadUint32BE(); + loop.loopLength = file.ReadUint32BE(); + loopList.push_back(loop); + } + } + + if(actualSmp) + { + nonLooped.resize(actualSmp); + loopInfo.resize(actualSmp); + loopInfo[actualSmp - 1] = loopList; + } + } + + // Load patterns + uint16 numPatterns = 128; + if(fileHeader.version == 0) + numPatterns = file.ReadUint16BE(); + + uint16 patternLength = fileHeader.patternLength; + CHANNELINDEX channels = 4; + if(fileHeader.version > 0) + { + // Scan for total number of channels + FileReader::off_t patOffset = file.GetPosition(); + for(uint16 pat = 0; pat < numPatterns; pat++) + { + PATTERNINDEX actualPat = file.ReadUint16BE(); + if(actualPat == 0xFFFF) + break; + + patternLength = file.ReadUint16BE(); + channels = file.ReadUint16BE(); + m_nChannels = std::max(m_nChannels, channels); + + file.Skip(channels * patternLength * 4u); + } + file.Seek(patOffset); + if(m_nChannels > MAX_BASECHANNELS) + return false; + } + + uint8 globalVolSlide = 0; + std::vector<uint8> autoFinePorta(m_nChannels, 0); + std::vector<uint8> autoPortaUp(m_nChannels, 0); + std::vector<uint8> autoPortaDown(m_nChannels, 0); + std::vector<uint8> autoVolSlide(m_nChannels, 0); + std::vector<uint8> autoVibrato(m_nChannels, 0); + std::vector<uint8> vibratoMem(m_nChannels, 0); + std::vector<uint8> autoTremolo(m_nChannels, 0); + std::vector<uint8> autoTonePorta(m_nChannels, 0); + std::vector<uint8> tonePortaMem(m_nChannels, 0); + + for(uint16 pat = 0; pat < numPatterns; pat++) + { + PATTERNINDEX actualPat = pat; + + if(fileHeader.version > 0) + { + actualPat = file.ReadUint16BE(); + if(actualPat == 0xFFFF) + break; + + patternLength = file.ReadUint16BE(); + channels = file.ReadUint16BE(); + } + + if(!(loadFlags & loadPatternData) || !Patterns.Insert(actualPat, patternLength)) + { + file.Skip(channels * patternLength * 4u); + continue; + } + + for(ROWINDEX row = 0; row < patternLength; row++) + { + PatternRow rowBase = Patterns[actualPat].GetpModCommand(row, 0); + + bool didGlobalVolSlide = false; + bool shouldDelay = false; + + // if a fractional speed value is in use then determine if we should stick a fine pattern delay somewhere + switch(fileHeader.speedFrac & 3) + { + // 1/4 + case 1: shouldDelay = (row & 3) == 0; break; + // 1/2 + case 2: shouldDelay = (row & 1) == 0; break; + // 3/4 + case 3: shouldDelay = (row & 3) != 3; break; + } + + for(CHANNELINDEX chn = 0; chn < channels; chn++) + { + ModCommand &m = rowBase[chn]; + uint8 data[4]; + file.ReadArray(data); + + m.instr = data[0]; + m.note = data[1]; + m.command = data[2]; + m.param = data[3]; + + if(m.note) + { + m.note += 24 + NOTE_MIN; + + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoVolSlide[chn] = 0; + autoVibrato[chn] = vibratoMem[chn] = 0; + autoTremolo[chn] = 0; + autoTonePorta[chn] = tonePortaMem[chn] = 0; + } + + // this is a nibble-swapped param value used for auto fine volside + // and auto global fine volside + uint8 swap = (m.param >> 4) | (m.param << 4); + + if((m.command & 0xF0) == 0xF0) + { + m.param = mpt::saturate_cast<ModCommand::PARAM>(Util::Round(ConvertTempo(m.param | (((uint16)m.command & 0xF) << 8)).ToDouble())); + m.command = CMD_TEMPO; + } else switch(m.command) + { + case 0x00: // arpeggio + if(m.param) + m.command = CMD_ARPEGGIO; + break; + + case 0x01: // portamento up + m.command = CMD_PORTAMENTOUP; + break; + + case 0x02: // portamento down + m.command = CMD_PORTAMENTODOWN; + break; + + case 0x03: // auto fine portamento up + autoFinePorta[chn] = 0x10 | std::min(m.param, ModCommand::PARAM(15)); + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x04: // auto fine portamento down + autoFinePorta[chn] = 0x20 | std::min(m.param, ModCommand::PARAM(15)); + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x05: // auto portamento up + autoFinePorta[chn] = 0; + autoPortaUp[chn] = m.param; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x06: // auto portamento down + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = m.param; + autoTonePorta[chn] = 0; + + m.command = m.param = 0; + break; + + case 0x07: // set global volume + m.command = CMD_GLOBALVOLUME; + globalVolSlide = 0; + break; + + case 0x08: // auto global fine volume slide + globalVolSlide = swap; + m.command = m.param = 0; + break; + + case 0x09: // fine portamento up + m.command = CMD_MODCMDEX; + m.param = 0x10 | std::min(m.param, ModCommand::PARAM(15)); + break; + + case 0x0A: // fine portamento down + m.command = CMD_MODCMDEX; + m.param = 0x20 | std::min(m.param, ModCommand::PARAM(15)); + break; + + case 0x0B: // auto fine volume slide + autoVolSlide[chn] = swap; + m.command = m.param = 0; + break; + + case 0x0C: // set volume + m.volcmd = VOLCMD_VOLUME; + m.vol = m.param; + autoVolSlide[chn] = 0; + m.command = m.param = 0; + break; + + case 0x0D: // volume slide (param is swapped compared to .mod) + if(m.param & 0xF0) + { + m.volcmd = VOLCMD_VOLSLIDEDOWN; + m.vol = m.param >> 4; + } else if(m.param & 0x0F) + { + m.volcmd = VOLCMD_VOLSLIDEUP; + m.vol = m.param & 0xF; + } + autoVolSlide[chn] = 0; + m.command = m.param = 0; + break; + + case 0x0E: // set filter (also uses opposite value compared to .mod) + m.command = CMD_MODCMDEX; + m.param = 1 ^ (m.param ? 1 : 0); + break; + + case 0x0F: // set speed + m.command = CMD_SPEED; + fileHeader.speedFrac = m.param & 0xF; + m.param >>= 4; + break; + + case 0x10: // auto vibrato + autoVibrato[chn] = m.param; + vibratoMem[chn] = 0; + m.command = m.param = 0; + break; + + case 0x11: // auto tremolo + if(m.param & 0xF) + autoTremolo[chn] = m.param; + else + autoTremolo[chn] = 0; + m.command = m.param = 0; + break; + + case 0x12: // pattern break + m.command = CMD_PATTERNBREAK; + break; + + case 0x13: // auto tone portamento + autoFinePorta[chn] = 0; + autoPortaUp[chn] = 0; + autoPortaDown[chn] = 0; + autoTonePorta[chn] = m.param; + + tonePortaMem[chn] = 0; + m.command = m.param = 0; + break; + + case 0x14: // position jump + m.command = CMD_POSITIONJUMP; + break; + + case 0x16: // start loop sequence + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList &loopList = loopInfo[m.instr - 1]; + + m.param--; + if(m.param < std::min(MPT_ARRAY_COUNT(ModSample().cues), loopList.size())) + { + m.volcmd = VOLCMD_OFFSET; + m.vol = m.param; + } + } + + m.command = m.param = 0; + break; + + case 0x17: // play only loop nn + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList &loopList = loopInfo[m.instr - 1]; + + m.param--; + if(m.param < loopList.size()) + { + if(!loopList[m.param].looped && m_nSamples < MAX_SAMPLES - 1) + loopList[m.param].looped = ++m_nSamples; + m.instr = static_cast<ModCommand::INSTR>(loopList[m.param].looped); + } + } + + m.command = m.param = 0; + break; + + case 0x18: // play sequence without loop + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList &loopList = loopInfo[m.instr - 1]; + + m.param--; + if(m.param < std::min(MPT_ARRAY_COUNT(ModSample().cues), loopList.size())) + { + m.volcmd = VOLCMD_OFFSET; + m.vol = m.param; + } + // switch to non-looped version of sample and create it if needed + if(!nonLooped[m.instr - 1] && m_nSamples < MAX_SAMPLES - 1) + nonLooped[m.instr - 1] = ++m_nSamples; + m.instr = static_cast<ModCommand::INSTR>(nonLooped[m.instr - 1]); + } + + m.command = m.param = 0; + break; + + case 0x19: // play only loop nn without loop + if(m.instr && m.instr <= loopInfo.size()) + { + STPLoopList &loopList = loopInfo[m.instr - 1]; + + m.param--; + if(m.param < loopList.size()) + { + if(!loopList[m.param].nonLooped && m_nSamples < MAX_SAMPLES-1) + loopList[m.param].nonLooped = ++m_nSamples; + m.instr = static_cast<ModCommand::INSTR>(loopList[m.param].nonLooped); + } + } + + m.command = m.param = 0; + break; + + case 0x1D: // fine volume slide (nibble order also swapped) + m.command = CMD_VOLUMESLIDE; + m.param = swap; + if(m.param & 0xF0) // slide down + m.param |= 0x0F; + else if(m.param & 0x0F) + m.param |= 0xF0; + break; + + case 0x20: // "delayed fade" + // just behave like either a normal fade or a notecut + // depending on the speed + if(m.param & 0xF0) + { + autoVolSlide[chn] = m.param >> 4; + m.command = m.param = 0; + } else + { + m.command = CMD_MODCMDEX; + m.param = 0xC0 | (m.param & 0xF); + } + break; + + case 0x21: // note delay + m.command = CMD_MODCMDEX; + m.param = 0xD0 | std::min(m.param, ModCommand::PARAM(15)); + break; + + case 0x22: // retrigger note + m.command = CMD_RETRIG; + m.param = std::min(m.param, ModCommand::PARAM(15)); + break; + + case 0x49: // set sample offset + m.command = CMD_OFFSET; + break; + + case 0x4E: // other protracker commands (pattern loop / delay) + if((m.param & 0xF0) == 0x60 || (m.param & 0xF0) == 0xE0) + m.command = CMD_MODCMDEX; + else + m.command = m.param = 0; + break; + + case 0x4F: // set speed/tempo + if(m.param < 0x20) + { + m.command = CMD_SPEED; + fileHeader.speedFrac = 0; + } else + { + m.command = CMD_TEMPO; + } + break; + + default: + m.command = CMD_NONE; + break; + } + + bool didVolSlide = false; + + // try to put volume slide in volume command + if(autoVolSlide[chn] && !m.volcmd) + { + if(autoVolSlide[chn] & 0xF0) + { + m.volcmd = VOLCMD_FINEVOLUP; + m.vol = autoVolSlide[chn] >> 4; + } else + { + m.volcmd = VOLCMD_FINEVOLDOWN; + m.vol = autoVolSlide[chn] & 0xF; + } + didVolSlide = true; + } + + // try to place/combine all remaining running effects. + if(m.command == CMD_NONE) + { + if(autoPortaUp[chn]) + { + m.command = CMD_PORTAMENTOUP; + m.param = autoPortaUp[chn]; + + } else if(autoPortaDown[chn]) + { + m.command = CMD_PORTAMENTODOWN; + m.param = autoPortaDown[chn]; + + } else if(autoFinePorta[chn]) + { + m.command = CMD_MODCMDEX; + m.param = autoFinePorta[chn]; + + } else if(autoTonePorta[chn]) + { + m.command = CMD_TONEPORTAMENTO; + m.param = tonePortaMem[chn] = autoTonePorta[chn]; + + } else if(autoVibrato[chn]) + { + m.command = CMD_VIBRATO; + m.param = vibratoMem[chn] = autoVibrato[chn]; + + } else if(!didVolSlide && autoVolSlide[chn]) + { + m.command = CMD_VOLUMESLIDE; + m.param = autoVolSlide[chn]; + // convert to a "fine" value by setting the other nibble to 0xF + if(m.param & 0x0F) + m.param |= 0xF0; + else if(m.param & 0xF0) + m.param |= 0x0F; + didVolSlide = true; + + } else if(autoTremolo[chn]) + { + m.command = CMD_TREMOLO; + m.param = autoTremolo[chn]; + + } else if(shouldDelay) + { + // insert a fine pattern delay here + m.command = CMD_S3MCMDEX; + m.param = 0x61; + shouldDelay = false; + + } else if(!didGlobalVolSlide && globalVolSlide) + { + m.command = CMD_GLOBALVOLSLIDE; + m.param = globalVolSlide; + // convert to a "fine" value by setting the other nibble to 0xF + if(m.param & 0x0F) + m.param |= 0xF0; + else if(m.param & 0xF0) + m.param |= 0x0F; + + didGlobalVolSlide = true; + } + } + } + + // TODO: create/use extra channels for global volslide/delay if needed + } + } + + // after we know how many channels there really are... + m_nSamplePreAmp = 256 / m_nChannels; + // Setup channel pan positions and volume + SetupMODPanning(true); + + // Skip over scripts and drumpad info + if(fileHeader.version > 0) + { + while(file.CanRead(2)) + { + uint16 scriptNum = file.ReadUint16BE(); + if(scriptNum == 0xFFFF) + break; + + file.Skip(2); + uint32 length = file.ReadUint32BE(); + file.Skip(length); + } + + // Skip drumpad stuff + file.Skip(17*2); + } + + // Reading samples + if(loadFlags & loadSampleData) + { + for(SAMPLEINDEX smp = 1; smp <= samplesInFile; smp++) if(Samples[smp].nLength) + { + SampleIO( + SampleIO::_8bit, + SampleIO::mono, + SampleIO::littleEndian, + SampleIO::signedPCM) + .ReadSample(Samples[smp], file); + + ConvertLoopSequence(Samples[smp], loopInfo[smp - 1]); + + // make a non-looping duplicate of this sample if needed + if(nonLooped[smp - 1]) + { + ConvertLoopSlice(Samples[smp], Samples[nonLooped[smp-1]], 0, Samples[smp].nLength, false); + } + + for(SAMPLEINDEX loop = 0; loop < loopInfo[smp - 1].size(); loop++) + { + STPLoopInfo &info = loopInfo[smp - 1][loop]; + + // make duplicate samples for this individual section if needed + if(info.looped) + { + ConvertLoopSlice(Samples[smp], Samples[info.looped], info.loopStart, info.loopLength, true); + } + if(info.nonLooped) + { + ConvertLoopSlice(Samples[smp], Samples[info.nonLooped], info.loopStart, info.loopLength, false); + } + } + } + } + + return true; +} + +OPENMPT_NAMESPACE_END Property changes on: soundlib/Load_stp.cpp ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/x-c++src \ No newline at end of property Index: soundlib/Snd_defs.h =================================================================== --- soundlib/Snd_defs.h (revision 7555) +++ soundlib/Snd_defs.h (working copy) @@ -98,6 +98,7 @@ MOD_TYPE_UAX = 0x10000000, // sampleset as module MOD_TYPE_PLM = 0x20000000, MOD_TYPE_SFX = 0x40000000, + MOD_TYPE_STP = 0x80000000, }; DECLARE_FLAGSET(MODTYPE) Index: soundlib/Snd_fx.cpp =================================================================== --- soundlib/Snd_fx.cpp (revision 7555) +++ soundlib/Snd_fx.cpp (working copy) @@ -3434,7 +3434,7 @@ else param = pChn->nOldPortaUpDown; - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI)); + const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP)); // Process MIDI pitch bend for instrument plugins MidiPortamento(nChn, param, doFineSlides); @@ -3493,7 +3493,7 @@ else param = pChn->nOldPortaUpDown; - const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI)); + const bool doFineSlides = !doFinePortamentoAsRegular && !(GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_STP)); // Process MIDI pitch bend for instrument plugins MidiPortamento(nChn, -static_cast<int>(param), doFineSlides); @@ -3989,7 +3989,7 @@ else param = pChn->nOldVolumeSlide; - if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI))) + if((GetType() & (MOD_TYPE_MOD | MOD_TYPE_XM | MOD_TYPE_MT2 | MOD_TYPE_MED | MOD_TYPE_DIGI | MOD_TYPE_STP))) { // MOD / XM nibble priority if((param & 0xF0) != 0) Index: soundlib/Sndfile.cpp =================================================================== --- soundlib/Sndfile.cpp (revision 7555) +++ soundlib/Sndfile.cpp (working copy) @@ -309,6 +309,7 @@ && !ReadJ2B(file, loadFlags) && !ReadPT36(file, loadFlags) && !ReadSFX(file, loadFlags) + && !ReadSTP(file, loadFlags) && !ReadMod(file, loadFlags) && !ReadICE(file, loadFlags) && !Read669(file, loadFlags) @@ -1075,6 +1076,7 @@ case MOD_TYPE_AMF0: case MOD_TYPE_DIGI: case MOD_TYPE_SFX: + case MOD_TYPE_STP: return MOD_TYPE_MOD; case MOD_TYPE_MED: if(m_nDefaultTempo == TEMPO(125, 0) && m_nDefaultSpeed == 6 && !m_nInstruments) Index: soundlib/Sndfile.h =================================================================== --- soundlib/Sndfile.h (revision 7555) +++ soundlib/Sndfile.h (working copy) @@ -680,6 +680,7 @@ bool ReadS3M(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSFX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadSTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); + bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadUlt(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadUMX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); bool ReadWav(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule); @@ -884,7 +885,7 @@ // Returns true if the current format uses transpose+finetune rather than frequency in Hz to specify middle-C. static bool UseFinetuneAndTranspose(MODTYPE type) { - return (type & (MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_MTM | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_XM)); + return (type & (MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_MTM | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_STP | MOD_TYPE_XM)); } bool UseFinetuneAndTranspose() const { Index: soundlib/Tables.cpp =================================================================== --- soundlib/Tables.cpp (revision 7555) +++ soundlib/Tables.cpp (working copy) @@ -90,6 +90,7 @@ { MOD_TYPE_SFX, "SoundFX", "sfx" }, { MOD_TYPE_SFX, "SoundFX", "sfx2" }, { MOD_TYPE_SFX, "MultiMedia Sound", "mms" }, + { MOD_TYPE_STP, "Soundtracker Pro II", "stp" }, #ifndef NO_ARCHIVE_SUPPORT // Compressed modules @@ -151,6 +152,7 @@ { MOD_TYPE_DBM , mpt::CharsetISO8859_1 }, { MOD_TYPE_DIGI, mpt::CharsetISO8859_1 }, { MOD_TYPE_SFX , mpt::CharsetISO8859_1 }, + { MOD_TYPE_STP, mpt::CharsetISO8859_1 }, // Amiga // DOS { MOD_TYPE_MOD , mpt::CharsetISO8859_1 }, { MOD_TYPE_MED , mpt::CharsetISO8859_1 }, |
|
Hi, sorry I haven't replied to this issue recently; I've been a bit busy with work and other projects, etc. I haven't checked out any of the mods Johan posted yet, but I'll take a look at both those and the latest version of the patch sometime soon. I wish I had had more time to spend revising the code / finding more test cases back when I first submitted this, but thanks for keeping it under consideration since then. |
|
Seems like it has something to do with ignoring the sample header size in v2 files. Not ignoring that makes the file load, but the sample sizes are way off.
Edit: Got it to work. The string size limits were off by one. Now the file loads! |
|
Merged as of r7568. Thanks a lot for your contribution once again. If you have any further improvements to the loader, do not hesitate to submit them! Now I just have to restart all the fuzzers to find all the new crashes we just introduced. ;) |
|
Hm, I noticed that ModSample::cues[0] is only set for v2 files, but v1 files can also contains loop slices and cue points as far as I can tell. Is this intentional? My guess would be that cues[0] should be set for both v1 and v2 files. |
|
Yeah, I believe it should be done both for v1 and v2 files. It looks like in my original versions of the patch I was just forgetting to set it in STPSampleHeaderOld::ConvertToMPT. |
|
Okay, fixed in r7583. |
|
Date Modified | Username | Field | Change |
---|---|---|---|
2016-03-05 04:15 | Revenant | New Issue | |
2016-03-05 04:15 | Revenant | File Added: stpro2.patch | |
2016-03-05 09:06 | manx | Note Added: 0002274 | |
2016-03-05 09:37 | Revenant | Note Added: 0002275 | |
2016-03-05 10:30 | Saga Musix | Note Added: 0002276 | |
2016-03-10 05:41 | manx | Assigned To | => Saga Musix |
2016-03-10 05:41 | manx | Status | new => assigned |
2016-03-13 16:32 | Saga Musix | Note Added: 0002283 | |
2016-03-13 16:32 | Saga Musix | Note Edited: 0002283 | |
2016-03-13 18:44 | Revenant | Note Added: 0002284 | |
2016-03-14 06:08 | Revenant | Note Added: 0002285 | |
2016-03-14 12:25 | Saga Musix | Note Added: 0002286 | |
2016-03-14 16:53 | Revenant | Note Added: 0002287 | |
2016-03-14 16:55 | Saga Musix | Note Added: 0002288 | |
2016-03-31 06:31 | Revenant | File Added: stpro2_r2.patch | |
2016-03-31 06:36 | Revenant | Note Added: 0002314 | |
2016-04-24 00:29 | Saga Musix | Target Version | => OpenMPT 1.26.01.00 / libopenmpt 0.2-beta17 (upgrade first) |
2016-04-30 13:18 | Saga Musix | Note Added: 0002356 | |
2016-04-30 13:19 | Saga Musix | Note Edited: 0002356 | |
2016-04-30 13:20 | Saga Musix | Note Edited: 0002356 | |
2016-04-30 13:25 | Saga Musix | Note Edited: 0002356 | |
2016-04-30 13:34 | Saga Musix | Note Added: 0002357 | |
2016-05-17 22:38 | Saga Musix | Target Version | OpenMPT 1.26.01.00 / libopenmpt 0.2-beta17 (upgrade first) => OpenMPT 1.?? (long term goals) |
2016-06-08 23:49 | Saga Musix | File Added: stpro2_r3.patch | |
2016-06-08 23:51 | Saga Musix | Note Added: 0002446 | |
2016-08-20 12:34 | Saga Musix | File Added: stpro2_r4.patch | |
2016-08-20 12:35 | Saga Musix | Note Added: 0002621 | |
2016-08-22 17:58 | johan.bakker | Note Added: 0002624 | |
2017-02-07 17:51 | Saga Musix | Note Added: 0002865 | |
2017-02-07 17:52 | Saga Musix | Target Version | OpenMPT 1.?? (long term goals) => OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) |
2017-02-07 18:37 | Saga Musix | File Added: stpro2_r5.patch | |
2017-02-07 18:37 | Saga Musix | Note Added: 0002866 | |
2017-02-07 23:43 | Revenant | Note Added: 0002867 | |
2017-02-08 19:15 | Saga Musix | Note Added: 0002868 | |
2017-02-08 19:25 | Saga Musix | Note Edited: 0002868 | |
2017-02-08 19:27 | Saga Musix | Note Edited: 0002868 | |
2017-02-08 20:30 | Saga Musix | Note View State: 0002866: private | |
2017-02-08 20:31 | Saga Musix | Note View State: 0002866: public | |
2017-02-08 20:31 | Saga Musix | Status | assigned => resolved |
2017-02-08 20:31 | Saga Musix | Resolution | open => fixed |
2017-02-08 20:31 | Saga Musix | Fixed in Version | => OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) |
2017-02-08 20:31 | Saga Musix | Note Added: 0002869 | |
2017-02-10 18:32 | Saga Musix | Note Added: 0002873 | |
2017-02-11 00:38 | Revenant | Status | resolved => feedback |
2017-02-11 00:38 | Revenant | Resolution | fixed => reopened |
2017-02-11 00:38 | Revenant | Note Added: 0002874 | |
2017-02-11 00:43 | Saga Musix | Status | feedback => resolved |
2017-02-11 00:43 | Saga Musix | Resolution | reopened => fixed |
2017-02-11 00:43 | Saga Musix | Note Added: 0002875 |