From: <sag...@us...> - 2012-03-21 14:19:06
|
Revision: 1227 http://modplug.svn.sourceforge.net/modplug/?rev=1227&view=rev Author: saga-games Date: 2012-03-21 14:18:54 +0000 (Wed, 21 Mar 2012) Log Message: ----------- [Fix] DBM Loader: Global volume command was broken since OpenMPT 1.19.02.00 [Imp] XM Loader: Samples that are not associated to any instrument are now tried to be written to the XM file anyway (http://forum.openmpt.org/index.php?topic=4688.0, http://bugs.openmpt.org/view.php?id=234). [Mod] OpenMPT: Version is now 1.20.00.80 Modified Paths: -------------- trunk/OpenMPT/mptrack/version.h trunk/OpenMPT/soundlib/LOAD_DBM.CPP trunk/OpenMPT/soundlib/Load_xm.cpp Modified: trunk/OpenMPT/mptrack/version.h =================================================================== --- trunk/OpenMPT/mptrack/version.h 2012-03-21 00:36:20 UTC (rev 1226) +++ trunk/OpenMPT/mptrack/version.h 2012-03-21 14:18:54 UTC (rev 1227) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 20 #define VER_MINOR 00 -#define VER_MINORMINOR 79 +#define VER_MINORMINOR 80 //Creates version number from version parts that appears in version string. //For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of Modified: trunk/OpenMPT/soundlib/LOAD_DBM.CPP =================================================================== --- trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-03-21 00:36:20 UTC (rev 1226) +++ trunk/OpenMPT/soundlib/LOAD_DBM.CPP 2012-03-21 14:18:54 UTC (rev 1227) @@ -26,70 +26,70 @@ #pragma pack(push, 1) -typedef struct DBMFILEHEADER +struct DBMFileHeader { - DWORD dbm_id; // "DBM0" = 0x304d4244 - WORD trkver; // Tracker version: 02.15 - WORD reserved; - DWORD name_id; // "NAME" = 0x454d414e - DWORD name_len; // name length: always 44 - CHAR songname[44]; - DWORD info_id; // "INFO" = 0x4f464e49 - DWORD info_len; // 0x0a000000 - WORD instruments; - WORD samples; - WORD songs; - WORD patterns; - WORD channels; - DWORD song_id; // "SONG" = 0x474e4f53 - DWORD song_len; - CHAR songname2[44]; - WORD orders; -// WORD orderlist[0]; // orderlist[orders] in words -} DBMFILEHEADER; + uint32 dbm_id; // "DBM0" = 0x304d4244 + uint16 trkver; // Tracker version: 02.15 + uint16 reserved; + uint32 name_id; // "NAME" = 0x454d414e + uint32 name_len; // name length: always 44 + char songname[44]; + uint32 info_id; // "INFO" = 0x4f464e49 + uint32 info_len; // 0x0a000000 + uint16 instruments; + uint16 samples; + uint16 songs; + uint16 patterns; + uint16 channels; + uint32 song_id; // "SONG" = 0x474e4f53 + uint32 song_len; + char songname2[44]; + uint16 orders; +// uint16 orderlist[0]; // orderlist[orders] in words +}; -typedef struct DBMINSTRUMENT +struct DBMInstrument { - CHAR name[30]; - WORD sampleno; - WORD volume; - DWORD finetune; - DWORD loopstart; - DWORD looplen; - WORD panning; - WORD flags; -} DBMINSTRUMENT; + char name[30]; + uint16 sampleno; + uint16 volume; + uint32 finetune; + uint32 loopstart; + uint32 looplen; + uint16 panning; + uint16 flags; +}; -typedef struct DBMENVELOPE +struct DBMEnvelope { - WORD instrument; - BYTE flags; - BYTE numpoints; - BYTE sustain1; - BYTE loopbegin; - BYTE loopend; - BYTE sustain2; - WORD volenv[2*32]; -} DBMENVELOPE; + uint16 instrument; + uint8 flags; + uint8 numpoints; + uint8 sustain1; + uint8 loopbegin; + uint8 loopend; + uint8 sustain2; + uint16 volenv[2 * 32]; +}; -typedef struct DBMPATTERN +struct DBMPattern { - WORD rows; - DWORD packedsize; - BYTE patterndata[2]; // [packedsize] -} DBMPATTERN; + uint16 rows; + uint32 packedsize; + uint8 patterndata[2]; // [packedsize] +}; -typedef struct DBMSAMPLE +struct DBMSample { - DWORD flags; - DWORD samplesize; - BYTE sampledata[2]; // [samplesize] -} DBMSAMPLE; + uint32 flags; + uint32 samplesize; + uint8 sampledata[2]; // [samplesize] +}; #pragma pack(pop) -static ModCommand::COMMAND dbm_efftrans[23] = +static const ModCommand::COMMAND dbmEffects[23] = { CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, @@ -103,8 +103,8 @@ void ConvertDBMEffect(uint8 &command, uint8 ¶m) //------------------------------------------------- { - if(command < CountOf(dbm_efftrans)) - command = dbm_efftrans[command]; + if(command < CountOf(dbmEffects)) + command = dbmEffects[command]; else command = CMD_NONE; @@ -114,15 +114,19 @@ if(param == 0) command = CMD_NONE; break; + case CMD_VOLUMESLIDE: if(param & 0xF0) param &= 0xF0; break; + case CMD_GLOBALVOLUME: if(param <= 64) param *= 2; else param = 128; + break; + case CMD_MODCMDEX: switch(param & 0xF0) { @@ -158,15 +162,18 @@ break; } break; + case CMD_TEMPO: if(param <= 0x1F) command = CMD_SPEED; break; + case CMD_KEYOFF: if (param == 0) { // TODO key of at tick 0 } break; + case CMD_OFFSET: // TODO Sample offset slide command = CMD_NONE; @@ -178,15 +185,15 @@ bool CSoundFile::ReadDBM(const BYTE *lpStream, const DWORD dwMemLength) //--------------------------------------------------------------------- { - const DBMFILEHEADER *pfh = (DBMFILEHEADER *)lpStream; + const DBMFileHeader *pfh = (DBMFileHeader *)lpStream; DWORD dwMemPos; uint16 nOrders, nSamples, nInstruments, nPatterns; - if ((!lpStream) || (dwMemLength <= sizeof(DBMFILEHEADER)) || (!pfh->channels) + if ((!lpStream) || (dwMemLength <= sizeof(DBMFileHeader)) || (!pfh->channels) || (pfh->dbm_id != DBM_FILE_MAGIC) || (!pfh->songs) || (pfh->song_id != DBM_ID_SONG) || (pfh->name_id != DBM_ID_NAME) || (pfh->name_len != DBM_NAMELEN) || (pfh->info_id != DBM_ID_INFO) || (pfh->info_len != DBM_INFOLEN)) return false; - dwMemPos = sizeof(DBMFILEHEADER); + dwMemPos = sizeof(DBMFileHeader); nOrders = BigEndianW(pfh->orders); if (dwMemPos + 2 * nOrders + 8*3 >= dwMemLength) return false; nInstruments = BigEndianW(pfh->instruments); @@ -210,12 +217,12 @@ if (iOrd >= MAX_ORDERS) break; Order[iOrd] = (PATTERNINDEX)BigEndianW(*((WORD *)(lpStream + dwMemPos + iOrd * 2))); } - dwMemPos += 2*nOrders; + dwMemPos += 2 * nOrders; while (dwMemPos + 10 < dwMemLength) { - DWORD chunk_id = LittleEndian(((LPDWORD)(lpStream+dwMemPos))[0]); - DWORD chunk_size = BigEndian(((LPDWORD)(lpStream+dwMemPos))[1]); - DWORD chunk_pos; + uint32 chunk_id = LittleEndian(((uint32 *)(lpStream + dwMemPos))[0]); + uint32 chunk_size = BigEndian(((uint32 *)(lpStream + dwMemPos))[1]); + uint32 chunk_pos; dwMemPos += 8; chunk_pos = dwMemPos; @@ -229,12 +236,12 @@ { ModSample *psmp; ModInstrument *pIns; - DBMINSTRUMENT *pih; - WORD nsmp; + DBMInstrument *pih; + uint16 nsmp; - if (chunk_pos + sizeof(DBMINSTRUMENT) > dwMemPos) break; + if (chunk_pos + sizeof(DBMInstrument) > dwMemPos) break; - pih = (DBMINSTRUMENT *)(lpStream + chunk_pos); + pih = (DBMInstrument *)(lpStream + chunk_pos); nsmp = BigEndianW(pih->sampleno); psmp = ((nsmp) && (nsmp < MAX_SAMPLES)) ? &Samples[nsmp] : nullptr; @@ -262,26 +269,24 @@ pIns->nPan = 128; // Sample Info - if (psmp) + if(psmp) { - DWORD sflags = BigEndianW(pih->flags); + uint16 sflags = BigEndianW(pih->flags); psmp->nVolume = BigEndianW(pih->volume) * 4; - if ((!psmp->nVolume) || (psmp->nVolume > 256)) psmp->nVolume = 256; + if(/*!psmp->nVolume ||*/ psmp->nVolume > 256) psmp->nVolume = 256; // XXX First condition looks like a typical "modplug-ism" psmp->nGlobalVol = 64; psmp->nC5Speed = BigEndian(pih->finetune); - int f2t = FrequencyToTranspose(psmp->nC5Speed); - psmp->RelativeTone = (signed char)(f2t >> 7); - psmp->nFineTune = f2t & 0x7F; - if ((pih->looplen) && (sflags & 3)) + + if(pih->looplen && (sflags & 3)) { psmp->nLoopStart = BigEndian(pih->loopstart); psmp->nLoopEnd = psmp->nLoopStart + BigEndian(pih->looplen); psmp->uFlags |= CHN_LOOP; psmp->uFlags &= ~CHN_PINGPONGLOOP; - if (sflags & 2) psmp->uFlags |= CHN_PINGPONGLOOP; + if(sflags & 2) psmp->uFlags |= CHN_PINGPONGLOOP; } } - chunk_pos += sizeof(DBMINSTRUMENT); + chunk_pos += sizeof(DBMInstrument); m_nInstruments = iIns + 1; } } else @@ -293,11 +298,11 @@ chunk_pos += 2; for (UINT iEnv=0; iEnv<nEnvelopes; iEnv++) { - DBMENVELOPE *peh; + DBMEnvelope *peh; UINT nins; - if (chunk_pos + sizeof(DBMENVELOPE) > dwMemPos) break; - peh = (DBMENVELOPE *)(lpStream+chunk_pos); + if (chunk_pos + sizeof(DBMEnvelope) > dwMemPos) break; + peh = (DBMEnvelope *)(lpStream+chunk_pos); nins = BigEndianW(peh->instrument); if ((nins) && (nins < MAX_INSTRUMENTS) && (Instruments[nins]) && (peh->numpoints)) { @@ -317,7 +322,7 @@ pIns->VolEnv.Values[i] = (BYTE)BigEndianW(peh->volenv[i*2+1]); } } - chunk_pos += sizeof(DBMENVELOPE); + chunk_pos += sizeof(DBMEnvelope); } } else // Packed Pattern Data @@ -326,12 +331,12 @@ if (nPatterns > MAX_PATTERNS) nPatterns = MAX_PATTERNS; for(PATTERNINDEX iPat = 0; iPat < nPatterns; iPat++) { - DBMPATTERN *pph; + DBMPattern *pph; DWORD pksize; UINT nRows; - if (chunk_pos + sizeof(DBMPATTERN) > dwMemPos) break; - pph = (DBMPATTERN *)(lpStream+chunk_pos); + if (chunk_pos + sizeof(DBMPattern) > dwMemPos) break; + pph = (DBMPattern *)(lpStream+chunk_pos); pksize = BigEndian(pph->packedsize); if ((chunk_pos + pksize + 6 > dwMemPos) || (pksize > dwMemPos)) break; nRows = BigEndianW(pph->rows); @@ -444,12 +449,12 @@ for (UINT iSmp=1; iSmp<=nSamples; iSmp++) { ModSample *pSmp; - DBMSAMPLE *psh; + DBMSample *psh; DWORD samplesize; DWORD sampleflags; - if (chunk_pos + sizeof(DBMSAMPLE) >= dwMemPos) break; - psh = (DBMSAMPLE *)(lpStream+chunk_pos); + if (chunk_pos + sizeof(DBMSample) >= dwMemPos) break; + psh = (DBMSample *)(lpStream+chunk_pos); chunk_pos += 8; samplesize = BigEndian(psh->samplesize); sampleflags = BigEndian(psh->flags); Modified: trunk/OpenMPT/soundlib/Load_xm.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_xm.cpp 2012-03-21 00:36:20 UTC (rev 1226) +++ trunk/OpenMPT/soundlib/Load_xm.cpp 2012-03-21 14:18:54 UTC (rev 1227) @@ -606,7 +606,7 @@ \ if((len > uint16_max - (UINT)x) && GetpModDoc()) /*Reaching the limits of file format?*/ \ { \ - CString str; str.Format("%s (%s %u)\n", str_tooMuchPatternData, str_pattern, i); \ + CString str; str.Format("%s (%s %u)\n", str_tooMuchPatternData, str_pattern, pat); \ GetpModDoc()->AddToLog(str); \ break; \ } @@ -620,7 +620,6 @@ //BYTE s[64*64*5]; vector<BYTE> s(64*64*5, 0); BYTE xmph[9]; - int i; bool addChannel = false; // avoid odd channel count for FT2 compatibility XMFileHeader xmheader; @@ -691,19 +690,19 @@ } // Writing patterns - for (i = 0; i < nPatterns; i++) if (Patterns[i]) + for(PATTERNINDEX pat = 0; pat < nPatterns; pat++) if (Patterns[pat]) { - ModCommand *p = Patterns[i]; + ModCommand *p = Patterns[pat]; UINT len = 0; // Empty patterns are always loaded as 64-row patterns in FT2, regardless of their real size... - bool emptyPatNeedsFixing = (Patterns[i].GetNumRows() != 64); + bool emptyPatNeedsFixing = (Patterns[pat].GetNumRows() != 64); MemsetZero(xmph); xmph[0] = 9; - xmph[5] = (BYTE)(Patterns[i].GetNumRows() & 0xFF); - xmph[6] = (BYTE)(Patterns[i].GetNumRows() >> 8); + xmph[5] = (BYTE)(Patterns[pat].GetNumRows() & 0xFF); + xmph[6] = (BYTE)(Patterns[pat].GetNumRows() >> 8); - for (UINT j = m_nChannels * Patterns[i].GetNumRows(); j > 0; j--, p++) + for (UINT 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; @@ -801,32 +800,70 @@ { MemsetZero(xmph); xmph[0] = 9; - xmph[5] = (BYTE)(Patterns[i].GetNumRows() & 0xFF); - xmph[6] = (BYTE)(Patterns[i].GetNumRows() >> 8); + xmph[5] = (BYTE)(Patterns[pat].GetNumRows() & 0xFF); + xmph[6] = (BYTE)(Patterns[pat].GetNumRows() >> 8); fwrite(xmph, 1, 9, f); } + // Check which samples are referenced by which instruments (for assigning unreferenced samples to instruments) + vector<bool> sampleAssigned(GetNumSamples(), false); + for(INSTRUMENTINDEX ins = 1; ins <= GetNumInstruments(); ins++) + { + if(Instruments[ins] == nullptr) + { + continue; + } + const std::set<SAMPLEINDEX> referencedSamples = Instruments[ins]->GetSamples(); + for(std::set<SAMPLEINDEX>::const_iterator sample = referencedSamples.begin(); sample != referencedSamples.end(); sample++) + { + if(*sample <= GetNumSamples()) + { + sampleAssigned[*sample - 1] = true; + } + } + } + // Writing instruments - for(i = 1; i <= writeInstruments; i++) + for(INSTRUMENTINDEX ins = 1; ins <= writeInstruments; ins++) { XMInstrumentHeader insHeader; vector<SAMPLEINDEX> samples; if(GetNumInstruments()) { - if(Instruments[i] != nullptr) + if(Instruments[ins] != nullptr) { // Convert instrument - insHeader.ConvertToXM(*Instruments[i], compatibilityExport); + insHeader.ConvertToXM(*Instruments[ins], compatibilityExport); - samples = insHeader.instrument.GetSampleList(*Instruments[i], compatibilityExport); + samples = insHeader.instrument.GetSampleList(*Instruments[ins], compatibilityExport); if(samples.size() > 0 && samples[0] <= GetNumSamples()) { // Copy over auto-vibrato settings of first sample insHeader.instrument.ApplyAutoVibratoToXM(Samples[samples[0]], GetType()); } - // XXX Try to save "instrument-less" samples as well. + vector<SAMPLEINDEX> additionalSamples; + + // Try to save "instrument-less" samples as well by adding those after the "normal" samples of our sample. + // We look for unassigned samples directly after the samples assigned to our current instrument, so if + // f.e. sample 1 is assigned to instrument 1 and samples 2 to 10 aren't assigned to any instrument, + // we will assign those to sample 1. Any samples before the first referenced sample are going to be lost, + // but hey, I wrote this mostly for preserving instrument texts in existing modules, where we shouldn't encounter this situation... + for(vector<SAMPLEINDEX>::const_iterator sample = samples.begin(); sample != samples.end(); sample++) + { + SAMPLEINDEX smp = *sample; + while(smp < GetNumSamples() + && !sampleAssigned[smp] // zero-based + && insHeader.numSamples < (compatibilityExport ? 16 : 32)) + { + sampleAssigned[smp++] = true; // Don't want to add this sample again. + additionalSamples.push_back(smp); // Not zero-based :) + insHeader.numSamples++; + } + } + + samples.insert(samples.end(), additionalSamples.begin(), additionalSamples.end()); } else { MemsetZero(insHeader); @@ -836,8 +873,8 @@ // Convert samples to instruments MemsetZero(insHeader); insHeader.numSamples = 1; - insHeader.instrument.ApplyAutoVibratoToXM(Samples[i], GetType()); - samples.push_back(i); + insHeader.instrument.ApplyAutoVibratoToXM(Samples[ins], GetType()); + samples.push_back(ins); } insHeader.Finalise(); @@ -848,29 +885,29 @@ vector<UINT> sampleFlags(samples.size()); // Write Sample Headers - for(SAMPLEINDEX i = 0; i < samples.size(); i++) + for(SAMPLEINDEX smp = 0; smp < samples.size(); smp++) { XMSample xmSample; - if(samples[i] <= GetNumSamples()) + if(samples[smp] <= GetNumSamples()) { - xmSample.ConvertToXM(Samples[samples[i]], GetType(), compatibilityExport); + xmSample.ConvertToXM(Samples[samples[smp]], GetType(), compatibilityExport); } else { MemsetZero(xmSample); } - sampleFlags[i] = xmSample.GetSampleFormat(); + sampleFlags[smp] = xmSample.GetSampleFormat(); - StringFixer::WriteString<StringFixer::spacePadded>(xmSample.name, m_szNames[samples[i]]); + StringFixer::WriteString<StringFixer::spacePadded>(xmSample.name, m_szNames[samples[smp]]); fwrite(&xmSample, 1, sizeof(xmSample), f); } // Write Sample Data - for(SAMPLEINDEX i = 0; i < samples.size(); i++) + for(SAMPLEINDEX smp = 0; smp < samples.size(); smp++) { - if(samples[i] <= GetNumSamples()) + if(samples[smp] <= GetNumSamples()) { - WriteSample(f, &Samples[samples[i]], sampleFlags[i]); + WriteSample(f, &Samples[samples[smp]], sampleFlags[smp]); } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |