123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613 |
- #include "stdafx.h"
- #include "Loaders.h"
- #include "BitReader.h"
- OPENMPT_NAMESPACE_BEGIN
- struct DSymFileHeader
- {
- char magic[8];
- uint8le version;
- uint8le numChannels;
- uint16le numOrders;
- uint16le numTracks;
- uint16le infoLenLo;
- uint8le infoLenHi;
- bool Validate() const
- {
- return !std::memcmp(magic, "\x02\x01\x13\x13\x14\x12\x01\x0B", 8)
- && version <= 1
- && numChannels >= 1 && numChannels <= 8
- && numOrders <= 4096
- && numTracks <= 4096;
- }
- uint64 GetHeaderMinimumAdditionalSize() const
- {
- return 72u;
- }
- };
- MPT_BINARY_STRUCT(DSymFileHeader, 17)
- static std::vector<std::byte> DecompressDSymLZW(FileReader &file, uint32 size)
- {
- BitReader bitFile(file);
- const auto startPos = bitFile.GetPosition();
-
-
- std::vector<std::byte> output;
- output.reserve(std::min(size, std::min(mpt::saturate_cast<uint32>(file.BytesLeft()), Util::MaxValueOfType(size) / 50u) * 50u));
- static constexpr uint16 lzwBits = 13, MaxNodes = 1 << lzwBits;
- static constexpr uint16 ResetDict = 256, EndOfStream = 257;
- struct LZWEntry
- {
- uint16 prev;
- std::byte value;
- };
- std::vector<LZWEntry> dictionary(MaxNodes);
- std::vector<std::byte> match(MaxNodes);
-
- for(int i = 0; i < 256; i++)
- {
- dictionary[i].prev = MaxNodes;
- dictionary[i].value = static_cast<std::byte>(i);
- }
- uint8 codeSize = 9;
- uint16 prevCode = 0;
- uint16 nextIndex = 257;
- while(true)
- {
-
- const auto newCode = static_cast<uint16>(bitFile.ReadBits(codeSize));
- if(newCode == EndOfStream || newCode > nextIndex || output.size() >= size)
- break;
-
- if(newCode == ResetDict)
- {
- codeSize = 9;
- prevCode = 0;
- nextIndex = 257;
- continue;
- }
-
- auto code = (newCode < nextIndex) ? newCode : prevCode;
- auto writeOffset = MaxNodes;
- do
- {
- match[--writeOffset] = dictionary[code].value;
- code = dictionary[code].prev;
- } while(code < MaxNodes);
- output.insert(output.end(), match.begin() + writeOffset, match.end());
-
- if(newCode == nextIndex)
- output.push_back(match[writeOffset]);
-
- if(nextIndex < MaxNodes)
- {
-
-
- if(output.size() >= size)
- continue;
- dictionary[nextIndex].value = match[writeOffset];
- dictionary[nextIndex].prev = prevCode;
-
- nextIndex++;
- if(nextIndex != MaxNodes && nextIndex == (1u << codeSize))
- codeSize++;
- }
- prevCode = newCode;
- }
- MPT_ASSERT(output.size() == size);
-
- file.Seek(startPos + ((bitFile.GetPosition() - startPos + 3u) & ~FileReader::off_t(3)));
- return output;
- }
- static std::vector<std::byte> DecompressDSymSigmaDelta(FileReader &file, uint32 size)
- {
- const uint8 maxRunLength = std::max(file.ReadUint8(), uint8(1));
- BitReader bitFile(file);
- const auto startPos = bitFile.GetPosition();
-
-
- LimitMax(size, std::min(mpt::saturate_cast<uint32>(file.BytesLeft()), Util::MaxValueOfType(size) / 8u) * 8u);
- std::vector<std::byte> output(size);
- uint32 pos = 0;
- uint8 runLength = maxRunLength;
- uint8 numBits = 8;
- uint8 accum = static_cast<uint8>(bitFile.ReadBits(numBits));
- output[pos++] = mpt::byte_cast<std::byte>(accum);
- while(pos < size)
- {
- const uint32 value = bitFile.ReadBits(numBits);
-
- if(value == 0)
- {
- if(numBits >= 9)
- break;
- numBits++;
- runLength = maxRunLength;
- continue;
- }
- if(value & 1)
- accum -= static_cast<uint8>(value >> 1);
- else
- accum += static_cast<uint8>(value >> 1);
- output[pos++] = mpt::byte_cast<std::byte>(accum);
-
- if((value >> (numBits - 1u)) != 0)
- {
- runLength = maxRunLength;
- continue;
- }
-
- if(--runLength == 0)
- {
- if(numBits > 1)
- numBits--;
- runLength = maxRunLength;
- }
- }
-
- file.Seek(startPos + ((bitFile.GetPosition() - startPos + 3u) & ~FileReader::off_t(3)));
- return output;
- }
- static bool ReadDSymChunk(FileReader &file, std::vector<std::byte> &data, uint32 size)
- {
- const uint8 packingType = file.ReadUint8();
- if(packingType > 1)
- return false;
- if(packingType)
- {
- try
- {
- data = DecompressDSymLZW(file, size);
- } catch(const BitReader::eof &)
- {
- return false;
- }
- } else
- {
- if(!file.CanRead(size))
- return false;
- file.ReadVector(data, size);
- }
- return data.size() >= size;
- }
- CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderDSym(MemoryFileReader file, const uint64 *pfilesize)
- {
- DSymFileHeader fileHeader;
- if(!file.ReadStruct(fileHeader))
- return ProbeWantMoreData;
- if(!fileHeader.Validate())
- return ProbeFailure;
- return ProbeAdditionalSize(file, pfilesize, fileHeader.GetHeaderMinimumAdditionalSize());
- }
- bool CSoundFile::ReadDSym(FileReader &file, ModLoadingFlags loadFlags)
- {
- DSymFileHeader fileHeader;
- file.Rewind();
- if(!file.ReadStruct(fileHeader) || !fileHeader.Validate())
- return false;
- if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(fileHeader.GetHeaderMinimumAdditionalSize())))
- return false;
- if(loadFlags == onlyVerifyHeader)
- return true;
- InitializeGlobals(MOD_TYPE_MOD);
- m_SongFlags.set(SONG_IMPORTED | SONG_AMIGALIMITS);
- m_SongFlags.reset(SONG_ISAMIGA);
- m_nChannels = fileHeader.numChannels;
- m_nSamples = 63;
- for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
- {
- InitChannel(chn);
- ChnSettings[chn].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 64 : 192;
- }
- uint8 sampleNameLength[64] = {};
- for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++)
- {
- Samples[smp].Initialize(MOD_TYPE_MOD);
- sampleNameLength[smp] = file.ReadUint8();
- if(!(sampleNameLength[smp] & 0x80))
- Samples[smp].nLength = file.ReadUint24LE() << 1;
- }
- file.ReadSizedString<uint8le, mpt::String::spacePadded>(m_songName);
- const auto allowedCommands = file.ReadArray<uint8, 8>();
- std::vector<std::byte> sequenceData;
- if(fileHeader.numOrders)
- {
- const uint32 sequenceSize = fileHeader.numOrders * fileHeader.numChannels * 2u;
- if(!ReadDSymChunk(file, sequenceData, sequenceSize))
- return false;
- }
- const auto sequence = mpt::as_span(reinterpret_cast<uint16le *>(sequenceData.data()), sequenceData.size() / 2u);
- std::vector<std::byte> trackData;
- trackData.reserve(fileHeader.numTracks * 256u);
-
- for(uint16 offset = 0; offset < fileHeader.numTracks; offset += 2000)
- {
- const uint32 chunkSize = std::min(fileHeader.numTracks - offset, 2000) * 256;
- std::vector<std::byte> chunk;
- if(!ReadDSymChunk(file, chunk, chunkSize))
- return false;
- trackData.insert(trackData.end(), chunk.begin(), chunk.end());
- }
- const auto tracks = mpt::byte_cast<mpt::span<uint8>>(mpt::as_span(trackData));
- Order().resize(fileHeader.numOrders);
- for(ORDERINDEX pat = 0; pat < fileHeader.numOrders; pat++)
- {
- Order()[pat] = pat;
- if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64))
- continue;
- for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
- {
- const uint16 track = sequence[pat * m_nChannels + chn];
- if(track >= fileHeader.numTracks)
- continue;
- ModCommand *m = Patterns[pat].GetpModCommand(0, chn);
- for(ROWINDEX row = 0; row < 64; row++, m += m_nChannels)
- {
- const auto data = tracks.subspan(track * 256 + row * 4, 4);
- m->note = data[0] & 0x3F;
- if(m->note)
- m->note += 47 + NOTE_MIN;
- else
- m->note = NOTE_NONE;
- m->instr = (data[0] >> 6) | ((data[1] & 0x0F) << 2);
- const uint8 command = (data[1] >> 6) | ((data[2] & 0x0F) << 2);
- const uint16 param = (data[2] >> 4) | (data[3] << 4);
- if(!(allowedCommands[command >> 3u] & (1u << (command & 7u))))
- continue;
- if(command == 0 && param == 0)
- continue;
- m->command = command;
- m->param = static_cast<uint8>(param);
- m->vol = static_cast<ModCommand::VOL>(param >> 8);
-
- switch(command)
- {
- case 0x00:
- case 0x01:
- case 0x02:
- case 0x20:
- case 0x21:
- case 0x22:
- m->command &= 0x0F;
- ConvertModCommand(*m);
- if(m->vol)
- m->volcmd = (command < 0x20) ? VOLCMD_VOLSLIDEUP : VOLCMD_VOLSLIDEDOWN;
- break;
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x0C:
- ConvertModCommand(*m);
- break;
- case 0x09:
- m->command = CMD_OFFSET;
- m->param = static_cast<ModCommand::PARAM>(param >> 1);
- if(param >= 0x200)
- {
- m->volcmd = VOLCMD_OFFSET;
- m->vol >>= 1;
- }
- break;
- case 0x0A:
- case 0x2A:
- if(param < 0xFF)
- {
- m->command &= 0x0F;
- ConvertModCommand(*m);
- } else
- {
- m->command = CMD_MODCMDEX;
- m->param = static_cast<ModCommand::PARAM>(((command < 0x20) ? 0x10 : 0x20) | (param >> 8));
- if(param & 0xF0)
- {
- m->volcmd = VOLCMD_VOLSLIDEUP;
- m->vol = static_cast<ModCommand::VOL>((param >> 4) & 0x0F);
- } else
- {
- m->volcmd = VOLCMD_VOLSLIDEDOWN;
- m->vol = static_cast<ModCommand::VOL>(param & 0x0F);
- }
- }
- break;
- case 0x0B:
- case 0x0F:
- m->command = (command == 0x0B) ? CMD_POSITIONJUMP : CMD_SPEED;
- m->param = mpt::saturate_cast<ModCommand::PARAM>(param);
- break;
- case 0x0D:
- m->command = CMD_PATTERNBREAK;
- if(m->param > 63)
- m->param = 0;
- break;
- case 0x10:
- case 0x13:
- case 0x14:
- case 0x15:
- case 0x17:
- case 0x1F:
- m->command = CMD_MODCMDEX;
- m->param = (command << 4) | (m->param & 0x0F);
- break;
- case 0x16:
- case 0x19:
- case 0x1C:
- case 0x1D:
- case 0x1E:
- m->command = CMD_MODCMDEX;
- m->param = (command << 4) | static_cast<ModCommand::PARAM>(std::min(param, uint16(0x0F)));
- break;
- case 0x11:
- case 0x12:
- case 0x1A:
- case 0x1B:
- m->command = CMD_MODCMDEX;
- if(m->param & 0xFF)
- {
- m->param = static_cast<ModCommand::PARAM>(((command == 0x11 || command == 0x1A) ? 0x10 : 0x20) | (param & 0x0F));
- if(param & 0xF00)
- m->volcmd = (command >= 0x1A) ? VOLCMD_FINEVOLDOWN : VOLCMD_FINEVOLUP;
- } else
- {
- m->param = static_cast<ModCommand::PARAM>(((command >= 0x1A) ? 0xB0 : 0xA0) | (param >> 8));
- }
- break;
- case 0x2F:
- if(param > 0)
- {
- m->command = CMD_TEMPO;
- m->param = mpt::saturate_cast<ModCommand::PARAM>(std::max(8, param + 4) / 8);
- #ifdef MODPLUG_TRACKER
- m->param = std::max(m->param, ModCommand::PARAM(0x20));
- #endif
- } else
- {
- m->command = CMD_NONE;
- }
- break;
- case 0x2B:
- m->command = CMD_PATTERNBREAK;
- for(CHANNELINDEX brkChn = 0; brkChn < m_nChannels; brkChn++)
- {
- ModCommand &cmd = *(m - chn + brkChn);
- if(cmd.command != CMD_NONE)
- continue;
- cmd.command = CMD_POSITIONJUMP;
- cmd.param = mpt::saturate_cast<ModCommand::PARAM>(pat);
- }
- break;
- case 0x30:
- m->command = CMD_PANNING8;
- if(param & 7)
- {
- static constexpr uint8 panning[8] = {0x00, 0x00, 0x2B, 0x56, 0x80, 0xAA, 0xD4, 0xFF};
- m->param = panning[param & 7];
- } else if((param >> 4) != 0x80)
- {
- m->param = static_cast<ModCommand::PARAM>(param >> 4);
- if(m->param < 0x80)
- m->param += 0x80;
- else
- m->param = 0xFF - m->param;
- } else
- {
- m->command = CMD_NONE;
- }
- break;
- case 0x32:
- m->command = CMD_NONE;
- m->param = 0;
- if(m->note == NOTE_NONE)
- m->note = NOTE_KEYOFF;
- else
- m->command = CMD_KEYOFF;
- break;
- case 0x31:
- default:
- m->command = CMD_NONE;
- break;
- }
- }
- }
- }
- for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++)
- {
- file.ReadString<mpt::String::maybeNullTerminated>(m_szNames[smp], sampleNameLength[smp] & 0x3F);
- if(sampleNameLength[smp] & 0x80)
- continue;
- ModSample &mptSmp = Samples[smp];
- mptSmp.nSustainStart = file.ReadUint24LE() << 1;
- if(const auto loopLen = file.ReadUint24LE() << 1; loopLen > 2)
- {
- mptSmp.nSustainEnd = mptSmp.nSustainStart + loopLen;
- mptSmp.uFlags.set(CHN_SUSTAINLOOP);
- }
- mptSmp.nVolume = std::min(file.ReadUint8(), uint8(64)) * 4u;
- mptSmp.nFineTune = MOD2XMFineTune(file.ReadUint8());
- mptSmp.Set16BitCuePoints();
- if(!mptSmp.nLength)
- continue;
- const uint8 packingType = file.ReadUint8();
- switch(packingType)
- {
- case 0:
- if(loadFlags & loadSampleData)
- {
- std::vector<std::byte> sampleData;
- if(!file.CanRead(mptSmp.nLength))
- return false;
- file.ReadVector(sampleData, mptSmp.nLength);
- for(auto &b : sampleData)
- {
- uint8 v = mpt::byte_cast<uint8>(b);
- v = (v << 7) | (static_cast<uint8>(~v) >> 1);
- b = mpt::byte_cast<std::byte>(v);
- }
- FileReader sampleDataFile = FileReader(mpt::as_span(sampleData));
- SampleIO(
- SampleIO::_16bit,
- SampleIO::mono,
- SampleIO::littleEndian,
- SampleIO::uLaw)
- .ReadSample(mptSmp, sampleDataFile);
- } else
- {
- file.Skip(mptSmp.nLength);
- }
- break;
- case 1:
- {
- std::vector<std::byte> sampleData;
- try
- {
- sampleData = DecompressDSymLZW(file, mptSmp.nLength);
- } catch(const BitReader::eof &)
- {
- return false;
- }
- if(!(loadFlags & loadSampleData))
- break;
- FileReader sampleDataFile = FileReader(mpt::as_span(sampleData));
- SampleIO(
- SampleIO::_8bit,
- SampleIO::mono,
- SampleIO::littleEndian,
- SampleIO::deltaPCM)
- .ReadSample(mptSmp, sampleDataFile);
- }
- break;
- case 2:
- case 3:
- if(loadFlags & loadSampleData)
- {
- SampleIO(
- (packingType == 2) ? SampleIO::_8bit : SampleIO::_16bit,
- SampleIO::mono,
- SampleIO::littleEndian,
- SampleIO::signedPCM)
- .ReadSample(mptSmp, file);
- } else
- {
- file.Skip(mptSmp.nLength * (packingType - 1));
- }
- break;
- case 4:
- case 5:
- {
- std::vector<std::byte> sampleData;
- try
- {
- sampleData = DecompressDSymSigmaDelta(file, mptSmp.nLength);
- } catch(const BitReader::eof &)
- {
- return false;
- }
- if(!(loadFlags & loadSampleData))
- break;
- if(packingType == 5)
- {
- static constexpr uint8 xorMask[] = {0x00, 0x7F};
- for(auto &b : sampleData)
- {
- uint8 v = mpt::byte_cast<uint8>(b);
- v ^= xorMask[v >> 7];
- b = mpt::byte_cast<std::byte>(v);
- }
- }
- FileReader sampleDataFile = FileReader(mpt::as_span(sampleData));
- SampleIO(
- (packingType == 5) ? SampleIO::_16bit : SampleIO::_8bit,
- SampleIO::mono,
- SampleIO::littleEndian,
- (packingType == 5) ? SampleIO::uLaw : SampleIO::unsignedPCM)
- .ReadSample(mptSmp, sampleDataFile);
- }
- break;
- default:
- return false;
- }
- }
- if(const uint32 infoLen = fileHeader.infoLenLo | (fileHeader.infoLenHi << 16); infoLen > 0)
- {
- std::vector<std::byte> infoData;
- if(!ReadDSymChunk(file, infoData, infoLen))
- return false;
- FileReader infoChunk = FileReader(mpt::as_span(infoData));
- m_songMessage.Read(infoChunk, infoLen, SongMessage::leLF);
- }
- m_modFormat.formatName = MPT_UFORMAT("Digital Symphony v{}")(fileHeader.version);
- m_modFormat.type = U_("dsym");
- m_modFormat.madeWithTracker = U_("Digital Symphony");
- m_modFormat.charset = mpt::Charset::RISC_OS;
- return true;
- }
- OPENMPT_NAMESPACE_END
|