123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- #include "stdafx.h"
- #include "Loaders.h"
- OPENMPT_NAMESPACE_BEGIN
- struct OktIffChunk
- {
-
- enum ChunkIdentifiers
- {
- idCMOD = MagicBE("CMOD"),
- idSAMP = MagicBE("SAMP"),
- idSPEE = MagicBE("SPEE"),
- idSLEN = MagicBE("SLEN"),
- idPLEN = MagicBE("PLEN"),
- idPATT = MagicBE("PATT"),
- idPBOD = MagicBE("PBOD"),
- idSBOD = MagicBE("SBOD"),
- };
- uint32be signature;
- uint32be chunksize;
- };
- MPT_BINARY_STRUCT(OktIffChunk, 8)
- struct OktSample
- {
- char name[20];
- uint32be length;
- uint16be loopStart;
- uint16be loopLength;
- uint16be volume;
- uint16be type;
- };
- MPT_BINARY_STRUCT(OktSample, 32)
- static void ReadOKTSamples(FileReader &chunk, CSoundFile &sndFile)
- {
- sndFile.m_nSamples = std::min(static_cast<SAMPLEINDEX>(chunk.BytesLeft() / sizeof(OktSample)), static_cast<SAMPLEINDEX>(MAX_SAMPLES - 1));
- for(SAMPLEINDEX smp = 1; smp <= sndFile.GetNumSamples(); smp++)
- {
- ModSample &mptSmp = sndFile.GetSample(smp);
- OktSample oktSmp;
- chunk.ReadStruct(oktSmp);
- mptSmp.Initialize();
- sndFile.m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, oktSmp.name);
- mptSmp.nC5Speed = 8287;
- mptSmp.nVolume = std::min(oktSmp.volume.get(), uint16(64)) * 4u;
- mptSmp.nLength = oktSmp.length & ~1;
- mptSmp.cues[0] = oktSmp.type;
-
- const SmpLength loopStart = oktSmp.loopStart * 2;
- const SmpLength loopLength = oktSmp.loopLength * 2;
- if(loopLength > 2 && loopStart + loopLength <= mptSmp.nLength)
- {
- mptSmp.uFlags.set(CHN_SUSTAINLOOP);
- mptSmp.nSustainStart = loopStart;
- mptSmp.nSustainEnd = loopStart + loopLength;
- }
- }
- }
- static void ReadOKTPattern(FileReader &chunk, PATTERNINDEX pat, CSoundFile &sndFile, const std::array<int8, 8> pairedChn)
- {
- if(!chunk.CanRead(2))
- {
-
- sndFile.Patterns.Insert(pat, 64);
- return;
- }
- ROWINDEX rows = Clamp(static_cast<ROWINDEX>(chunk.ReadUint16BE()), ROWINDEX(1), MAX_PATTERN_ROWS);
- if(!sndFile.Patterns.Insert(pat, rows))
- {
- return;
- }
- const CHANNELINDEX chns = sndFile.GetNumChannels();
- for(ROWINDEX row = 0; row < rows; row++)
- {
- auto rowCmd = sndFile.Patterns[pat].GetRow(row);
- for(CHANNELINDEX chn = 0; chn < chns; chn++)
- {
- ModCommand &m = rowCmd[chn];
- const auto [note, instr, effect, param] = chunk.ReadArray<uint8, 4>();
- if(note > 0 && note <= 36)
- {
- m.note = note + (NOTE_MIDDLEC - 13);
- m.instr = instr + 1;
- if(m.instr > 0 && m.instr <= sndFile.GetNumSamples())
- {
- const auto &sample = sndFile.GetSample(m.instr);
-
- if(pairedChn[chn] && sample.nVolume < 256)
- {
- m.volcmd = VOLCMD_VOLUME;
- m.vol = 64;
- }
-
- if((sample.cues[0] == 1 && pairedChn[chn] != 0) || (sample.cues[0] == 0 && pairedChn[chn] == 0))
- {
- m.instr += 100;
- }
- }
- }
- switch(effect)
- {
- case 0:
- break;
- case 1:
- if(param)
- {
- m.command = CMD_PORTAMENTOUP;
- m.param = param;
- }
- break;
- case 2:
- if(param)
- {
- m.command = CMD_PORTAMENTODOWN;
- m.param = param;
- }
- break;
- #if 0
-
- case 10:
- case 11:
- if(param)
- {
- m.command = CMD_ARPEGGIO;
- m.param = param;
- }
- break;
- #endif
-
- case 12:
- if(param)
- {
- m.command = CMD_ARPEGGIO;
- m.param = param;
- }
- break;
- case 13:
- if(param)
- {
- m.command = CMD_NOTESLIDEDOWN;
- m.param = 0x10 | std::min(uint8(0x0F), param);
- }
- break;
- case 30:
- if(param)
- {
- m.command = CMD_NOTESLIDEUP;
- m.param = 0x10 | std::min(uint8(0x0F), param);
- }
- break;
-
-
-
- case 21:
- if(param)
- {
- m.command = CMD_NOTESLIDEDOWN;
- m.param = 0x50 | std::min(uint8(0x0F), param);
- }
- break;
- case 17:
- if(param)
- {
- m.command = CMD_NOTESLIDEUP;
- m.param = 0x50 | std::min(uint8(0x0F), param);
- }
- break;
- case 15:
- m.command = CMD_MODCMDEX;
- m.param = !!param;
- break;
- case 25:
- m.command = CMD_POSITIONJUMP;
- m.param = param;
- break;
- case 27:
- m.Clear();
- m.note = NOTE_KEYOFF;
- break;
- case 28:
- if(param < 0x20)
- {
- m.command = CMD_SPEED;
- m.param = param;
- }
- break;
- case 31:
-
- if(param & 0x0F)
- {
- m.command = pairedChn[chn] ? CMD_CHANNELVOLSLIDE : CMD_VOLUMESLIDE;
- m.param = param & 0x0F;
- }
- switch(param >> 4)
- {
- case 4:
- if(param != 0x40)
- break;
-
- [[fallthrough]];
- case 0: case 1: case 2: case 3:
- if(pairedChn[chn])
- {
- m.command = CMD_CHANNELVOLUME;
- m.param = param;
- } else
- {
- m.volcmd = VOLCMD_VOLUME;
- m.vol = param;
- m.command = CMD_NONE;
- }
- break;
- case 5:
- m.param <<= 4;
- break;
- case 6:
- m.param = 0xF0 | std::min(static_cast<uint8>(m.param), uint8(0x0E));
- break;
- case 7:
- m.param = (std::min(static_cast<uint8>(m.param), uint8(0x0E)) << 4) | 0x0F;
- break;
- default:
-
- m.command = CMD_NONE;
- break;
- }
-
- if(m.command == CMD_CHANNELVOLUME || m.command == CMD_CHANNELVOLSLIDE)
- {
- ModCommand &other = rowCmd[chn + pairedChn[chn]];
-
- if(other.ConvertVolEffect(other.command, other.param, true))
- {
- other.volcmd = other.command;
- other.vol = other.param;
- }
- other.command = m.command;
- other.param = m.param;
- }
- break;
- #if 0
- case 24:
- m.command = CMD_VOLUMESLIDE;
- m.param = 0;
- break;
- #endif
- default:
- m.command = CMD_NONE;
- break;
- }
- }
- }
- }
- CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize)
- {
- if(!file.CanRead(8))
- {
- return ProbeWantMoreData;
- }
- if(!file.ReadMagic("OKTASONG"))
- {
- return ProbeFailure;
- }
- OktIffChunk iffHead;
- if(!file.ReadStruct(iffHead))
- {
- return ProbeWantMoreData;
- }
- if(iffHead.chunksize == 0)
- {
- return ProbeFailure;
- }
- if((iffHead.signature & 0x80808080u) != 0)
- {
- return ProbeFailure;
- }
- MPT_UNREFERENCED_PARAMETER(pfilesize);
- return ProbeSuccess;
- }
- bool CSoundFile::ReadOKT(FileReader &file, ModLoadingFlags loadFlags)
- {
- file.Rewind();
- if(!file.ReadMagic("OKTASONG"))
- {
- return false;
- }
-
- std::vector<FileReader> patternChunks;
- std::vector<FileReader> sampleChunks;
- std::array<int8, 8> pairedChn{{}};
- ORDERINDEX numOrders = 0;
- InitializeGlobals(MOD_TYPE_OKT);
- m_modFormat.formatName = U_("Oktalyzer");
- m_modFormat.type = U_("okt");
- m_modFormat.charset = mpt::Charset::Amiga_no_C1;
-
- while(file.CanRead(sizeof(OktIffChunk)))
- {
- OktIffChunk iffHead;
- if(!file.ReadStruct(iffHead))
- {
- break;
- }
- FileReader chunk = file.ReadChunk(iffHead.chunksize);
- if(!chunk.IsValid())
- {
- break;
- }
- switch(iffHead.signature)
- {
- case OktIffChunk::idCMOD:
-
- if(m_nChannels == 0 && chunk.GetLength() >= 8)
- {
- const auto chnTable = chunk.ReadArray<uint16be, 4>();
- for(CHANNELINDEX chn = 0; chn < 4; chn++)
- {
- if(chnTable[chn])
- {
- pairedChn[m_nChannels] = 1;
- pairedChn[m_nChannels + 1] = -1;
- ChnSettings[m_nChannels].Reset();
- ChnSettings[m_nChannels++].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40;
- }
- ChnSettings[m_nChannels].Reset();
- ChnSettings[m_nChannels++].nPan = (((chn & 3) == 1) || ((chn & 3) == 2)) ? 0xC0 : 0x40;
- }
- if(loadFlags == onlyVerifyHeader)
- {
- return true;
- }
- }
- break;
- case OktIffChunk::idSAMP:
-
- if(m_nSamples > 0)
- {
- break;
- }
- ReadOKTSamples(chunk, *this);
- break;
- case OktIffChunk::idSPEE:
-
- if(chunk.GetLength() >= 2)
- {
- m_nDefaultSpeed = Clamp(chunk.ReadUint16BE(), uint16(1), uint16(255));
- }
- break;
- case OktIffChunk::idSLEN:
-
- break;
- case OktIffChunk::idPLEN:
-
- if(chunk.GetLength() >= 2)
- {
- numOrders = chunk.ReadUint16BE();
- }
- break;
- case OktIffChunk::idPATT:
-
- ReadOrderFromFile<uint8>(Order(), chunk, chunk.GetLength(), 0xFF, 0xFE);
- break;
- case OktIffChunk::idPBOD:
-
- if(patternChunks.size() < 256)
- {
- patternChunks.push_back(chunk);
- }
- break;
- case OktIffChunk::idSBOD:
-
- if(sampleChunks.size() < MAX_SAMPLES - 1 && chunk.GetLength() > 0)
- {
- sampleChunks.push_back(chunk);
- }
- break;
- default:
-
- if(iffHead.signature & 0x80808080)
- return false;
- break;
- }
- }
-
- if(m_nChannels == 0)
- return false;
- m_nDefaultTempo.Set(125);
- m_nDefaultGlobalVolume = MAX_GLOBAL_VOLUME;
- m_nSamplePreAmp = m_nVSTiVolume = 48;
- m_nMinPeriod = 113 * 4;
- m_nMaxPeriod = 856 * 4;
-
- Order().resize(numOrders);
-
- if(loadFlags & loadPatternData)
- {
- Patterns.ResizeArray(static_cast<PATTERNINDEX>(patternChunks.size()));
- for(PATTERNINDEX pat = 0; pat < patternChunks.size(); pat++)
- {
- ReadOKTPattern(patternChunks[pat], pat, *this, pairedChn);
- }
- }
-
- size_t fileSmp = 0;
- for(SAMPLEINDEX smp = 1; smp < m_nSamples; smp++)
- {
- if(fileSmp >= sampleChunks.size() || !(loadFlags & loadSampleData))
- break;
- ModSample &mptSample = Samples[smp];
- mptSample.SetDefaultCuePoints();
- if(mptSample.nLength == 0)
- continue;
-
- LimitMax(mptSample.nLength, mpt::saturate_cast<SmpLength>(sampleChunks[fileSmp].GetLength()));
- SampleIO(
- SampleIO::_8bit,
- SampleIO::mono,
- SampleIO::bigEndian,
- SampleIO::signedPCM)
- .ReadSample(mptSample, sampleChunks[fileSmp]);
- fileSmp++;
- }
- return true;
- }
- OPENMPT_NAMESPACE_END
|