1
0

Load_gdm.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. * Load_gdm.cpp
  3. * ------------
  4. * Purpose: GDM (BWSB Soundsystem) module loader
  5. * Notes : This code is partly based on zilym's original code / specs (which are utterly wrong :P).
  6. * Thanks to the MenTaLguY for gdm.txt and ajs for gdm2s3m and some hints.
  7. *
  8. * Hint 1: Most (all?) of the unsupported features were not supported in 2GDM / BWSB either.
  9. * Hint 2: Files will be played like their original formats would be played in MPT, so no
  10. * BWSB quirks including crashes and freezes are supported. :-P
  11. * Authors: Johannes Schultz
  12. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  13. */
  14. #include "stdafx.h"
  15. #include "Loaders.h"
  16. #include "mod_specifications.h"
  17. OPENMPT_NAMESPACE_BEGIN
  18. // GDM File Header
  19. struct GDMFileHeader
  20. {
  21. char magic[4]; // ID: 'GDM\xFE'
  22. char songTitle[32]; // Music's title
  23. char songMusician[32]; // Name of music's composer
  24. char dosEOF[3]; // 13, 10, 26
  25. char magic2[4]; // ID: 'GMFS'
  26. uint8le formatMajorVer; // Format major version
  27. uint8le formatMinorVer; // Format minor version
  28. uint16le trackerID; // Composing Tracker ID code (00 = 2GDM)
  29. uint8le trackerMajorVer; // Tracker's major version
  30. uint8le trackerMinorVer; // Tracker's minor version
  31. uint8le panMap[32]; // 0-Left to 15-Right, 255-N/U
  32. uint8le masterVol; // Range: 0...64
  33. uint8le tempo; // Initial music tempo (6)
  34. uint8le bpm; // Initial music BPM (125)
  35. uint16le originalFormat; // Original format ID:
  36. // 1-MOD, 2-MTM, 3-S3M, 4-669, 5-FAR, 6-ULT, 7-STM, 8-MED, 9-PSM
  37. // (versions of 2GDM prior to v1.15 won't set this correctly)
  38. // 2GDM v1.17 will only spit out 0-byte files when trying to convert a PSM16 file,
  39. // and fail outright when trying to convert a new PSM file.
  40. uint32le orderOffset;
  41. uint8le lastOrder; // Number of orders in module - 1
  42. uint32le patternOffset;
  43. uint8le lastPattern; // Number of patterns in module - 1
  44. uint32le sampleHeaderOffset;
  45. uint32le sampleDataOffset;
  46. uint8le lastSample; // Number of samples in module - 1
  47. uint32le messageTextOffset; // Offset of song message
  48. uint32le messageTextLength;
  49. uint32le scrollyScriptOffset; // Offset of scrolly script (huh?)
  50. uint16le scrollyScriptLength;
  51. uint32le textGraphicOffset; // Offset of text graphic (huh?)
  52. uint16le textGraphicLength;
  53. };
  54. MPT_BINARY_STRUCT(GDMFileHeader, 157)
  55. // GDM Sample Header
  56. struct GDMSampleHeader
  57. {
  58. enum SampleFlags
  59. {
  60. smpLoop = 0x01,
  61. smp16Bit = 0x02, // 16-Bit samples are not handled correctly by 2GDM (not implemented)
  62. smpVolume = 0x04, // Use default volume
  63. smpPanning = 0x08,
  64. smpLZW = 0x10, // LZW-compressed samples are not implemented in 2GDM
  65. smpStereo = 0x20, // Stereo samples are not handled correctly by 2GDM (not implemented)
  66. };
  67. char name[32]; // sample's name
  68. char fileName[12]; // sample's filename
  69. uint8le emsHandle; // useless
  70. uint32le length; // length in bytes
  71. uint32le loopBegin; // loop start in samples
  72. uint32le loopEnd; // loop end in samples
  73. uint8le flags; // see SampleFlags
  74. uint16le c4Hertz; // frequency
  75. uint8le volume; // default volume
  76. uint8le panning; // default pan
  77. };
  78. MPT_BINARY_STRUCT(GDMSampleHeader, 62)
  79. static constexpr MODTYPE gdmFormatOrigin[] =
  80. {
  81. MOD_TYPE_NONE, MOD_TYPE_MOD, MOD_TYPE_MTM, MOD_TYPE_S3M, MOD_TYPE_669, MOD_TYPE_FAR, MOD_TYPE_ULT, MOD_TYPE_STM, MOD_TYPE_MED, MOD_TYPE_PSM
  82. };
  83. static constexpr mpt::uchar gdmFormatOriginType[][4] =
  84. {
  85. UL_(""), UL_("mod"), UL_("mtm"), UL_("s3m"), UL_("669"), UL_("far"), UL_("ult"), UL_("stm"), UL_("med"), UL_("psm")
  86. };
  87. static constexpr const mpt::uchar * gdmFormatOriginFormat[] =
  88. {
  89. UL_(""),
  90. UL_("Generic MOD"),
  91. UL_("MultiTracker"),
  92. UL_("Scream Tracker 3"),
  93. UL_("Composer 669 / UNIS 669"),
  94. UL_("Farandole Composer"),
  95. UL_("UltraTracker"),
  96. UL_("Scream Tracker 2"),
  97. UL_("OctaMED"),
  98. UL_("Epic Megagames MASI")
  99. };
  100. static bool ValidateHeader(const GDMFileHeader &fileHeader)
  101. {
  102. if(std::memcmp(fileHeader.magic, "GDM\xFE", 4)
  103. || fileHeader.dosEOF[0] != 13 || fileHeader.dosEOF[1] != 10 || fileHeader.dosEOF[2] != 26
  104. || std::memcmp(fileHeader.magic2, "GMFS", 4)
  105. || fileHeader.formatMajorVer != 1 || fileHeader.formatMinorVer != 0
  106. || fileHeader.originalFormat >= std::size(gdmFormatOrigin)
  107. || fileHeader.originalFormat == 0)
  108. {
  109. return false;
  110. }
  111. return true;
  112. }
  113. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize)
  114. {
  115. GDMFileHeader fileHeader;
  116. if(!file.ReadStruct(fileHeader))
  117. {
  118. return ProbeWantMoreData;
  119. }
  120. if(!ValidateHeader(fileHeader))
  121. {
  122. return ProbeFailure;
  123. }
  124. MPT_UNREFERENCED_PARAMETER(pfilesize);
  125. return ProbeSuccess;
  126. }
  127. bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
  128. {
  129. file.Rewind();
  130. GDMFileHeader fileHeader;
  131. if(!file.ReadStruct(fileHeader))
  132. {
  133. return false;
  134. }
  135. if(!ValidateHeader(fileHeader))
  136. {
  137. return false;
  138. }
  139. if(loadFlags == onlyVerifyHeader)
  140. {
  141. return true;
  142. }
  143. InitializeGlobals(gdmFormatOrigin[fileHeader.originalFormat]);
  144. m_SongFlags.set(SONG_IMPORTED);
  145. m_modFormat.formatName = U_("General Digital Music");
  146. m_modFormat.type = U_("gdm");
  147. m_modFormat.madeWithTracker = MPT_UFORMAT("BWSB 2GDM {}.{}")(fileHeader.trackerMajorVer, fileHeader.formatMinorVer);
  148. m_modFormat.originalType = gdmFormatOriginType[fileHeader.originalFormat];
  149. m_modFormat.originalFormatName = gdmFormatOriginFormat[fileHeader.originalFormat];
  150. m_modFormat.charset = mpt::Charset::CP437;
  151. // Song name
  152. m_songName = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songTitle);
  153. // Artist name
  154. {
  155. std::string artist = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, fileHeader.songMusician);
  156. if(artist != "Unknown")
  157. {
  158. m_songArtist = mpt::ToUnicode(mpt::Charset::CP437, artist);
  159. }
  160. }
  161. // Read channel pan map... 0...15 = channel panning, 16 = surround channel, 255 = channel does not exist
  162. m_nChannels = 32;
  163. for(CHANNELINDEX i = 0; i < 32; i++)
  164. {
  165. ChnSettings[i].Reset();
  166. if(fileHeader.panMap[i] < 16)
  167. {
  168. ChnSettings[i].nPan = static_cast<uint16>(std::min((fileHeader.panMap[i] * 16) + 8, 256));
  169. } else if(fileHeader.panMap[i] == 16)
  170. {
  171. ChnSettings[i].nPan = 128;
  172. ChnSettings[i].dwFlags = CHN_SURROUND;
  173. } else if(fileHeader.panMap[i] == 0xFF)
  174. {
  175. m_nChannels = i;
  176. break;
  177. }
  178. }
  179. if(m_nChannels < 1)
  180. {
  181. return false;
  182. }
  183. m_nDefaultGlobalVolume = std::min(fileHeader.masterVol * 4u, 256u);
  184. m_nDefaultSpeed = fileHeader.tempo;
  185. m_nDefaultTempo.Set(fileHeader.bpm);
  186. // Read orders
  187. if(file.Seek(fileHeader.orderOffset))
  188. {
  189. ReadOrderFromFile<uint8>(Order(), file, fileHeader.lastOrder + 1, 0xFF, 0xFE);
  190. }
  191. // Read samples
  192. if(!file.Seek(fileHeader.sampleHeaderOffset))
  193. {
  194. return false;
  195. }
  196. m_nSamples = fileHeader.lastSample + 1;
  197. // Sample headers
  198. for(SAMPLEINDEX smp = 1; smp <= m_nSamples; smp++)
  199. {
  200. GDMSampleHeader gdmSample;
  201. if(!file.ReadStruct(gdmSample))
  202. {
  203. break;
  204. }
  205. ModSample &sample = Samples[smp];
  206. sample.Initialize();
  207. m_szNames[smp] = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, gdmSample.name);
  208. sample.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, gdmSample.fileName);
  209. sample.nC5Speed = gdmSample.c4Hertz;
  210. if(UseFinetuneAndTranspose())
  211. {
  212. // Use the same inaccurate table as 2GDM for translating back to finetune, as our own routines
  213. // give slightly different results for the provided sample rates that may result in transpose != 0.
  214. static constexpr uint16 rate2finetune[] = { 8363, 8424, 8485, 8547, 8608, 8671, 8734, 8797, 7894, 7951, 8009, 8067, 8125, 8184, 8244, 8303 };
  215. for(uint8 i = 0; i < 16; i++)
  216. {
  217. if(sample.nC5Speed == rate2finetune[i])
  218. {
  219. sample.nFineTune = MOD2XMFineTune(i);
  220. break;
  221. }
  222. }
  223. }
  224. sample.nGlobalVol = 64; // Not supported in this format
  225. sample.nLength = gdmSample.length; // in bytes
  226. // Sample format
  227. if(gdmSample.flags & GDMSampleHeader::smp16Bit)
  228. {
  229. sample.uFlags.set(CHN_16BIT);
  230. sample.nLength /= 2;
  231. }
  232. sample.nLoopStart = gdmSample.loopBegin;
  233. sample.nLoopEnd = gdmSample.loopEnd - 1;
  234. if(gdmSample.flags & GDMSampleHeader::smpLoop)
  235. sample.uFlags.set(CHN_LOOP);
  236. if((gdmSample.flags & GDMSampleHeader::smpVolume) && gdmSample.volume != 0xFF)
  237. sample.nVolume = std::min(static_cast<uint8>(gdmSample.volume), uint8(64)) * 4;
  238. else
  239. sample.uFlags.set(SMP_NODEFAULTVOLUME);
  240. if(gdmSample.flags & GDMSampleHeader::smpPanning)
  241. {
  242. // Default panning is used
  243. sample.uFlags.set(CHN_PANNING);
  244. // 0...15, 16 = surround (not supported), 255 = no default panning
  245. sample.nPan = static_cast<uint16>((gdmSample.panning > 15) ? 128 : std::min((gdmSample.panning * 16) + 8, 256));
  246. sample.uFlags.set(CHN_SURROUND, gdmSample.panning == 16);
  247. } else
  248. {
  249. sample.nPan = 128;
  250. }
  251. }
  252. // Read sample data
  253. if((loadFlags & loadSampleData) && file.Seek(fileHeader.sampleDataOffset))
  254. {
  255. for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
  256. {
  257. SampleIO(
  258. Samples[smp].uFlags[CHN_16BIT] ? SampleIO::_16bit : SampleIO::_8bit,
  259. SampleIO::mono,
  260. SampleIO::littleEndian,
  261. SampleIO::unsignedPCM)
  262. .ReadSample(Samples[smp], file);
  263. }
  264. }
  265. // Read patterns
  266. Patterns.ResizeArray(fileHeader.lastPattern + 1);
  267. const CModSpecifications &modSpecs = GetModSpecifications(GetBestSaveFormat());
  268. bool onlyAmigaNotes = true;
  269. // We'll start at position patternsOffset and decode all patterns
  270. file.Seek(fileHeader.patternOffset);
  271. for(PATTERNINDEX pat = 0; pat <= fileHeader.lastPattern; pat++)
  272. {
  273. // Read pattern length *including* the two "length" bytes
  274. uint16 patternLength = file.ReadUint16LE();
  275. if(patternLength <= 2)
  276. {
  277. // Huh, no pattern data present?
  278. continue;
  279. }
  280. FileReader chunk = file.ReadChunk(patternLength - 2);
  281. if(!(loadFlags & loadPatternData) || !chunk.IsValid() || !Patterns.Insert(pat, 64))
  282. {
  283. continue;
  284. }
  285. enum
  286. {
  287. rowDone = 0x00, // Advance to next row
  288. channelMask = 0x1F, // Mask for retrieving channel information
  289. noteFlag = 0x20, // Note / instrument information present
  290. effectFlag = 0x40, // Effect information present
  291. effectMask = 0x1F, // Mask for retrieving effect command
  292. effectMore = 0x20, // Another effect follows
  293. };
  294. for(ROWINDEX row = 0; row < 64; row++)
  295. {
  296. PatternRow rowBase = Patterns[pat].GetRow(row);
  297. uint8 channelByte;
  298. // If channel byte is zero, advance to next row.
  299. while((channelByte = chunk.ReadUint8()) != rowDone)
  300. {
  301. CHANNELINDEX channel = channelByte & channelMask;
  302. if(channel >= m_nChannels) break; // Better safe than sorry!
  303. ModCommand &m = rowBase[channel];
  304. if(channelByte & noteFlag)
  305. {
  306. // Note and sample follows
  307. auto [note, instr] = chunk.ReadArray<uint8, 2>();
  308. if(note)
  309. {
  310. note = (note & 0x7F) - 1; // High bit = no-retrig flag (notes with portamento have this set)
  311. m.note = (note & 0x0F) + 12 * (note >> 4) + 12 + NOTE_MIN;
  312. if(!m.IsAmigaNote())
  313. {
  314. onlyAmigaNotes = false;
  315. }
  316. }
  317. m.instr = instr;
  318. }
  319. if(channelByte & effectFlag)
  320. {
  321. // Effect(s) follow(s)
  322. m.command = CMD_NONE;
  323. m.volcmd = VOLCMD_NONE;
  324. while(chunk.CanRead(2))
  325. {
  326. // We may want to restore the old command in some cases.
  327. const ModCommand oldCmd = m;
  328. const auto [effByte, param] = chunk.ReadArray<uint8, 2>();
  329. m.param = param;
  330. // Effect translation LUT
  331. static constexpr EffectCommand gdmEffTrans[] =
  332. {
  333. CMD_NONE, CMD_PORTAMENTOUP, CMD_PORTAMENTODOWN, CMD_TONEPORTAMENTO,
  334. CMD_VIBRATO, CMD_TONEPORTAVOL, CMD_VIBRATOVOL, CMD_TREMOLO,
  335. CMD_TREMOR, CMD_OFFSET, CMD_VOLUMESLIDE, CMD_POSITIONJUMP,
  336. CMD_VOLUME, CMD_PATTERNBREAK, CMD_MODCMDEX, CMD_SPEED,
  337. CMD_ARPEGGIO, CMD_NONE /* set internal flag */, CMD_RETRIG, CMD_GLOBALVOLUME,
  338. CMD_FINEVIBRATO, CMD_NONE, CMD_NONE, CMD_NONE,
  339. CMD_NONE, CMD_NONE, CMD_NONE, CMD_NONE,
  340. CMD_NONE, CMD_NONE, CMD_S3MCMDEX, CMD_TEMPO,
  341. };
  342. // Translate effect
  343. uint8 command = effByte & effectMask;
  344. if(command < std::size(gdmEffTrans))
  345. m.command = gdmEffTrans[command];
  346. else
  347. m.command = CMD_NONE;
  348. // Fix some effects
  349. switch(m.command)
  350. {
  351. case CMD_PORTAMENTOUP:
  352. case CMD_PORTAMENTODOWN:
  353. if(m.param >= 0xE0 && m_nType != MOD_TYPE_MOD)
  354. m.param = 0xDF; // Don't spill into fine slide territory
  355. break;
  356. case CMD_TONEPORTAVOL:
  357. case CMD_VIBRATOVOL:
  358. if(m.param & 0xF0)
  359. m.param &= 0xF0;
  360. break;
  361. case CMD_VOLUME:
  362. m.param = std::min(m.param, uint8(64));
  363. if(modSpecs.HasVolCommand(VOLCMD_VOLUME))
  364. {
  365. m.volcmd = VOLCMD_VOLUME;
  366. m.vol = m.param;
  367. // Don't destroy old command, if there was one.
  368. m.command = oldCmd.command;
  369. m.param = oldCmd.param;
  370. }
  371. break;
  372. case CMD_MODCMDEX:
  373. switch(m.param >> 4)
  374. {
  375. case 0x8:
  376. m.command = CMD_PORTAMENTOUP;
  377. m.param = 0xE0 | (m.param & 0x0F);
  378. break;
  379. case 0x9:
  380. m.command = CMD_PORTAMENTODOWN;
  381. m.param = 0xE0 | (m.param & 0x0F);
  382. break;
  383. default:
  384. if(!modSpecs.HasCommand(CMD_MODCMDEX))
  385. m.ExtendedMODtoS3MEffect();
  386. break;
  387. }
  388. break;
  389. case CMD_RETRIG:
  390. if(!modSpecs.HasCommand(CMD_RETRIG) && modSpecs.HasCommand(CMD_MODCMDEX))
  391. {
  392. // Retrig in "MOD style"
  393. m.command = CMD_MODCMDEX;
  394. m.param = 0x90 | (m.param & 0x0F);
  395. }
  396. break;
  397. case CMD_S3MCMDEX:
  398. // Some really special commands
  399. if(m.param == 0x01)
  400. {
  401. // Surround (implemented in 2GDM but not in BWSB itself)
  402. m.param = 0x91;
  403. } else if((m.param & 0xF0) == 0x80)
  404. {
  405. // 4-Bit Panning
  406. if (!modSpecs.HasCommand(CMD_S3MCMDEX))
  407. m.command = CMD_MODCMDEX;
  408. } else
  409. {
  410. // All other effects are implemented neither in 2GDM nor in BWSB.
  411. m.command = CMD_NONE;
  412. }
  413. break;
  414. }
  415. // Move pannings to volume column - should never happen
  416. if(m.command == CMD_S3MCMDEX && ((m.param >> 4) == 0x8) && m.volcmd == VOLCMD_NONE)
  417. {
  418. m.volcmd = VOLCMD_PANNING;
  419. m.vol = ((m.param & 0x0F) * 64 + 8) / 15;
  420. m.command = oldCmd.command;
  421. m.param = oldCmd.param;
  422. }
  423. if(!(effByte & effectMore))
  424. break;
  425. }
  426. }
  427. }
  428. }
  429. }
  430. m_SongFlags.set(SONG_AMIGALIMITS | SONG_ISAMIGA, GetType() == MOD_TYPE_MOD && GetNumChannels() == 4 && onlyAmigaNotes);
  431. // Read song comments
  432. if(fileHeader.messageTextLength > 0 && file.Seek(fileHeader.messageTextOffset))
  433. {
  434. m_songMessage.Read(file, fileHeader.messageTextLength, SongMessage::leAutodetect);
  435. }
  436. return true;
  437. }
  438. OPENMPT_NAMESPACE_END