12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148 |
- #include "stdafx.h"
- #include "Loaders.h"
- #include "BitReader.h"
- OPENMPT_NAMESPACE_BEGIN
- struct DMFFileHeader
- {
- char signature[4];
- uint8 version;
- char tracker[8];
- char songname[30];
- char composer[20];
- uint8 creationDay;
- uint8 creationMonth;
- uint8 creationYear;
- };
- MPT_BINARY_STRUCT(DMFFileHeader, 66)
- struct DMFChunk
- {
-
- enum ChunkIdentifiers
- {
- idCMSG = MagicLE("CMSG"),
- idSEQU = MagicLE("SEQU"),
- idPATT = MagicLE("PATT"),
- idSMPI = MagicLE("SMPI"),
- idSMPD = MagicLE("SMPD"),
- idSMPJ = MagicLE("SMPJ"),
- idENDE = MagicLE("ENDE"),
- idSETT = MagicLE("SETT"),
- };
- uint32le id;
- uint32le length;
- size_t GetLength() const
- {
- return length;
- }
- ChunkIdentifiers GetID() const
- {
- return static_cast<ChunkIdentifiers>(id.get());
- }
- };
- MPT_BINARY_STRUCT(DMFChunk, 8)
- struct DMFPatterns
- {
- uint16le numPatterns;
- uint8le numTracks;
- };
- MPT_BINARY_STRUCT(DMFPatterns, 3)
- struct DMFPatternHeader
- {
- uint8le numTracks;
- uint8le beat;
- uint16le numRows;
- uint32le patternLength;
-
- };
- MPT_BINARY_STRUCT(DMFPatternHeader, 8)
- struct DMFSampleHeader
- {
- enum SampleFlags
- {
-
- smpLoop = 0x01,
- smp16Bit = 0x02,
- smpCompMask = 0x0C,
- smpComp1 = 0x04,
- smpComp2 = 0x08,
- smpComp3 = 0x0C,
- smpLibrary = 0x80,
- };
- uint32le length;
- uint32le loopStart;
- uint32le loopEnd;
- uint16le c3freq;
- uint8le volume;
- uint8le flags;
-
- void ConvertToMPT(ModSample &mptSmp) const
- {
- mptSmp.Initialize();
- mptSmp.nLength = length;
- mptSmp.nSustainStart = loopStart;
- mptSmp.nSustainEnd = loopEnd;
- mptSmp.nC5Speed = c3freq;
- mptSmp.nGlobalVol = 64;
- if(volume)
- mptSmp.nVolume = volume + 1;
- else
- mptSmp.nVolume = 256;
- mptSmp.uFlags.set(SMP_NODEFAULTVOLUME, volume == 0);
- if((flags & smpLoop) != 0 && mptSmp.nSustainEnd > mptSmp.nSustainStart)
- {
- mptSmp.uFlags.set(CHN_SUSTAINLOOP);
- }
- if((flags & smp16Bit) != 0)
- {
- mptSmp.uFlags.set(CHN_16BIT);
- mptSmp.nLength /= 2;
- mptSmp.nSustainStart /= 2;
- mptSmp.nSustainEnd /= 2;
- }
- }
- };
- MPT_BINARY_STRUCT(DMFSampleHeader, 16)
- struct DMFPatternSettings
- {
- struct ChannelState
- {
- ModCommand::NOTE noteBuffer = NOTE_NONE;
- ModCommand::NOTE lastNote = NOTE_NONE;
- uint8 vibratoType = 8;
- uint8 tremoloType = 4;
- uint8 highOffset = 6;
- bool playDir = false;
- };
- std::vector<ChannelState> channels;
- bool realBPMmode = false;
- uint8 beat = 0;
- uint8 tempoTicks = 32;
- uint8 tempoBPM = 120;
- uint8 internalTicks = 6;
- DMFPatternSettings(CHANNELINDEX numChannels)
- : channels(numChannels)
- { }
- };
- static uint8 DMFporta2MPT(uint8 val, const uint8 internalTicks, const bool hasFine)
- {
- if(val == 0)
- return 0;
- else if((val <= 0x0F && hasFine) || internalTicks < 2)
- return (val | 0xF0);
- else
- return std::max(uint8(1), static_cast<uint8>((val / (internalTicks - 1))));
- }
- static uint8 DMFslide2MPT(uint8 val, const uint8 internalTicks, const bool up)
- {
- val = std::max(uint8(1), static_cast<uint8>(val / 4));
- const bool isFine = (val < 0x0F) || (internalTicks < 2);
- if(!isFine)
- val = std::max(uint8(1), static_cast<uint8>((val + internalTicks - 2) / (internalTicks - 1)));
- if(up)
- return (isFine ? 0x0F : 0x00) | (val << 4);
- else
- return (isFine ? 0xF0 : 0x00) | (val & 0x0F);
- }
- static uint8 DMFtremor2MPT(uint8 val, const uint8 internalTicks)
- {
- uint8 ontime = (val >> 4);
- uint8 offtime = (val & 0x0F);
- ontime = static_cast<uint8>(Clamp(ontime * internalTicks / 15, 1, 15));
- offtime = static_cast<uint8>(Clamp(offtime * internalTicks / 15, 1, 15));
- return (ontime << 4) | offtime;
- }
- static uint8 DMFdelay2MPT(uint8 val, const uint8 internalTicks)
- {
- int newval = (int)val * (int)internalTicks / 255;
- Limit(newval, 0, 15);
- return (uint8)newval;
- }
- static uint8 DMFvibrato2MPT(uint8 val, const uint8 internalTicks)
- {
-
-
- const int periodInTicks = std::max(1, (val >> 4)) * internalTicks;
- const uint8 matchingPeriod = static_cast<uint8>(Clamp((128 / periodInTicks), 1, 15));
- return (matchingPeriod << 4) | std::max(uint8(1), static_cast<uint8>(val & 0x0F));
- }
- static void ApplyEffectMemory(const ModCommand *m, ROWINDEX row, CHANNELINDEX numChannels, uint8 effect, uint8 ¶m)
- {
- if(effect == CMD_NONE || param == 0)
- return;
- const bool isTonePortaEffect = (effect == CMD_PORTAMENTOUP || effect == CMD_PORTAMENTODOWN || effect == CMD_TONEPORTAMENTO);
- const bool isVolSlideEffect = (effect == CMD_VOLUMESLIDE || effect == CMD_TONEPORTAVOL || effect == CMD_VIBRATOVOL);
- while(row > 0)
- {
- m -= numChannels;
- row--;
-
- bool isSame = (effect == m->command);
- if(isTonePortaEffect && (m->command == CMD_PORTAMENTOUP || m->command == CMD_PORTAMENTODOWN || m->command == CMD_TONEPORTAMENTO))
- {
- if(m->param < 0xE0)
- {
-
- isSame = true;
- } else
- {
- return;
- }
- } else if(isVolSlideEffect && (m->command == CMD_VOLUMESLIDE || m->command == CMD_TONEPORTAVOL || m->command == CMD_VIBRATOVOL))
- {
- isSame = true;
- }
- if(isTonePortaEffect
- && (m->volcmd == VOLCMD_PORTAUP || m->volcmd == VOLCMD_PORTADOWN || m->volcmd == VOLCMD_TONEPORTAMENTO)
- && m->vol != 0)
- {
-
- return;
- } else if(isVolSlideEffect
- && (m->volcmd == VOLCMD_FINEVOLUP || m->volcmd == VOLCMD_FINEVOLDOWN || m->volcmd == VOLCMD_VOLSLIDEUP || m->volcmd == VOLCMD_VOLSLIDEDOWN)
- && m->vol != 0)
- {
-
- return;
- }
- if(isSame)
- {
- if(param != m->param && m->param != 0)
- {
-
- return;
- } else if(param == m->param)
- {
-
- param = 0;
- return;
- }
- }
- }
- }
- static PATTERNINDEX ConvertDMFPattern(FileReader &file, const uint8 fileVersion, DMFPatternSettings &settings, CSoundFile &sndFile)
- {
-
- enum PatternFlags
- {
-
- patGlobPack = 0x80,
- patGlobMask = 0x3F,
-
- patCounter = 0x80,
- patInstr = 0x40,
- patNote = 0x20,
- patVolume = 0x10,
- patInsEff = 0x08,
- patNoteEff = 0x04,
- patVolEff = 0x02,
- };
- file.Rewind();
-
- DMFPatternHeader patHead;
- if(fileVersion < 3)
- {
- patHead.numTracks = file.ReadUint8();
- file.Skip(2);
- patHead.numRows = file.ReadUint16LE();
- patHead.patternLength = file.ReadUint32LE();
- } else
- {
- file.ReadStruct(patHead);
- }
- if(fileVersion < 6)
- patHead.beat = 0;
- const ROWINDEX numRows = Clamp(ROWINDEX(patHead.numRows), ROWINDEX(1), MAX_PATTERN_ROWS);
- const PATTERNINDEX pat = sndFile.Patterns.InsertAny(numRows);
- if(pat == PATTERNINDEX_INVALID)
- {
- return pat;
- }
- PatternRow m = sndFile.Patterns[pat].GetRow(0);
- const CHANNELINDEX numChannels = std::min(static_cast<CHANNELINDEX>(sndFile.GetNumChannels() - 1), static_cast<CHANNELINDEX>(patHead.numTracks));
-
-
- for(CHANNELINDEX chn = numChannels + 1; chn < sndFile.GetNumChannels(); chn++)
- {
- m[chn].note = NOTE_NOTECUT;
- }
-
- settings.beat = (patHead.beat >> 4);
- bool tempoChange = settings.realBPMmode;
- uint8 writeDelay = 0;
-
- std::vector<uint8> channelCounter(numChannels + 1, 0);
- for(ROWINDEX row = 0; row < numRows; row++)
- {
-
- if(channelCounter[0] == 0)
- {
- uint8 globalInfo = file.ReadUint8();
-
- if((globalInfo & patGlobPack) != 0)
- {
- channelCounter[0] = file.ReadUint8();
- }
- globalInfo &= patGlobMask;
- uint8 globalData = 0;
- if(globalInfo != 0)
- {
- globalData = file.ReadUint8();
- }
- switch(globalInfo)
- {
- case 1:
- settings.realBPMmode = false;
- settings.tempoTicks = std::max(uint8(1), globalData);
- settings.tempoBPM = 0;
- tempoChange = true;
- break;
- case 2:
- if(globalData)
- {
- settings.realBPMmode = true;
- settings.tempoBPM = globalData;
- if(settings.beat != 0)
- {
- settings.tempoTicks = (globalData * settings.beat * 15);
- }
- tempoChange = true;
- }
- break;
- case 3:
- settings.beat = (globalData >> 4);
- if(settings.beat != 0)
- {
-
- tempoChange = settings.realBPMmode;
- } else
- {
-
- settings.realBPMmode = false;
- }
- break;
- case 4:
- writeDelay = globalData;
- break;
- case 5:
- break;
- case 6:
- if(globalData > 0)
- {
- uint8 &tempoData = (settings.realBPMmode) ? settings.tempoBPM : settings.tempoTicks;
- if(tempoData < 256 - globalData)
- {
- tempoData += globalData;
- } else
- {
- tempoData = 255;
- }
- tempoChange = true;
- }
- break;
- case 7:
- if(globalData > 0)
- {
- uint8 &tempoData = (settings.realBPMmode) ? settings.tempoBPM : settings.tempoTicks;
- if(tempoData > 1 + globalData)
- {
- tempoData -= globalData;
- } else
- {
- tempoData = 1;
- }
- tempoChange = true;
- }
- break;
- }
- } else
- {
- channelCounter[0]--;
- }
-
- int speed = 0, tempo = 0;
- if(tempoChange)
- {
-
- if(!settings.realBPMmode || settings.beat)
- {
-
-
-
-
-
-
-
-
- const int tickspeed = (settings.realBPMmode) ? std::max(1, settings.tempoBPM * settings.beat * 2) : ((settings.tempoTicks + 1) * 30);
-
- for(speed = 255; speed >= 1; speed--)
- {
-
-
- tempo = tickspeed * speed / 48;
- if(tempo >= 32 && tempo <= 255)
- break;
- }
- Limit(tempo, 32, 255);
- settings.internalTicks = static_cast<uint8>(std::max(1, speed));
- } else
- {
- tempoChange = false;
- }
- }
- m = sndFile.Patterns[pat].GetpModCommand(row, 1);
- for(CHANNELINDEX chn = 1; chn <= numChannels; chn++, m++)
- {
-
- if(channelCounter[chn] == 0)
- {
- const uint8 channelInfo = file.ReadUint8();
-
-
- if((channelInfo & patCounter) != 0)
- {
- channelCounter[chn] = file.ReadUint8();
- }
-
-
- bool slideNote = true;
- if((channelInfo & patInstr) != 0)
- {
- m->instr = file.ReadUint8();
- if(m->instr != 0)
- {
- slideNote = false;
- }
- }
-
-
- if((channelInfo & patNote) != 0)
- {
- m->note = file.ReadUint8();
- if(m->note >= 1 && m->note <= 108)
- {
- m->note = static_cast<uint8>(Clamp(m->note + 24, NOTE_MIN, NOTE_MAX));
- settings.channels[chn].lastNote = m->note;
- } else if(m->note >= 129 && m->note <= 236)
- {
-
- m->note = static_cast<uint8>(Clamp((m->note & 0x7F) + 24, NOTE_MIN, NOTE_MAX));
- settings.channels[chn].noteBuffer = m->note;
- m->note = NOTE_NONE;
- } else if(m->note == 255)
- {
- m->note = NOTE_NOTECUT;
- }
- }
-
- if(m->note == NOTE_NONE && m->instr > 0)
- {
- m->note = settings.channels[chn].lastNote;
- m->instr = 0;
- }
- if(m->IsNote())
- {
- settings.channels[chn].playDir = false;
- }
- uint8 effect1 = CMD_NONE, effect2 = CMD_NONE, effect3 = CMD_NONE;
- uint8 effectParam1 = 0, effectParam2 = 0, effectParam3 = 0;
- bool useMem2 = false, useMem3 = false;
-
-
- if((channelInfo & patVolume) != 0)
- {
- m->volcmd = VOLCMD_VOLUME;
- m->vol = (file.ReadUint8() + 2) / 4;
- }
-
-
- if((channelInfo & patInsEff) != 0)
- {
- effect1 = file.ReadUint8();
- effectParam1 = file.ReadUint8();
- switch(effect1)
- {
- case 1:
- m->note = NOTE_NOTECUT;
- effect1 = CMD_NONE;
- break;
- case 2:
- m->note = NOTE_KEYOFF;
- effect1 = CMD_NONE;
- break;
- case 3:
- m->note = settings.channels[chn].lastNote;
- settings.channels[chn].playDir = false;
- effect1 = CMD_NONE;
- break;
- case 4:
- effectParam1 = DMFdelay2MPT(effectParam1, settings.internalTicks);
- if(effectParam1)
- {
- effect1 = CMD_S3MCMDEX;
- effectParam1 = 0xD0 | (effectParam1);
- } else
- {
- effect1 = CMD_NONE;
- }
- if(m->note == NOTE_NONE)
- {
- m->note = settings.channels[chn].lastNote;
- settings.channels[chn].playDir = false;
- }
- break;
- case 5:
- effectParam1 = std::max(uint8(1), DMFdelay2MPT(effectParam1, settings.internalTicks));
- effect1 = CMD_RETRIG;
- settings.channels[chn].playDir = false;
- break;
- case 6:
- case 7:
- case 8:
- case 9:
-
- if(row > 0 && effect1 != settings.channels[chn].highOffset)
- {
- if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0xA0 | (effect1 - 6))).Row(row - 1).Channel(chn).RetryPreviousRow()))
- {
- settings.channels[chn].highOffset = effect1;
- }
- }
- effect1 = CMD_OFFSET;
- if(m->note == NOTE_NONE)
- {
-
- m->note = settings.channels[chn].lastNote;
- }
- settings.channels[chn].playDir = false;
- break;
- case 10:
- effect1 = CMD_S3MCMDEX;
- if(settings.channels[chn].playDir == false)
- effectParam1 = 0x9F;
- else
- effectParam1 = 0x9E;
- settings.channels[chn].playDir = !settings.channels[chn].playDir;
- break;
- default:
- effect1 = CMD_NONE;
- break;
- }
- }
-
-
- if((channelInfo & patNoteEff) != 0)
- {
- effect2 = file.ReadUint8();
- effectParam2 = file.ReadUint8();
- switch(effect2)
- {
- case 1:
- {
- const auto fine = std::div(static_cast<int8>(effectParam2) * 8, 128);
- if(m->IsNote())
- m->note = static_cast<ModCommand::NOTE>(Clamp(m->note + fine.quot, NOTE_MIN, NOTE_MAX));
- effect2 = CMD_FINETUNE;
- effectParam2 = static_cast<uint8>(fine.rem) ^ 0x80;
- }
- break;
- case 2:
- effectParam2 = DMFdelay2MPT(effectParam2, settings.internalTicks);
- if(effectParam2)
- {
- effect2 = CMD_S3MCMDEX;
- effectParam2 = 0xD0 | (effectParam2);
- } else
- {
- effect2 = CMD_NONE;
- }
- useMem2 = true;
- break;
- case 3:
- effect2 = CMD_ARPEGGIO;
- useMem2 = true;
- break;
- case 4:
- case 5:
- effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, true);
- effect2 = (effect2 == 4) ? CMD_PORTAMENTOUP : CMD_PORTAMENTODOWN;
- useMem2 = true;
- break;
- case 6:
- if(m->note == NOTE_NONE)
- {
- m->note = settings.channels[chn].noteBuffer;
- }
- effectParam2 = DMFporta2MPT(effectParam2, settings.internalTicks, false);
- effect2 = CMD_TONEPORTAMENTO;
- useMem2 = true;
- break;
- case 7:
- m->note = static_cast<ModCommand::NOTE>(Clamp(effectParam2 + 25, NOTE_MIN, NOTE_MAX));
- effect2 = CMD_TONEPORTAMENTO;
- effectParam2 = 0xFF;
- useMem2 = true;
- break;
- case 8:
- case 9:
- case 10:
-
- if(row > 0 && effect2 != settings.channels[chn].vibratoType)
- {
- if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x30 | (effect2 - 8))).Row(row - 1).Channel(chn).RetryPreviousRow()))
- {
- settings.channels[chn].vibratoType = effect2;
- }
- }
- effect2 = CMD_VIBRATO;
- effectParam2 = DMFvibrato2MPT(effectParam2, settings.internalTicks);
- useMem2 = true;
- break;
- case 11:
- effectParam2 = DMFtremor2MPT(effectParam2, settings.internalTicks);
- effect2 = CMD_TREMOR;
- useMem2 = true;
- break;
- case 12:
- effectParam2 = DMFdelay2MPT(effectParam2, settings.internalTicks);
- if(effectParam2)
- {
- effect2 = CMD_S3MCMDEX;
- effectParam2 = 0xC0 | (effectParam2);
- } else
- {
- effect2 = CMD_NONE;
- m->note = NOTE_NOTECUT;
- }
- useMem2 = true;
- break;
- default:
- effect2 = CMD_NONE;
- break;
- }
- }
-
-
- if((channelInfo & patVolEff) != 0)
- {
- effect3 = file.ReadUint8();
- effectParam3 = file.ReadUint8();
- switch(effect3)
- {
- case 1:
- case 2:
- effectParam3 = DMFslide2MPT(effectParam3, settings.internalTicks, (effect3 == 1));
- effect3 = CMD_VOLUMESLIDE;
- useMem3 = true;
- break;
- case 3:
- effectParam3 = DMFtremor2MPT(effectParam3, settings.internalTicks);
- effect3 = CMD_TREMOR;
- useMem3 = true;
- break;
- case 4:
- case 5:
- case 6:
-
- if(row > 0 && effect3 != settings.channels[chn].tremoloType)
- {
- if(sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, (0x40 | (effect3 - 4))).Row(row - 1).Channel(chn).RetryPreviousRow()))
- {
- settings.channels[chn].tremoloType = effect3;
- }
- }
- effect3 = CMD_TREMOLO;
- effectParam3 = DMFvibrato2MPT(effectParam3, settings.internalTicks);
- useMem3 = true;
- break;
- case 7:
- effect3 = CMD_PANNING8;
- break;
- case 8:
- case 9:
- effectParam3 = DMFslide2MPT(effectParam3, settings.internalTicks, (effect3 == 8));
- effect3 = CMD_PANNINGSLIDE;
- useMem3 = true;
- break;
- case 10:
- effect3 = CMD_PANBRELLO;
- effectParam3 = DMFvibrato2MPT(effectParam3, settings.internalTicks);
- useMem3 = true;
- break;
- default:
- effect3 = CMD_NONE;
- break;
- }
- }
-
- if(useMem2)
- ApplyEffectMemory(m, row, sndFile.GetNumChannels(), effect2, effectParam2);
- if(useMem3)
- ApplyEffectMemory(m, row, sndFile.GetNumChannels(), effect3, effectParam3);
-
- if(slideNote && m->IsNote())
- {
- if(effect2 == CMD_NONE)
- {
- effect2 = CMD_TONEPORTAMENTO;
- effectParam2 = 0xFF;
- } else if(effect3 == CMD_NONE && effect2 != CMD_TONEPORTAMENTO)
- {
- effect3 = CMD_TONEPORTAMENTO;
- effectParam3 = 0xFF;
- }
- }
-
- if(m->volcmd == VOLCMD_VOLUME)
- {
- if(effect2 == CMD_NONE)
- {
- effect2 = CMD_VOLUME;
- effectParam2 = m->vol;
- m->volcmd = VOLCMD_NONE;
- } else if(effect3 == CMD_NONE)
- {
- effect3 = CMD_VOLUME;
- effectParam3 = m->vol;
- m->volcmd = VOLCMD_NONE;
- }
- }
- ModCommand::TwoRegularCommandsToMPT(effect2, effectParam2, effect3, effectParam3);
- if(m->volcmd == VOLCMD_NONE && effect2 != VOLCMD_NONE)
- {
- m->volcmd = effect2;
- m->vol = effectParam2;
- }
-
- if(effect1 != CMD_NONE)
- {
- ModCommand::TwoRegularCommandsToMPT(effect3, effectParam3, effect1, effectParam1);
- if(m->volcmd == VOLCMD_NONE && effect3 != VOLCMD_NONE)
- {
- m->volcmd = effect3;
- m->vol = effectParam3;
- }
- m->command = effect1;
- m->param = effectParam1;
- } else if(effect3 != CMD_NONE)
- {
- m->command = effect3;
- m->param = effectParam3;
- }
- } else
- {
- channelCounter[chn]--;
- }
- }
-
- if(tempoChange)
- {
- tempoChange = false;
-
- sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_TEMPO, static_cast<ModCommand::PARAM>(tempo)).Row(row).Channel(0).RetryNextRow());
- sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, static_cast<ModCommand::PARAM>(speed)).Row(row).RetryNextRow());
- }
-
- if(writeDelay & 0xF0)
- {
- sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0xE0 | (writeDelay >> 4)).Row(row).AllowMultiple());
- }
- if(writeDelay & 0x0F)
- {
- const uint8 param = (writeDelay & 0x0F) * settings.internalTicks / 15;
- sndFile.Patterns[pat].WriteEffect(EffectWriter(CMD_S3MCMDEX, 0x60u | Clamp(param, uint8(1), uint8(15))).Row(row).AllowMultiple());
- }
- writeDelay = 0;
- }
- return pat;
- }
- static bool ValidateHeader(const DMFFileHeader &fileHeader)
- {
- if(std::memcmp(fileHeader.signature, "DDMF", 4)
- || !fileHeader.version || fileHeader.version > 10)
- {
- return false;
- }
- return true;
- }
- CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize)
- {
- DMFFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader))
- {
- return ProbeWantMoreData;
- }
- if(!ValidateHeader(fileHeader))
- {
- return ProbeFailure;
- }
- MPT_UNREFERENCED_PARAMETER(pfilesize);
- return ProbeSuccess;
- }
- bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
- {
- file.Rewind();
- DMFFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader))
- {
- return false;
- }
- if(!ValidateHeader(fileHeader))
- {
- return false;
- }
- if(loadFlags == onlyVerifyHeader)
- {
- return true;
- }
- InitializeGlobals(MOD_TYPE_DMF);
- m_modFormat.formatName = MPT_UFORMAT("X-Tracker v{}")(fileHeader.version);
- m_modFormat.type = U_("dmf");
- m_modFormat.charset = mpt::Charset::CP437;
- m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songname);
- m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.composer));
- FileHistory mptHistory;
- mptHistory.loadDate.tm_mday = Clamp(fileHeader.creationDay, uint8(1), uint8(31));
- mptHistory.loadDate.tm_mon = Clamp(fileHeader.creationMonth, uint8(1), uint8(12)) - 1;
- mptHistory.loadDate.tm_year = fileHeader.creationYear;
- m_FileHistory.clear();
- m_FileHistory.push_back(mptHistory);
-
- ChunkReader::ChunkList<DMFChunk> chunks;
- while(file.CanRead(sizeof(DMFChunk)))
- {
- DMFChunk chunkHeader;
- file.Read(chunkHeader);
- uint32 chunkLength = chunkHeader.length, chunkSkip = 0;
-
- if(fileHeader.version == 3 && chunkHeader.GetID() == DMFChunk::idSEQU)
- chunkSkip = 2;
-
- else if(fileHeader.version == 4 && chunkHeader.GetID() == DMFChunk::idSEQU)
- chunkSkip = 4;
-
-
-
- else if(fileHeader.version < 8 && chunkHeader.GetID() == DMFChunk::idSMPD)
- chunkLength = uint32_max;
- chunks.chunks.push_back(ChunkReader::Item<DMFChunk>{chunkHeader, file.ReadChunk(chunkLength)});
- file.Skip(chunkSkip);
- }
- FileReader chunk;
-
- chunk = chunks.GetChunk(DMFChunk::idSEQU);
- ORDERINDEX seqLoopStart = 0, seqLoopEnd = ORDERINDEX_MAX;
- if(fileHeader.version >= 3)
- seqLoopStart = chunk.ReadUint16LE();
- if(fileHeader.version >= 4)
- seqLoopEnd = chunk.ReadUint16LE();
-
-
- if(fileHeader.version == 4 && seqLoopEnd == 0)
- seqLoopEnd = ORDERINDEX_MAX;
- ReadOrderFromFile<uint16le>(Order(), chunk, chunk.BytesLeft() / 2);
- LimitMax(seqLoopStart, Order().GetLastIndex());
- LimitMax(seqLoopEnd, Order().GetLastIndex());
-
- chunk = chunks.GetChunk(DMFChunk::idPATT);
- if(chunk.IsValid() && (loadFlags & loadPatternData))
- {
- DMFPatterns patHeader;
- chunk.ReadStruct(patHeader);
- m_nChannels = Clamp<uint8, uint8>(patHeader.numTracks, 1, 32) + 1;
-
- std::vector<FileReader> patternChunks(patHeader.numPatterns);
- for(auto &patternChunk : patternChunks)
- {
- const uint8 headerSize = fileHeader.version < 3 ? 9 : 8;
- chunk.Skip(headerSize - sizeof(uint32le));
- const uint32 patLength = chunk.ReadUint32LE();
- chunk.SkipBack(headerSize);
- patternChunk = chunk.ReadChunk(headerSize + patLength);
- }
-
- DMFPatternSettings settings(GetNumChannels());
- Patterns.ResizeArray(Order().GetLength());
- for(PATTERNINDEX &pat : Order())
- {
-
- if(pat < patternChunks.size())
- {
- pat = ConvertDMFPattern(patternChunks[pat], fileHeader.version, settings, *this);
- }
- }
-
- if(Order().IsValidPat(seqLoopEnd) && (seqLoopStart > 0 || seqLoopEnd < Order().GetLastIndex()))
- {
- PATTERNINDEX pat = Order()[seqLoopEnd];
- Patterns[pat].WriteEffect(EffectWriter(CMD_POSITIONJUMP, static_cast<ModCommand::PARAM>(seqLoopStart)).Row(Patterns[pat].GetNumRows() - 1).RetryPreviousRow());
- }
- }
-
- chunk = chunks.GetChunk(DMFChunk::idCMSG);
- if(chunk.IsValid())
- {
-
-
-
- chunk.Skip(1);
- m_songMessage.ReadFixedLineLength(chunk, chunk.BytesLeft(), 40, 0);
- }
-
-
- FileReader sampleDataChunk = chunks.GetChunk(DMFChunk::idSMPD);
- chunk = chunks.GetChunk(DMFChunk::idSMPI);
- m_nSamples = chunk.ReadUint8();
- for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
- {
- const uint8 nameLength = (fileHeader.version < 2) ? 30 : chunk.ReadUint8();
- chunk.ReadString<mpt::String::spacePadded>(m_szNames[smp], nameLength);
- DMFSampleHeader sampleHeader;
- ModSample &sample = Samples[smp];
- chunk.ReadStruct(sampleHeader);
- sampleHeader.ConvertToMPT(sample);
-
- if(fileHeader.version >= 8)
- chunk.ReadString<mpt::String::spacePadded>(sample.filename, 8);
-
- chunk.Skip(fileHeader.version > 1 ? 6 : 2);
-
- FileReader sampleData = sampleDataChunk.ReadChunk(sampleDataChunk.ReadUint32LE());
- if(sampleData.IsValid() && (loadFlags & loadSampleData))
- {
- SampleIO(
- sample.uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit,
- SampleIO::mono,
- SampleIO::littleEndian,
- (sampleHeader.flags & DMFSampleHeader::smpCompMask) == DMFSampleHeader::smpComp1 ? SampleIO::DMF : SampleIO::signedPCM)
- .ReadSample(sample, sampleData);
- }
- }
- InitializeChannels();
- m_SongFlags = SONG_LINEARSLIDES | SONG_ITCOMPATGXX;
- m_nDefaultSpeed = 6;
- m_nDefaultTempo.Set(120);
- m_nDefaultGlobalVolume = 256;
- m_nSamplePreAmp = m_nVSTiVolume = 48;
- m_playBehaviour.set(kApplyOffsetWithoutNote);
- return true;
- }
- struct DMFHNode
- {
- int16 left, right;
- uint8 value;
- };
- struct DMFHTree
- {
- BitReader file;
- int lastnode = 0, nodecount = 0;
- DMFHNode nodes[256]{};
- DMFHTree(FileReader &file)
- : file(file)
- {
- }
-
-
-
-
- void DMFNewNode()
- {
- int actnode = nodecount;
- if(actnode > 255) return;
- nodes[actnode].value = static_cast<uint8>(file.ReadBits(7));
- bool isLeft = file.ReadBits(1) != 0;
- bool isRight = file.ReadBits(1) != 0;
- actnode = lastnode;
- if(actnode > 255) return;
- nodecount++;
- lastnode = nodecount;
- if(isLeft)
- {
- nodes[actnode].left = (int16)lastnode;
- DMFNewNode();
- } else
- {
- nodes[actnode].left = -1;
- }
- lastnode = nodecount;
- if(isRight)
- {
- nodes[actnode].right = (int16)lastnode;
- DMFNewNode();
- } else
- {
- nodes[actnode].right = -1;
- }
- }
- };
- uintptr_t DMFUnpack(FileReader &file, uint8 *psample, uint32 maxlen)
- {
- DMFHTree tree(file);
- uint8 value = 0, delta = 0;
- try
- {
- tree.DMFNewNode();
- if(tree.nodes[0].left < 0 || tree.nodes[0].right < 0)
- return tree.file.GetPosition();
- for(uint32 i = 0; i < maxlen; i++)
- {
- int actnode = 0;
- bool sign = tree.file.ReadBits(1) != 0;
- do
- {
- if(tree.file.ReadBits(1))
- actnode = tree.nodes[actnode].right;
- else
- actnode = tree.nodes[actnode].left;
- if(actnode > 255) break;
- delta = tree.nodes[actnode].value;
- } while((tree.nodes[actnode].left >= 0) && (tree.nodes[actnode].right >= 0));
- if(sign) delta ^= 0xFF;
- value += delta;
- psample[i] = value;
- }
- } catch(const BitReader::eof &)
- {
-
- }
- return tree.file.GetPosition();
- }
- OPENMPT_NAMESPACE_END
|