1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984 |
- #include "stdafx.h"
- #include "Loaders.h"
- #include "../common/ComponentManager.h"
- #include "mpt/io/base.hpp"
- #include "mpt/io/io.hpp"
- #include "mpt/io/io_stdstream.hpp"
- #include "Tables.h"
- #include "../common/version.h"
- #include "mpt/audio/span.hpp"
- #include "MPEGFrame.h"
- #include "OggStream.h"
- #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
- #include <sstream>
- #endif
- #if defined(MPT_WITH_VORBIS)
- #if MPT_COMPILER_CLANG
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wreserved-id-macro"
- #endif
- #include <vorbis/codec.h>
- #if MPT_COMPILER_CLANG
- #pragma clang diagnostic pop
- #endif
- #endif
- #if defined(MPT_WITH_VORBISFILE)
- #if MPT_COMPILER_CLANG
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wreserved-id-macro"
- #endif
- #include <vorbis/vorbisfile.h>
- #if MPT_COMPILER_CLANG
- #pragma clang diagnostic pop
- #endif
- #include "openmpt/soundbase/Copy.hpp"
- #endif
- #ifdef MPT_WITH_STBVORBIS
- #include <stb_vorbis/stb_vorbis.c>
- #include "openmpt/soundbase/Copy.hpp"
- #endif
- OPENMPT_NAMESPACE_BEGIN
- struct MO3FileHeader
- {
- enum MO3HeaderFlags
- {
- linearSlides = 0x0001,
- isS3M = 0x0002,
- s3mFastSlides = 0x0004,
- isMTM = 0x0008,
- s3mAmigaLimits = 0x0010,
-
-
- isMOD = 0x0080,
- isIT = 0x0100,
- instrumentMode = 0x0200,
- itCompatGxx = 0x0400,
- itOldFX = 0x0800,
- modplugMode = 0x10000,
- unknown = 0x20000,
- modVBlank = 0x80000,
- hasPlugins = 0x100000,
- extFilterRange = 0x200000,
- };
- uint8le numChannels;
- uint16le numOrders;
- uint16le restartPos;
- uint16le numPatterns;
- uint16le numTracks;
- uint16le numInstruments;
- uint16le numSamples;
- uint8le defaultSpeed;
- uint8le defaultTempo;
- uint32le flags;
- uint8le globalVol;
- uint8le panSeparation;
- int8le sampleVolume;
- uint8le chnVolume[64];
- uint8le chnPan[64];
- uint8le sfxMacros[16];
- uint8le fixedMacros[128][2];
- };
- MPT_BINARY_STRUCT(MO3FileHeader, 422)
- struct MO3Envelope
- {
- enum MO3EnvelopeFlags
- {
- envEnabled = 0x01,
- envSustain = 0x02,
- envLoop = 0x04,
- envFilter = 0x10,
- envCarry = 0x20,
- };
- uint8le flags;
- uint8le numNodes;
- uint8le sustainStart;
- uint8le sustainEnd;
- uint8le loopStart;
- uint8le loopEnd;
- int16le points[25][2];
-
- void ConvertToMPT(InstrumentEnvelope &mptEnv, uint8 envShift) const
- {
- if(flags & envEnabled) mptEnv.dwFlags.set(ENV_ENABLED);
- if(flags & envSustain) mptEnv.dwFlags.set(ENV_SUSTAIN);
- if(flags & envLoop) mptEnv.dwFlags.set(ENV_LOOP);
- if(flags & envFilter) mptEnv.dwFlags.set(ENV_FILTER);
- if(flags & envCarry) mptEnv.dwFlags.set(ENV_CARRY);
- mptEnv.resize(std::min(numNodes.get(), uint8(25)));
- mptEnv.nSustainStart = sustainStart;
- mptEnv.nSustainEnd = sustainEnd;
- mptEnv.nLoopStart = loopStart;
- mptEnv.nLoopEnd = loopEnd;
- for(uint32 ev = 0; ev < mptEnv.size(); ev++)
- {
- mptEnv[ev].tick = points[ev][0];
- if(ev > 0 && mptEnv[ev].tick < mptEnv[ev - 1].tick)
- mptEnv[ev].tick = mptEnv[ev - 1].tick + 1;
- mptEnv[ev].value = static_cast<uint8>(Clamp(points[ev][1] >> envShift, 0, 64));
- }
- }
- };
- MPT_BINARY_STRUCT(MO3Envelope, 106)
- struct MO3Instrument
- {
- enum MO3InstrumentFlags
- {
- playOnMIDI = 0x01,
- mute = 0x02,
- };
- uint32le flags;
- uint16le sampleMap[120][2];
- MO3Envelope volEnv;
- MO3Envelope panEnv;
- MO3Envelope pitchEnv;
- struct XMVibratoSettings
- {
- uint8le type;
- uint8le sweep;
- uint8le depth;
- uint8le rate;
- } vibrato;
- uint16le fadeOut;
- uint8le midiChannel;
- uint8le midiBank;
- uint8le midiPatch;
- uint8le midiBend;
- uint8le globalVol;
- uint16le panning;
- uint8le nna;
- uint8le pps;
- uint8le ppc;
- uint8le dct;
- uint8le dca;
- uint16le volSwing;
- uint16le panSwing;
- uint8le cutoff;
- uint8le resonance;
-
- void ConvertToMPT(ModInstrument &mptIns, MODTYPE type) const
- {
- if(type == MOD_TYPE_XM)
- {
- for(size_t i = 0; i < 96; i++)
- {
- mptIns.Keyboard[i + 12] = sampleMap[i][1] + 1;
- }
- } else
- {
- for(size_t i = 0; i < 120; i++)
- {
- mptIns.NoteMap[i] = static_cast<uint8>(sampleMap[i][0] + NOTE_MIN);
- mptIns.Keyboard[i] = sampleMap[i][1] + 1;
- }
- }
- volEnv.ConvertToMPT(mptIns.VolEnv, 0);
- panEnv.ConvertToMPT(mptIns.PanEnv, 0);
- pitchEnv.ConvertToMPT(mptIns.PitchEnv, 5);
- mptIns.nFadeOut = fadeOut;
- if(midiChannel >= 128)
- {
-
- mptIns.nMixPlug = midiChannel - 127;
- } else if(midiChannel < 17 && (flags & playOnMIDI))
- {
-
- mptIns.nMidiChannel = midiChannel + MidiFirstChannel;
- } else if(midiChannel > 0 && midiChannel < 17)
- {
-
- mptIns.nMidiChannel = midiChannel + MidiFirstChannel;
- }
- if(mptIns.nMidiChannel != MidiNoChannel)
- {
- if(type == MOD_TYPE_XM)
- {
- mptIns.nMidiProgram = midiPatch + 1;
- } else
- {
- if(midiBank < 128)
- mptIns.wMidiBank = midiBank + 1;
- if(midiPatch < 128)
- mptIns.nMidiProgram = midiPatch + 1;
- }
- mptIns.midiPWD = midiBend;
- }
- if(type == MOD_TYPE_IT)
- mptIns.nGlobalVol = std::min(static_cast<uint8>(globalVol), uint8(128)) / 2u;
- if(panning <= 256)
- {
- mptIns.nPan = panning;
- mptIns.dwFlags.set(INS_SETPANNING);
- }
- mptIns.nNNA = static_cast<NewNoteAction>(nna.get());
- mptIns.nPPS = pps;
- mptIns.nPPC = ppc;
- mptIns.nDCT = static_cast<DuplicateCheckType>(dct.get());
- mptIns.nDNA = static_cast<DuplicateNoteAction>(dca.get());
- mptIns.nVolSwing = static_cast<uint8>(std::min(volSwing.get(), uint16(100)));
- mptIns.nPanSwing = static_cast<uint8>(std::min(panSwing.get(), uint16(256)) / 4u);
- mptIns.SetCutoff(cutoff & 0x7F, (cutoff & 0x80) != 0);
- mptIns.SetResonance(resonance & 0x7F, (resonance & 0x80) != 0);
- }
- };
- MPT_BINARY_STRUCT(MO3Instrument, 826)
- struct MO3Sample
- {
- enum MO3SampleFlags
- {
- smp16Bit = 0x01,
- smpLoop = 0x10,
- smpPingPongLoop = 0x20,
- smpSustain = 0x100,
- smpSustainPingPong = 0x200,
- smpStereo = 0x400,
- smpCompressionMPEG = 0x1000,
- smpCompressionOgg = 0x1000 | 0x2000,
- smpSharedOgg = 0x1000 | 0x2000 | 0x4000,
- smpDeltaCompression = 0x2000,
- smpDeltaPrediction = 0x4000,
- smpOPLInstrument = 0x8000,
- smpCompressionMask = 0x1000 | 0x2000 | 0x4000 | 0x8000
- };
- uint32le freqFinetune;
- int8le transpose;
- uint8le defaultVolume;
- uint16le panning;
- uint32le length;
- uint32le loopStart;
- uint32le loopEnd;
- uint16le flags;
- uint8le vibType;
- uint8le vibSweep;
- uint8le vibDepth;
- uint8le vibRate;
- uint8le globalVol;
- uint32le sustainStart;
- uint32le sustainEnd;
- int32le compressedSize;
- uint16le encoderDelay;
-
- void ConvertToMPT(ModSample &mptSmp, MODTYPE type, bool frequencyIsHertz) const
- {
- mptSmp.Initialize();
- mptSmp.SetDefaultCuePoints();
- if(type & (MOD_TYPE_IT | MOD_TYPE_S3M))
- {
- if(frequencyIsHertz)
- mptSmp.nC5Speed = freqFinetune;
- else
- mptSmp.nC5Speed = mpt::saturate_round<uint32>(8363.0 * std::pow(2.0, static_cast<int32>(freqFinetune + 1408) / 1536.0));
- } else
- {
- mptSmp.nFineTune = static_cast<int8>(freqFinetune);
- if(type != MOD_TYPE_MTM)
- mptSmp.nFineTune -= 128;
- mptSmp.RelativeTone = transpose;
- }
- mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4u;
- if(panning <= 256)
- {
- mptSmp.nPan = panning;
- mptSmp.uFlags.set(CHN_PANNING);
- }
- mptSmp.nLength = length;
- mptSmp.nLoopStart = loopStart;
- mptSmp.nLoopEnd = loopEnd;
- if(flags & smpLoop)
- mptSmp.uFlags.set(CHN_LOOP);
- if(flags & smpPingPongLoop)
- mptSmp.uFlags.set(CHN_PINGPONGLOOP);
- if(flags & smpSustain)
- mptSmp.uFlags.set(CHN_SUSTAINLOOP);
- if(flags & smpSustainPingPong)
- mptSmp.uFlags.set(CHN_PINGPONGSUSTAIN);
- mptSmp.nVibType = static_cast<VibratoType>(AutoVibratoIT2XM[vibType & 7]);
- mptSmp.nVibSweep = vibSweep;
- mptSmp.nVibDepth = vibDepth;
- mptSmp.nVibRate = vibRate;
- if(type == MOD_TYPE_IT)
- mptSmp.nGlobalVol = std::min(static_cast<uint8>(globalVol), uint8(64));
- mptSmp.nSustainStart = sustainStart;
- mptSmp.nSustainEnd = sustainEnd;
- }
- };
- MPT_BINARY_STRUCT(MO3Sample, 41)
- struct MO3SampleChunk
- {
- FileReader chunk;
- uint16 headerSize;
- int16 sharedHeader;
- MO3SampleChunk(const FileReader &chunk_ = FileReader(), uint16 headerSize_ = 0, int16 sharedHeader_ = 0)
- : chunk(chunk_), headerSize(headerSize_), sharedHeader(sharedHeader_) {}
- };
- #define READ_CTRL_BIT \
- data <<= 1; \
- carry = (data > 0xFF); \
- data &= 0xFF; \
- if(data == 0) \
- { \
- uint8 nextByte; \
- if(!file.Read(nextByte)) \
- break; \
- data = nextByte; \
- data = (data << 1) + 1; \
- carry = (data > 0xFF); \
- data &= 0xFF; \
- }
- #define DECODE_CTRL_BITS \
- { \
- strLen++; \
- do \
- { \
- READ_CTRL_BIT; \
- strLen = mpt::lshift_signed(strLen, 1) + carry; \
- READ_CTRL_BIT; \
- } while(carry); \
- }
- static bool UnpackMO3Data(FileReader &file, std::vector<uint8> &uncompressed, const uint32 size)
- {
- if(!size)
- return false;
- uint16 data = 0;
- int8 carry = 0;
- int32 strLen = 0;
- int32 strOffset;
- uint32 previousPtr = 0;
-
- uncompressed.push_back(file.ReadUint8());
- uint32 remain = size - 1;
- while(remain > 0)
- {
- READ_CTRL_BIT;
- if(!carry)
- {
-
- if(uint8 b; file.Read(b))
- uncompressed.push_back(b);
- else
- break;
- remain--;
- } else
- {
-
- uint8 lengthAdjust = 0;
- DECODE_CTRL_BITS;
- strLen -= 3;
- if(strLen < 0)
- {
-
- strOffset = previousPtr;
- strLen++;
- } else
- {
-
- if(uint8 b; file.Read(b))
- strOffset = mpt::lshift_signed(strLen, 8) | b;
- else
- break;
- strLen = 0;
- strOffset = ~strOffset;
- if(strOffset < -1280)
- lengthAdjust++;
- lengthAdjust++;
- if(strOffset < -32000)
- lengthAdjust++;
- previousPtr = strOffset;
- }
-
- READ_CTRL_BIT;
- strLen = mpt::lshift_signed(strLen, 1) + carry;
- READ_CTRL_BIT;
- strLen = mpt::lshift_signed(strLen, 1) + carry;
- if(strLen == 0)
- {
-
- DECODE_CTRL_BITS;
- strLen += 2;
- }
- strLen += lengthAdjust;
- if(remain < static_cast<uint32>(strLen) || strLen <= 0)
- break;
- if(strOffset >= 0 || -static_cast<ptrdiff_t>(uncompressed.size()) > strOffset)
- break;
-
-
- uncompressed.insert(uncompressed.end(), strLen, 0);
- remain -= strLen;
- auto src = uncompressed.cend() - strLen + strOffset;
- auto dst = uncompressed.end() - strLen;
- do
- {
- strLen--;
- *dst++ = *src++;
- } while(strLen > 0);
- }
- }
- #ifdef MPT_BUILD_FUZZER
-
-
- return true;
- #else
- return remain == 0;
- #endif
- }
- struct MO3Delta8BitParams
- {
- using sample_t = int8;
- using unsigned_t = uint8;
- static constexpr int shift = 7;
- static constexpr uint8 dhInit = 4;
- static inline void Decode(FileReader &file, int8 &carry, uint16 &data, uint8 & , unsigned_t &val)
- {
- do
- {
- READ_CTRL_BIT;
- val = (val << 1) + carry;
- READ_CTRL_BIT;
- } while(carry);
- }
- };
- struct MO3Delta16BitParams
- {
- using sample_t = int16;
- using unsigned_t = uint16;
- static constexpr int shift = 15;
- static constexpr uint8 dhInit = 8;
- static inline void Decode(FileReader &file, int8 &carry, uint16 &data, uint8 &dh, unsigned_t &val)
- {
- if(dh < 5)
- {
- do
- {
- READ_CTRL_BIT;
- val = (val << 1) + carry;
- READ_CTRL_BIT;
- val = (val << 1) + carry;
- READ_CTRL_BIT;
- } while(carry);
- } else
- {
- do
- {
- READ_CTRL_BIT;
- val = (val << 1) + carry;
- READ_CTRL_BIT;
- } while(carry);
- }
- }
- };
- template <typename Properties>
- static void UnpackMO3DeltaSample(FileReader &file, typename Properties::sample_t *dst, uint32 length, uint8 numChannels)
- {
- uint8 dh = Properties::dhInit, cl = 0;
- int8 carry = 0;
- uint16 data = 0;
- typename Properties::unsigned_t val;
- typename Properties::sample_t previous = 0;
- for(uint8 chn = 0; chn < numChannels; chn++)
- {
- typename Properties::sample_t *p = dst + chn;
- const typename Properties::sample_t *const pEnd = p + length * numChannels;
- while(p < pEnd)
- {
- val = 0;
- Properties::Decode(file, carry, data, dh, val);
- cl = dh;
- while(cl > 0)
- {
- READ_CTRL_BIT;
- val = (val << 1) + carry;
- cl--;
- }
- cl = 1;
- if(val >= 4)
- {
- cl = Properties::shift;
- while(((1 << cl) & val) == 0 && cl > 1)
- cl--;
- }
- dh = dh + cl;
- dh >>= 1;
- carry = val & 1;
- val >>= 1;
- if(carry == 0)
- val = ~val;
- val += previous;
- *p = val;
- p += numChannels;
- previous = val;
- }
- }
- }
- template <typename Properties>
- static void UnpackMO3DeltaPredictionSample(FileReader &file, typename Properties::sample_t *dst, uint32 length, uint8 numChannels)
- {
- uint8 dh = Properties::dhInit, cl = 0;
- int8 carry;
- uint16 data = 0;
- int32 next = 0;
- typename Properties::unsigned_t val = 0;
- typename Properties::sample_t sval = 0, delta = 0, previous = 0;
- for(uint8 chn = 0; chn < numChannels; chn++)
- {
- typename Properties::sample_t *p = dst + chn;
- const typename Properties::sample_t *const pEnd = p + length * numChannels;
- while(p < pEnd)
- {
- val = 0;
- Properties::Decode(file, carry, data, dh, val);
- cl = dh;
- while(cl > 0)
- {
- READ_CTRL_BIT;
- val = (val << 1) + carry;
- cl--;
- }
- cl = 1;
- if(val >= 4)
- {
- cl = Properties::shift;
- while(((1 << cl) & val) == 0 && cl > 1)
- cl--;
- }
- dh = dh + cl;
- dh >>= 1;
- carry = val & 1;
- val >>= 1;
- if(carry == 0)
- val = ~val;
- delta = static_cast<typename Properties::sample_t>(val);
- val = val + static_cast<typename Properties::unsigned_t>(next);
- *p = val;
- p += numChannels;
- sval = static_cast<typename Properties::sample_t>(val);
- next = (sval * (1 << 1)) + (delta >> 1) - previous;
- Limit(next, std::numeric_limits<typename Properties::sample_t>::min(), std::numeric_limits<typename Properties::sample_t>::max());
- previous = sval;
- }
- }
- }
- #undef READ_CTRL_BIT
- #undef DECODE_CTRL_BITS
- #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
- static size_t VorbisfileFilereaderRead(void *ptr, size_t size, size_t nmemb, void *datasource)
- {
- FileReader &file = *reinterpret_cast<FileReader *>(datasource);
- return file.ReadRaw(mpt::span(mpt::void_cast<std::byte *>(ptr), size * nmemb)).size() / size;
- }
- static int VorbisfileFilereaderSeek(void *datasource, ogg_int64_t offset, int whence)
- {
- FileReader &file = *reinterpret_cast<FileReader *>(datasource);
- switch(whence)
- {
- case SEEK_SET:
- if(!mpt::in_range<FileReader::off_t>(offset))
- {
- return -1;
- }
- return file.Seek(mpt::saturate_cast<FileReader::off_t>(offset)) ? 0 : -1;
- case SEEK_CUR:
- if(offset < 0)
- {
- if(offset == std::numeric_limits<ogg_int64_t>::min())
- {
- return -1;
- }
- if(!mpt::in_range<FileReader::off_t>(0 - offset))
- {
- return -1;
- }
- return file.SkipBack(mpt::saturate_cast<FileReader::off_t>(0 - offset)) ? 0 : -1;
- } else
- {
- if(!mpt::in_range<FileReader::off_t>(offset))
- {
- return -1;
- }
- return file.Skip(mpt::saturate_cast<FileReader::off_t>(offset)) ? 0 : -1;
- }
- break;
- case SEEK_END:
- if(!mpt::in_range<FileReader::off_t>(offset))
- {
- return -1;
- }
- if(!mpt::in_range<FileReader::off_t>(file.GetLength() + offset))
- {
- return -1;
- }
- return file.Seek(mpt::saturate_cast<FileReader::off_t>(file.GetLength() + offset)) ? 0 : -1;
- default:
- return -1;
- }
- }
- static long VorbisfileFilereaderTell(void *datasource)
- {
- FileReader &file = *reinterpret_cast<FileReader *>(datasource);
- FileReader::off_t result = file.GetPosition();
- if(!mpt::in_range<long>(result))
- {
- return -1;
- }
- return static_cast<long>(result);
- }
- #endif
- struct MO3ContainerHeader
- {
- char magic[3];
- uint8le version;
- uint32le musicSize;
- };
- MPT_BINARY_STRUCT(MO3ContainerHeader, 8)
- static bool ValidateHeader(const MO3ContainerHeader &containerHeader)
- {
- if(std::memcmp(containerHeader.magic, "MO3", 3))
- {
- return false;
- }
- if(containerHeader.musicSize <= sizeof(MO3FileHeader) || containerHeader.musicSize >= uint32_max / 2u)
- {
- return false;
- }
- if(containerHeader.version > 5)
- {
- return false;
- }
- return true;
- }
- CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize)
- {
- MO3ContainerHeader containerHeader;
- if(!file.ReadStruct(containerHeader))
- {
- return ProbeWantMoreData;
- }
- if(!ValidateHeader(containerHeader))
- {
- return ProbeFailure;
- }
- MPT_UNREFERENCED_PARAMETER(pfilesize);
- return ProbeSuccess;
- }
- bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
- {
- file.Rewind();
- MO3ContainerHeader containerHeader;
- if(!file.ReadStruct(containerHeader))
- {
- return false;
- }
- if(!ValidateHeader(containerHeader))
- {
- return false;
- }
- if(loadFlags == onlyVerifyHeader)
- {
- return true;
- }
- const uint8 version = containerHeader.version;
- uint32 compressedSize = uint32_max, reserveSize = 1024 * 1024;
- if(version >= 5)
- {
-
- compressedSize = file.ReadUint32LE();
- if(!file.CanRead(compressedSize))
- return false;
-
- reserveSize = std::min(Util::MaxValueOfType(reserveSize) / 32u, compressedSize) * 32u;
- }
- std::vector<uint8> musicData;
-
-
-
-
- musicData.reserve(std::min(reserveSize, containerHeader.musicSize.get()));
- if(!UnpackMO3Data(file, musicData, containerHeader.musicSize))
- {
- return false;
- }
- if(version >= 5)
- {
- file.Seek(12 + compressedSize);
- }
- InitializeGlobals();
- InitializeChannels();
- FileReader musicChunk(mpt::as_span(musicData));
- musicChunk.ReadNullString(m_songName);
- musicChunk.ReadNullString(m_songMessage);
- MO3FileHeader fileHeader;
- if(!musicChunk.ReadStruct(fileHeader)
- || fileHeader.numChannels == 0 || fileHeader.numChannels > MAX_BASECHANNELS
- || fileHeader.numInstruments >= MAX_INSTRUMENTS
- || fileHeader.numSamples >= MAX_SAMPLES)
- {
- return false;
- }
- m_nChannels = fileHeader.numChannels;
- Order().SetRestartPos(fileHeader.restartPos);
- m_nInstruments = fileHeader.numInstruments;
- m_nSamples = fileHeader.numSamples;
- m_nDefaultSpeed = fileHeader.defaultSpeed ? fileHeader.defaultSpeed : 6;
- m_nDefaultTempo.Set(fileHeader.defaultTempo ? fileHeader.defaultTempo : 125, 0);
- if(fileHeader.flags & MO3FileHeader::isIT)
- SetType(MOD_TYPE_IT);
- else if(fileHeader.flags & MO3FileHeader::isS3M)
- SetType(MOD_TYPE_S3M);
- else if(fileHeader.flags & MO3FileHeader::isMOD)
- SetType(MOD_TYPE_MOD);
- else if(fileHeader.flags & MO3FileHeader::isMTM)
- SetType(MOD_TYPE_MTM);
- else
- SetType(MOD_TYPE_XM);
- m_SongFlags.set(SONG_IMPORTED);
- if(fileHeader.flags & MO3FileHeader::linearSlides)
- m_SongFlags.set(SONG_LINEARSLIDES);
- if((fileHeader.flags & MO3FileHeader::s3mAmigaLimits) && m_nType == MOD_TYPE_S3M)
- m_SongFlags.set(SONG_AMIGALIMITS);
- if((fileHeader.flags & MO3FileHeader::s3mFastSlides) && m_nType == MOD_TYPE_S3M)
- m_SongFlags.set(SONG_FASTVOLSLIDES);
- if(!(fileHeader.flags & MO3FileHeader::itOldFX) && m_nType == MOD_TYPE_IT)
- m_SongFlags.set(SONG_ITOLDEFFECTS);
- if(!(fileHeader.flags & MO3FileHeader::itCompatGxx) && m_nType == MOD_TYPE_IT)
- m_SongFlags.set(SONG_ITCOMPATGXX);
- if(fileHeader.flags & MO3FileHeader::extFilterRange)
- m_SongFlags.set(SONG_EXFILTERRANGE);
- if(fileHeader.flags & MO3FileHeader::modVBlank)
- m_playBehaviour.set(kMODVBlankTiming);
- if(m_nType == MOD_TYPE_IT)
- m_nDefaultGlobalVolume = std::min(fileHeader.globalVol.get(), uint8(128)) * 2;
- else if(m_nType == MOD_TYPE_S3M)
- m_nDefaultGlobalVolume = std::min(fileHeader.globalVol.get(), uint8(64)) * 4;
- if(fileHeader.sampleVolume < 0)
- m_nSamplePreAmp = fileHeader.sampleVolume + 52;
- else
- m_nSamplePreAmp = static_cast<uint32>(std::exp(fileHeader.sampleVolume * 3.1 / 20.0)) + 51;
-
- const CHANNELINDEX headerChannels = std::min(m_nChannels, CHANNELINDEX(64));
- for(CHANNELINDEX i = 0; i < headerChannels; i++)
- {
- if(m_nType == MOD_TYPE_IT)
- ChnSettings[i].nVolume = std::min(fileHeader.chnVolume[i].get(), uint8(64));
- if(m_nType != MOD_TYPE_XM)
- {
- if(fileHeader.chnPan[i] == 127)
- ChnSettings[i].dwFlags = CHN_SURROUND;
- else if(fileHeader.chnPan[i] == 255)
- ChnSettings[i].nPan = 256;
- else
- ChnSettings[i].nPan = fileHeader.chnPan[i];
- }
- }
- bool anyMacros = false;
- for(uint32 i = 0; i < 16; i++)
- {
- if(fileHeader.sfxMacros[i])
- anyMacros = true;
- }
- for(uint32 i = 0; i < 128; i++)
- {
- if(fileHeader.fixedMacros[i][1])
- anyMacros = true;
- }
- if(anyMacros)
- {
- for(uint32 i = 0; i < 16; i++)
- {
- if(fileHeader.sfxMacros[i])
- m_MidiCfg.SFx[i] = MPT_AFORMAT("F0F0{}z")(mpt::afmt::HEX0<2>(fileHeader.sfxMacros[i] - 1));
- else
- m_MidiCfg.SFx[i] = "";
- }
- for(uint32 i = 0; i < 128; i++)
- {
- if(fileHeader.fixedMacros[i][1])
- m_MidiCfg.Zxx[i] = MPT_AFORMAT("F0F0{}{}")(mpt::afmt::HEX0<2>(fileHeader.fixedMacros[i][1] - 1), mpt::afmt::HEX0<2>(fileHeader.fixedMacros[i][0].get()));
- else
- m_MidiCfg.Zxx[i] = "";
- }
- }
- const bool hasOrderSeparators = !(m_nType & (MOD_TYPE_MOD | MOD_TYPE_XM));
- ReadOrderFromFile<uint8>(Order(), musicChunk, fileHeader.numOrders, hasOrderSeparators ? 0xFF : uint16_max, hasOrderSeparators ? 0xFE : uint16_max);
-
- FileReader trackChunk = musicChunk.ReadChunk(fileHeader.numPatterns * fileHeader.numChannels * sizeof(uint16));
- FileReader patLengthChunk = musicChunk.ReadChunk(fileHeader.numPatterns * sizeof(uint16));
- std::vector<FileReader> tracks(fileHeader.numTracks);
- for(auto &track : tracks)
- {
- uint32 len = musicChunk.ReadUint32LE();
- track = musicChunk.ReadChunk(len);
- }
-
- static constexpr ModCommand::COMMAND effTrans[] =
- {
- CMD_NONE, CMD_NONE, CMD_NONE, CMD_ARPEGGIO,
- CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO, CMD_VIBRATO,
- CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO, CMD_PANNING8,
- CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP, CMD_VOLUME,
- CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_TEMPO, CMD_TREMOR,
- VOLCMD_VOLSLIDEUP, VOLCMD_FINEVOLUP, CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE,
- CMD_KEYOFF, CMD_SETENVPOSITION, CMD_PANNINGSLIDE, VOLCMD_PANSLIDELEFT,
- CMD_RETRIG, CMD_XFINEPORTAUPDOWN, CMD_XFINEPORTAUPDOWN, VOLCMD_VIBRATOSPEED,
- VOLCMD_VIBRATODEPTH, CMD_SPEED, CMD_VOLUMESLIDE, CMD_PORTAMENTODOWN,
- CMD_PORTAMENTOUP, CMD_TREMOR, CMD_RETRIG, CMD_FINEVIBRATO,
- CMD_CHANNELVOLUME, CMD_CHANNELVOLSLIDE, CMD_PANNINGSLIDE, CMD_S3MCMDEX,
- CMD_TEMPO, CMD_GLOBALVOLSLIDE, CMD_PANBRELLO, CMD_MIDI,
- VOLCMD_FINEVOLUP, VOLCMD_PORTADOWN, VOLCMD_PORTAUP, CMD_NONE,
- VOLCMD_OFFSET, CMD_XPARAM, CMD_SMOOTHMIDI, CMD_DELAYCUT,
- CMD_FINETUNE, CMD_FINETUNE_SMOOTH,
- };
- uint8 noteOffset = NOTE_MIN;
- if(m_nType == MOD_TYPE_MTM)
- noteOffset = 13 + NOTE_MIN;
- else if(m_nType != MOD_TYPE_IT)
- noteOffset = 12 + NOTE_MIN;
- bool onlyAmigaNotes = true;
- if(loadFlags & loadPatternData)
- Patterns.ResizeArray(fileHeader.numPatterns);
- for(PATTERNINDEX pat = 0; pat < fileHeader.numPatterns; pat++)
- {
- const ROWINDEX numRows = patLengthChunk.ReadUint16LE();
- if(!(loadFlags & loadPatternData) || !Patterns.Insert(pat, numRows))
- continue;
- for(CHANNELINDEX chn = 0; chn < fileHeader.numChannels; chn++)
- {
- uint16 trackIndex = trackChunk.ReadUint16LE();
- if(trackIndex >= tracks.size())
- continue;
- FileReader &track = tracks[trackIndex];
- track.Rewind();
- ROWINDEX row = 0;
- ModCommand *patData = Patterns[pat].GetpModCommand(0, chn);
- while(row < numRows)
- {
- const uint8 b = track.ReadUint8();
- if(!b)
- break;
- const uint8 numCommands = (b & 0x0F), rep = (b >> 4);
- ModCommand m = ModCommand::Empty();
- for(uint8 c = 0; c < numCommands; c++)
- {
- uint8 cmd[2];
- track.ReadArray(cmd);
-
- switch(cmd[0])
- {
- case 0x01:
-
- m.note = cmd[1];
- if(m.note < 120)
- m.note += noteOffset;
- else if(m.note == 0xFF)
- m.note = NOTE_KEYOFF;
- else if(m.note == 0xFE)
- m.note = NOTE_NOTECUT;
- else
- m.note = NOTE_FADE;
- if(!m.IsAmigaNote())
- onlyAmigaNotes = false;
- break;
- case 0x02:
-
- m.instr = cmd[1] + 1;
- break;
- case 0x06:
-
- if(m.volcmd == VOLCMD_NONE && m_nType == MOD_TYPE_XM && !(cmd[1] & 0x0F))
- {
- m.volcmd = VOLCMD_TONEPORTAMENTO;
- m.vol = cmd[1] >> 4;
- break;
- } else if(m.volcmd == VOLCMD_NONE && m_nType == MOD_TYPE_IT)
- {
- for(uint8 i = 0; i < 10; i++)
- {
- if(ImpulseTrackerPortaVolCmd[i] == cmd[1])
- {
- m.volcmd = VOLCMD_TONEPORTAMENTO;
- m.vol = i;
- break;
- }
- }
- if(m.volcmd != VOLCMD_NONE)
- break;
- }
- m.command = CMD_TONEPORTAMENTO;
- m.param = cmd[1];
- break;
- case 0x07:
-
- if(m.volcmd == VOLCMD_NONE && cmd[1] < 10 && m_nType == MOD_TYPE_IT)
- {
- m.volcmd = VOLCMD_VIBRATODEPTH;
- m.vol = cmd[1];
- } else
- {
- m.command = CMD_VIBRATO;
- m.param = cmd[1];
- }
- break;
- case 0x0B:
-
- if(m.volcmd == VOLCMD_NONE)
- {
- if(m_nType == MOD_TYPE_IT && cmd[1] == 0xFF)
- {
- m.volcmd = VOLCMD_PANNING;
- m.vol = 64;
- break;
- }
- if((m_nType == MOD_TYPE_IT && !(cmd[1] & 0x03))
- || (m_nType == MOD_TYPE_XM && !(cmd[1] & 0x0F)))
- {
- m.volcmd = VOLCMD_PANNING;
- m.vol = cmd[1] / 4;
- break;
- }
- }
- m.command = CMD_PANNING8;
- m.param = cmd[1];
- break;
- case 0x0F:
-
- if(m_nType != MOD_TYPE_MOD && m.volcmd == VOLCMD_NONE && cmd[1] <= 64)
- {
- m.volcmd = VOLCMD_VOLUME;
- m.vol = cmd[1];
- } else
- {
- m.command = CMD_VOLUME;
- m.param = cmd[1];
- }
- break;
- case 0x10:
-
- m.command = CMD_PATTERNBREAK;
- m.param = cmd[1];
- if(m_nType != MOD_TYPE_IT)
- m.param = ((m.param >> 4) * 10) + (m.param & 0x0F);
- break;
- case 0x12:
-
- m.param = cmd[1];
- if(m.param < 0x20)
- m.command = CMD_SPEED;
- else
- m.command = CMD_TEMPO;
- break;
- case 0x14:
- case 0x15:
-
- if(cmd[1] & 0xF0)
- {
- m.volcmd = static_cast<ModCommand::VOLCMD>((cmd[0] == 0x14) ? VOLCMD_VOLSLIDEUP : VOLCMD_FINEVOLUP);
- m.vol = cmd[1] >> 4;
- } else
- {
- m.volcmd = static_cast<ModCommand::VOLCMD>((cmd[0] == 0x14) ? VOLCMD_VOLSLIDEDOWN : VOLCMD_FINEVOLDOWN);
- m.vol = cmd[1] & 0x0F;
- }
- break;
- case 0x1B:
-
- if(cmd[1] & 0xF0)
- {
- m.volcmd = VOLCMD_PANSLIDERIGHT;
- m.vol = cmd[1] >> 4;
- } else
- {
- m.volcmd = VOLCMD_PANSLIDELEFT;
- m.vol = cmd[1] & 0x0F;
- }
- break;
- case 0x1D:
-
- m.command = CMD_XFINEPORTAUPDOWN;
- m.param = 0x10 | cmd[1];
- break;
- case 0x1E:
-
- m.command = CMD_XFINEPORTAUPDOWN;
- m.param = 0x20 | cmd[1];
- break;
- case 0x1F:
- case 0x20:
-
- m.volcmd = effTrans[cmd[0]];
- m.vol = cmd[1];
- break;
- case 0x22:
-
- if(m.command == CMD_TONEPORTAMENTO)
- m.command = CMD_TONEPORTAVOL;
- else if(m.command == CMD_VIBRATO)
- m.command = CMD_VIBRATOVOL;
- else
- m.command = CMD_VOLUMESLIDE;
- m.param = cmd[1];
- break;
- case 0x30:
-
- m.vol = cmd[1] % 10;
- if(cmd[1] < 10)
- m.volcmd = VOLCMD_FINEVOLUP;
- else if(cmd[1] < 20)
- m.volcmd = VOLCMD_FINEVOLDOWN;
- else if(cmd[1] < 30)
- m.volcmd = VOLCMD_VOLSLIDEUP;
- else if(cmd[1] < 40)
- m.volcmd = VOLCMD_VOLSLIDEDOWN;
- break;
- case 0x31:
- case 0x32:
-
- m.volcmd = effTrans[cmd[0]];
- m.vol = cmd[1];
- break;
- case 0x34:
-
- if(cmd[1] >= 223 && cmd[1] <= 232)
- {
- m.volcmd = VOLCMD_OFFSET;
- m.vol = cmd[1] - 223;
- }
- break;
- default:
- if(cmd[0] < std::size(effTrans))
- {
- m.command = effTrans[cmd[0]];
- m.param = cmd[1];
- }
- break;
- }
- }
- #ifdef MODPLUG_TRACKER
- if(m_nType == MOD_TYPE_MTM)
- m.Convert(MOD_TYPE_MTM, MOD_TYPE_S3M, *this);
- #endif
- ROWINDEX targetRow = std::min(row + rep, numRows);
- while(row < targetRow)
- {
- *patData = m;
- patData += fileHeader.numChannels;
- row++;
- }
- }
- }
- }
- if(GetType() == MOD_TYPE_MOD && GetNumChannels() == 4 && onlyAmigaNotes)
- {
- m_SongFlags.set(SONG_AMIGALIMITS | SONG_ISAMIGA);
- }
- const bool isSampleMode = (m_nType != MOD_TYPE_XM && !(fileHeader.flags & MO3FileHeader::instrumentMode));
- std::vector<MO3Instrument::XMVibratoSettings> instrVibrato(m_nType == MOD_TYPE_XM ? m_nInstruments : 0);
- for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++)
- {
- ModInstrument *pIns = nullptr;
- if(isSampleMode || (pIns = AllocateInstrument(ins)) == nullptr)
- {
-
- while(musicChunk.ReadUint8() != 0)
- ;
- if(version >= 5)
- {
- while(musicChunk.ReadUint8() != 0)
- ;
- }
- musicChunk.Skip(sizeof(MO3Instrument));
- continue;
- }
- std::string name;
- musicChunk.ReadNullString(name);
- pIns->name = name;
- if(version >= 5)
- {
- musicChunk.ReadNullString(name);
- pIns->filename = name;
- }
- MO3Instrument insHeader;
- if(!musicChunk.ReadStruct(insHeader))
- break;
- insHeader.ConvertToMPT(*pIns, m_nType);
- if(m_nType == MOD_TYPE_XM)
- instrVibrato[ins - 1] = insHeader.vibrato;
- }
- if(isSampleMode)
- m_nInstruments = 0;
- std::vector<MO3SampleChunk> sampleChunks(m_nSamples);
- const bool frequencyIsHertz = (version >= 5 || !(fileHeader.flags & MO3FileHeader::linearSlides));
- bool unsupportedSamples = false;
- for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++)
- {
- ModSample &sample = Samples[smp];
- std::string name;
- musicChunk.ReadNullString(name);
- m_szNames[smp] = name;
- if(version >= 5)
- {
- musicChunk.ReadNullString(name);
- sample.filename = name;
- }
- MO3Sample smpHeader;
- if(!musicChunk.ReadStruct(smpHeader))
- break;
- smpHeader.ConvertToMPT(sample, m_nType, frequencyIsHertz);
- int16 sharedOggHeader = 0;
- if(version >= 5 && (smpHeader.flags & MO3Sample::smpCompressionMask) == MO3Sample::smpSharedOgg)
- {
- sharedOggHeader = musicChunk.ReadInt16LE();
- }
- if(!(loadFlags & loadSampleData))
- continue;
- const uint32 compression = (smpHeader.flags & MO3Sample::smpCompressionMask);
- if(!compression && smpHeader.compressedSize == 0)
- {
-
- SampleIO(
- (smpHeader.flags & MO3Sample::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit,
- (smpHeader.flags & MO3Sample::smpStereo) ? SampleIO::stereoSplit : SampleIO::mono,
- SampleIO::littleEndian,
- SampleIO::signedPCM)
- .ReadSample(Samples[smp], file);
- } else if(smpHeader.compressedSize < 0 && (smp + smpHeader.compressedSize) > 0)
- {
-
- sample.CopyWaveform(Samples[smp + smpHeader.compressedSize]);
- } else if(smpHeader.compressedSize > 0)
- {
- if(smpHeader.flags & MO3Sample::smp16Bit)
- sample.uFlags.set(CHN_16BIT);
- if(smpHeader.flags & MO3Sample::smpStereo)
- sample.uFlags.set(CHN_STEREO);
- FileReader sampleData = file.ReadChunk(smpHeader.compressedSize);
- const uint8 numChannels = sample.GetNumChannels();
- if(compression == MO3Sample::smpDeltaCompression || compression == MO3Sample::smpDeltaPrediction)
- {
-
-
- auto maxLength = sampleData.GetLength();
- uint8 maxSamplesPerByte = 4 / numChannels;
- if(Util::MaxValueOfType(maxLength) / maxSamplesPerByte >= maxLength)
- maxLength *= maxSamplesPerByte;
- else
- maxLength = Util::MaxValueOfType(maxLength);
- LimitMax(sample.nLength, mpt::saturate_cast<SmpLength>(maxLength));
- }
- if(compression == MO3Sample::smpDeltaCompression)
- {
- if(sample.AllocateSample())
- {
- if(smpHeader.flags & MO3Sample::smp16Bit)
- UnpackMO3DeltaSample<MO3Delta16BitParams>(sampleData, sample.sample16(), sample.nLength, numChannels);
- else
- UnpackMO3DeltaSample<MO3Delta8BitParams>(sampleData, sample.sample8(), sample.nLength, numChannels);
- }
- } else if(compression == MO3Sample::smpDeltaPrediction)
- {
- if(sample.AllocateSample())
- {
- if(smpHeader.flags & MO3Sample::smp16Bit)
- UnpackMO3DeltaPredictionSample<MO3Delta16BitParams>(sampleData, sample.sample16(), sample.nLength, numChannels);
- else
- UnpackMO3DeltaPredictionSample<MO3Delta8BitParams>(sampleData, sample.sample8(), sample.nLength, numChannels);
- }
- } else if(compression == MO3Sample::smpCompressionOgg || compression == MO3Sample::smpSharedOgg)
- {
-
- sampleChunks[smp - 1] = MO3SampleChunk(sampleData, smpHeader.encoderDelay, sharedOggHeader);
- } else if(compression == MO3Sample::smpCompressionMPEG)
- {
-
-
-
-
-
-
- FileReader mpegData(sampleData);
- MPEGFrame frame(sampleData);
- uint16 frameDelay = frame.numSamples * 2;
- if(frame.isLAME && smpHeader.encoderDelay >= frameDelay)
- {
-
- smpHeader.encoderDelay -= frameDelay;
- sampleData.Seek(frame.frameSize);
- mpegData = sampleData.ReadChunk(sampleData.BytesLeft());
- }
- if(ReadMP3Sample(smp, mpegData, true, true) || ReadMediaFoundationSample(smp, mpegData, true))
- {
- if(smpHeader.encoderDelay > 0 && smpHeader.encoderDelay < sample.GetSampleSizeInBytes())
- {
- SmpLength delay = smpHeader.encoderDelay / sample.GetBytesPerSample();
- memmove(sample.sampleb(), sample.sampleb() + smpHeader.encoderDelay, sample.GetSampleSizeInBytes() - smpHeader.encoderDelay);
- sample.nLength -= delay;
- }
- LimitMax(sample.nLength, smpHeader.length);
- } else
- {
- unsupportedSamples = true;
- }
- } else if(compression == MO3Sample::smpOPLInstrument)
- {
- OPLPatch patch;
- if(sampleData.ReadArray(patch))
- {
- sample.SetAdlib(true, patch);
- }
- } else
- {
- unsupportedSamples = true;
- }
- }
- }
-
- if(loadFlags & loadSampleData)
- {
- for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++)
- {
- MO3SampleChunk &sampleChunk = sampleChunks[smp - 1];
-
- if(!sampleChunk.chunk.IsValid())
- continue;
- SAMPLEINDEX sharedOggHeader = smp + sampleChunk.sharedHeader;
-
-
-
-
- const bool sharedHeader = sharedOggHeader != smp && sharedOggHeader > 0 && sharedOggHeader <= m_nSamples && sampleChunk.headerSize > 0;
- #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
- std::vector<char> mergedData;
- if(sharedHeader)
- {
-
-
-
-
-
-
-
-
- #if 0
-
-
-
-
- std::ostringstream mergedStream(std::ios::binary);
- mergedStream.imbue(std::locale::classic());
- sampleChunks[sharedOggHeader - 1].chunk.Rewind();
- FileReader sharedChunk = sampleChunks[sharedOggHeader - 1].chunk.ReadChunk(sampleChunk.headerSize);
- sharedChunk.Rewind();
- std::vector<uint32> streamSerials;
- Ogg::PageInfo oggPageInfo;
- std::vector<uint8> oggPageData;
- streamSerials.clear();
- while(Ogg::ReadPageAndSkipJunk(sharedChunk, oggPageInfo, oggPageData))
- {
- auto it = std::find(streamSerials.begin(), streamSerials.end(), oggPageInfo.header.bitstream_serial_number);
- if(it == streamSerials.end())
- {
- streamSerials.push_back(oggPageInfo.header.bitstream_serial_number);
- it = streamSerials.begin() + (streamSerials.size() - 1);
- }
- uint32 newSerial = it - streamSerials.begin() + 1;
- oggPageInfo.header.bitstream_serial_number = newSerial;
- Ogg::UpdatePageCRC(oggPageInfo, oggPageData);
- Ogg::WritePage(mergedStream, oggPageInfo, oggPageData);
- }
- streamSerials.clear();
- while(Ogg::ReadPageAndSkipJunk(sampleChunk.chunk, oggPageInfo, oggPageData))
- {
- auto it = std::find(streamSerials.begin(), streamSerials.end(), oggPageInfo.header.bitstream_serial_number);
- if(it == streamSerials.end())
- {
- streamSerials.push_back(oggPageInfo.header.bitstream_serial_number);
- it = streamSerials.begin() + (streamSerials.size() - 1);
- }
- uint32 newSerial = it - streamSerials.begin() + 1;
- oggPageInfo.header.bitstream_serial_number = newSerial;
- Ogg::UpdatePageCRC(oggPageInfo, oggPageData);
- Ogg::WritePage(mergedStream, oggPageInfo, oggPageData);
- }
- std::string mergedStreamData = mergedStream.str();
- mergedData.insert(mergedData.end(), mergedStreamData.begin(), mergedStreamData.end());
- #else
-
-
- std::ostringstream mergedStream(std::ios::binary);
- mergedStream.imbue(std::locale::classic());
- sampleChunks[sharedOggHeader - 1].chunk.Rewind();
- FileReader sharedChunk = sampleChunks[sharedOggHeader - 1].chunk.ReadChunk(sampleChunk.headerSize);
- sharedChunk.Rewind();
- std::vector<uint32> dataStreamSerials;
- std::vector<uint32> headStreamSerials;
- Ogg::PageInfo oggPageInfo;
- std::vector<uint8> oggPageData;
-
- dataStreamSerials.clear();
- while(Ogg::ReadPageAndSkipJunk(sampleChunk.chunk, oggPageInfo, oggPageData))
- {
- if(!mpt::contains(dataStreamSerials, oggPageInfo.header.bitstream_serial_number))
- {
- dataStreamSerials.push_back(oggPageInfo.header.bitstream_serial_number);
- }
- }
-
- headStreamSerials.clear();
- while(Ogg::ReadPageAndSkipJunk(sharedChunk, oggPageInfo, oggPageData))
- {
- auto it = std::find(headStreamSerials.begin(), headStreamSerials.end(), oggPageInfo.header.bitstream_serial_number);
- if(it == headStreamSerials.end())
- {
- headStreamSerials.push_back(oggPageInfo.header.bitstream_serial_number);
- it = headStreamSerials.begin() + (headStreamSerials.size() - 1);
- }
- uint32 newSerial = 0;
- if(dataStreamSerials.size() >= static_cast<std::size_t>(it - headStreamSerials.begin()))
- {
-
- newSerial = dataStreamSerials[it - headStreamSerials.begin()];
- } else
- {
-
- std::size_t extraIndex = (it - headStreamSerials.begin()) - dataStreamSerials.size();
- for(newSerial = 1; newSerial < 0xffffffffu; ++newSerial)
- {
- if(!mpt::contains(dataStreamSerials, newSerial))
- {
- extraIndex -= 1;
- }
- if(extraIndex == 0)
- {
- break;
- }
- }
- }
- oggPageInfo.header.bitstream_serial_number = newSerial;
- Ogg::UpdatePageCRC(oggPageInfo, oggPageData);
- Ogg::WritePage(mergedStream, oggPageInfo, oggPageData);
- }
- if(headStreamSerials.size() > 1)
- {
- AddToLog(LogWarning, MPT_UFORMAT("Sample {}: Ogg Vorbis data with shared header and multiple logical bitstreams in header chunk found. This may be handled incorrectly.")(smp));
- } else if(dataStreamSerials.size() > 1)
- {
- AddToLog(LogWarning, MPT_UFORMAT("Sample {}: Ogg Vorbis sample with shared header and multiple logical bitstreams found. This may be handled incorrectly.")(smp));
- } else if((dataStreamSerials.size() == 1) && (headStreamSerials.size() == 1) && (dataStreamSerials[0] != headStreamSerials[0]))
- {
- AddToLog(LogInformation, MPT_UFORMAT("Sample {}: Ogg Vorbis data with shared header and different logical bitstream serials found.")(smp));
- }
- std::string mergedStreamData = mergedStream.str();
- mergedData.insert(mergedData.end(), mergedStreamData.begin(), mergedStreamData.end());
- sampleChunk.chunk.Rewind();
- FileReader::PinnedView sampleChunkView = sampleChunk.chunk.GetPinnedView();
- mpt::span<const char> sampleChunkViewSpan = mpt::byte_cast<mpt::span<const char>>(sampleChunkView.span());
- mergedData.insert(mergedData.end(), sampleChunkViewSpan.begin(), sampleChunkViewSpan.end());
- #endif
- }
- FileReader mergedDataChunk(mpt::byte_cast<mpt::const_byte_span>(mpt::as_span(mergedData)));
- FileReader &sampleData = sharedHeader ? mergedDataChunk : sampleChunk.chunk;
- FileReader &headerChunk = sampleData;
- #else
- FileReader &sampleData = sampleChunk.chunk;
- FileReader &headerChunk = sharedHeader ? sampleChunks[sharedOggHeader - 1].chunk : sampleData;
- #if defined(MPT_WITH_STBVORBIS)
- std::size_t initialRead = sharedHeader ? sampleChunk.headerSize : headerChunk.GetLength();
- #endif
- #endif
- headerChunk.Rewind();
- if(sharedHeader && !headerChunk.CanRead(sampleChunk.headerSize))
- continue;
- #if defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
- ov_callbacks callbacks = {
- &VorbisfileFilereaderRead,
- &VorbisfileFilereaderSeek,
- nullptr,
- &VorbisfileFilereaderTell};
- OggVorbis_File vf;
- MemsetZero(vf);
- if(ov_open_callbacks(&sampleData, &vf, nullptr, 0, callbacks) == 0)
- {
- if(ov_streams(&vf) == 1)
- {
- vorbis_info *vi = ov_info(&vf, -1);
- if(vi && vi->rate > 0 && vi->channels > 0)
- {
- ModSample &sample = Samples[smp];
- sample.AllocateSample();
- SmpLength offset = 0;
- int channels = vi->channels;
- int current_section = 0;
- long decodedSamples = 0;
- bool eof = false;
- while(!eof && offset < sample.nLength && sample.HasSampleData())
- {
- float **output = nullptr;
- long ret = ov_read_float(&vf, &output, 1024, ¤t_section);
- if(ret == 0)
- {
- eof = true;
- } else if(ret < 0)
- {
-
- } else
- {
- decodedSamples = ret;
- LimitMax(decodedSamples, mpt::saturate_cast<long>(sample.nLength - offset));
- if(decodedSamples > 0 && channels == sample.GetNumChannels())
- {
- if(sample.uFlags[CHN_16BIT])
- {
- CopyAudio(mpt::audio_span_interleaved(sample.sample16() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples));
- } else
- {
- CopyAudio(mpt::audio_span_interleaved(sample.sample8() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples));
- }
- }
- offset += decodedSamples;
- }
- }
- } else
- {
- unsupportedSamples = true;
- }
- } else
- {
- AddToLog(LogWarning, MPT_UFORMAT("Sample {}: Unsupported Ogg Vorbis chained stream found.")(smp));
- unsupportedSamples = true;
- }
- ov_clear(&vf);
- } else
- {
- unsupportedSamples = true;
- }
- #elif defined(MPT_WITH_STBVORBIS)
-
-
-
-
-
-
-
- int consumed = 0, error = 0;
- stb_vorbis *vorb = nullptr;
- if(sharedHeader)
- {
- FileReader::PinnedView headChunkView = headerChunk.GetPinnedView(initialRead);
- vorb = stb_vorbis_open_pushdata(mpt::byte_cast<const unsigned char *>(headChunkView.data()), mpt::saturate_cast<int>(headChunkView.size()), &consumed, &error, nullptr);
- headerChunk.Skip(consumed);
- }
- FileReader::PinnedView sampleDataView = sampleData.GetPinnedView();
- const std::byte *data = sampleDataView.data();
- std::size_t dataLeft = sampleDataView.size();
- if(!sharedHeader)
- {
- vorb = stb_vorbis_open_pushdata(mpt::byte_cast<const unsigned char *>(data), mpt::saturate_cast<int>(dataLeft), &consumed, &error, nullptr);
- sampleData.Skip(consumed);
- data += consumed;
- dataLeft -= consumed;
- }
- if(vorb)
- {
-
- ModSample &sample = Samples[smp];
- sample.AllocateSample();
- SmpLength offset = 0;
- while((error == VORBIS__no_error || (error == VORBIS_need_more_data && dataLeft > 0))
- && offset < sample.nLength && sample.HasSampleData())
- {
- int channels = 0, decodedSamples = 0;
- float **output;
- consumed = stb_vorbis_decode_frame_pushdata(vorb, mpt::byte_cast<const unsigned char *>(data), mpt::saturate_cast<int>(dataLeft), &channels, &output, &decodedSamples);
- sampleData.Skip(consumed);
- data += consumed;
- dataLeft -= consumed;
- LimitMax(decodedSamples, mpt::saturate_cast<int>(sample.nLength - offset));
- if(decodedSamples > 0 && channels == sample.GetNumChannels())
- {
- if(sample.uFlags[CHN_16BIT])
- {
- CopyAudio(mpt::audio_span_interleaved(sample.sample16() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples));
- } else
- {
- CopyAudio(mpt::audio_span_interleaved(sample.sample8() + (offset * sample.GetNumChannels()), sample.GetNumChannels(), decodedSamples), mpt::audio_span_planar(output, channels, decodedSamples));
- }
- }
- offset += decodedSamples;
- error = stb_vorbis_get_error(vorb);
- }
- stb_vorbis_close(vorb);
- } else
- {
- unsupportedSamples = true;
- }
- #else
- unsupportedSamples = true;
- #endif
- }
- }
- if(m_nType == MOD_TYPE_XM)
- {
-
- for(INSTRUMENTINDEX ins = 0; ins < m_nInstruments; ins++)
- {
- PropagateXMAutoVibrato(ins + 1, static_cast<VibratoType>(instrVibrato[ins].type.get()), instrVibrato[ins].sweep, instrVibrato[ins].depth, instrVibrato[ins].rate);
- }
- }
- if((fileHeader.flags & MO3FileHeader::hasPlugins) && musicChunk.CanRead(1))
- {
-
- uint8 pluginFlags = musicChunk.ReadUint8();
- if(pluginFlags & 1)
- {
-
- for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
- {
- ChnSettings[chn].nMixPlugin = static_cast<PLUGINDEX>(musicChunk.ReadUint32LE());
- }
- }
- while(musicChunk.CanRead(1))
- {
- PLUGINDEX plug = musicChunk.ReadUint8();
- if(!plug)
- break;
- FileReader pluginChunk = musicChunk.ReadChunk(musicChunk.ReadUint32LE());
- #ifndef NO_PLUGINS
- if(plug <= MAX_MIXPLUGINS)
- {
- ReadMixPluginChunk(pluginChunk, m_MixPlugins[plug - 1]);
- }
- #endif
- }
- }
- mpt::ustring madeWithTracker;
- uint16 cwtv = 0;
- uint16 cmwt = 0;
- while(musicChunk.CanRead(8))
- {
- uint32 id = musicChunk.ReadUint32LE();
- uint32 len = musicChunk.ReadUint32LE();
- FileReader chunk = musicChunk.ReadChunk(len);
- switch(id)
- {
- case MagicLE("VERS"):
-
- switch(m_nType)
- {
- case MOD_TYPE_IT:
- cwtv = chunk.ReadUint16LE();
- cmwt = chunk.ReadUint16LE();
-
- break;
- case MOD_TYPE_S3M:
- cwtv = chunk.ReadUint16LE();
- break;
- case MOD_TYPE_XM:
- chunk.ReadString<mpt::String::spacePadded>(madeWithTracker, mpt::Charset::CP437, std::min(FileReader::off_t(32), chunk.GetLength()));
- break;
- case MOD_TYPE_MTM:
- {
- uint8 mtmVersion = chunk.ReadUint8();
- madeWithTracker = MPT_UFORMAT("MultiTracker {}.{}")(mtmVersion >> 4, mtmVersion & 0x0F);
- }
- break;
- default:
- break;
- }
- break;
- case MagicLE("PRHI"):
- m_nDefaultRowsPerBeat = chunk.ReadUint8();
- m_nDefaultRowsPerMeasure = chunk.ReadUint8();
- break;
- case MagicLE("MIDI"):
-
- chunk.ReadStruct<MIDIMacroConfigData>(m_MidiCfg);
- m_MidiCfg.Sanitize();
- break;
- case MagicLE("OMPT"):
-
- if(chunk.ReadMagic("PNAM"))
- {
- FileReader patterns = chunk.ReadChunk(chunk.ReadUint32LE());
- const PATTERNINDEX namedPats = std::min(static_cast<PATTERNINDEX>(patterns.GetLength() / MAX_PATTERNNAME), Patterns.Size());
- for(PATTERNINDEX pat = 0; pat < namedPats; pat++)
- {
- char patName[MAX_PATTERNNAME];
- patterns.ReadString<mpt::String::maybeNullTerminated>(patName, MAX_PATTERNNAME);
- Patterns[pat].SetName(patName);
- }
- }
-
- if(chunk.ReadMagic("CNAM"))
- {
- FileReader channels = chunk.ReadChunk(chunk.ReadUint32LE());
- const CHANNELINDEX namedChans = std::min(static_cast<CHANNELINDEX>(channels.GetLength() / MAX_CHANNELNAME), GetNumChannels());
- for(CHANNELINDEX chn = 0; chn < namedChans; chn++)
- {
- channels.ReadString<mpt::String::maybeNullTerminated>(ChnSettings[chn].szName, MAX_CHANNELNAME);
- }
- }
- LoadExtendedInstrumentProperties(chunk);
- LoadExtendedSongProperties(chunk, true);
- if(cwtv > 0x0889 && cwtv <= 0x8FF)
- {
- m_nType = MOD_TYPE_MPT;
- LoadMPTMProperties(chunk, cwtv);
- }
- if(m_dwLastSavedWithVersion)
- {
- madeWithTracker = U_("OpenMPT ") + mpt::ufmt::val(m_dwLastSavedWithVersion);
- }
- break;
- }
- }
- if((GetType() == MOD_TYPE_IT && cwtv >= 0x0100 && cwtv < 0x0214)
- || (GetType() == MOD_TYPE_S3M && cwtv >= 0x3100 && cwtv < 0x3214)
- || (GetType() == MOD_TYPE_S3M && cwtv >= 0x1300 && cwtv < 0x1320))
- {
-
- m_MidiCfg.ClearZxxMacros();
- }
- if(fileHeader.flags & MO3FileHeader::modplugMode)
- {
-
- if(!m_dwLastSavedWithVersion)
- {
-
- for(INSTRUMENTINDEX i = 1; i <= GetNumInstruments(); i++)
- {
- if(ModInstrument *ins = Instruments[i])
- {
-
- ins->GetEnvelope(ENV_PITCH).Convert(MOD_TYPE_XM, GetType());
-
- ins->nPanSwing = (ins->nPanSwing + 3) / 4u;
- }
- }
- }
- if(m_dwLastSavedWithVersion < MPT_V("1.18.00.00"))
- {
- m_playBehaviour.reset(kITOffset);
- m_playBehaviour.reset(kFT2ST3OffsetOutOfRange);
- }
- if(m_dwLastSavedWithVersion < MPT_V("1.23.00.00"))
- m_playBehaviour.reset(kFT2Periods);
- if(m_dwLastSavedWithVersion < MPT_V("1.26.00.00"))
- m_playBehaviour.reset(kITInstrWithNoteOff);
- }
- if(madeWithTracker.empty())
- madeWithTracker = MPT_UFORMAT("MO3 v{}")(version);
- else
- madeWithTracker = MPT_UFORMAT("MO3 v{} ({})")(version, madeWithTracker);
- m_modFormat.formatName = MPT_UFORMAT("Un4seen MO3 v{}")(version);
- m_modFormat.type = U_("mo3");
- switch(GetType())
- {
- case MOD_TYPE_MTM:
- m_modFormat.originalType = U_("mtm");
- m_modFormat.originalFormatName = U_("MultiTracker");
- break;
- case MOD_TYPE_MOD:
- m_modFormat.originalType = U_("mod");
- m_modFormat.originalFormatName = U_("Generic MOD");
- break;
- case MOD_TYPE_XM:
- m_modFormat.originalType = U_("xm");
- m_modFormat.originalFormatName = U_("FastTracker 2");
- break;
- case MOD_TYPE_S3M:
- m_modFormat.originalType = U_("s3m");
- m_modFormat.originalFormatName = U_("Scream Tracker 3");
- break;
- case MOD_TYPE_IT:
- m_modFormat.originalType = U_("it");
- if(cmwt)
- m_modFormat.originalFormatName = MPT_UFORMAT("Impulse Tracker {}.{}")(cmwt >> 8, mpt::ufmt::hex0<2>(cmwt & 0xFF));
- else
- m_modFormat.originalFormatName = U_("Impulse Tracker");
- break;
- case MOD_TYPE_MPT:
- m_modFormat.originalType = U_("mptm");
- m_modFormat.originalFormatName = U_("OpenMPT MPTM");
- break;
- default:
- MPT_ASSERT_NOTREACHED();
- }
- m_modFormat.madeWithTracker = std::move(madeWithTracker);
- if(m_dwLastSavedWithVersion)
- m_modFormat.charset = mpt::Charset::Windows1252;
- else if(GetType() == MOD_TYPE_MOD)
- m_modFormat.charset = mpt::Charset::Amiga_no_C1;
- else
- m_modFormat.charset = mpt::Charset::CP437;
- if(unsupportedSamples)
- {
- AddToLog(LogWarning, U_("Some compressed samples could not be loaded because they use an unsupported codec."));
- }
- return true;
- }
- OPENMPT_NAMESPACE_END
|