1
0

pattern.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /*
  2. * Pattern.cpp
  3. * -----------
  4. * Purpose: Module Pattern header class
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "pattern.h"
  11. #include "patternContainer.h"
  12. #include "../common/serialization_utils.h"
  13. #include "../common/version.h"
  14. #include "ITTools.h"
  15. #include "Sndfile.h"
  16. #include "mod_specifications.h"
  17. #include "mpt/io/io.hpp"
  18. #include "mpt/io/io_stdstream.hpp"
  19. OPENMPT_NAMESPACE_BEGIN
  20. CSoundFile& CPattern::GetSoundFile() { return m_rPatternContainer.GetSoundFile(); }
  21. const CSoundFile& CPattern::GetSoundFile() const { return m_rPatternContainer.GetSoundFile(); }
  22. CHANNELINDEX CPattern::GetNumChannels() const
  23. {
  24. return GetSoundFile().GetNumChannels();
  25. }
  26. // Check if there is any note data on a given row.
  27. bool CPattern::IsEmptyRow(ROWINDEX row) const
  28. {
  29. if(m_ModCommands.empty() || !IsValidRow(row))
  30. {
  31. return true;
  32. }
  33. PatternRow data = GetRow(row);
  34. for(CHANNELINDEX chn = 0; chn < GetNumChannels(); chn++, data++)
  35. {
  36. if(!data->IsEmpty())
  37. {
  38. return false;
  39. }
  40. }
  41. return true;
  42. }
  43. bool CPattern::SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure)
  44. {
  45. if(rowsPerBeat < 1
  46. || rowsPerBeat > GetSoundFile().GetModSpecifications().patternRowsMax
  47. || rowsPerMeasure < rowsPerBeat
  48. || rowsPerMeasure > GetSoundFile().GetModSpecifications().patternRowsMax)
  49. {
  50. return false;
  51. }
  52. m_RowsPerBeat = rowsPerBeat;
  53. m_RowsPerMeasure = rowsPerMeasure;
  54. return true;
  55. }
  56. // Add or remove rows from the pattern.
  57. bool CPattern::Resize(const ROWINDEX newRowCount, bool enforceFormatLimits, bool resizeAtEnd)
  58. {
  59. CSoundFile &sndFile = GetSoundFile();
  60. if(newRowCount == m_Rows || newRowCount < 1 || newRowCount > MAX_PATTERN_ROWS)
  61. {
  62. return false;
  63. }
  64. if(enforceFormatLimits)
  65. {
  66. auto &specs = sndFile.GetModSpecifications();
  67. if(newRowCount > specs.patternRowsMax || newRowCount < specs.patternRowsMin) return false;
  68. }
  69. try
  70. {
  71. size_t count = ((newRowCount > m_Rows) ? (newRowCount - m_Rows) : (m_Rows - newRowCount)) * GetNumChannels();
  72. if(newRowCount > m_Rows)
  73. m_ModCommands.insert(resizeAtEnd ? m_ModCommands.end() : m_ModCommands.begin(), count, ModCommand::Empty());
  74. else if(resizeAtEnd)
  75. m_ModCommands.erase(m_ModCommands.end() - count, m_ModCommands.end());
  76. else
  77. m_ModCommands.erase(m_ModCommands.begin(), m_ModCommands.begin() + count);
  78. } catch(mpt::out_of_memory e)
  79. {
  80. mpt::delete_out_of_memory(e);
  81. return false;
  82. }
  83. m_Rows = newRowCount;
  84. return true;
  85. }
  86. void CPattern::ClearCommands()
  87. {
  88. std::fill(m_ModCommands.begin(), m_ModCommands.end(), ModCommand::Empty());
  89. }
  90. bool CPattern::AllocatePattern(ROWINDEX rows)
  91. {
  92. size_t newSize = GetNumChannels() * rows;
  93. if(rows == 0)
  94. {
  95. return false;
  96. } else if(rows == GetNumRows() && m_ModCommands.size() == newSize)
  97. {
  98. // Re-use allocated memory
  99. ClearCommands();
  100. return true;
  101. } else
  102. {
  103. // Do this in two steps in order to keep the old pattern data in case of OOM
  104. decltype(m_ModCommands) newPattern(newSize, ModCommand::Empty());
  105. m_ModCommands = std::move(newPattern);
  106. }
  107. m_Rows = rows;
  108. return true;
  109. }
  110. void CPattern::Deallocate()
  111. {
  112. m_Rows = m_RowsPerBeat = m_RowsPerMeasure = 0;
  113. m_ModCommands.clear();
  114. m_PatternName.clear();
  115. }
  116. CPattern& CPattern::operator= (const CPattern &pat)
  117. {
  118. m_ModCommands = pat.m_ModCommands;
  119. m_Rows = pat.m_Rows;
  120. m_RowsPerBeat = pat.m_RowsPerBeat;
  121. m_RowsPerMeasure = pat.m_RowsPerMeasure;
  122. m_tempoSwing = pat.m_tempoSwing;
  123. m_PatternName = pat.m_PatternName;
  124. return *this;
  125. }
  126. bool CPattern::operator== (const CPattern &other) const
  127. {
  128. return GetNumRows() == other.GetNumRows()
  129. && GetNumChannels() == other.GetNumChannels()
  130. && GetOverrideSignature() == other.GetOverrideSignature()
  131. && GetRowsPerBeat() == other.GetRowsPerBeat()
  132. && GetRowsPerMeasure() == other.GetRowsPerMeasure()
  133. && GetTempoSwing() == other.GetTempoSwing()
  134. && m_ModCommands == other.m_ModCommands;
  135. }
  136. #ifdef MODPLUG_TRACKER
  137. bool CPattern::Expand()
  138. {
  139. const ROWINDEX newRows = m_Rows * 2;
  140. const CHANNELINDEX nChns = GetNumChannels();
  141. if(m_ModCommands.empty()
  142. || newRows > GetSoundFile().GetModSpecifications().patternRowsMax)
  143. {
  144. return false;
  145. }
  146. decltype(m_ModCommands) newPattern;
  147. try
  148. {
  149. newPattern.assign(m_ModCommands.size() * 2, ModCommand::Empty());
  150. } catch(mpt::out_of_memory e)
  151. {
  152. mpt::delete_out_of_memory(e);
  153. return false;
  154. }
  155. for(auto mSrc = m_ModCommands.begin(), mDst = newPattern.begin(); mSrc != m_ModCommands.end(); mSrc += nChns, mDst += 2 * nChns)
  156. {
  157. std::copy(mSrc, mSrc + nChns, mDst);
  158. }
  159. m_ModCommands = std::move(newPattern);
  160. m_Rows = newRows;
  161. return true;
  162. }
  163. bool CPattern::Shrink()
  164. {
  165. if (m_ModCommands.empty()
  166. || m_Rows < GetSoundFile().GetModSpecifications().patternRowsMin * 2)
  167. {
  168. return false;
  169. }
  170. m_Rows /= 2;
  171. const CHANNELINDEX nChns = GetNumChannels();
  172. for(ROWINDEX y = 0; y < m_Rows; y++)
  173. {
  174. const PatternRow srcRow = GetRow(y * 2);
  175. const PatternRow nextSrcRow = GetRow(y * 2 + 1);
  176. PatternRow destRow = GetRow(y);
  177. for(CHANNELINDEX x = 0; x < nChns; x++)
  178. {
  179. const ModCommand &src = srcRow[x];
  180. const ModCommand &srcNext = nextSrcRow[x];
  181. ModCommand &dest = destRow[x];
  182. dest = src;
  183. if(dest.note == NOTE_NONE && !dest.instr)
  184. {
  185. // Fill in data from next row if field is empty
  186. dest.note = srcNext.note;
  187. dest.instr = srcNext.instr;
  188. if(srcNext.volcmd != VOLCMD_NONE)
  189. {
  190. dest.volcmd = srcNext.volcmd;
  191. dest.vol = srcNext.vol;
  192. }
  193. if(dest.command == CMD_NONE)
  194. {
  195. dest.command = srcNext.command;
  196. dest.param = srcNext.param;
  197. }
  198. }
  199. }
  200. }
  201. m_ModCommands.resize(m_Rows * nChns);
  202. return true;
  203. }
  204. #endif // MODPLUG_TRACKER
  205. bool CPattern::SetName(const std::string &newName)
  206. {
  207. m_PatternName = newName;
  208. return true;
  209. }
  210. bool CPattern::SetName(const char *newName, size_t maxChars)
  211. {
  212. if(newName == nullptr || maxChars == 0)
  213. {
  214. return false;
  215. }
  216. const auto nameEnd = std::find(newName, newName + maxChars, '\0');
  217. m_PatternName.assign(newName, nameEnd);
  218. return true;
  219. }
  220. // Write some kind of effect data to the pattern. Exact data to be written and write behaviour can be found in the EffectWriter object.
  221. bool CPattern::WriteEffect(EffectWriter &settings)
  222. {
  223. // First, reject invalid parameters.
  224. if(m_ModCommands.empty()
  225. || settings.m_row >= GetNumRows()
  226. || (settings.m_channel >= GetNumChannels() && settings.m_channel != CHANNELINDEX_INVALID))
  227. {
  228. return false;
  229. }
  230. CHANNELINDEX scanChnMin = settings.m_channel, scanChnMax = settings.m_channel;
  231. // Scan all channels
  232. if(settings.m_channel == CHANNELINDEX_INVALID)
  233. {
  234. scanChnMin = 0;
  235. scanChnMax = GetNumChannels() - 1;
  236. }
  237. ModCommand * const baseCommand = GetpModCommand(settings.m_row, scanChnMin);
  238. ModCommand *m;
  239. // Scan channel(s) for same effect type - if an effect of the same type is already present, exit.
  240. if(!settings.m_allowMultiple)
  241. {
  242. m = baseCommand;
  243. for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++)
  244. {
  245. if(!settings.m_isVolEffect && m->command == settings.m_command)
  246. return true;
  247. if(settings.m_isVolEffect && m->volcmd == settings.m_volcmd)
  248. return true;
  249. }
  250. }
  251. // Easy case: check if there's some space left to put the effect somewhere
  252. m = baseCommand;
  253. for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++)
  254. {
  255. if(!settings.m_isVolEffect && m->command == CMD_NONE)
  256. {
  257. m->command = settings.m_command;
  258. m->param = settings.m_param;
  259. return true;
  260. }
  261. if(settings.m_isVolEffect && m->volcmd == VOLCMD_NONE)
  262. {
  263. m->volcmd = settings.m_volcmd;
  264. m->vol = settings.m_vol;
  265. return true;
  266. }
  267. }
  268. // Ok, apparently there's no space. If we haven't tried already, try to map it to the volume column or effect column instead.
  269. if(settings.m_retry)
  270. {
  271. const bool isS3M = (GetSoundFile().GetType() & MOD_TYPE_S3M);
  272. // Move some effects that also work in the volume column, so there's place for our new effect.
  273. if(!settings.m_isVolEffect)
  274. {
  275. m = baseCommand;
  276. for(CHANNELINDEX i = scanChnMin; i <= scanChnMax; i++, m++)
  277. {
  278. switch(m->command)
  279. {
  280. case CMD_VOLUME:
  281. if(!GetSoundFile().GetModSpecifications().HasVolCommand(VOLCMD_VOLUME))
  282. {
  283. break;
  284. }
  285. m->volcmd = VOLCMD_VOLUME;
  286. m->vol = m->param;
  287. m->command = settings.m_command;
  288. m->param = settings.m_param;
  289. return true;
  290. case CMD_PANNING8:
  291. if(isS3M && m->param > 0x80)
  292. {
  293. break;
  294. }
  295. m->volcmd = VOLCMD_PANNING;
  296. m->command = settings.m_command;
  297. if(isS3M)
  298. m->vol = (m->param + 1u) / 2u;
  299. else
  300. m->vol = (m->param + 2u) / 4u;
  301. m->param = settings.m_param;
  302. return true;
  303. default:
  304. break;
  305. }
  306. }
  307. }
  308. // Let's try it again by writing into the "other" effect column.
  309. if(settings.m_isVolEffect)
  310. {
  311. // Convert volume effect to normal effect
  312. ModCommand::COMMAND newCommand = CMD_NONE;
  313. ModCommand::PARAM newParam = settings.m_vol;
  314. switch(settings.m_volcmd)
  315. {
  316. case VOLCMD_PANNING:
  317. newCommand = CMD_PANNING8;
  318. newParam = mpt::saturate_cast<ModCommand::PARAM>(settings.m_vol * (isS3M ? 2u : 4u));
  319. break;
  320. case VOLCMD_VOLUME:
  321. newCommand = CMD_VOLUME;
  322. break;
  323. default:
  324. break;
  325. }
  326. if(newCommand != CMD_NONE)
  327. {
  328. settings.m_command = static_cast<EffectCommand>(newCommand);
  329. settings.m_param = newParam;
  330. settings.m_retry = false;
  331. }
  332. } else
  333. {
  334. // Convert normal effect to volume effect
  335. ModCommand::VOLCMD newVolCmd = VOLCMD_NONE;
  336. ModCommand::VOL newVol = settings.m_param;
  337. if(settings.m_command == CMD_PANNING8 && isS3M)
  338. {
  339. // This needs some manual fixing.
  340. if(settings.m_param <= 0x80)
  341. {
  342. // Can't have surround in volume column, only normal panning
  343. newVolCmd = VOLCMD_PANNING;
  344. newVol /= 2u;
  345. }
  346. } else
  347. {
  348. newVolCmd = settings.m_command;
  349. if(!ModCommand::ConvertVolEffect(newVolCmd, newVol, true))
  350. {
  351. // No Success :(
  352. newVolCmd = VOLCMD_NONE;
  353. }
  354. }
  355. if(newVolCmd != CMD_NONE)
  356. {
  357. settings.m_volcmd = static_cast<VolumeCommand>(newVolCmd);
  358. settings.m_vol = newVol;
  359. settings.m_retry = false;
  360. }
  361. }
  362. if(!settings.m_retry)
  363. {
  364. settings.m_isVolEffect = !settings.m_isVolEffect;
  365. if(WriteEffect(settings))
  366. {
  367. return true;
  368. }
  369. }
  370. }
  371. // Try in the next row if possible (this may also happen if we already retried)
  372. if(settings.m_retryMode == EffectWriter::rmTryNextRow && settings.m_row + 1 < GetNumRows())
  373. {
  374. settings.m_row++;
  375. settings.m_retry = true;
  376. return WriteEffect(settings);
  377. } else if(settings.m_retryMode == EffectWriter::rmTryPreviousRow && settings.m_row > 0)
  378. {
  379. settings.m_row--;
  380. settings.m_retry = true;
  381. return WriteEffect(settings);
  382. }
  383. return false;
  384. }
  385. ////////////////////////////////////////////////////////////////////////
  386. //
  387. // Pattern serialization functions
  388. //
  389. ////////////////////////////////////////////////////////////////////////
  390. enum maskbits
  391. {
  392. noteBit = (1 << 0),
  393. instrBit = (1 << 1),
  394. volcmdBit = (1 << 2),
  395. volBit = (1 << 3),
  396. commandBit = (1 << 4),
  397. effectParamBit = (1 << 5),
  398. extraData = (1 << 6)
  399. };
  400. void WriteData(std::ostream& oStrm, const CPattern& pat);
  401. void ReadData(std::istream& iStrm, CPattern& pat, const size_t nSize = 0);
  402. void WriteModPattern(std::ostream& oStrm, const CPattern& pat)
  403. {
  404. srlztn::SsbWrite ssb(oStrm);
  405. ssb.BeginWrite(FileIdPattern, Version::Current().GetRawVersion());
  406. ssb.WriteItem(pat, "data", &WriteData);
  407. // pattern time signature
  408. if(pat.GetOverrideSignature())
  409. {
  410. ssb.WriteItem<uint32>(pat.GetRowsPerBeat(), "RPB.");
  411. ssb.WriteItem<uint32>(pat.GetRowsPerMeasure(), "RPM.");
  412. }
  413. if(pat.HasTempoSwing())
  414. {
  415. ssb.WriteItem<TempoSwing>(pat.GetTempoSwing(), "SWNG", TempoSwing::Serialize);
  416. }
  417. ssb.FinishWrite();
  418. }
  419. void ReadModPattern(std::istream& iStrm, CPattern& pat, const size_t)
  420. {
  421. srlztn::SsbRead ssb(iStrm);
  422. ssb.BeginRead(FileIdPattern, Version::Current().GetRawVersion());
  423. if ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0)
  424. return;
  425. ssb.ReadItem(pat, "data", &ReadData);
  426. // pattern time signature
  427. uint32 rpb = 0, rpm = 0;
  428. ssb.ReadItem<uint32>(rpb, "RPB.");
  429. ssb.ReadItem<uint32>(rpm, "RPM.");
  430. pat.SetSignature(rpb, rpm);
  431. TempoSwing swing;
  432. ssb.ReadItem<TempoSwing>(swing, "SWNG", TempoSwing::Deserialize);
  433. if(!swing.empty())
  434. swing.resize(pat.GetRowsPerBeat());
  435. pat.SetTempoSwing(swing);
  436. }
  437. static uint8 CreateDiffMask(const ModCommand &chnMC, const ModCommand &newMC)
  438. {
  439. uint8 mask = 0;
  440. if(chnMC.note != newMC.note)
  441. mask |= noteBit;
  442. if(chnMC.instr != newMC.instr)
  443. mask |= instrBit;
  444. if(chnMC.volcmd != newMC.volcmd)
  445. mask |= volcmdBit;
  446. if(chnMC.vol != newMC.vol)
  447. mask |= volBit;
  448. if(chnMC.command != newMC.command)
  449. mask |= commandBit;
  450. if(chnMC.param != newMC.param)
  451. mask |= effectParamBit;
  452. return mask;
  453. }
  454. // Writes pattern data. Adapted from SaveIT.
  455. void WriteData(std::ostream& oStrm, const CPattern& pat)
  456. {
  457. if(!pat.IsValid())
  458. return;
  459. const ROWINDEX rows = pat.GetNumRows();
  460. const CHANNELINDEX chns = pat.GetNumChannels();
  461. std::vector<ModCommand> lastChnMC(chns);
  462. for(ROWINDEX r = 0; r<rows; r++)
  463. {
  464. for(CHANNELINDEX c = 0; c<chns; c++)
  465. {
  466. const ModCommand m = *pat.GetpModCommand(r, c);
  467. // Writing only commands not written in IT-pattern writing:
  468. // For now this means only NOTE_PC and NOTE_PCS.
  469. if(!m.IsPcNote())
  470. continue;
  471. uint8 diffmask = CreateDiffMask(lastChnMC[c], m);
  472. uint8 chval = static_cast<uint8>(c+1);
  473. if(diffmask != 0)
  474. chval |= IT_bitmask_patternChanEnabled_c;
  475. mpt::IO::WriteIntLE<uint8>(oStrm, chval);
  476. if(diffmask)
  477. {
  478. lastChnMC[c] = m;
  479. mpt::IO::WriteIntLE<uint8>(oStrm, diffmask);
  480. if(diffmask & noteBit) mpt::IO::WriteIntLE<uint8>(oStrm, m.note);
  481. if(diffmask & instrBit) mpt::IO::WriteIntLE<uint8>(oStrm, m.instr);
  482. if(diffmask & volcmdBit) mpt::IO::WriteIntLE<uint8>(oStrm, m.volcmd);
  483. if(diffmask & volBit) mpt::IO::WriteIntLE<uint8>(oStrm, m.vol);
  484. if(diffmask & commandBit) mpt::IO::WriteIntLE<uint8>(oStrm, m.command);
  485. if(diffmask & effectParamBit) mpt::IO::WriteIntLE<uint8>(oStrm, m.param);
  486. }
  487. }
  488. mpt::IO::WriteIntLE<uint8>(oStrm, 0); // Write end of row marker.
  489. }
  490. }
  491. #define READITEM(itembit,id) \
  492. if(diffmask & itembit) \
  493. { \
  494. mpt::IO::ReadIntLE<uint8>(iStrm, temp); \
  495. if(ch < chns) \
  496. lastChnMC[ch].id = temp; \
  497. } \
  498. if(ch < chns) \
  499. m.id = lastChnMC[ch].id;
  500. void ReadData(std::istream& iStrm, CPattern& pat, const size_t)
  501. {
  502. if (!pat.IsValid()) // Expecting patterns to be allocated and resized properly.
  503. return;
  504. const CHANNELINDEX chns = pat.GetNumChannels();
  505. const ROWINDEX rows = pat.GetNumRows();
  506. std::vector<ModCommand> lastChnMC(chns);
  507. ROWINDEX row = 0;
  508. while(row < rows && iStrm.good())
  509. {
  510. uint8 t = 0;
  511. mpt::IO::ReadIntLE<uint8>(iStrm, t);
  512. if(t == 0)
  513. {
  514. row++;
  515. continue;
  516. }
  517. CHANNELINDEX ch = (t & IT_bitmask_patternChanField_c);
  518. if(ch > 0)
  519. ch--;
  520. uint8 diffmask = 0;
  521. if((t & IT_bitmask_patternChanEnabled_c) != 0)
  522. mpt::IO::ReadIntLE<uint8>(iStrm, diffmask);
  523. uint8 temp = 0;
  524. ModCommand dummy = ModCommand::Empty();
  525. ModCommand& m = (ch < chns) ? *pat.GetpModCommand(row, ch) : dummy;
  526. READITEM(noteBit, note);
  527. READITEM(instrBit, instr);
  528. READITEM(volcmdBit, volcmd);
  529. READITEM(volBit, vol);
  530. READITEM(commandBit, command);
  531. READITEM(effectParamBit, param);
  532. if(diffmask & extraData)
  533. {
  534. //Ignore additional data.
  535. uint8 size;
  536. mpt::IO::ReadIntLE<uint8>(iStrm, size);
  537. iStrm.ignore(size);
  538. }
  539. }
  540. }
  541. #undef READITEM
  542. OPENMPT_NAMESPACE_END