load_j2b.cpp 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. /*
  2. * load_j2b.cpp
  3. * ------------
  4. * Purpose: RIFF AM and RIFF AMFF (Galaxy Sound System) module loader
  5. * Notes : J2B is a compressed variant of RIFF AM and RIFF AMFF files used in Jazz Jackrabbit 2.
  6. * It seems like no other game used the AM(FF) format.
  7. * RIFF AM is the newer version of the format, generally following the RIFF "standard" closely.
  8. * Authors: Johannes Schultz (OpenMPT port, reverse engineering + loader implementation of the instrument format)
  9. * kode54 (foo_dumb - this is almost a complete port of his code, thanks)
  10. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  11. */
  12. #include "stdafx.h"
  13. #include "Loaders.h"
  14. #include "mpt/io/base.hpp"
  15. #if defined(MPT_WITH_ZLIB)
  16. #include <zlib.h>
  17. #elif defined(MPT_WITH_MINIZ)
  18. #include <miniz/miniz.h>
  19. #endif
  20. #ifdef MPT_ALL_LOGGING
  21. #define J2B_LOG
  22. #endif
  23. OPENMPT_NAMESPACE_BEGIN
  24. // First off, a nice vibrato translation LUT.
  25. static constexpr VibratoType j2bAutoVibratoTrans[] =
  26. {
  27. VIB_SINE, VIB_SQUARE, VIB_RAMP_UP, VIB_RAMP_DOWN, VIB_RANDOM,
  28. };
  29. // header for compressed j2b files
  30. struct J2BFileHeader
  31. {
  32. // Magic Bytes
  33. // 32-Bit J2B header identifiers
  34. enum : uint32 {
  35. magicDEADBEAF = 0xAFBEADDEu,
  36. magicDEADBABE = 0xBEBAADDEu
  37. };
  38. char signature[4]; // MUSE
  39. uint32le deadbeaf; // 0xDEADBEAF (AM) or 0xDEADBABE (AMFF)
  40. uint32le fileLength; // complete filesize
  41. uint32le crc32; // checksum of the compressed data block
  42. uint32le packedLength; // length of the compressed data block
  43. uint32le unpackedLength; // length of the decompressed module
  44. };
  45. MPT_BINARY_STRUCT(J2BFileHeader, 24)
  46. // AM(FF) stuff
  47. struct AMFFRiffChunk
  48. {
  49. // 32-Bit chunk identifiers
  50. enum ChunkIdentifiers
  51. {
  52. idRIFF = MagicLE("RIFF"),
  53. idAMFF = MagicLE("AMFF"),
  54. idAM__ = MagicLE("AM "),
  55. idMAIN = MagicLE("MAIN"),
  56. idINIT = MagicLE("INIT"),
  57. idORDR = MagicLE("ORDR"),
  58. idPATT = MagicLE("PATT"),
  59. idINST = MagicLE("INST"),
  60. idSAMP = MagicLE("SAMP"),
  61. idAI__ = MagicLE("AI "),
  62. idAS__ = MagicLE("AS "),
  63. };
  64. uint32le id; // See ChunkIdentifiers
  65. uint32le length; // Chunk size without header
  66. size_t GetLength() const
  67. {
  68. return length;
  69. }
  70. ChunkIdentifiers GetID() const
  71. {
  72. return static_cast<ChunkIdentifiers>(id.get());
  73. }
  74. };
  75. MPT_BINARY_STRUCT(AMFFRiffChunk, 8)
  76. // This header is used for both AM's "INIT" as well as AMFF's "MAIN" chunk
  77. struct AMFFMainChunk
  78. {
  79. // Main Chunk flags
  80. enum MainFlags
  81. {
  82. amigaSlides = 0x01,
  83. };
  84. char songname[64];
  85. uint8le flags;
  86. uint8le channels;
  87. uint8le speed;
  88. uint8le tempo;
  89. uint16le minPeriod; // 16x Amiga periods, but we should ignore them - otherwise some high notes in Medivo.j2b won't sound correct.
  90. uint16le maxPeriod; // Ditto
  91. uint8le globalvolume;
  92. };
  93. MPT_BINARY_STRUCT(AMFFMainChunk, 73)
  94. // AMFF instrument envelope (old format)
  95. struct AMFFEnvelope
  96. {
  97. // Envelope flags (also used for RIFF AM)
  98. enum EnvelopeFlags
  99. {
  100. envEnabled = 0x01,
  101. envSustain = 0x02,
  102. envLoop = 0x04,
  103. };
  104. struct EnvPoint
  105. {
  106. uint16le tick;
  107. uint8le value; // 0...64
  108. };
  109. uint8le envFlags; // high nibble = pan env flags, low nibble = vol env flags (both nibbles work the same way)
  110. uint8le envNumPoints; // high nibble = pan env length, low nibble = vol env length
  111. uint8le envSustainPoints; // you guessed it... high nibble = pan env sustain point, low nibble = vol env sustain point
  112. uint8le envLoopStarts; // I guess you know the pattern now.
  113. uint8le envLoopEnds; // same here.
  114. EnvPoint volEnv[10];
  115. EnvPoint panEnv[10];
  116. // Convert weird envelope data to OpenMPT's internal format.
  117. void ConvertEnvelope(uint8 flags, uint8 numPoints, uint8 sustainPoint, uint8 loopStart, uint8 loopEnd, const EnvPoint (&points)[10], InstrumentEnvelope &mptEnv) const
  118. {
  119. // The buggy mod2j2b converter will actually NOT limit this to 10 points if the envelope is longer.
  120. mptEnv.resize(std::min(numPoints, static_cast<uint8>(10)));
  121. mptEnv.nSustainStart = mptEnv.nSustainEnd = sustainPoint;
  122. mptEnv.nLoopStart = loopStart;
  123. mptEnv.nLoopEnd = loopEnd;
  124. for(uint32 i = 0; i < mptEnv.size(); i++)
  125. {
  126. mptEnv[i].tick = points[i].tick >> 4;
  127. if(i == 0)
  128. mptEnv[0].tick = 0;
  129. else if(mptEnv[i].tick < mptEnv[i - 1].tick)
  130. mptEnv[i].tick = mptEnv[i - 1].tick + 1;
  131. mptEnv[i].value = Clamp<uint8, uint8>(points[i].value, 0, 64);
  132. }
  133. mptEnv.dwFlags.set(ENV_ENABLED, (flags & AMFFEnvelope::envEnabled) != 0);
  134. mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & AMFFEnvelope::envSustain) && mptEnv.nSustainStart <= mptEnv.size());
  135. mptEnv.dwFlags.set(ENV_LOOP, (flags & AMFFEnvelope::envLoop) && mptEnv.nLoopStart <= mptEnv.nLoopEnd && mptEnv.nLoopStart <= mptEnv.size());
  136. }
  137. void ConvertToMPT(ModInstrument &mptIns) const
  138. {
  139. // interleaved envelope data... meh. gotta split it up here and decode it separately.
  140. // note: mod2j2b is BUGGY and always writes ($original_num_points & 0x0F) in the header,
  141. // but just has room for 10 envelope points. That means that long (>= 16 points)
  142. // envelopes are cut off, and envelopes have to be trimmed to 10 points, even if
  143. // the header claims that they are longer.
  144. // For XM files the number of points also appears to be off by one,
  145. // but luckily there are no official J2Bs using envelopes anyway.
  146. ConvertEnvelope(envFlags & 0x0F, envNumPoints & 0x0F, envSustainPoints & 0x0F, envLoopStarts & 0x0F, envLoopEnds & 0x0F, volEnv, mptIns.VolEnv);
  147. ConvertEnvelope(envFlags >> 4, envNumPoints >> 4, envSustainPoints >> 4, envLoopStarts >> 4, envLoopEnds >> 4, panEnv, mptIns.PanEnv);
  148. }
  149. };
  150. MPT_BINARY_STRUCT(AMFFEnvelope::EnvPoint, 3)
  151. MPT_BINARY_STRUCT(AMFFEnvelope, 65)
  152. // AMFF instrument header (old format)
  153. struct AMFFInstrumentHeader
  154. {
  155. uint8le unknown; // 0x00
  156. uint8le index; // actual instrument number
  157. char name[28];
  158. uint8le numSamples;
  159. uint8le sampleMap[120];
  160. uint8le vibratoType;
  161. uint16le vibratoSweep;
  162. uint16le vibratoDepth;
  163. uint16le vibratoRate;
  164. AMFFEnvelope envelopes;
  165. uint16le fadeout;
  166. // Convert instrument data to OpenMPT's internal format.
  167. void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX baseSample)
  168. {
  169. mptIns.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, name);
  170. static_assert(mpt::array_size<decltype(sampleMap)>::size <= mpt::array_size<decltype(mptIns.Keyboard)>::size);
  171. for(size_t i = 0; i < std::size(sampleMap); i++)
  172. {
  173. mptIns.Keyboard[i] = sampleMap[i] + baseSample + 1;
  174. }
  175. mptIns.nFadeOut = fadeout << 5;
  176. envelopes.ConvertToMPT(mptIns);
  177. }
  178. };
  179. MPT_BINARY_STRUCT(AMFFInstrumentHeader, 225)
  180. // AMFF sample header (old format)
  181. struct AMFFSampleHeader
  182. {
  183. // Sample flags (also used for RIFF AM)
  184. enum SampleFlags
  185. {
  186. smp16Bit = 0x04,
  187. smpLoop = 0x08,
  188. smpPingPong = 0x10,
  189. smpPanning = 0x20,
  190. smpExists = 0x80,
  191. // some flags are still missing... what is e.g. 0x8000?
  192. };
  193. uint32le id; // "SAMP"
  194. uint32le chunkSize; // header + sample size
  195. char name[28];
  196. uint8le pan;
  197. uint8le volume;
  198. uint16le flags;
  199. uint32le length;
  200. uint32le loopStart;
  201. uint32le loopEnd;
  202. uint32le sampleRate;
  203. uint32le reserved1;
  204. uint32le reserved2;
  205. // Convert sample header to OpenMPT's internal format.
  206. void ConvertToMPT(AMFFInstrumentHeader &instrHeader, ModSample &mptSmp) const
  207. {
  208. mptSmp.Initialize();
  209. mptSmp.nPan = pan * 4;
  210. mptSmp.nVolume = volume * 4;
  211. mptSmp.nGlobalVol = 64;
  212. mptSmp.nLength = length;
  213. mptSmp.nLoopStart = loopStart;
  214. mptSmp.nLoopEnd = loopEnd;
  215. mptSmp.nC5Speed = sampleRate;
  216. if(instrHeader.vibratoType < std::size(j2bAutoVibratoTrans))
  217. mptSmp.nVibType = j2bAutoVibratoTrans[instrHeader.vibratoType];
  218. mptSmp.nVibSweep = static_cast<uint8>(instrHeader.vibratoSweep);
  219. mptSmp.nVibRate = static_cast<uint8>(instrHeader.vibratoRate / 16);
  220. mptSmp.nVibDepth = static_cast<uint8>(instrHeader.vibratoDepth / 4);
  221. if((mptSmp.nVibRate | mptSmp.nVibDepth) != 0)
  222. {
  223. // Convert XM-style vibrato sweep to IT
  224. mptSmp.nVibSweep = 255 - mptSmp.nVibSweep;
  225. }
  226. if(flags & AMFFSampleHeader::smp16Bit)
  227. mptSmp.uFlags.set(CHN_16BIT);
  228. if(flags & AMFFSampleHeader::smpLoop)
  229. mptSmp.uFlags.set(CHN_LOOP);
  230. if(flags & AMFFSampleHeader::smpPingPong)
  231. mptSmp.uFlags.set(CHN_PINGPONGLOOP);
  232. if(flags & AMFFSampleHeader::smpPanning)
  233. mptSmp.uFlags.set(CHN_PANNING);
  234. }
  235. // Retrieve the internal sample format flags for this sample.
  236. SampleIO GetSampleFormat() const
  237. {
  238. return SampleIO(
  239. (flags & AMFFSampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit,
  240. SampleIO::mono,
  241. SampleIO::littleEndian,
  242. SampleIO::signedPCM);
  243. }
  244. };
  245. MPT_BINARY_STRUCT(AMFFSampleHeader, 64)
  246. // AM instrument envelope (new format)
  247. struct AMEnvelope
  248. {
  249. struct EnvPoint
  250. {
  251. uint16le tick;
  252. int16le value;
  253. };
  254. uint16le flags;
  255. uint8le numPoints; // actually, it's num. points - 1, and 0xFF if there is no envelope
  256. uint8le sustainPoint;
  257. uint8le loopStart;
  258. uint8le loopEnd;
  259. EnvPoint values[10];
  260. uint16le fadeout; // why is this here? it's only needed for the volume envelope...
  261. // Convert envelope data to OpenMPT's internal format.
  262. void ConvertToMPT(InstrumentEnvelope &mptEnv, EnvelopeType envType) const
  263. {
  264. if(numPoints == 0xFF || numPoints == 0)
  265. return;
  266. mptEnv.resize(std::min(numPoints + 1, 10));
  267. mptEnv.nSustainStart = mptEnv.nSustainEnd = sustainPoint;
  268. mptEnv.nLoopStart = loopStart;
  269. mptEnv.nLoopEnd = loopEnd;
  270. int32 scale = 0, offset = 0;
  271. switch(envType)
  272. {
  273. case ENV_VOLUME: // 0....32767
  274. default:
  275. scale = 32767 / ENVELOPE_MAX;
  276. break;
  277. case ENV_PITCH: // -4096....4096
  278. scale = 8192 / ENVELOPE_MAX;
  279. offset = 4096;
  280. break;
  281. case ENV_PANNING: // -32768...32767
  282. scale = 65536 / ENVELOPE_MAX;
  283. offset = 32768;
  284. break;
  285. }
  286. for(uint32 i = 0; i < mptEnv.size(); i++)
  287. {
  288. mptEnv[i].tick = values[i].tick >> 4;
  289. if(i == 0)
  290. mptEnv[i].tick = 0;
  291. else if(mptEnv[i].tick < mptEnv[i - 1].tick)
  292. mptEnv[i].tick = mptEnv[i - 1].tick + 1;
  293. int32 val = values[i].value + offset;
  294. val = (val + scale / 2) / scale;
  295. mptEnv[i].value = static_cast<EnvelopeNode::value_t>(std::clamp(val, int32(ENVELOPE_MIN), int32(ENVELOPE_MAX)));
  296. }
  297. mptEnv.dwFlags.set(ENV_ENABLED, (flags & AMFFEnvelope::envEnabled) != 0);
  298. mptEnv.dwFlags.set(ENV_SUSTAIN, (flags & AMFFEnvelope::envSustain) && mptEnv.nSustainStart <= mptEnv.size());
  299. mptEnv.dwFlags.set(ENV_LOOP, (flags & AMFFEnvelope::envLoop) && mptEnv.nLoopStart <= mptEnv.nLoopEnd && mptEnv.nLoopStart <= mptEnv.size());
  300. }
  301. };
  302. MPT_BINARY_STRUCT(AMEnvelope::EnvPoint, 4)
  303. MPT_BINARY_STRUCT(AMEnvelope, 48)
  304. // AM instrument header (new format)
  305. struct AMInstrumentHeader
  306. {
  307. uint32le headSize; // Header size (i.e. the size of this struct)
  308. uint8le unknown1; // 0x00
  309. uint8le index; // Actual instrument number
  310. char name[32];
  311. uint8le sampleMap[128];
  312. uint8le vibratoType;
  313. uint16le vibratoSweep;
  314. uint16le vibratoDepth;
  315. uint16le vibratoRate;
  316. uint8le unknown2[7];
  317. AMEnvelope volEnv;
  318. AMEnvelope pitchEnv;
  319. AMEnvelope panEnv;
  320. uint16le numSamples;
  321. // Convert instrument data to OpenMPT's internal format.
  322. void ConvertToMPT(ModInstrument &mptIns, SAMPLEINDEX baseSample)
  323. {
  324. mptIns.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, name);
  325. static_assert(mpt::array_size<decltype(sampleMap)>::size <= mpt::array_size<decltype(mptIns.Keyboard)>::size);
  326. for(uint8 i = 0; i < std::size(sampleMap); i++)
  327. {
  328. mptIns.Keyboard[i] = sampleMap[i] + baseSample + 1;
  329. }
  330. mptIns.nFadeOut = volEnv.fadeout << 5;
  331. volEnv.ConvertToMPT(mptIns.VolEnv, ENV_VOLUME);
  332. pitchEnv.ConvertToMPT(mptIns.PitchEnv, ENV_PITCH);
  333. panEnv.ConvertToMPT(mptIns.PanEnv, ENV_PANNING);
  334. if(numSamples == 0)
  335. {
  336. MemsetZero(mptIns.Keyboard);
  337. }
  338. }
  339. };
  340. MPT_BINARY_STRUCT(AMInstrumentHeader, 326)
  341. // AM sample header (new format)
  342. struct AMSampleHeader
  343. {
  344. uint32le headSize; // Header size (i.e. the size of this struct), apparently not including headSize.
  345. char name[32];
  346. uint16le pan;
  347. uint16le volume;
  348. uint16le flags;
  349. uint16le unknown; // 0x0000 / 0x0080?
  350. uint32le length;
  351. uint32le loopStart;
  352. uint32le loopEnd;
  353. uint32le sampleRate;
  354. // Convert sample header to OpenMPT's internal format.
  355. void ConvertToMPT(AMInstrumentHeader &instrHeader, ModSample &mptSmp) const
  356. {
  357. mptSmp.Initialize();
  358. mptSmp.nPan = std::min(pan.get(), uint16(32767)) * 256 / 32767;
  359. mptSmp.nVolume = std::min(volume.get(), uint16(32767)) * 256 / 32767;
  360. mptSmp.nGlobalVol = 64;
  361. mptSmp.nLength = length;
  362. mptSmp.nLoopStart = loopStart;
  363. mptSmp.nLoopEnd = loopEnd;
  364. mptSmp.nC5Speed = sampleRate;
  365. if(instrHeader.vibratoType < std::size(j2bAutoVibratoTrans))
  366. mptSmp.nVibType = j2bAutoVibratoTrans[instrHeader.vibratoType];
  367. mptSmp.nVibSweep = static_cast<uint8>(instrHeader.vibratoSweep);
  368. mptSmp.nVibRate = static_cast<uint8>(instrHeader.vibratoRate / 16);
  369. mptSmp.nVibDepth = static_cast<uint8>(instrHeader.vibratoDepth / 4);
  370. if((mptSmp.nVibRate | mptSmp.nVibDepth) != 0)
  371. {
  372. // Convert XM-style vibrato sweep to IT
  373. mptSmp.nVibSweep = 255 - mptSmp.nVibSweep;
  374. }
  375. if(flags & AMFFSampleHeader::smp16Bit)
  376. mptSmp.uFlags.set(CHN_16BIT);
  377. if(flags & AMFFSampleHeader::smpLoop)
  378. mptSmp.uFlags.set(CHN_LOOP);
  379. if(flags & AMFFSampleHeader::smpPingPong)
  380. mptSmp.uFlags.set(CHN_PINGPONGLOOP);
  381. if(flags & AMFFSampleHeader::smpPanning)
  382. mptSmp.uFlags.set(CHN_PANNING);
  383. }
  384. // Retrieve the internal sample format flags for this sample.
  385. SampleIO GetSampleFormat() const
  386. {
  387. return SampleIO(
  388. (flags & AMFFSampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit,
  389. SampleIO::mono,
  390. SampleIO::littleEndian,
  391. SampleIO::signedPCM);
  392. }
  393. };
  394. MPT_BINARY_STRUCT(AMSampleHeader, 60)
  395. // Convert RIFF AM(FF) pattern data to MPT pattern data.
  396. static bool ConvertAMPattern(FileReader chunk, PATTERNINDEX pat, bool isAM, CSoundFile &sndFile)
  397. {
  398. // Effect translation LUT
  399. static constexpr EffectCommand amEffTrans[] =
  400. {
  401. CMD_ARPEGGIO, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO,
  402. CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO,
  403. CMD_PANNING8, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP,
  404. CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_TEMPO,
  405. CMD_GLOBALVOLUME, CMD_GLOBALVOLSLIDE, CMD_KEYOFF, CMD_SETENVPOSITION,
  406. CMD_CHANNELVOLUME, CMD_CHANNELVOLSLIDE, CMD_PANNINGSLIDE, CMD_RETRIG,
  407. CMD_TREMOR, CMD_XFINEPORTAUPDOWN,
  408. };
  409. enum
  410. {
  411. rowDone = 0, // Advance to next row
  412. channelMask = 0x1F, // Mask for retrieving channel information
  413. volFlag = 0x20, // Volume effect present
  414. noteFlag = 0x40, // Note + instr present
  415. effectFlag = 0x80, // Effect information present
  416. dataFlag = 0xE0, // Channel data present
  417. };
  418. if(chunk.NoBytesLeft())
  419. {
  420. return false;
  421. }
  422. ROWINDEX numRows = Clamp(static_cast<ROWINDEX>(chunk.ReadUint8()) + 1, ROWINDEX(1), MAX_PATTERN_ROWS);
  423. if(!sndFile.Patterns.Insert(pat, numRows))
  424. return false;
  425. const CHANNELINDEX channels = sndFile.GetNumChannels();
  426. if(channels == 0)
  427. return false;
  428. ROWINDEX row = 0;
  429. while(row < numRows && chunk.CanRead(1))
  430. {
  431. const uint8 flags = chunk.ReadUint8();
  432. if(flags == rowDone)
  433. {
  434. row++;
  435. continue;
  436. }
  437. ModCommand &m = *sndFile.Patterns[pat].GetpModCommand(row, std::min(static_cast<CHANNELINDEX>(flags & channelMask), static_cast<CHANNELINDEX>(channels - 1)));
  438. if(flags & dataFlag)
  439. {
  440. if(flags & effectFlag) // effect
  441. {
  442. m.param = chunk.ReadUint8();
  443. uint8 command = chunk.ReadUint8();
  444. if(command < std::size(amEffTrans))
  445. {
  446. // command translation
  447. m.command = amEffTrans[command];
  448. } else
  449. {
  450. #ifdef J2B_LOG
  451. MPT_LOG_GLOBAL(LogDebug, "J2B", MPT_UFORMAT("J2B: Unknown command: 0x{}, param 0x{}")(mpt::ufmt::HEX0<2>(command), mpt::ufmt::HEX0<2>(m.param)));
  452. #endif
  453. m.command = CMD_NONE;
  454. }
  455. // Handling special commands
  456. switch(m.command)
  457. {
  458. case CMD_ARPEGGIO:
  459. if(m.param == 0) m.command = CMD_NONE;
  460. break;
  461. case CMD_VOLUME:
  462. if(m.volcmd == VOLCMD_NONE)
  463. {
  464. m.volcmd = VOLCMD_VOLUME;
  465. m.vol = Clamp(m.param, uint8(0), uint8(64));
  466. m.command = CMD_NONE;
  467. m.param = 0;
  468. }
  469. break;
  470. case CMD_TONEPORTAVOL:
  471. case CMD_VIBRATOVOL:
  472. case CMD_VOLUMESLIDE:
  473. case CMD_GLOBALVOLSLIDE:
  474. case CMD_PANNINGSLIDE:
  475. if (m.param & 0xF0) m.param &= 0xF0;
  476. break;
  477. case CMD_PANNING8:
  478. if(m.param <= 0x80) m.param = mpt::saturate_cast<uint8>(m.param * 2);
  479. else if(m.param == 0xA4) {m.command = CMD_S3MCMDEX; m.param = 0x91;}
  480. break;
  481. case CMD_PATTERNBREAK:
  482. m.param = ((m.param >> 4) * 10) + (m.param & 0x0F);
  483. break;
  484. case CMD_MODCMDEX:
  485. m.ExtendedMODtoS3MEffect();
  486. break;
  487. case CMD_TEMPO:
  488. if(m.param <= 0x1F) m.command = CMD_SPEED;
  489. break;
  490. case CMD_XFINEPORTAUPDOWN:
  491. switch(m.param & 0xF0)
  492. {
  493. case 0x10:
  494. m.command = CMD_PORTAMENTOUP;
  495. break;
  496. case 0x20:
  497. m.command = CMD_PORTAMENTODOWN;
  498. break;
  499. }
  500. m.param = (m.param & 0x0F) | 0xE0;
  501. break;
  502. }
  503. }
  504. if (flags & noteFlag) // note + ins
  505. {
  506. const auto [instr, note] = chunk.ReadArray<uint8, 2>();
  507. m.instr = instr;
  508. m.note = note;
  509. if(m.note == 0x80) m.note = NOTE_KEYOFF;
  510. else if(m.note > 0x80) m.note = NOTE_FADE; // I guess the support for IT "note fade" notes was not intended in mod2j2b, but hey, it works! :-D
  511. }
  512. if (flags & volFlag) // volume
  513. {
  514. m.volcmd = VOLCMD_VOLUME;
  515. m.vol = chunk.ReadUint8();
  516. if(isAM)
  517. {
  518. m.vol = m.vol * 64 / 127;
  519. }
  520. }
  521. }
  522. }
  523. return true;
  524. }
  525. struct AMFFRiffChunkFormat
  526. {
  527. uint32le format;
  528. };
  529. MPT_BINARY_STRUCT(AMFFRiffChunkFormat, 4)
  530. static bool ValidateHeader(const AMFFRiffChunk &fileHeader)
  531. {
  532. if(fileHeader.id != AMFFRiffChunk::idRIFF)
  533. {
  534. return false;
  535. }
  536. if(fileHeader.GetLength() < 8 + sizeof(AMFFMainChunk))
  537. {
  538. return false;
  539. }
  540. return true;
  541. }
  542. static bool ValidateHeader(const AMFFRiffChunkFormat &formatHeader)
  543. {
  544. if(formatHeader.format != AMFFRiffChunk::idAMFF && formatHeader.format != AMFFRiffChunk::idAM__)
  545. {
  546. return false;
  547. }
  548. return true;
  549. }
  550. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize)
  551. {
  552. AMFFRiffChunk fileHeader;
  553. if(!file.ReadStruct(fileHeader))
  554. {
  555. return ProbeWantMoreData;
  556. }
  557. if(!ValidateHeader(fileHeader))
  558. {
  559. return ProbeFailure;
  560. }
  561. AMFFRiffChunkFormat formatHeader;
  562. if(!file.ReadStruct(formatHeader))
  563. {
  564. return ProbeWantMoreData;
  565. }
  566. if(!ValidateHeader(formatHeader))
  567. {
  568. return ProbeFailure;
  569. }
  570. MPT_UNREFERENCED_PARAMETER(pfilesize);
  571. return ProbeSuccess;
  572. }
  573. bool CSoundFile::ReadAM(FileReader &file, ModLoadingFlags loadFlags)
  574. {
  575. file.Rewind();
  576. AMFFRiffChunk fileHeader;
  577. if(!file.ReadStruct(fileHeader))
  578. {
  579. return false;
  580. }
  581. if(!ValidateHeader(fileHeader))
  582. {
  583. return false;
  584. }
  585. AMFFRiffChunkFormat formatHeader;
  586. if(!file.ReadStruct(formatHeader))
  587. {
  588. return false;
  589. }
  590. if(!ValidateHeader(formatHeader))
  591. {
  592. return false;
  593. }
  594. bool isAM; // false: AMFF, true: AM
  595. uint32 format = formatHeader.format;
  596. if(format == AMFFRiffChunk::idAMFF)
  597. isAM = false; // "AMFF"
  598. else if(format == AMFFRiffChunk::idAM__)
  599. isAM = true; // "AM "
  600. else
  601. return false;
  602. ChunkReader chunkFile(file);
  603. // The main chunk is almost identical in both formats but uses different chunk IDs.
  604. // "MAIN" - Song info (AMFF)
  605. // "INIT" - Song info (AM)
  606. AMFFRiffChunk::ChunkIdentifiers mainChunkID = isAM ? AMFFRiffChunk::idINIT : AMFFRiffChunk::idMAIN;
  607. // RIFF AM has a padding byte so that all chunks have an even size.
  608. ChunkReader::ChunkList<AMFFRiffChunk> chunks;
  609. if(loadFlags == onlyVerifyHeader)
  610. chunks = chunkFile.ReadChunksUntil<AMFFRiffChunk>(isAM ? 2 : 1, mainChunkID);
  611. else
  612. chunks = chunkFile.ReadChunks<AMFFRiffChunk>(isAM ? 2 : 1);
  613. FileReader chunkMain(chunks.GetChunk(mainChunkID));
  614. AMFFMainChunk mainChunk;
  615. if(!chunkMain.IsValid()
  616. || !chunkMain.ReadStruct(mainChunk)
  617. || mainChunk.channels < 1
  618. || !chunkMain.CanRead(mainChunk.channels))
  619. {
  620. return false;
  621. } else if(loadFlags == onlyVerifyHeader)
  622. {
  623. return true;
  624. }
  625. InitializeGlobals(MOD_TYPE_J2B);
  626. m_SongFlags = SONG_ITOLDEFFECTS | SONG_ITCOMPATGXX;
  627. m_SongFlags.set(SONG_LINEARSLIDES, !(mainChunk.flags & AMFFMainChunk::amigaSlides));
  628. m_nChannels = std::min(static_cast<CHANNELINDEX>(mainChunk.channels), static_cast<CHANNELINDEX>(MAX_BASECHANNELS));
  629. m_nDefaultSpeed = mainChunk.speed;
  630. m_nDefaultTempo.Set(mainChunk.tempo);
  631. m_nDefaultGlobalVolume = mainChunk.globalvolume * 2;
  632. m_modFormat.formatName = isAM ? UL_("Galaxy Sound System (new version)") : UL_("Galaxy Sound System (old version)");
  633. m_modFormat.type = U_("j2b");
  634. m_modFormat.charset = mpt::Charset::CP437;
  635. m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, mainChunk.songname);
  636. // It seems like there's no way to differentiate between
  637. // Muted and Surround channels (they're all 0xA0) - might
  638. // be a limitation in mod2j2b.
  639. for(CHANNELINDEX nChn = 0; nChn < m_nChannels; nChn++)
  640. {
  641. ChnSettings[nChn].Reset();
  642. uint8 pan = chunkMain.ReadUint8();
  643. if(isAM)
  644. {
  645. if(pan > 128)
  646. ChnSettings[nChn].dwFlags = CHN_MUTE;
  647. else
  648. ChnSettings[nChn].nPan = pan * 2;
  649. } else
  650. {
  651. if(pan >= 128)
  652. ChnSettings[nChn].dwFlags = CHN_MUTE;
  653. else
  654. ChnSettings[nChn].nPan = static_cast<uint16>(std::min(pan * 4, 256));
  655. }
  656. }
  657. if(chunks.ChunkExists(AMFFRiffChunk::idORDR))
  658. {
  659. // "ORDR" - Order list
  660. FileReader chunk(chunks.GetChunk(AMFFRiffChunk::idORDR));
  661. uint8 numOrders = chunk.ReadUint8() + 1;
  662. ReadOrderFromFile<uint8>(Order(), chunk, numOrders, 0xFF, 0xFE);
  663. }
  664. // "PATT" - Pattern data for one pattern
  665. if(loadFlags & loadPatternData)
  666. {
  667. PATTERNINDEX maxPattern = 0;
  668. auto pattChunks = chunks.GetAllChunks(AMFFRiffChunk::idPATT);
  669. Patterns.ResizeArray(static_cast<PATTERNINDEX>(pattChunks.size()));
  670. for(auto chunk : pattChunks)
  671. {
  672. PATTERNINDEX pat = chunk.ReadUint8();
  673. size_t patternSize = chunk.ReadUint32LE();
  674. ConvertAMPattern(chunk.ReadChunk(patternSize), pat, isAM, *this);
  675. maxPattern = std::max(maxPattern, pat);
  676. }
  677. for(PATTERNINDEX pat = 0; pat < maxPattern; pat++)
  678. {
  679. if(!Patterns.IsValidPat(pat))
  680. Patterns.Insert(pat, 64);
  681. }
  682. }
  683. if(!isAM)
  684. {
  685. // "INST" - Instrument (only in RIFF AMFF)
  686. auto instChunks = chunks.GetAllChunks(AMFFRiffChunk::idINST);
  687. for(auto chunk : instChunks)
  688. {
  689. AMFFInstrumentHeader instrHeader;
  690. if(!chunk.ReadStruct(instrHeader))
  691. {
  692. continue;
  693. }
  694. const INSTRUMENTINDEX instr = instrHeader.index + 1;
  695. if(instr >= MAX_INSTRUMENTS)
  696. continue;
  697. ModInstrument *pIns = AllocateInstrument(instr);
  698. if(pIns == nullptr)
  699. {
  700. continue;
  701. }
  702. instrHeader.ConvertToMPT(*pIns, m_nSamples);
  703. // read sample sub-chunks - this is a rather "flat" format compared to RIFF AM and has no nested RIFF chunks.
  704. for(size_t samples = 0; samples < instrHeader.numSamples; samples++)
  705. {
  706. AMFFSampleHeader sampleHeader;
  707. if(!CanAddMoreSamples() || !chunk.ReadStruct(sampleHeader))
  708. {
  709. continue;
  710. }
  711. const SAMPLEINDEX smp = ++m_nSamples;
  712. if(sampleHeader.id != AMFFRiffChunk::idSAMP)
  713. {
  714. continue;
  715. }
  716. m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name);
  717. sampleHeader.ConvertToMPT(instrHeader, Samples[smp]);
  718. if(loadFlags & loadSampleData)
  719. sampleHeader.GetSampleFormat().ReadSample(Samples[smp], chunk);
  720. else
  721. chunk.Skip(Samples[smp].GetSampleSizeInBytes());
  722. }
  723. }
  724. } else
  725. {
  726. // "RIFF" - Instrument (only in RIFF AM)
  727. auto instChunks = chunks.GetAllChunks(AMFFRiffChunk::idRIFF);
  728. for(ChunkReader chunk : instChunks)
  729. {
  730. if(chunk.ReadUint32LE() != AMFFRiffChunk::idAI__)
  731. {
  732. continue;
  733. }
  734. AMFFRiffChunk instChunk;
  735. if(!chunk.ReadStruct(instChunk) || instChunk.id != AMFFRiffChunk::idINST)
  736. {
  737. continue;
  738. }
  739. AMInstrumentHeader instrHeader;
  740. if(!chunk.ReadStruct(instrHeader))
  741. {
  742. continue;
  743. }
  744. MPT_ASSERT(instrHeader.headSize + 4 == sizeof(instrHeader));
  745. const INSTRUMENTINDEX instr = instrHeader.index + 1;
  746. if(instr >= MAX_INSTRUMENTS)
  747. continue;
  748. ModInstrument *pIns = AllocateInstrument(instr);
  749. if(pIns == nullptr)
  750. {
  751. continue;
  752. }
  753. instrHeader.ConvertToMPT(*pIns, m_nSamples);
  754. // Read sample sub-chunks (RIFF nesting ftw)
  755. auto sampleChunks = chunk.ReadChunks<AMFFRiffChunk>(2).GetAllChunks(AMFFRiffChunk::idRIFF);
  756. MPT_ASSERT(sampleChunks.size() == instrHeader.numSamples);
  757. for(auto sampleChunk : sampleChunks)
  758. {
  759. if(sampleChunk.ReadUint32LE() != AMFFRiffChunk::idAS__ || !CanAddMoreSamples())
  760. {
  761. continue;
  762. }
  763. // Don't read more samples than the instrument header claims to have.
  764. if((instrHeader.numSamples--) == 0)
  765. {
  766. break;
  767. }
  768. const SAMPLEINDEX smp = ++m_nSamples;
  769. // Aaand even more nested chunks! Great, innit?
  770. AMFFRiffChunk sampleHeaderChunk;
  771. if(!sampleChunk.ReadStruct(sampleHeaderChunk) || sampleHeaderChunk.id != AMFFRiffChunk::idSAMP)
  772. {
  773. break;
  774. }
  775. FileReader sampleFileChunk = sampleChunk.ReadChunk(sampleHeaderChunk.length);
  776. AMSampleHeader sampleHeader;
  777. if(!sampleFileChunk.ReadStruct(sampleHeader))
  778. {
  779. break;
  780. }
  781. m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, sampleHeader.name);
  782. sampleHeader.ConvertToMPT(instrHeader, Samples[smp]);
  783. if(loadFlags & loadSampleData)
  784. {
  785. sampleFileChunk.Seek(sampleHeader.headSize + 4);
  786. sampleHeader.GetSampleFormat().ReadSample(Samples[smp], sampleFileChunk);
  787. }
  788. }
  789. }
  790. }
  791. return true;
  792. }
  793. static bool ValidateHeader(const J2BFileHeader &fileHeader)
  794. {
  795. if(std::memcmp(fileHeader.signature, "MUSE", 4)
  796. || (fileHeader.deadbeaf != J2BFileHeader::magicDEADBEAF // 0xDEADBEAF (RIFF AM)
  797. && fileHeader.deadbeaf != J2BFileHeader::magicDEADBABE) // 0xDEADBABE (RIFF AMFF)
  798. )
  799. {
  800. return false;
  801. }
  802. if(fileHeader.packedLength == 0)
  803. {
  804. return false;
  805. }
  806. if(fileHeader.fileLength != fileHeader.packedLength + sizeof(J2BFileHeader))
  807. {
  808. return false;
  809. }
  810. return true;
  811. }
  812. static bool ValidateHeaderFileSize(const J2BFileHeader &fileHeader, uint64 filesize)
  813. {
  814. if(filesize != fileHeader.fileLength)
  815. {
  816. return false;
  817. }
  818. return true;
  819. }
  820. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize)
  821. {
  822. J2BFileHeader fileHeader;
  823. if(!file.ReadStruct(fileHeader))
  824. {
  825. return ProbeWantMoreData;
  826. }
  827. if(!ValidateHeader(fileHeader))
  828. {
  829. return ProbeFailure;
  830. }
  831. if(pfilesize)
  832. {
  833. if(!ValidateHeaderFileSize(fileHeader, *pfilesize))
  834. {
  835. return ProbeFailure;
  836. }
  837. }
  838. MPT_UNREFERENCED_PARAMETER(pfilesize);
  839. return ProbeSuccess;
  840. }
  841. bool CSoundFile::ReadJ2B(FileReader &file, ModLoadingFlags loadFlags)
  842. {
  843. #if !defined(MPT_WITH_ZLIB) && !defined(MPT_WITH_MINIZ)
  844. MPT_UNREFERENCED_PARAMETER(file);
  845. MPT_UNREFERENCED_PARAMETER(loadFlags);
  846. return false;
  847. #else
  848. file.Rewind();
  849. J2BFileHeader fileHeader;
  850. if(!file.ReadStruct(fileHeader))
  851. {
  852. return false;
  853. }
  854. if(!ValidateHeader(fileHeader))
  855. {
  856. return false;
  857. }
  858. if(fileHeader.fileLength != file.GetLength()
  859. || fileHeader.packedLength != file.BytesLeft()
  860. )
  861. {
  862. return false;
  863. }
  864. if(loadFlags == onlyVerifyHeader)
  865. {
  866. return true;
  867. }
  868. // Header is valid, now unpack the RIFF AM file using inflate
  869. z_stream strm{};
  870. if(inflateInit(&strm) != Z_OK)
  871. return false;
  872. uint32 remainRead = fileHeader.packedLength, remainWrite = fileHeader.unpackedLength, totalWritten = 0;
  873. uint32 crc = 0;
  874. std::vector<Bytef> amFileData(remainWrite);
  875. int retVal = Z_OK;
  876. while(remainRead && remainWrite && retVal != Z_STREAM_END)
  877. {
  878. Bytef buffer[mpt::IO::BUFFERSIZE_TINY];
  879. uint32 readSize = std::min(static_cast<uint32>(sizeof(buffer)), remainRead);
  880. file.ReadRaw(mpt::span(buffer, readSize));
  881. crc = crc32(crc, buffer, readSize);
  882. strm.avail_in = readSize;
  883. strm.next_in = buffer;
  884. do
  885. {
  886. strm.avail_out = remainWrite;
  887. strm.next_out = amFileData.data() + totalWritten;
  888. retVal = inflate(&strm, Z_NO_FLUSH);
  889. uint32 written = remainWrite - strm.avail_out;
  890. totalWritten += written;
  891. remainWrite -= written;
  892. } while(remainWrite && strm.avail_out == 0);
  893. remainRead -= readSize;
  894. }
  895. inflateEnd(&strm);
  896. bool result = false;
  897. #ifndef MPT_BUILD_FUZZER
  898. if(fileHeader.crc32 == crc && !remainWrite && retVal == Z_STREAM_END)
  899. #endif
  900. {
  901. // Success, now load the RIFF AM(FF) module.
  902. FileReader amFile(mpt::as_span(amFileData));
  903. result = ReadAM(amFile, loadFlags);
  904. }
  905. return result;
  906. #endif
  907. }
  908. OPENMPT_NAMESPACE_END