123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- #include "stdafx.h"
- #include "Loaders.h"
- OPENMPT_NAMESPACE_BEGIN
- struct _669FileHeader
- {
- char magic[2];
- char songMessage[108];
- uint8 samples;
- uint8 patterns;
- uint8 restartPos;
- uint8 orders[128];
- uint8 tempoList[128];
- uint8 breaks[128];
- };
- MPT_BINARY_STRUCT(_669FileHeader, 497)
- struct _669Sample
- {
- char filename[13];
- uint32le length;
- uint32le loopStart;
- uint32le loopEnd;
-
- void ConvertToMPT(ModSample &mptSmp) const
- {
- mptSmp.Initialize();
- mptSmp.nC5Speed = 8363;
- mptSmp.nLength = length;
- mptSmp.nLoopStart = loopStart;
- mptSmp.nLoopEnd = loopEnd;
- if(mptSmp.nLoopEnd > mptSmp.nLength && mptSmp.nLoopStart == 0)
- {
- mptSmp.nLoopEnd = 0;
- }
- if(mptSmp.nLoopEnd != 0)
- {
- mptSmp.uFlags = CHN_LOOP;
- mptSmp.SanitizeLoops();
- }
- }
- };
- MPT_BINARY_STRUCT(_669Sample, 25)
- static bool ValidateHeader(const _669FileHeader &fileHeader)
- {
- if((std::memcmp(fileHeader.magic, "if", 2) && std::memcmp(fileHeader.magic, "JN", 2))
- || fileHeader.samples > 64
- || fileHeader.restartPos >= 128
- || fileHeader.patterns > 128)
- {
- return false;
- }
- for(std::size_t i = 0; i < std::size(fileHeader.breaks); i++)
- {
- if(fileHeader.orders[i] >= 128 && fileHeader.orders[i] < 0xFE)
- return false;
- if(fileHeader.orders[i] < 128 && fileHeader.tempoList[i] == 0)
- return false;
- if(fileHeader.tempoList[i] > 15)
- return false;
- if(fileHeader.breaks[i] >= 64)
- return false;
- }
- return true;
- }
- static uint64 GetHeaderMinimumAdditionalSize(const _669FileHeader &fileHeader)
- {
- return fileHeader.samples * sizeof(_669Sample) + fileHeader.patterns * 1536u;
- }
- CSoundFile::ProbeResult CSoundFile::ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize)
- {
- _669FileHeader fileHeader;
- if(!file.ReadStruct(fileHeader))
- {
- return ProbeWantMoreData;
- }
- if(!ValidateHeader(fileHeader))
- {
- return ProbeFailure;
- }
- return ProbeAdditionalSize(file, pfilesize, GetHeaderMinimumAdditionalSize(fileHeader));
- }
- bool CSoundFile::Read669(FileReader &file, ModLoadingFlags loadFlags)
- {
- _669FileHeader fileHeader;
- file.Rewind();
- if(!file.ReadStruct(fileHeader))
- {
- return false;
- }
- if(!ValidateHeader(fileHeader))
- {
- return false;
- }
- if(loadFlags == onlyVerifyHeader)
- {
- return true;
- }
-
- if(!file.CanRead(mpt::saturate_cast<FileReader::off_t>(GetHeaderMinimumAdditionalSize(fileHeader))))
- {
- return false;
- }
- InitializeGlobals(MOD_TYPE_669);
- m_nMinPeriod = 28 << 2;
- m_nMaxPeriod = 1712 << 3;
- m_nDefaultTempo.Set(78);
- m_nDefaultSpeed = 4;
- m_nChannels = 8;
- m_playBehaviour.set(kPeriodsAreHertz);
- #ifdef MODPLUG_TRACKER
-
-
- #endif
- m_modFormat.formatName = U_("Composer 669");
- m_modFormat.type = U_("669");
- m_modFormat.madeWithTracker = !memcmp(fileHeader.magic, "if", 2) ? UL_("Composer 669") : UL_("UNIS 669");
- m_modFormat.charset = mpt::Charset::CP437;
- m_nSamples = fileHeader.samples;
- for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++)
- {
- _669Sample sampleHeader;
- file.ReadStruct(sampleHeader);
-
-
- if(sampleHeader.length >= 0x4000000)
- return false;
- sampleHeader.ConvertToMPT(Samples[smp]);
- m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.filename);
- }
-
- m_songName = mpt::String::ReadBuf(mpt::String::spacePadded, fileHeader.songMessage, 36);
-
- m_songMessage.ReadFixedLineLength(mpt::byte_cast<const std::byte*>(fileHeader.songMessage), 108, 36, 0);
-
- ReadOrderFromArray(Order(), fileHeader.orders, std::size(fileHeader.orders), 0xFF, 0xFE);
- if(Order()[fileHeader.restartPos] < fileHeader.patterns)
- Order().SetRestartPos(fileHeader.restartPos);
-
- for(CHANNELINDEX chn = 0; chn < 8; chn++)
- {
- ChnSettings[chn].Reset();
- ChnSettings[chn].nPan = (chn & 1) ? 0xD0 : 0x30;
- }
-
- Patterns.ResizeArray(fileHeader.patterns);
- for(PATTERNINDEX pat = 0; pat < fileHeader.patterns; pat++)
- {
- if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, 64))
- {
- file.Skip(64 * 8 * 3);
- continue;
- }
- static constexpr ModCommand::COMMAND effTrans[] =
- {
- CMD_PORTAMENTOUP,
- CMD_PORTAMENTODOWN,
- CMD_TONEPORTAMENTO,
- CMD_S3MCMDEX,
- CMD_VIBRATO,
- CMD_SPEED,
- CMD_PANNINGSLIDE,
- CMD_RETRIG,
- };
- uint8 effect[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
- for(ROWINDEX row = 0; row < 64; row++)
- {
- PatternRow m = Patterns[pat].GetRow(row);
- for(CHANNELINDEX chn = 0; chn < 8; chn++, m++)
- {
- const auto [noteInstr, instrVol, effParam] = file.ReadArray<uint8, 3>();
- uint8 note = noteInstr >> 2;
- uint8 instr = ((noteInstr & 0x03) << 4) | (instrVol >> 4);
- uint8 vol = instrVol & 0x0F;
- if(noteInstr < 0xFE)
- {
- m->note = note + 36 + NOTE_MIN;
- m->instr = instr + 1;
- effect[chn] = 0xFF;
- }
- if(noteInstr <= 0xFE)
- {
- m->volcmd = VOLCMD_VOLUME;
- m->vol = ((vol * 64 + 8) / 15);
- }
- if(effParam != 0xFF)
- {
- effect[chn] = effParam;
- }
- if((effParam & 0x0F) == 0 && effParam != 0x30)
- {
-
- effect[chn] = 0xFF;
- }
- if(effect[chn] == 0xFF)
- {
- continue;
- }
- m->param = effect[chn] & 0x0F;
-
- uint8 command = effect[chn] >> 4;
- if(command < static_cast<uint8>(std::size(effTrans)))
- {
- m->command = effTrans[command];
- } else
- {
- m->command = CMD_NONE;
- continue;
- }
-
- switch(command)
- {
- case 3:
-
- #ifdef MODPLUG_TRACKER
-
- m->command = CMD_PORTAMENTOUP;
- m->param |= 0xF0;
- #else
- m->param |= 0x20;
- #endif
- effect[chn] = 0xFF;
- break;
- case 4:
-
- #ifdef MODPLUG_TRACKER
- m->command = CMD_ARPEGGIO;
- #endif
- m->param |= (m->param << 4);
- break;
- case 5:
-
-
- effect[chn] = 0xFF;
- break;
- case 6:
-
- switch(m->param)
- {
- case 0:
-
- m->param = 0x4F;
- break;
- case 1:
-
- m->param = 0xF4;
- break;
- default:
- m->command = CMD_NONE;
- }
- break;
- }
- }
- }
-
- if(fileHeader.breaks[pat] < 63)
- {
- Patterns[pat].WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(fileHeader.breaks[pat]).RetryNextRow());
- }
-
- Patterns[pat].WriteEffect(EffectWriter(CMD_SPEED, fileHeader.tempoList[pat]).RetryNextRow());
- }
- if(loadFlags & loadSampleData)
- {
-
- const SampleIO sampleIO(
- SampleIO::_8bit,
- SampleIO::mono,
- SampleIO::littleEndian,
- SampleIO::unsignedPCM);
- for(SAMPLEINDEX n = 1; n <= m_nSamples; n++)
- {
- sampleIO.ReadSample(Samples[n], file);
- }
- }
- return true;
- }
- OPENMPT_NAMESPACE_END
|