|
From: <sag...@us...> - 2012-12-14 10:13:39
|
Revision: 1460
http://sourceforge.net/p/modplug/code/1460
Author: saga-games
Date: 2012-12-14 10:13:33 +0000 (Fri, 14 Dec 2012)
Log Message:
-----------
[Fix] XM instrument saving failed if there were samples in the sample map that were only referenced below C-1 or above B-8.
Modified Paths:
--------------
trunk/OpenMPT/soundlib/Load_xm.cpp
trunk/OpenMPT/soundlib/SampleFormats.cpp
trunk/OpenMPT/soundlib/XMTools.cpp
trunk/OpenMPT/soundlib/XMTools.h
Modified: trunk/OpenMPT/soundlib/Load_xm.cpp
===================================================================
--- trunk/OpenMPT/soundlib/Load_xm.cpp 2012-12-12 23:02:43 UTC (rev 1459)
+++ trunk/OpenMPT/soundlib/Load_xm.cpp 2012-12-14 10:13:33 UTC (rev 1460)
@@ -17,10 +17,7 @@
#include "XMTools.h"
#include <algorithm>
-////////////////////////////////////////////////////////
-// FastTracker II XM file support
-
// Allocate samples for an instrument
vector<SAMPLEINDEX> AllocateXMSamples(CSoundFile &sndFile, SAMPLEINDEX numSamples)
//--------------------------------------------------------------------------------
@@ -319,6 +316,7 @@
// Now, read the complete struct.
file.SkipBack(4);
file.ReadStructPartial(instrHeader, instrHeader.size);
+ instrHeader.ConvertEndianness();
// Time for some version detection stuff.
if(madeWith == verOldModPlug)
@@ -348,7 +346,6 @@
continue;
}
- instrHeader.ConvertEndianness();
instrHeader.ConvertToMPT(*Instruments[instr]);
if(instrHeader.numSamples > 0)
@@ -386,6 +383,7 @@
{
XMSample sampleHeader;
file.ReadStructPartial(sampleHeader, copyBytes);
+ sampleHeader.ConvertEndianness();
sampleFlags.push_back(sampleHeader.GetSampleFormat());
sampleSize[sample] = sampleHeader.length;
@@ -575,25 +573,25 @@
BYTE xmph[9];
bool addChannel = false; // avoid odd channel count for FT2 compatibility
- XMFileHeader xmheader;
- MemsetZero(xmheader);
+ XMFileHeader fileHeader;
+ MemsetZero(fileHeader);
- memcpy(xmheader.signature, "Extended Module: ", 17);
- StringFixer::WriteString<StringFixer::spacePadded>(xmheader.songName, m_szNames[0]);
- xmheader.eof = 0x1A;
- memcpy(xmheader.trackerName, "OpenMPT " MPT_VERSION_STR " ", 20);
+ memcpy(fileHeader.signature, "Extended Module: ", 17);
+ StringFixer::WriteString<StringFixer::spacePadded>(fileHeader.songName, m_szNames[0]);
+ fileHeader.eof = 0x1A;
+ memcpy(fileHeader.trackerName, "OpenMPT " MPT_VERSION_STR " ", 20);
// Writing song header
- xmheader.version = 0x0104; // XM Format v1.04
- xmheader.size = sizeof(XMFileHeader) - 60; // minus everything before this field
- xmheader.restartPos = m_nRestartPos;
+ fileHeader.version = 0x0104; // XM Format v1.04
+ fileHeader.size = sizeof(XMFileHeader) - 60; // minus everything before this field
+ fileHeader.restartPos = m_nRestartPos;
- xmheader.channels = (m_nChannels + 1) & 0xFFFE; // avoid odd channel count for FT2 compatibility
+ fileHeader.channels = (m_nChannels + 1) & 0xFFFE; // avoid odd channel count for FT2 compatibility
if((m_nChannels & 1) && m_nChannels < MAX_BASECHANNELS) addChannel = true;
- if(compatibilityExport && xmheader.channels > 32)
- xmheader.channels = 32;
- if(xmheader.channels > MAX_BASECHANNELS) xmheader.channels = MAX_BASECHANNELS;
- xmheader.channels = xmheader.channels;
+ if(compatibilityExport && fileHeader.channels > 32)
+ fileHeader.channels = 32;
+ if(fileHeader.channels > MAX_BASECHANNELS) fileHeader.channels = MAX_BASECHANNELS;
+ fileHeader.channels = fileHeader.channels;
// Find out number of orders and patterns used.
// +++ and --- patterns are not taken into consideration as FastTracker does not support them.
@@ -609,29 +607,29 @@
}
if(!compatibilityExport) nMaxOrds = Order.GetLengthTailTrimmed(); // should really be removed at some point
- xmheader.orders = nMaxOrds;
- xmheader.patterns = nPatterns;
- xmheader.size = xmheader.size + nMaxOrds;
+ fileHeader.orders = nMaxOrds;
+ fileHeader.patterns = nPatterns;
+ fileHeader.size = fileHeader.size + nMaxOrds;
uint16 writeInstruments;
if(m_nInstruments > 0)
- xmheader.instruments = writeInstruments = m_nInstruments;
+ fileHeader.instruments = writeInstruments = m_nInstruments;
else
- xmheader.instruments = writeInstruments = m_nSamples;
+ fileHeader.instruments = writeInstruments = m_nSamples;
- if(m_SongFlags[SONG_LINEARSLIDES]) xmheader.flags |= XMFileHeader::linearSlides;
- if(m_SongFlags[SONG_EXFILTERRANGE] && !compatibilityExport) xmheader.flags |= XMFileHeader::extendedFilterRange;
- xmheader.flags = xmheader.flags;
+ if(m_SongFlags[SONG_LINEARSLIDES]) fileHeader.flags |= XMFileHeader::linearSlides;
+ if(m_SongFlags[SONG_EXFILTERRANGE] && !compatibilityExport) fileHeader.flags |= XMFileHeader::extendedFilterRange;
+ fileHeader.flags = fileHeader.flags;
// if(compatibilityExport)
// xmheader.tempo = static_cast<uint16>(Clamp(m_nDefaultTempo, 32u, 255u));
// else
// Fasttracker 2 will happily accept any tempo faster than 255 BPM. XMPlay does also support this, great!
- xmheader.tempo = static_cast<uint16>(Clamp(m_nDefaultTempo, 32u, 512u));
- xmheader.speed = static_cast<uint16>(Clamp(m_nDefaultSpeed, 1u, 31u));
+ fileHeader.tempo = static_cast<uint16>(Clamp(m_nDefaultTempo, 32u, 512u));
+ fileHeader.speed = static_cast<uint16>(Clamp(m_nDefaultSpeed, 1u, 31u));
- xmheader.ConvertEndianness();
- fwrite(&xmheader, 1, sizeof(xmheader), f);
+ fileHeader.ConvertEndianness();
+ fwrite(&fileHeader, 1, sizeof(fileHeader), f);
// write order list (wihout +++ and ---, explained above)
for(ORDERINDEX ord = 0; ord < Order.GetLengthTailTrimmed(); ord++)
@@ -647,7 +645,7 @@
for(PATTERNINDEX pat = 0; pat < nPatterns; pat++) if (Patterns[pat])
{
ModCommand *p = Patterns[pat];
- UINT len = 0;
+ size_t len = 0;
// Empty patterns are always loaded as 64-row patterns in FT2, regardless of their real size...
bool emptyPattern = true;
@@ -656,7 +654,7 @@
xmph[5] = (BYTE)(Patterns[pat].GetNumRows() & 0xFF);
xmph[6] = (BYTE)(Patterns[pat].GetNumRows() >> 8);
- for (UINT j = m_nChannels * Patterns[pat].GetNumRows(); j > 0; j--, p++)
+ for (size_t j = m_nChannels * Patterns[pat].GetNumRows(); j > 0; j--, p++)
{
// Don't write more than 32 channels
if(compatibilityExport && m_nChannels - ((j - 1) % m_nChannels) > 32) continue;
@@ -852,6 +850,7 @@
StringFixer::WriteString<StringFixer::spacePadded>(xmSample.name, m_szNames[samples[smp]]);
+ xmSample.ConvertEndianness();
fwrite(&xmSample, 1, sizeof(xmSample), f);
}
Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp
===================================================================
--- trunk/OpenMPT/soundlib/SampleFormats.cpp 2012-12-12 23:02:43 UTC (rev 1459)
+++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2012-12-14 10:13:33 UTC (rev 1460)
@@ -982,7 +982,7 @@
for(SAMPLEINDEX i = 0; i < fileHeader.numSamples; i++)
{
XMSample sampleHeader;
- if(!file.Read(sampleHeader)
+ if(!file.ReadConvertEndianness(sampleHeader)
|| !sampleMap[i])
{
continue;
@@ -1047,6 +1047,7 @@
header.instrument.ApplyAutoVibratoToXM(Samples[samples[0]], GetType());
}
+ header.ConvertEndianness();
fwrite(&header, 1, sizeof(XIInstrumentHeader), f);
vector<SampleIO> sampleFlags(samples.size());
@@ -1066,6 +1067,7 @@
StringFixer::WriteString<StringFixer::spacePadded>(xmSample.name, m_szNames[samples[i]]);
+ xmSample.ConvertEndianness();
fwrite(&xmSample, 1, sizeof(xmSample), f);
}
@@ -1111,7 +1113,7 @@
// Read first sample header
XMSample sampleHeader;
- file.Read(sampleHeader);
+ file.ReadConvertEndianness(sampleHeader);
// Gotta skip 'em all!
file.Skip(sizeof(XMSample) * (fileHeader.numSamples - 1));
Modified: trunk/OpenMPT/soundlib/XMTools.cpp
===================================================================
--- trunk/OpenMPT/soundlib/XMTools.cpp 2012-12-12 23:02:43 UTC (rev 1459)
+++ trunk/OpenMPT/soundlib/XMTools.cpp 2012-12-14 10:13:33 UTC (rev 1460)
@@ -32,6 +32,22 @@
}
+// Convert all multi-byte numeric values to current platform's endianness or vice versa.
+void XMInstrument::ConvertEndianness()
+//------------------------------------
+{
+ for(size_t i = 0; i < CountOf(volEnv); i++)
+ {
+ SwapBytesLE(volEnv[i]);
+ SwapBytesLE(panEnv[i]);
+ }
+ SwapBytesLE(volFade);
+ SwapBytesLE(midiProgram);
+ SwapBytesLE(pitchWheelRange);
+}
+
+
+
// Convert OpenMPT's internal envelope representation to XM envelope data.
void XMInstrument::ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8 &numPoints, uint8 &flags, uint8 &sustain, uint8 &loopStart, uint8 &loopEnd, uint16 (&envData)[24])
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -41,8 +57,8 @@
// Envelope Data
for(size_t i = 0; i < numPoints; i++)
{
- envData[i * 2] = LittleEndianW(min(mptEnv.Ticks[i], uint16_max));
- envData[i * 2 + 1] = LittleEndianW(mptEnv.Values[i]);
+ envData[i * 2] = Util::Min(mptEnv.Ticks[i], uint16_max);
+ envData[i * 2 + 1] = mptEnv.Values[i];
}
// Envelope Flags
@@ -59,13 +75,13 @@
// Convert OpenMPT's internal sample representation to an XMInstrument.
-void XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport)
-//-----------------------------------------------------------------------------------
+uint16 XMInstrument::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport)
+//-------------------------------------------------------------------------------------
{
MemsetZero(*this);
// FFF is maximum in the FT2 GUI, but it can also accept other values. MilkyTracker just allows 0...4095 and 32767 ("cut")
- volFade = static_cast<uint16>(LittleEndianW(min(mptIns.nFadeOut, 32767)));
+ volFade = static_cast<uint16>(Util::Min(mptIns.nFadeOut, uint32(32767)));
// Convert envelopes
ConvertEnvelopeToXM(mptIns.VolEnv, volPoints, volFlags, volSustain, volLoopStart, volLoopEnd, volEnv);
@@ -93,6 +109,8 @@
}
midiProgram = (mptIns.nMidiProgram != 0 ? mptIns.nMidiProgram - 1 : 0);
pitchWheelRange = Util::Min(mptIns.midiPWD, int8(36));
+
+ return static_cast<uint16>(sampleList.size());
}
@@ -136,8 +154,8 @@
// Envelope Data
for(size_t i = 0; i < 12; i++)
{
- mptEnv.Ticks[i] = static_cast<WORD>(LittleEndianW(envData[i * 2]));
- mptEnv.Values[i] = static_cast<BYTE>(LittleEndianW(envData[i * 2 + 1]));
+ mptEnv.Ticks[i] = envData[i * 2];
+ mptEnv.Values[i] = static_cast<uint8>(envData[i * 2 + 1]);
if(i > 0 && mptEnv.Ticks[i] < mptEnv.Ticks[i - 1])
{
@@ -235,6 +253,7 @@
SwapBytesLE(size);
SwapBytesLE(sampleHeaderSize);
SwapBytesLE(numSamples);
+ instrument.ConvertEndianness();
}
@@ -258,13 +277,10 @@
void XMInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport)
//-----------------------------------------------------------------------------------------
{
- instrument.ConvertToXM(mptIns, compatibilityExport);
-
+ numSamples = instrument.ConvertToXM(mptIns, compatibilityExport);
StringFixer::WriteString<StringFixer::spacePadded>(name, mptIns.name);
- type = mptIns.nMidiProgram; // If FT2 writes crap here, we can do so, too!
-
- numSamples = static_cast<uint16>(Util::Min(mptIns.GetSamples().size(), size_t(compatibilityExport ? 16 : 32)));
+ type = mptIns.nMidiProgram; // If FT2 writes crap here, we can do so, too! (we probably shouldn't, though.)
}
@@ -298,6 +314,7 @@
{
SwapBytesLE(version);
SwapBytesLE(numSamples);
+ instrument.ConvertEndianness();
}
@@ -305,7 +322,7 @@
void XIInstrumentHeader::ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport)
//-----------------------------------------------------------------------------------------
{
- instrument.ConvertToXM(mptIns, compatibilityExport);
+ numSamples = instrument.ConvertToXM(mptIns, compatibilityExport);
memcpy(signature, "Extended Instrument: ", 21);
StringFixer::WriteString<StringFixer::spacePadded>(name, mptIns.name);
@@ -313,9 +330,7 @@
memcpy(trackerName, "Created by OpenMPT ", 20);
- version = LittleEndianW(0x102);
-
- numSamples = static_cast<uint16>(LittleEndianW(Util::Min(mptIns.GetSamples().size(), size_t(compatibilityExport ? 16 : 32))));
+ version = 0x102;
}
@@ -338,6 +353,16 @@
}
+// Convert all multi-byte numeric values to current platform's endianness or vice versa.
+void XMSample::ConvertEndianness()
+//--------------------------------
+{
+ SwapBytesLE(length);
+ SwapBytesLE(loopStart);
+ SwapBytesLE(loopLength);
+}
+
+
// Convert OpenMPT's internal sample representation to an XMSample.
void XMSample::ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compatibilityExport)
//---------------------------------------------------------------------------------------------
@@ -386,10 +411,6 @@
loopStart *= 2;
loopLength *= 2;
}
-
- SwapBytesLE(length);
- SwapBytesLE(loopStart);
- SwapBytesLE(loopLength);
}
@@ -412,9 +433,9 @@
mptSmp.RelativeTone = relnote;
// Sample Length and Loops
- mptSmp.nLength = LittleEndian(length);
- mptSmp.nLoopStart = LittleEndian(loopStart);
- mptSmp.nLoopEnd = mptSmp.nLoopStart + LittleEndian(loopLength);
+ mptSmp.nLength = length;
+ mptSmp.nLoopStart = loopStart;
+ mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength;
if((flags & XMSample::sample16Bit))
{
Modified: trunk/OpenMPT/soundlib/XMTools.h
===================================================================
--- trunk/OpenMPT/soundlib/XMTools.h 2012-12-12 23:02:43 UTC (rev 1459)
+++ trunk/OpenMPT/soundlib/XMTools.h 2012-12-14 10:13:33 UTC (rev 1460)
@@ -79,13 +79,16 @@
uint8 muteComputer; // Mute instrument if MIDI is enabled (0 / 1)
uint8 reserved[15]; // Reserved
+ // Convert all multi-byte numeric values to current platform's endianness or vice versa.
+ void ConvertEndianness();
+
// Convert OpenMPT's internal envelope representation to XM envelope data.
void ConvertEnvelopeToXM(const InstrumentEnvelope &mptEnv, uint8 &numPoints, uint8 &flags, uint8 &sustain, uint8 &loopStart, uint8 &loopEnd, uint16 (&envData)[24]);
// Convert XM envelope data to an OpenMPT's internal envelope representation.
void ConvertEnvelopeToMPT(InstrumentEnvelope &mptEnv, uint8 numPoints, uint8 flags, uint8 sustain, uint8 loopStart, uint8 loopEnd, const uint16 (&envData)[24]) const;
// Convert OpenMPT's internal sample representation to an XMInstrument.
- void ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport);
+ uint16 ConvertToXM(const ModInstrument &mptIns, bool compatibilityExport);
// Convert an XMInstrument to OpenMPT's internal instrument representation.
void ConvertToMPT(ModInstrument &mptIns) const;
// Apply auto-vibrato settings from sample to file.
@@ -177,6 +180,9 @@
uint8 reserved; // Reserved (abused for ModPlug's ADPCM compression)
char name[22]; // Sample Name, not null-terminated (any nulls are treated as spaces)
+ // Convert all multi-byte numeric values to current platform's endianness or vice versa.
+ void ConvertEndianness();
+
// Convert OpenMPT's internal sample representation to an XMSample.
void ConvertToXM(const ModSample &mptSmp, MODTYPE fromType, bool compatibilityExport);
// Convert an XMSample to OpenMPT's internal sample representation.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|