1
0

Load_symmod.cpp 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947
  1. /*
  2. * Load_symmod.cpp
  3. * ---------------
  4. * Purpose: SymMOD (Symphonie / Symphonie Pro) module loader
  5. * Notes : Based in part on Patrick Meng's Java-based Symphonie player and its source.
  6. * Some effect behaviour and other things are based on the original Amiga assembly source.
  7. * Symphonie is an interesting beast, with a surprising combination of features and lack thereof.
  8. * It offers advanced DSPs (for its time) but has a fixed track tempo. It can handle stereo samples
  9. * but free panning support was only added in one of the very last versions. Still, a good number
  10. * of high-quality modules were made with it despite (or because of) its lack of features.
  11. * Authors: Devin Acker
  12. * OpenMPT Devs
  13. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  14. */
  15. #include "stdafx.h"
  16. #include "Loaders.h"
  17. #include "Mixer.h"
  18. #include "MixFuncTable.h"
  19. #include "modsmp_ctrl.h"
  20. #include "openmpt/soundbase/SampleConvert.hpp"
  21. #include "openmpt/soundbase/SampleConvertFixedPoint.hpp"
  22. #include "openmpt/soundbase/SampleDecode.hpp"
  23. #include "SampleCopy.h"
  24. #ifdef MPT_EXTERNAL_SAMPLES
  25. #include "../common/mptPathString.h"
  26. #endif // MPT_EXTERNAL_SAMPLES
  27. #include "mpt/base/numbers.hpp"
  28. #include <map>
  29. OPENMPT_NAMESPACE_BEGIN
  30. struct SymFileHeader
  31. {
  32. char magic[4]; // "SymM"
  33. uint32be version;
  34. bool Validate() const
  35. {
  36. return !std::memcmp(magic, "SymM", 4) && version == 1;
  37. }
  38. };
  39. MPT_BINARY_STRUCT(SymFileHeader, 8)
  40. struct SymEvent
  41. {
  42. enum Command : uint8
  43. {
  44. KeyOn = 0,
  45. VolSlideUp,
  46. VolSlideDown,
  47. PitchSlideUp,
  48. PitchSlideDown,
  49. ReplayFrom,
  50. FromAndPitch,
  51. SetFromAdd,
  52. FromAdd,
  53. SetSpeed,
  54. AddPitch,
  55. AddVolume,
  56. Tremolo,
  57. Vibrato,
  58. SampleVib,
  59. PitchSlideTo,
  60. Retrig,
  61. Emphasis,
  62. AddHalfTone,
  63. CV,
  64. CVAdd,
  65. Filter = 23,
  66. DSPEcho,
  67. DSPDelay,
  68. };
  69. enum Volume : uint8
  70. {
  71. VolCommand = 200,
  72. StopSample = 254,
  73. ContSample = 253,
  74. StartSample = 252, // unused
  75. KeyOff = 251,
  76. SpeedDown = 250,
  77. SpeedUp = 249,
  78. SetPitch = 248,
  79. PitchUp = 247,
  80. PitchDown = 246,
  81. PitchUp2 = 245,
  82. PitchDown2 = 244,
  83. PitchUp3 = 243,
  84. PitchDown3 = 242
  85. };
  86. uint8be command; // See Command enum
  87. int8be note;
  88. uint8be param; // Volume if <= 100, see Volume enum otherwise
  89. uint8be inst;
  90. bool IsGlobal() const
  91. {
  92. if(command == SymEvent::SetSpeed || command == SymEvent::DSPEcho || command == SymEvent::DSPDelay)
  93. return true;
  94. if(command == SymEvent::KeyOn && (param == SymEvent::SpeedUp || param == SymEvent::SpeedDown))
  95. return true;
  96. return false;
  97. }
  98. // used to compare DSP events for mapping them to MIDI macro numbers
  99. bool operator<(const SymEvent &other) const
  100. {
  101. return std::tie(command, note, param, inst) < std::tie(other.command, other.note, other.param, other.inst);
  102. }
  103. };
  104. MPT_BINARY_STRUCT(SymEvent, 4)
  105. struct SymVirtualHeader
  106. {
  107. char id[4]; // "ViRT"
  108. uint8be zero;
  109. uint8be filler1;
  110. uint16be version; // 0 = regular, 1 = transwave
  111. uint16be mixInfo; // unused, but not 0 in all modules
  112. uint16be filler2;
  113. uint16be eos; // 0
  114. uint16be numEvents;
  115. uint16be maxEvents; // always 20
  116. uint16be eventSize; // 4 for virtual instruments, 10 for transwave instruments (number of cycles, not used)
  117. bool IsValid() const
  118. {
  119. return !memcmp(id, "ViRT", 4) && zero == 0 && version <= 1 && eos == 0 && maxEvents == 20;
  120. }
  121. bool IsVirtual() const
  122. {
  123. return IsValid() && version == 0 && numEvents <= 20 && eventSize == sizeof(SymEvent);
  124. }
  125. bool IsTranswave() const
  126. {
  127. return IsValid() && version == 1 && numEvents == 2 && eventSize == 10;
  128. }
  129. };
  130. MPT_BINARY_STRUCT(SymVirtualHeader, 20)
  131. // Virtual instrument info
  132. // This allows instruments to be created based on a mix of other instruments.
  133. // The sample mixing is done at load time.
  134. struct SymVirtualInst
  135. {
  136. SymVirtualHeader header;
  137. SymEvent noteEvents[20];
  138. char padding[28];
  139. bool Render(CSoundFile &sndFile, const bool asQueue, ModSample &target, uint16 sampleBoost) const
  140. {
  141. if(header.numEvents < 1 || header.numEvents > std::size(noteEvents) || noteEvents[0].inst >= sndFile.GetNumSamples())
  142. return false;
  143. target.Initialize(MOD_TYPE_IT);
  144. target.uFlags = CHN_16BIT;
  145. const auto events = mpt::as_span(noteEvents).subspan(0, header.numEvents);
  146. const double rateFactor = 1.0 / std::max(sndFile.GetSample(events[0].inst + 1).nC5Speed, uint32(1));
  147. for(const auto &event : events.subspan(0, asQueue ? events.size() : 1u))
  148. {
  149. if(event.inst >= sndFile.GetNumSamples() || event.note < 0)
  150. continue;
  151. const ModSample &sourceSmp = sndFile.GetSample(event.inst + 1);
  152. const double length = sourceSmp.nLength * std::pow(2.0, (event.note - events[0].note) / -12.0) * sourceSmp.nC5Speed * rateFactor;
  153. target.nLength += mpt::saturate_round<SmpLength>(length);
  154. }
  155. if(!target.AllocateSample())
  156. return false;
  157. std::vector<ModChannel> channels(events.size());
  158. SmpLength lastSampleOffset = 0;
  159. for(size_t ev = 0; ev < events.size(); ev++)
  160. {
  161. const SymEvent &event = events[ev];
  162. ModChannel &chn = channels[ev];
  163. if(event.inst >= sndFile.GetNumSamples() || event.note < 0)
  164. continue;
  165. int8 finetune = 0;
  166. if(event.param >= SymEvent::PitchDown3 && event.param <= SymEvent::PitchUp)
  167. {
  168. static constexpr int8 PitchTable[] = {-4, 4, -2, 2, -1, 1};
  169. static_assert(mpt::array_size<decltype(PitchTable)>::size == SymEvent::PitchUp - SymEvent::PitchDown3 + 1);
  170. finetune = PitchTable[event.param - SymEvent::PitchDown3];
  171. }
  172. const ModSample &sourceSmp = sndFile.GetSample(event.inst + 1);
  173. const double increment = std::pow(2.0, (event.note - events[0].note) / 12.0 + finetune / 96.0) * sourceSmp.nC5Speed * rateFactor;
  174. if(increment <= 0)
  175. continue;
  176. chn.increment = SamplePosition::FromDouble(increment);
  177. chn.pCurrentSample = sourceSmp.samplev();
  178. chn.nLength = sourceSmp.nLength;
  179. chn.dwFlags = sourceSmp.uFlags & CHN_SAMPLEFLAGS;
  180. if(asQueue)
  181. {
  182. // This determines when the queued sample will be played
  183. chn.oldOffset = lastSampleOffset;
  184. lastSampleOffset += mpt::saturate_round<SmpLength>(chn.nLength / chn.increment.ToDouble());
  185. }
  186. int32 volume = 4096 * sampleBoost / 10000; // avoid clipping the filters if the virtual sample is later also filtered (see e.g. 303 emulator.symmod)
  187. if(!asQueue)
  188. volume /= header.numEvents;
  189. chn.leftVol = chn.rightVol = volume;
  190. }
  191. SmpLength writeOffset = 0;
  192. while(writeOffset < target.nLength)
  193. {
  194. std::array<mixsample_t, MIXBUFFERSIZE * 2> buffer{};
  195. const SmpLength writeCount = std::min(static_cast<SmpLength>(MIXBUFFERSIZE), target.nLength - writeOffset);
  196. for(auto &chn : channels)
  197. {
  198. if(!chn.pCurrentSample)
  199. continue;
  200. // Should queued sample be played yet?
  201. if(chn.oldOffset >= writeCount)
  202. {
  203. chn.oldOffset -= writeCount;
  204. continue;
  205. }
  206. uint32 functionNdx = MixFuncTable::ndxLinear;
  207. if(chn.dwFlags[CHN_16BIT])
  208. functionNdx |= MixFuncTable::ndx16Bit;
  209. if(chn.dwFlags[CHN_STEREO])
  210. functionNdx |= MixFuncTable::ndxStereo;
  211. const SmpLength procCount = std::min(writeCount - chn.oldOffset, mpt::saturate_round<SmpLength>((chn.nLength - chn.position.ToDouble()) / chn.increment.ToDouble()));
  212. MixFuncTable::Functions[functionNdx](chn, sndFile.m_Resampler, buffer.data() + chn.oldOffset * 2, procCount);
  213. chn.oldOffset = 0;
  214. if(chn.position.GetUInt() >= chn.nLength)
  215. chn.pCurrentSample = nullptr;
  216. }
  217. CopySample<SC::ConversionChain<SC::ConvertFixedPoint<int16, mixsample_t, 27>, SC::DecodeIdentity<mixsample_t>>>(target.sample16() + writeOffset, writeCount, 1, buffer.data(), sizeof(buffer), 2);
  218. writeOffset += writeCount;
  219. }
  220. return true;
  221. }
  222. };
  223. MPT_BINARY_STRUCT(SymVirtualInst, 128)
  224. // Transwave instrument info
  225. // Similar to virtual instruments, allows blending between two sample loops
  226. struct SymTranswaveInst
  227. {
  228. struct Transwave
  229. {
  230. uint16be sourceIns;
  231. uint16be volume; // According to source label - but appears to be unused
  232. uint32be loopStart;
  233. uint32be loopLen;
  234. uint32be padding;
  235. std::pair<SmpLength, SmpLength> ConvertLoop(const ModSample &mptSmp) const
  236. {
  237. const double loopScale = static_cast<double>(mptSmp.nLength) / (100 << 16);
  238. const SmpLength start = mpt::saturate_cast<SmpLength>(loopScale * std::min(uint32(100 << 16), loopStart.get()));
  239. const SmpLength length = mpt::saturate_cast<SmpLength>(loopScale * std::min(uint32(100 << 16), loopLen.get()));
  240. return {start, std::min(mptSmp.nLength - start, length)};
  241. }
  242. };
  243. SymVirtualHeader header;
  244. Transwave points[2];
  245. char padding[76];
  246. // Morph between two sample loops
  247. bool Render(const ModSample &smp1, const ModSample &smp2, ModSample &target) const
  248. {
  249. target.Initialize(MOD_TYPE_IT);
  250. const auto [loop1Start, loop1Len] = points[0].ConvertLoop(smp1);
  251. const auto [loop2Start, loop2Len] = points[1].ConvertLoop(smp2);
  252. if(loop1Len < 1 || loop1Len > MAX_SAMPLE_LENGTH / (4u * 80u))
  253. return false;
  254. const SmpLength cycleLength = loop1Len * 4u;
  255. const double cycleFactor1 = loop1Len / static_cast<double>(cycleLength);
  256. const double cycleFactor2 = loop2Len / static_cast<double>(cycleLength);
  257. target.uFlags = CHN_16BIT;
  258. target.nLength = cycleLength * 80u;
  259. if(!target.AllocateSample())
  260. return false;
  261. const double ampFactor = 1.0 / target.nLength;
  262. for(SmpLength i = 0; i < cycleLength; i++)
  263. {
  264. const double v1 = TranswaveInterpolate(smp1, loop1Start + i * cycleFactor1);
  265. const double v2 = TranswaveInterpolate(smp2, loop2Start + i * cycleFactor2);
  266. SmpLength writeOffset = i;
  267. for(int cycle = 0; cycle < 80; cycle++, writeOffset += cycleLength)
  268. {
  269. const double amp = writeOffset * ampFactor;
  270. target.sample16()[writeOffset] = mpt::saturate_round<int16>(v1 * (1.0 - amp) + v2 * amp);
  271. }
  272. }
  273. return true;
  274. }
  275. static MPT_FORCEINLINE double TranswaveInterpolate(const ModSample &smp, double offset)
  276. {
  277. if(!smp.HasSampleData())
  278. return 0.0;
  279. SmpLength intOffset = static_cast<SmpLength>(offset);
  280. const double fractOffset = offset - intOffset;
  281. const uint8 numChannels = smp.GetNumChannels();
  282. intOffset *= numChannels;
  283. int16 v1, v2;
  284. if(smp.uFlags[CHN_16BIT])
  285. {
  286. v1 = smp.sample16()[intOffset];
  287. v2 = smp.sample16()[intOffset + numChannels];
  288. } else
  289. {
  290. v1 = smp.sample8()[intOffset] * 256;
  291. v2 = smp.sample8()[intOffset + numChannels] * 256;
  292. }
  293. return (v1 * (1.0 - fractOffset) + v2 * fractOffset);
  294. }
  295. };
  296. MPT_BINARY_STRUCT(SymTranswaveInst, 128)
  297. // Instrument definition
  298. struct SymInstrument
  299. {
  300. using SymInstrumentName = std::array<char, 128>;
  301. SymVirtualInst virt; // or SymInstrumentName, or SymTranswaveInst
  302. enum Type : int8
  303. {
  304. Silent = -8,
  305. Kill = -4,
  306. Normal = 0,
  307. Loop = 4,
  308. Sustain = 8
  309. };
  310. enum Channel : uint8
  311. {
  312. Mono,
  313. StereoL,
  314. StereoR,
  315. LineSrc // virtual mix instrument
  316. };
  317. enum SampleFlags : uint8
  318. {
  319. PlayReverse = 1, // reverse sample
  320. AsQueue = 2, // "queue" virtual instrument (rendereds samples one after another rather than simultaneously)
  321. MirrorX = 4, // invert sample phase
  322. Is16Bit = 8, // not used, we already know the bit depth of the samples
  323. NewLoopSystem = 16, // use fine loop start/len values
  324. MakeNewSample = (PlayReverse | MirrorX)
  325. };
  326. enum InstFlags : uint8
  327. {
  328. NoTranspose = 1, // don't apply sequence/position transpose
  329. NoDSP = 2, // don't apply DSP effects
  330. SyncPlay = 4 // play a stereo instrument pair (or two copies of the same mono instrument) on consecutive channels
  331. };
  332. int8be type; // see Type enum
  333. uint8be loopStartHigh;
  334. uint8be loopLenHigh;
  335. uint8be numRepetitions; // for "sustain" instruments
  336. uint8be channel; // see Channel enum
  337. uint8be dummy1; // called "automaximize" (normalize?) in Amiga source, but unused
  338. uint8be volume; // 0-199
  339. uint8be dummy2[3]; // info about "parent/child" and sample format
  340. int8be finetune; // -128..127 ~= 2 semitones
  341. int8be transpose;
  342. uint8be sampleFlags; // see SampleFlags enum
  343. int8be filter; // negative: highpass, positive: lowpass
  344. uint8be instFlags; // see InstFlags enum
  345. uint8be downsample; // downsample factor; affects sample tuning
  346. uint8be dummy3[2]; // resonance, "loadflags" (both unused)
  347. uint8be info; // bit 0 should indicate that rangeStart/rangeLen are valid, but they appear to be unused
  348. uint8be rangeStart; // ditto
  349. uint8be rangeLen; // ditto
  350. uint8be dummy4;
  351. uint16be loopStartFine;
  352. uint16be loopLenFine;
  353. uint8be dummy5[6];
  354. uint8be filterFlags; // bit 0 = enable, bit 1 = highpass
  355. uint8be numFilterPoints; // # of filter envelope points (up to 4, possibly only 1-2 ever actually used)
  356. struct SymFilterSetting
  357. {
  358. uint8be cutoff;
  359. uint8be resonance;
  360. } filterPoint[4];
  361. uint8be volFadeFlag;
  362. uint8be volFadeFrom;
  363. uint8be volFadeTo;
  364. uint8be padding[83];
  365. bool IsVirtual() const
  366. {
  367. return virt.header.IsValid();
  368. }
  369. // Valid instrument either is virtual or has a name
  370. bool IsEmpty() const
  371. {
  372. return virt.header.id[0] == 0 || type < 0;
  373. }
  374. std::string GetName() const
  375. {
  376. return mpt::String::ReadBuf(mpt::String::maybeNullTerminated, mpt::bit_cast<SymInstrumentName>(virt));
  377. }
  378. SymTranswaveInst GetTranswave() const
  379. {
  380. return mpt::bit_cast<SymTranswaveInst>(virt);
  381. }
  382. void ConvertToMPT(ModInstrument &mptIns, ModSample &mptSmp, CSoundFile &sndFile) const
  383. {
  384. if(!IsVirtual())
  385. mptIns.name = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, mpt::bit_cast<SymInstrumentName>(virt));
  386. mptSmp.uFlags.reset(CHN_LOOP | CHN_PINGPONGLOOP | CHN_SUSTAINLOOP | CHN_PANNING); // Avoid these coming in from sample files
  387. const auto [loopStart, loopLen] = GetSampleLoop(mptSmp);
  388. if(type == Loop && loopLen > 0)
  389. {
  390. mptSmp.uFlags.set(CHN_LOOP);
  391. mptSmp.nLoopStart = loopStart;
  392. mptSmp.nLoopEnd = loopStart + loopLen;
  393. }
  394. // volume (0-199, default 100)
  395. // Symphonie actually compresses the sample data if the volume is above 100 (see end of function)
  396. // We spread the volume between sample and instrument global volume if it's below 100 for the best possible resolution.
  397. // This can be simplified if instrument volume ever gets adjusted to 0...128 range like in IT.
  398. uint8 effectiveVolume = (volume > 0 && volume < 200) ? static_cast<uint8>(std::min(volume.get(), uint8(100)) * 128u / 100) : 128;
  399. mptSmp.nGlobalVol = std::max(effectiveVolume, uint8(64)) / 2u;
  400. mptIns.nGlobalVol = std::min(effectiveVolume, uint8(64));
  401. // Tuning info (we'll let our own mixer take care of the downsampling instead of doing it at load time)
  402. mptSmp.nC5Speed = 40460;
  403. mptSmp.Transpose(-downsample + (transpose / 12.0) + (finetune / (128.0 * 12.0)));
  404. // DSP settings
  405. mptIns.nMixPlug = (instFlags & NoDSP) ? 2 : 1;
  406. if(instFlags & NoDSP)
  407. {
  408. // This is not 100% correct: An instrument playing after this one should pick up previous filter settings.
  409. mptIns.SetCutoff(127, true);
  410. mptIns.SetResonance(0, true);
  411. }
  412. // Various sample processing follows
  413. if(!mptSmp.HasSampleData())
  414. return;
  415. if(sampleFlags & PlayReverse)
  416. ctrlSmp::ReverseSample(mptSmp, 0, 0, sndFile);
  417. if(sampleFlags & MirrorX)
  418. ctrlSmp::InvertSample(mptSmp, 0, 0, sndFile);
  419. // Always use 16-bit data to help with heavily filtered 8-bit samples (like in Future_Dream.SymMOD)
  420. const bool doVolFade = (volFadeFlag == 2) && (volFadeFrom <= 100) && (volFadeTo <= 100);
  421. if(!mptSmp.uFlags[CHN_16BIT] && (filterFlags || doVolFade || filter))
  422. {
  423. int16 *newSample = static_cast<int16 *>(ModSample::AllocateSample(mptSmp.nLength, 2 * mptSmp.GetNumChannels()));
  424. if(!newSample)
  425. return;
  426. CopySample<SC::ConversionChain<SC::Convert<int16, int8>, SC::DecodeIdentity<int8>>>(newSample, mptSmp.nLength * mptSmp.GetNumChannels(), 1, mptSmp.sample8(), mptSmp.GetSampleSizeInBytes(), 1);
  427. mptSmp.uFlags.set(CHN_16BIT);
  428. ctrlSmp::ReplaceSample(mptSmp, newSample, mptSmp.nLength, sndFile);
  429. }
  430. // Highpass
  431. if(filter < 0)
  432. {
  433. auto sampleData = mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels());
  434. for(int i = 0; i < -filter; i++)
  435. {
  436. int32 mix = sampleData[0];
  437. for(auto &sample : sampleData)
  438. {
  439. mix = mpt::rshift_signed(sample - mpt::rshift_signed(mix, 1), 1);
  440. sample = static_cast<int16>(mix);
  441. }
  442. }
  443. }
  444. // Volume Fade
  445. if(doVolFade)
  446. {
  447. auto sampleData = mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels());
  448. int32 amp = volFadeFrom << 24, inc = Util::muldivr(volFadeTo - volFadeFrom, 1 << 24, static_cast<SmpLength>(sampleData.size()));
  449. for(auto &sample : sampleData)
  450. {
  451. sample = static_cast<int16>(Util::muldivr(sample, amp, 100 << 24));
  452. amp += inc;
  453. }
  454. }
  455. // Resonant Filter Sweep
  456. if(filterFlags != 0)
  457. {
  458. auto sampleData = mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels());
  459. int32 cutoff = filterPoint[0].cutoff << 23, resonance = filterPoint[0].resonance << 23;
  460. const int32 cutoffStep = numFilterPoints > 1 ? Util::muldivr(filterPoint[1].cutoff - filterPoint[0].cutoff, 1 << 23, static_cast<SmpLength>(sampleData.size())) : 0;
  461. const int32 resoStep = numFilterPoints > 1 ? Util::muldivr(filterPoint[1].resonance - filterPoint[0].resonance, 1 << 23, static_cast<SmpLength>(sampleData.size())) : 0;
  462. const uint8 highpass = filterFlags & 2;
  463. int32 filterState[3]{};
  464. for(auto &sample : sampleData)
  465. {
  466. const int32 currentCutoff = cutoff / (1 << 23), currentReso = resonance / (1 << 23);
  467. cutoff += cutoffStep;
  468. resonance += resoStep;
  469. filterState[2] = mpt::rshift_signed(sample, 1) - filterState[0];
  470. filterState[1] += mpt::rshift_signed(currentCutoff * filterState[2], 8);
  471. filterState[0] += mpt::rshift_signed(currentCutoff * filterState[1], 6);
  472. filterState[0] += mpt::rshift_signed(currentReso * filterState[0], 6);
  473. filterState[0] = mpt::rshift_signed(filterState[0], 2);
  474. sample = mpt::saturate_cast<int16>(filterState[highpass]);
  475. }
  476. }
  477. // Lowpass
  478. if(filter > 0)
  479. {
  480. auto sampleData = mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels());
  481. for(int i = 0; i < filter; i++)
  482. {
  483. int32 mix = sampleData[0];
  484. for(auto &sample : sampleData)
  485. {
  486. mix = (sample + sample + mix) / 3;
  487. sample = static_cast<int16>(mix);
  488. }
  489. }
  490. }
  491. // Symphonie normalizes samples at load time (it normalizes them to the sample boost value - but we will use the full 16-bit range)
  492. // Indeed, the left and right channel instruments are normalized separately.
  493. const auto Normalize = [](auto sampleData)
  494. {
  495. const auto scale = Util::MaxValueOfType(sampleData[0]);
  496. const auto [minElem, maxElem] = std::minmax_element(sampleData.begin(), sampleData.end());
  497. const int max = std::max(-*minElem, +*maxElem);
  498. if(max >= scale || max == 0)
  499. return;
  500. for(auto &v : sampleData)
  501. {
  502. v = static_cast<typename std::remove_reference<decltype(v)>::type>(static_cast<int>(v) * scale / max);
  503. }
  504. };
  505. if(mptSmp.uFlags[CHN_16BIT])
  506. Normalize(mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels()));
  507. else
  508. Normalize(mpt::as_span(mptSmp.sample8(), mptSmp.nLength * mptSmp.GetNumChannels()));
  509. // "Non-destructive" over-amplification with hard knee compression
  510. if(volume > 100 && volume < 200)
  511. {
  512. const auto Amplify = [](auto sampleData, const uint8 gain)
  513. {
  514. const int32 knee = 16384 * (200 - gain) / 100, kneeInv = 32768 - knee;
  515. constexpr int32 scale = 1 << (16 - (sizeof(sampleData[0]) * 8));
  516. for(auto &sample : sampleData)
  517. {
  518. int32 v = sample * scale;
  519. if(v > knee)
  520. v = (v - knee) * knee / kneeInv + kneeInv;
  521. else if(v < -knee)
  522. v = (v + knee) * knee / kneeInv - kneeInv;
  523. else
  524. v = v * kneeInv / knee;
  525. sample = mpt::saturate_cast<typename std::remove_reference<decltype(sample)>::type>(v / scale);
  526. }
  527. };
  528. const auto length = mptSmp.nLength * mptSmp.GetNumChannels();
  529. if(mptSmp.uFlags[CHN_16BIT])
  530. Amplify(mpt::span(mptSmp.sample16(), mptSmp.sample16() + length), volume);
  531. else
  532. Amplify(mpt::span(mptSmp.sample8(), mptSmp.sample8() + length), volume);
  533. }
  534. // This must be applied last because some sample processors are time-dependent and Symphonie would be doing this during playback instead
  535. mptSmp.RemoveAllCuePoints();
  536. if(type == Sustain && numRepetitions > 0 && loopLen > 0)
  537. {
  538. mptSmp.cues[0] = loopStart + loopLen * (numRepetitions + 1u);
  539. mptSmp.nSustainStart = loopStart; // This is of purely informative value and not used for playback
  540. mptSmp.nSustainEnd = loopStart + loopLen;
  541. if(MAX_SAMPLE_LENGTH / numRepetitions < loopLen)
  542. return;
  543. if(MAX_SAMPLE_LENGTH - numRepetitions * loopLen < mptSmp.nLength)
  544. return;
  545. const uint8 bps = mptSmp.GetBytesPerSample();
  546. SmpLength loopEnd = loopStart + loopLen * (numRepetitions + 1);
  547. SmpLength newLength = mptSmp.nLength + loopLen * numRepetitions;
  548. std::byte *newSample = static_cast<std::byte *>(ModSample::AllocateSample(newLength, bps));
  549. if(!newSample)
  550. return;
  551. mptSmp.nLength = newLength;
  552. std::memcpy(newSample, mptSmp.sampleb(), (loopStart + loopLen) * bps);
  553. for(uint8 i = 0; i < numRepetitions; i++)
  554. {
  555. std::memcpy(newSample + (loopStart + loopLen * (i + 1)) * bps, mptSmp.sampleb() + loopStart * bps, loopLen * bps);
  556. }
  557. std::memcpy(newSample + loopEnd * bps, mptSmp.sampleb() + (loopStart + loopLen) * bps, (newLength - loopEnd) * bps);
  558. ctrlSmp::ReplaceSample(mptSmp, newSample, mptSmp.nLength, sndFile);
  559. }
  560. }
  561. std::pair<SmpLength, SmpLength> GetSampleLoop(const ModSample &mptSmp) const
  562. {
  563. if(type != Loop && type != Sustain)
  564. return {0, 0};
  565. SmpLength loopStart = static_cast<SmpLength>(std::min(loopStartHigh.get(), uint8(100)));
  566. SmpLength loopLen = static_cast<SmpLength>(std::min(loopLenHigh.get(), uint8(100)));
  567. if(sampleFlags & NewLoopSystem)
  568. {
  569. loopStart = (loopStart << 16) + loopStartFine;
  570. loopLen = (loopLen << 16) + loopLenFine;
  571. const double loopScale = static_cast<double>(mptSmp.nLength) / (100 << 16);
  572. loopStart = mpt::saturate_cast<SmpLength>(loopStart * loopScale);
  573. loopLen = std::min(mptSmp.nLength - loopStart, mpt::saturate_cast<SmpLength>(loopLen * loopScale));
  574. } else if(mptSmp.HasSampleData())
  575. {
  576. // The order of operations here may seem weird as it reduces precision, but it's taken directly from the original assembly source (UpdateRecalcLoop)
  577. loopStart = ((loopStart << 7) / 100u) * (mptSmp.nLength >> 7);
  578. loopLen = std::min(mptSmp.nLength - loopStart, ((loopLen << 7) / 100u) * (mptSmp.nLength >> 7));
  579. const auto FindLoopEnd = [](auto sampleData, const uint8 numChannels, SmpLength loopStart, SmpLength loopLen, const int threshold)
  580. {
  581. const auto valAtStart = sampleData.data()[loopStart * numChannels];
  582. auto *endPtr = sampleData.data() + (loopStart + loopLen) * numChannels;
  583. while(loopLen)
  584. {
  585. if(std::abs(*endPtr - valAtStart) < threshold)
  586. return loopLen;
  587. endPtr -= numChannels;
  588. loopLen--;
  589. }
  590. return loopLen;
  591. };
  592. if(mptSmp.uFlags[CHN_16BIT])
  593. loopLen = FindLoopEnd(mpt::as_span(mptSmp.sample16(), mptSmp.nLength * mptSmp.GetNumChannels()), mptSmp.GetNumChannels(), loopStart, loopLen, 6 * 256);
  594. else
  595. loopLen = FindLoopEnd(mpt::as_span(mptSmp.sample8(), mptSmp.nLength * mptSmp.GetNumChannels()), mptSmp.GetNumChannels(), loopStart, loopLen, 6);
  596. }
  597. return {loopStart, loopLen};
  598. }
  599. };
  600. MPT_BINARY_STRUCT(SymInstrument, 256)
  601. struct SymSequence
  602. {
  603. uint16be start;
  604. uint16be length;
  605. uint16be loop;
  606. int16be info;
  607. int16be transpose;
  608. uint8be padding[6];
  609. };
  610. MPT_BINARY_STRUCT(SymSequence, 16)
  611. struct SymPosition
  612. {
  613. uint8be dummy[4];
  614. uint16be loopNum;
  615. uint16be loopCount; // Only used during playback
  616. uint16be pattern;
  617. uint16be start;
  618. uint16be length;
  619. uint16be speed;
  620. int16be transpose;
  621. uint16be eventsPerLine; // Unused
  622. uint8be padding[12];
  623. // Used to compare position entries for mapping them to OpenMPT patterns
  624. bool operator<(const SymPosition &other) const
  625. {
  626. return std::tie(pattern, start, length, transpose, speed) < std::tie(other.pattern, other.start, other.length, other.transpose, other.speed);
  627. }
  628. };
  629. MPT_BINARY_STRUCT(SymPosition, 32)
  630. static std::vector<std::byte> DecodeSymChunk(FileReader &file)
  631. {
  632. std::vector<std::byte> data;
  633. const uint32 packedLength = file.ReadUint32BE();
  634. if(!file.CanRead(packedLength))
  635. {
  636. file.Skip(file.BytesLeft());
  637. return data;
  638. }
  639. FileReader chunk = file.ReadChunk(packedLength);
  640. if(packedLength >= 10 && chunk.ReadMagic("PACK\xFF\xFF"))
  641. {
  642. // RLE-compressed chunk
  643. uint32 unpackedLength = chunk.ReadUint32BE();
  644. // The best compression ratio can be achieved with type 1, where six bytes turn into up to 255*4 bytes, a ratio of 1:170.
  645. uint32 maxLength = packedLength - 10;
  646. if(Util::MaxValueOfType(maxLength) / 170 >= maxLength)
  647. maxLength *= 170;
  648. else
  649. maxLength = Util::MaxValueOfType(maxLength);
  650. LimitMax(unpackedLength, maxLength);
  651. data.resize(unpackedLength);
  652. bool done = false;
  653. uint32 offset = 0, remain = unpackedLength;
  654. while(!done && !chunk.EndOfFile())
  655. {
  656. uint8 len;
  657. std::array<std::byte, 4> dword;
  658. const int8 type = chunk.ReadInt8();
  659. switch(type)
  660. {
  661. case 0:
  662. // Copy raw bytes
  663. len = chunk.ReadUint8();
  664. if(remain >= len && chunk.CanRead(len))
  665. {
  666. chunk.ReadRaw(mpt::as_span(data).subspan(offset, len));
  667. offset += len;
  668. remain -= len;
  669. } else
  670. {
  671. done = true;
  672. }
  673. break;
  674. case 1:
  675. // Copy a dword multiple times
  676. len = chunk.ReadUint8();
  677. if(remain >= (len * 4u) && chunk.ReadArray(dword))
  678. {
  679. remain -= len * 4u;
  680. while(len--)
  681. {
  682. std::copy(dword.begin(), dword.end(), data.begin() + offset);
  683. offset += 4;
  684. }
  685. } else
  686. {
  687. done = true;
  688. }
  689. break;
  690. case 2:
  691. // Copy a dword twice
  692. if(remain >= 8 && chunk.ReadArray(dword))
  693. {
  694. std::copy(dword.begin(), dword.end(), data.begin() + offset);
  695. std::copy(dword.begin(), dword.end(), data.begin() + offset + 4);
  696. offset += 8;
  697. remain -= 8;
  698. } else
  699. {
  700. done = true;
  701. }
  702. break;
  703. case 3:
  704. // Zero bytes
  705. len = chunk.ReadUint8();
  706. if(remain >= len)
  707. {
  708. // vector is already initialized to zero
  709. offset += len;
  710. remain -= len;
  711. } else
  712. {
  713. done = true;
  714. }
  715. break;
  716. case -1:
  717. done = true;
  718. break;
  719. default:
  720. // error
  721. done = true;
  722. break;
  723. }
  724. }
  725. #ifndef MPT_BUILD_FUZZER
  726. // When using a fuzzer, we should not care if the decompressed buffer has the correct size.
  727. // This makes finding new interesting test cases much easier.
  728. if(remain)
  729. std::vector<std::byte>{}.swap(data);
  730. #endif
  731. } else
  732. {
  733. // Uncompressed chunk
  734. chunk.ReadVector(data, packedLength);
  735. }
  736. return data;
  737. }
  738. template<typename T>
  739. static std::vector<T> DecodeSymArray(FileReader &file)
  740. {
  741. const auto data = DecodeSymChunk(file);
  742. FileReader chunk(mpt::as_span(data));
  743. std::vector<T> retVal;
  744. chunk.ReadVector(retVal, data.size() / sizeof(T));
  745. return retVal;
  746. }
  747. static bool ReadRawSymSample(ModSample &sample, FileReader &file)
  748. {
  749. SampleIO sampleIO(SampleIO::_16bit, SampleIO::mono, SampleIO::bigEndian, SampleIO::signedPCM);
  750. SmpLength nullBytes = 0;
  751. sample.Initialize();
  752. file.Rewind();
  753. if(file.ReadMagic("MAESTRO"))
  754. {
  755. file.Seek(12);
  756. if(file.ReadUint32BE() == 0)
  757. sampleIO |= SampleIO::stereoInterleaved;
  758. file.Seek(24);
  759. } else if(file.ReadMagic("16BT"))
  760. {
  761. file.Rewind();
  762. nullBytes = 4; // In Symphonie, the anti-click would take care of those...
  763. } else
  764. {
  765. sampleIO |= SampleIO::_8bit;
  766. }
  767. sample.nLength = mpt::saturate_cast<SmpLength>(file.BytesLeft() / (sampleIO.GetNumChannels() * sampleIO.GetBitDepth() / 8u));
  768. const bool ok = sampleIO.ReadSample(sample, file) > 0;
  769. if(ok && nullBytes)
  770. std::memset(sample.samplev(), 0, std::min(nullBytes, sample.GetSampleSizeInBytes()));
  771. return ok;
  772. }
  773. static std::vector<std::byte> DecodeSample8(FileReader &file)
  774. {
  775. auto data = DecodeSymChunk(file);
  776. uint8 lastVal = 0;
  777. for(auto &val : data)
  778. {
  779. lastVal += mpt::byte_cast<uint8>(val);
  780. val = mpt::byte_cast<std::byte>(lastVal);
  781. }
  782. return data;
  783. }
  784. static std::vector<std::byte> DecodeSample16(FileReader &file)
  785. {
  786. auto data = DecodeSymChunk(file);
  787. std::array<std::byte, 4096> buf;
  788. constexpr size_t blockSize = buf.size() / 2; // Size of block in 16-bit samples
  789. for(size_t block = 0; block < data.size() / buf.size(); block++)
  790. {
  791. const size_t offset = block * sizeof(buf);
  792. uint8 lastVal = 0;
  793. // Decode LSBs
  794. for(size_t i = 0; i < blockSize; i++)
  795. {
  796. lastVal += mpt::byte_cast<uint8>(data[offset + i]);
  797. buf[i * 2 + 1] = mpt::byte_cast<std::byte>(lastVal);
  798. }
  799. // Decode MSBs
  800. for(size_t i = 0; i < blockSize; i++)
  801. {
  802. lastVal += mpt::byte_cast<uint8>(data[offset + i + blockSize]);
  803. buf[i * 2] = mpt::byte_cast<std::byte>(lastVal);
  804. }
  805. std::copy(buf.begin(), buf.end(), data.begin() + offset);
  806. }
  807. return data;
  808. }
  809. static bool ConvertDSP(const SymEvent event, MIDIMacroConfigData::Macro &macro, const CSoundFile &sndFile)
  810. {
  811. if(event.command == SymEvent::Filter)
  812. {
  813. // Symphonie practically uses the same filter for this as for the sample processing.
  814. // The cutoff and resonance are an approximation.
  815. const uint8 type = event.note % 5u;
  816. const uint8 cutoff = sndFile.FrequencyToCutOff(event.param * 10000.0 / 240.0);
  817. const uint8 reso = static_cast<uint8>(std::min(127, event.inst * 127 / 185));
  818. if(type == 1) // lowpass filter
  819. macro = MPT_AFORMAT("F0F000{} F0F001{} F0F00200")(mpt::afmt::HEX0<2>(cutoff), mpt::afmt::HEX0<2>(reso));
  820. else if(type == 2) // highpass filter
  821. macro = MPT_AFORMAT("F0F000{} F0F001{} F0F00210")(mpt::afmt::HEX0<2>(cutoff), mpt::afmt::HEX0<2>(reso));
  822. else // no filter or unsupported filter type
  823. macro = "F0F0007F F0F00100";
  824. return true;
  825. } else if(event.command == SymEvent::DSPEcho)
  826. {
  827. const uint8 type = (event.note < 5) ? event.note : 0;
  828. const uint8 length = (event.param < 128) ? event.param : 127;
  829. const uint8 feedback = (event.inst < 128) ? event.inst : 127;
  830. macro = MPT_AFORMAT("F0F080{} F0F081{} F0F082{}")(mpt::afmt::HEX0<2>(type), mpt::afmt::HEX0<2>(length), mpt::afmt::HEX0<2>(feedback));
  831. return true;
  832. } else if(event.command == SymEvent::DSPDelay)
  833. {
  834. // DSP first has to be turned on from the Symphonie GUI before it can be used in a track (unlike Echo),
  835. // so it's not implemented for now.
  836. return false;
  837. }
  838. return false;
  839. }
  840. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderSymMOD(MemoryFileReader file, const uint64 *pfilesize)
  841. {
  842. MPT_UNREFERENCED_PARAMETER(pfilesize);
  843. SymFileHeader fileHeader;
  844. if(!file.ReadStruct(fileHeader))
  845. return ProbeWantMoreData;
  846. if(!fileHeader.Validate())
  847. return ProbeFailure;
  848. if(!file.CanRead(sizeof(uint32be)))
  849. return ProbeWantMoreData;
  850. if(file.ReadInt32BE() >= 0)
  851. return ProbeFailure;
  852. return ProbeSuccess;
  853. }
  854. bool CSoundFile::ReadSymMOD(FileReader &file, ModLoadingFlags loadFlags)
  855. {
  856. file.Rewind();
  857. SymFileHeader fileHeader;
  858. if(!file.ReadStruct(fileHeader) || !fileHeader.Validate())
  859. return false;
  860. if(file.ReadInt32BE() >= 0)
  861. return false;
  862. else if(loadFlags == onlyVerifyHeader)
  863. return true;
  864. InitializeGlobals(MOD_TYPE_MPT);
  865. m_SongFlags.set(SONG_LINEARSLIDES | SONG_EXFILTERRANGE | SONG_IMPORTED);
  866. m_playBehaviour = GetDefaultPlaybackBehaviour(MOD_TYPE_IT);
  867. m_playBehaviour.reset(kITShortSampleRetrig);
  868. enum class ChunkType : int32
  869. {
  870. NumChannels = -1,
  871. TrackLength = -2,
  872. PatternSize = -3,
  873. NumInstruments = -4,
  874. EventSize = -5,
  875. Tempo = -6,
  876. ExternalSamples = -7,
  877. PositionList = -10,
  878. SampleFile = -11,
  879. EmptySample = -12,
  880. PatternEvents = -13,
  881. InstrumentList = -14,
  882. Sequences = -15,
  883. InfoText = -16,
  884. SamplePacked = -17,
  885. SamplePacked16 = -18,
  886. InfoType = -19,
  887. InfoBinary = -20,
  888. InfoString = -21,
  889. SampleBoost = 10, // All samples will be normalized to this value
  890. StereoDetune = 11, // Note: Not affected by no-DSP flag in instrument! So this would need to have its own plugin...
  891. StereoPhase = 12,
  892. };
  893. uint32 trackLen = 0;
  894. uint16 sampleBoost = 2500;
  895. bool isSymphoniePro = false;
  896. bool externalSamples = false;
  897. std::vector<SymPosition> positions;
  898. std::vector<SymSequence> sequences;
  899. std::vector<SymEvent> patternData;
  900. std::vector<SymInstrument> instruments;
  901. file.SkipBack(sizeof(int32));
  902. while(file.CanRead(sizeof(int32)))
  903. {
  904. const ChunkType chunkType = static_cast<ChunkType>(file.ReadInt32BE());
  905. switch(chunkType)
  906. {
  907. // Simple values
  908. case ChunkType::NumChannels:
  909. if(auto numChannels = static_cast<CHANNELINDEX>(file.ReadUint32BE()); !m_nChannels && numChannels > 0 && numChannels <= MAX_BASECHANNELS)
  910. {
  911. m_nChannels = numChannels;
  912. m_nSamplePreAmp = Clamp(512 / m_nChannels, 16, 128);
  913. }
  914. break;
  915. case ChunkType::TrackLength:
  916. trackLen = file.ReadUint32BE();
  917. if(trackLen > 1024)
  918. return false;
  919. break;
  920. case ChunkType::EventSize:
  921. if(auto eventSize = (file.ReadUint32BE() & 0xFFFF); eventSize != sizeof(SymEvent))
  922. return false;
  923. break;
  924. case ChunkType::Tempo:
  925. m_nDefaultTempo = TEMPO(1.24 * std::min(file.ReadUint32BE(), uint32(800)));
  926. break;
  927. // Unused values
  928. case ChunkType::NumInstruments: // determined from # of instrument headers instead
  929. case ChunkType::PatternSize:
  930. file.Skip(4);
  931. break;
  932. case ChunkType::SampleBoost:
  933. sampleBoost = static_cast<uint16>(Clamp(file.ReadUint32BE(), 0u, 10000u));
  934. isSymphoniePro = true;
  935. break;
  936. case ChunkType::StereoDetune:
  937. case ChunkType::StereoPhase:
  938. isSymphoniePro = true;
  939. if(uint32 val = file.ReadUint32BE(); val != 0)
  940. AddToLog(LogWarning, U_("Stereo Detune / Stereo Phase is not supported"));
  941. break;
  942. case ChunkType::ExternalSamples:
  943. file.Skip(4);
  944. if(!m_nSamples)
  945. externalSamples = true;
  946. break;
  947. // Binary chunk types
  948. case ChunkType::PositionList:
  949. if((loadFlags & loadPatternData) && positions.empty())
  950. positions = DecodeSymArray<SymPosition>(file);
  951. else
  952. file.Skip(file.ReadUint32BE());
  953. break;
  954. case ChunkType::SampleFile:
  955. case ChunkType::SamplePacked:
  956. case ChunkType::SamplePacked16:
  957. if(m_nSamples >= instruments.size())
  958. break;
  959. if(!externalSamples && (loadFlags & loadSampleData) && CanAddMoreSamples())
  960. {
  961. const SAMPLEINDEX sample = ++m_nSamples;
  962. std::vector<std::byte> unpackedSample;
  963. FileReader chunk;
  964. if(chunkType == ChunkType::SampleFile)
  965. {
  966. chunk = file.ReadChunk(file.ReadUint32BE());
  967. } else if(chunkType == ChunkType::SamplePacked)
  968. {
  969. unpackedSample = DecodeSample8(file);
  970. chunk = FileReader(mpt::as_span(unpackedSample));
  971. } else // SamplePacked16
  972. {
  973. unpackedSample = DecodeSample16(file);
  974. chunk = FileReader(mpt::as_span(unpackedSample));
  975. }
  976. if(!ReadIFFSample(sample, chunk)
  977. && !ReadWAVSample(sample, chunk)
  978. && !ReadAIFFSample(sample, chunk)
  979. && !ReadRawSymSample(Samples[sample], chunk))
  980. {
  981. AddToLog(LogWarning, U_("Unknown sample format."));
  982. }
  983. // Symphonie represents stereo instruments as two consecutive mono instruments which are
  984. // automatically played at the same time. If this one uses a stereo sample, split it
  985. // and map two OpenMPT instruments to the stereo halves to ensure correct playback
  986. if(Samples[sample].uFlags[CHN_STEREO] && CanAddMoreSamples())
  987. {
  988. const SAMPLEINDEX sampleL = ++m_nSamples;
  989. ctrlSmp::SplitStereo(Samples[sample], Samples[sampleL], Samples[sample], *this);
  990. Samples[sampleL].filename = "Left";
  991. Samples[sample].filename = "Right";
  992. } else if(sample < instruments.size() && instruments[sample].channel == SymInstrument::StereoR && CanAddMoreSamples())
  993. {
  994. // Prevent misalignment of samples in exit.symmod (see condition in MoveNextMonoInstrument in Symphonie source)
  995. m_nSamples++;
  996. }
  997. } else
  998. {
  999. // Skip sample
  1000. file.Skip(file.ReadUint32BE());
  1001. }
  1002. break;
  1003. case ChunkType::EmptySample:
  1004. if(CanAddMoreSamples())
  1005. m_nSamples++;
  1006. break;
  1007. case ChunkType::PatternEvents:
  1008. if((loadFlags & loadPatternData) && patternData.empty())
  1009. patternData = DecodeSymArray<SymEvent>(file);
  1010. else
  1011. file.Skip(file.ReadUint32BE());
  1012. break;
  1013. case ChunkType::InstrumentList:
  1014. if(instruments.empty())
  1015. instruments = DecodeSymArray<SymInstrument>(file);
  1016. else
  1017. file.Skip(file.ReadUint32BE());
  1018. break;
  1019. case ChunkType::Sequences:
  1020. if((loadFlags & loadPatternData) && sequences.empty())
  1021. sequences = DecodeSymArray<SymSequence>(file);
  1022. else
  1023. file.Skip(file.ReadUint32BE());
  1024. break;
  1025. case ChunkType::InfoText:
  1026. if(const auto text = DecodeSymChunk(file); !text.empty())
  1027. m_songMessage.Read(text.data(), text.size(), SongMessage::leLF);
  1028. break;
  1029. // Unused binary chunks
  1030. case ChunkType::InfoType:
  1031. case ChunkType::InfoBinary:
  1032. case ChunkType::InfoString:
  1033. file.Skip(file.ReadUint32BE());
  1034. break;
  1035. // Unrecognized chunk/value type
  1036. default:
  1037. return false;
  1038. }
  1039. }
  1040. if(!m_nChannels || !trackLen || instruments.empty())
  1041. return false;
  1042. if((loadFlags & loadPatternData) && (positions.empty() || patternData.empty() || sequences.empty()))
  1043. return false;
  1044. // Let's hope noone is going to use the 256th instrument ;)
  1045. if(instruments.size() >= MAX_INSTRUMENTS)
  1046. instruments.resize(MAX_INSTRUMENTS - 1u);
  1047. m_nInstruments = static_cast<INSTRUMENTINDEX>(instruments.size());
  1048. static_assert(MAX_SAMPLES >= MAX_INSTRUMENTS);
  1049. m_nSamples = std::max(m_nSamples, m_nInstruments);
  1050. // Supporting this is probably rather useless, as the paths will always be full Amiga paths. We just take the filename without path for now.
  1051. if(externalSamples)
  1052. {
  1053. #ifdef MPT_EXTERNAL_SAMPLES
  1054. m_nSamples = m_nInstruments;
  1055. for(SAMPLEINDEX sample = 1; sample <= m_nSamples; sample++)
  1056. {
  1057. const SymInstrument &symInst = instruments[sample - 1];
  1058. if(symInst.IsEmpty() || symInst.IsVirtual())
  1059. continue;
  1060. auto filename = mpt::PathString::FromUnicode(mpt::ToUnicode(mpt::Charset::Amiga_no_C1, symInst.GetName()));
  1061. if(file.GetOptionalFileName())
  1062. filename = file.GetOptionalFileName()->GetPath() + filename.GetFullFileName();
  1063. if(!LoadExternalSample(sample, filename))
  1064. AddToLog(LogError, MPT_UFORMAT("Unable to load sample {}: {}")(sample, filename));
  1065. else
  1066. ResetSamplePath(sample);
  1067. if(Samples[sample].uFlags[CHN_STEREO] && sample < m_nSamples)
  1068. {
  1069. const SAMPLEINDEX sampleL = sample + 1;
  1070. ctrlSmp::SplitStereo(Samples[sample], Samples[sampleL], Samples[sample], *this);
  1071. Samples[sampleL].filename = "Left";
  1072. Samples[sample].filename = "Right";
  1073. sample++;
  1074. }
  1075. }
  1076. #else
  1077. AddToLog(LogWarning, U_("External samples are not supported."));
  1078. #endif // MPT_EXTERNAL_SAMPLES
  1079. }
  1080. // Convert instruments
  1081. for(int pass = 0; pass < 2; pass++)
  1082. {
  1083. for(INSTRUMENTINDEX ins = 1; ins <= m_nInstruments; ins++)
  1084. {
  1085. SymInstrument &symInst = instruments[ins - 1];
  1086. if(symInst.IsEmpty())
  1087. continue;
  1088. // First load all regular instruments, and when we have the required information, render the virtual ones
  1089. if(symInst.IsVirtual() != (pass == 1))
  1090. continue;
  1091. SAMPLEINDEX sample = ins;
  1092. if(symInst.virt.header.IsVirtual())
  1093. {
  1094. const uint8 firstSource = symInst.virt.noteEvents[0].inst;
  1095. ModSample &target = Samples[sample];
  1096. if(symInst.virt.Render(*this, symInst.sampleFlags & SymInstrument::AsQueue, target, sampleBoost))
  1097. {
  1098. m_szNames[sample] = "Virtual";
  1099. if(firstSource < instruments.size())
  1100. symInst.downsample += instruments[firstSource].downsample;
  1101. } else
  1102. {
  1103. sample = firstSource + 1;
  1104. }
  1105. } else if(symInst.virt.header.IsTranswave())
  1106. {
  1107. const SymTranswaveInst transwaveInst = symInst.GetTranswave();
  1108. const auto &trans1 = transwaveInst.points[0], &trans2 = transwaveInst.points[1];
  1109. if(trans1.sourceIns < m_nSamples)
  1110. {
  1111. const ModSample emptySample;
  1112. const ModSample &smp1 = Samples[trans1.sourceIns + 1];
  1113. const ModSample &smp2 = trans2.sourceIns < m_nSamples ? Samples[trans2.sourceIns + 1] : emptySample;
  1114. ModSample &target = Samples[sample];
  1115. if(transwaveInst.Render(smp1, smp2, target))
  1116. {
  1117. m_szNames[sample] = "Transwave";
  1118. // Transwave instruments play an octave lower than the original source sample, but are 4x oversampled,
  1119. // so effectively they play an octave higher
  1120. symInst.transpose += 12;
  1121. }
  1122. }
  1123. }
  1124. if(ModInstrument *instr = AllocateInstrument(ins, sample); instr != nullptr && sample <= m_nSamples)
  1125. symInst.ConvertToMPT(*instr, Samples[sample], *this);
  1126. }
  1127. }
  1128. // Convert patterns
  1129. // map Symphonie positions to converted patterns
  1130. std::map<SymPosition, PATTERNINDEX> patternMap;
  1131. // map DSP commands to MIDI macro numbers
  1132. std::map<SymEvent, uint8> macroMap;
  1133. bool useDSP = false;
  1134. const uint32 patternSize = m_nChannels * trackLen;
  1135. const PATTERNINDEX numPatterns = mpt::saturate_cast<PATTERNINDEX>(patternData.size() / patternSize);
  1136. Patterns.ResizeArray(numPatterns);
  1137. Order().clear();
  1138. struct ChnState
  1139. {
  1140. float curVolSlide = 0; // Current volume slide factor of a channel
  1141. float curVolSlideAmt = 0; // Cumulative volume slide amount
  1142. float curPitchSlide = 0; // Current pitch slide factor of a channel
  1143. float curPitchSlideAmt = 0; // Cumulative pitch slide amount
  1144. bool stopped = false; // Sample paused or not (affects volume and pitch slides)
  1145. uint8 lastNote = 0; // Last note played on a channel
  1146. uint8 lastInst = 0; // Last instrument played on a channel
  1147. uint8 lastVol = 64; // Last specified volume of a channel (to avoid excessive Mxx commands)
  1148. uint8 channelVol = 100; // Volume multiplier, 0...100
  1149. uint8 calculatedVol = 64; // Final channel volume
  1150. uint8 fromAdd = 0; // Base sample offset for FROM and FR&P effects
  1151. uint8 curVibrato = 0;
  1152. uint8 curTremolo = 0;
  1153. uint8 sampleVibSpeed = 0;
  1154. uint8 sampleVibDepth = 0;
  1155. uint8 tonePortaAmt = 0;
  1156. uint16 sampleVibPhase = 0;
  1157. uint16 retriggerRemain = 0;
  1158. uint16 tonePortaRemain = 0;
  1159. };
  1160. std::vector<ChnState> chnStates(m_nChannels);
  1161. // In Symphonie, sequences represent the structure of a song, and not separate songs like in OpenMPT. Hence they will all be loaded into the same ModSequence.
  1162. for(SymSequence &seq : sequences)
  1163. {
  1164. if(seq.info == 1)
  1165. continue;
  1166. if(seq.info == -1)
  1167. break;
  1168. if(seq.start >= positions.size()
  1169. || seq.length > positions.size()
  1170. || seq.length == 0
  1171. || positions.size() - seq.length < seq.start)
  1172. continue;
  1173. auto seqPositions = mpt::as_span(positions).subspan(seq.start, seq.length);
  1174. // Sequences are all part of the same song, just add a skip index as a divider
  1175. ModSequence &order = Order();
  1176. if(!order.empty())
  1177. order.push_back(ModSequence::GetIgnoreIndex());
  1178. for(auto &pos : seqPositions)
  1179. {
  1180. // before checking the map, apply the sequence transpose value
  1181. pos.transpose += seq.transpose;
  1182. // pattern already converted?
  1183. PATTERNINDEX patternIndex = 0;
  1184. if(patternMap.count(pos))
  1185. {
  1186. patternIndex = patternMap[pos];
  1187. } else if(loadFlags & loadPatternData)
  1188. {
  1189. // Convert pattern now
  1190. patternIndex = Patterns.InsertAny(pos.length);
  1191. if(patternIndex == PATTERNINDEX_INVALID)
  1192. break;
  1193. patternMap[pos] = patternIndex;
  1194. if(pos.pattern >= numPatterns || pos.start >= trackLen)
  1195. continue;
  1196. uint8 patternSpeed = static_cast<uint8>(pos.speed);
  1197. // This may intentionally read into the next pattern
  1198. auto srcEvent = patternData.cbegin() + (pos.pattern * patternSize) + (pos.start * m_nChannels);
  1199. const SymEvent emptyEvent{};
  1200. ModCommand syncPlayCommand;
  1201. for(ROWINDEX row = 0; row < pos.length; row++)
  1202. {
  1203. ModCommand *rowBase = Patterns[patternIndex].GetpModCommand(row, 0);
  1204. bool applySyncPlay = false;
  1205. for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
  1206. {
  1207. ModCommand &m = rowBase[chn];
  1208. const SymEvent &event = (srcEvent != patternData.cend()) ? *srcEvent : emptyEvent;
  1209. if(srcEvent != patternData.cend())
  1210. srcEvent++;
  1211. int8 note = (event.note >= 0 && event.note <= 84) ? event.note + 25 : -1;
  1212. uint8 origInst = event.inst;
  1213. uint8 mappedInst = 0;
  1214. if(origInst < instruments.size())
  1215. {
  1216. mappedInst = static_cast<uint8>(origInst + 1);
  1217. if(!(instruments[origInst].instFlags & SymInstrument::NoTranspose) && note >= 0)
  1218. note = Clamp(static_cast<int8>(note + pos.transpose), NOTE_MIN, NOTE_MAX);
  1219. }
  1220. // If we duplicated a stereo channel to this cell but the event is non-empty, remove it again.
  1221. if(m.note != NOTE_NONE && (event.command != SymEvent::KeyOn || event.note != -1 || event.inst != 0 || event.param != 0)
  1222. && m.instr > 0 && m.instr <= instruments.size() && instruments[m.instr - 1].channel == SymInstrument::StereoR)
  1223. {
  1224. m.Clear();
  1225. }
  1226. auto &chnState = chnStates[chn];
  1227. if(applySyncPlay)
  1228. {
  1229. applySyncPlay = false;
  1230. m = syncPlayCommand;
  1231. if(m.command == CMD_NONE && chnState.calculatedVol != chnStates[chn - 1].calculatedVol)
  1232. {
  1233. m.command = CMD_CHANNELVOLUME;
  1234. m.param = chnState.calculatedVol = chnStates[chn - 1].calculatedVol;
  1235. }
  1236. if(!event.IsGlobal())
  1237. continue;
  1238. }
  1239. bool applyVolume = false;
  1240. switch(static_cast<SymEvent::Command>(event.command.get()))
  1241. {
  1242. case SymEvent::KeyOn:
  1243. if(event.param > SymEvent::VolCommand)
  1244. {
  1245. switch(event.param)
  1246. {
  1247. case SymEvent::StopSample:
  1248. m.volcmd = VOLCMD_PLAYCONTROL;
  1249. m.vol = 0;
  1250. chnState.stopped = true;
  1251. break;
  1252. case SymEvent::ContSample:
  1253. m.volcmd = VOLCMD_PLAYCONTROL;
  1254. m.vol = 1;
  1255. chnState.stopped = false;
  1256. break;
  1257. case SymEvent::KeyOff:
  1258. if(m.note == NOTE_NONE)
  1259. m.note = chnState.lastNote;
  1260. m.volcmd = VOLCMD_OFFSET;
  1261. m.vol = 1;
  1262. break;
  1263. case SymEvent::SpeedDown:
  1264. if(patternSpeed > 1)
  1265. {
  1266. m.command = CMD_SPEED;
  1267. m.param = --patternSpeed;
  1268. }
  1269. break;
  1270. case SymEvent::SpeedUp:
  1271. if(patternSpeed < 0xFF)
  1272. {
  1273. m.command = CMD_SPEED;
  1274. m.param = ++patternSpeed;
  1275. }
  1276. break;
  1277. case SymEvent::SetPitch:
  1278. chnState.lastNote = note;
  1279. if(mappedInst != chnState.lastInst)
  1280. break;
  1281. m.note = note;
  1282. m.command = CMD_TONEPORTAMENTO;
  1283. m.param = 0xFF;
  1284. chnState.curPitchSlide = 0;
  1285. chnState.tonePortaRemain = 0;
  1286. break;
  1287. // fine portamentos with range up to half a semitone
  1288. case SymEvent::PitchUp:
  1289. m.command = CMD_PORTAMENTOUP;
  1290. m.param = 0xF2;
  1291. break;
  1292. case SymEvent::PitchDown:
  1293. m.command = CMD_PORTAMENTODOWN;
  1294. m.param = 0xF2;
  1295. break;
  1296. case SymEvent::PitchUp2:
  1297. m.command = CMD_PORTAMENTOUP;
  1298. m.param = 0xF4;
  1299. break;
  1300. case SymEvent::PitchDown2:
  1301. m.command = CMD_PORTAMENTODOWN;
  1302. m.param = 0xF4;
  1303. break;
  1304. case SymEvent::PitchUp3:
  1305. m.command = CMD_PORTAMENTOUP;
  1306. m.param = 0xF8;
  1307. break;
  1308. case SymEvent::PitchDown3:
  1309. m.command = CMD_PORTAMENTODOWN;
  1310. m.param = 0xF8;
  1311. break;
  1312. }
  1313. } else
  1314. {
  1315. if(event.note >= 0 || event.param < 100)
  1316. {
  1317. if(event.note >= 0)
  1318. {
  1319. m.note = chnState.lastNote = note;
  1320. m.instr = chnState.lastInst = mappedInst;
  1321. chnState.curPitchSlide = 0;
  1322. chnState.tonePortaRemain = 0;
  1323. }
  1324. if(event.param > 0)
  1325. {
  1326. chnState.lastVol = mpt::saturate_round<uint8>(event.param * 0.64);
  1327. if(chnState.curVolSlide != 0)
  1328. applyVolume = true;
  1329. chnState.curVolSlide = 0;
  1330. }
  1331. }
  1332. }
  1333. if(const uint8 newVol = static_cast<uint8>(Util::muldivr_unsigned(chnState.lastVol, chnState.channelVol, 100));
  1334. applyVolume || chnState.calculatedVol != newVol)
  1335. {
  1336. chnState.calculatedVol = newVol;
  1337. m.command = CMD_CHANNELVOLUME;
  1338. m.param = newVol;
  1339. }
  1340. // Key-On commands with stereo instruments are played on both channels - unless there's already some sort of event
  1341. if(event.note > 0 && (chn < m_nChannels - 1) && !(chn % 2u)
  1342. && origInst < instruments.size() && instruments[origInst].channel == SymInstrument::StereoL)
  1343. {
  1344. ModCommand &next = rowBase[chn + 1];
  1345. next = m;
  1346. next.instr++;
  1347. chnStates[chn + 1].lastVol = chnState.lastVol;
  1348. chnStates[chn + 1].curVolSlide = chnState.curVolSlide;
  1349. chnStates[chn + 1].curVolSlideAmt = chnState.curVolSlideAmt;
  1350. chnStates[chn + 1].curPitchSlide = chnState.curPitchSlide;
  1351. chnStates[chn + 1].curPitchSlideAmt = chnState.curPitchSlideAmt;
  1352. chnStates[chn + 1].retriggerRemain = chnState.retriggerRemain;
  1353. }
  1354. break;
  1355. // volume effects
  1356. // Symphonie has very fine fractional volume slides which are applied at the output sample rate,
  1357. // rather than per tick or per row, so instead let's simulate it based on the pattern speed
  1358. // by keeping track of the volume and using normal volume commands
  1359. // the math here is an approximation which works fine for most songs
  1360. case SymEvent::VolSlideUp:
  1361. chnState.curVolSlideAmt = 0;
  1362. chnState.curVolSlide = event.param * 0.0333f;
  1363. break;
  1364. case SymEvent::VolSlideDown:
  1365. chnState.curVolSlideAmt = 0;
  1366. chnState.curVolSlide = event.param * -0.0333f;
  1367. break;
  1368. case SymEvent::AddVolume:
  1369. m.command = m.param = 0;
  1370. break;
  1371. case SymEvent::Tremolo:
  1372. {
  1373. // both tremolo speed and depth can go much higher than OpenMPT supports,
  1374. // but modules will probably use pretty sane, supportable values anyway
  1375. // TODO: handle very small nonzero params
  1376. uint8 speed = std::min<uint8>(15, event.inst >> 3);
  1377. uint8 depth = std::min<uint8>(15, event.param >> 3);
  1378. chnState.curTremolo = (speed << 4) | depth;
  1379. }
  1380. break;
  1381. // pitch effects
  1382. // Pitch slides have a similar granularity to volume slides, and are approximated
  1383. // the same way here based on a rough comparison against Exx/Fxx slides
  1384. case SymEvent::PitchSlideUp:
  1385. chnState.curPitchSlideAmt = 0;
  1386. chnState.curPitchSlide = event.param * 0.0333f;
  1387. chnState.tonePortaRemain = 0;
  1388. break;
  1389. case SymEvent::PitchSlideDown:
  1390. chnState.curPitchSlideAmt = 0;
  1391. chnState.curPitchSlide = event.param * -0.0333f;
  1392. chnState.tonePortaRemain = 0;
  1393. break;
  1394. case SymEvent::PitchSlideTo:
  1395. if(note >= 0 && event.param > 0)
  1396. {
  1397. const int distance = std::abs((note - chnState.lastNote) * 32);
  1398. chnState.curPitchSlide = 0;
  1399. m.note = chnState.lastNote = note;
  1400. m.command = CMD_TONEPORTAMENTO;
  1401. chnState.tonePortaAmt = m.param = mpt::saturate_cast<ModCommand::PARAM>(distance / (2 * event.param));
  1402. chnState.tonePortaRemain = static_cast<uint16>(distance - std::min(distance, chnState.tonePortaAmt * (patternSpeed - 1)));
  1403. }
  1404. break;
  1405. case SymEvent::AddPitch:
  1406. // "The range (-128...127) is about 4 half notes."
  1407. m.command = m.param = 0;
  1408. break;
  1409. case SymEvent::Vibrato:
  1410. {
  1411. // both vibrato speed and depth can go much higher than OpenMPT supports,
  1412. // but modules will probably use pretty sane, supportable values anyway
  1413. // TODO: handle very small nonzero params
  1414. uint8 speed = std::min<uint8>(15, event.inst >> 3);
  1415. uint8 depth = std::min<uint8>(15, event.param);
  1416. chnState.curVibrato = (speed << 4) | depth;
  1417. }
  1418. break;
  1419. case SymEvent::AddHalfTone:
  1420. m.note = chnState.lastNote = Clamp(static_cast<uint8>(chnState.lastNote + event.param), NOTE_MIN, NOTE_MAX);
  1421. m.command = CMD_TONEPORTAMENTO;
  1422. m.param = 0xFF;
  1423. chnState.tonePortaRemain = 0;
  1424. break;
  1425. // DSP effects
  1426. case SymEvent::Filter:
  1427. #ifndef NO_PLUGINS
  1428. case SymEvent::DSPEcho:
  1429. case SymEvent::DSPDelay:
  1430. #endif
  1431. if(macroMap.count(event))
  1432. {
  1433. m.command = CMD_MIDI;
  1434. m.param = macroMap[event];
  1435. } else if(macroMap.size() < m_MidiCfg.Zxx.size())
  1436. {
  1437. uint8 param = static_cast<uint8>(macroMap.size());
  1438. if(ConvertDSP(event, m_MidiCfg.Zxx[param], *this))
  1439. {
  1440. m.command = CMD_MIDI;
  1441. m.param = macroMap[event] = 0x80 | param;
  1442. if(event.command == SymEvent::DSPEcho || event.command == SymEvent::DSPDelay)
  1443. useDSP = true;
  1444. }
  1445. }
  1446. break;
  1447. // other effects
  1448. case SymEvent::Retrig:
  1449. // This plays the note <param> times every <inst>+1 ticks.
  1450. // The effect continues on the following rows until the correct amount is reached.
  1451. if(event.param < 1)
  1452. break;
  1453. m.command = CMD_RETRIG;
  1454. m.param = static_cast<uint8>(std::min(15, event.inst + 1));
  1455. chnState.retriggerRemain = event.param * (event.inst + 1u);
  1456. break;
  1457. case SymEvent::SetSpeed:
  1458. m.command = CMD_SPEED;
  1459. m.param = patternSpeed = event.param ? event.param : 4u;
  1460. break;
  1461. // TODO this applies a fade on the sample level
  1462. case SymEvent::Emphasis:
  1463. m.command = CMD_NONE;
  1464. break;
  1465. case SymEvent::CV:
  1466. if(event.note == 0 || event.note == 4)
  1467. {
  1468. uint8 pan = (event.note == 4) ? event.inst : 128;
  1469. uint8 vol = std::min<uint8>(event.param, 100);
  1470. uint8 volL = static_cast<uint8>(vol * std::min(128, 256 - pan) / 128);
  1471. uint8 volR = static_cast<uint8>(vol * std::min(uint8(128), pan) / 128);
  1472. if(volL != chnState.channelVol)
  1473. {
  1474. chnState.channelVol = volL;
  1475. m.command = CMD_CHANNELVOLUME;
  1476. m.param = chnState.calculatedVol = static_cast<uint8>(Util::muldivr_unsigned(chnState.lastVol, chnState.channelVol, 100));
  1477. }
  1478. if(event.note == 4 && chn < (m_nChannels - 1) && chnStates[chn + 1].channelVol != volR)
  1479. {
  1480. chnStates[chn + 1].channelVol = volR;
  1481. ModCommand &next = rowBase[chn + 1];
  1482. next.command = CMD_CHANNELVOLUME;
  1483. next.param = chnState.calculatedVol = static_cast<uint8>(Util::muldivr_unsigned(chnState.lastVol, chnState.channelVol, 100));
  1484. }
  1485. }
  1486. break;
  1487. case SymEvent::CVAdd:
  1488. // Effect doesn't seem to exist in UI and code looks like a no-op
  1489. m.command = CMD_NONE;
  1490. break;
  1491. case SymEvent::SetFromAdd:
  1492. chnState.fromAdd = event.param;
  1493. chnState.sampleVibSpeed = 0;
  1494. chnState.sampleVibDepth = 0;
  1495. break;
  1496. case SymEvent::FromAdd:
  1497. // TODO need to verify how signedness of this value is treated
  1498. // C = -128...+127
  1499. //FORMEL: Neuer FADD := alter FADD + C* Samplelaenge/16384
  1500. chnState.fromAdd += event.param;
  1501. break;
  1502. case SymEvent::SampleVib:
  1503. chnState.sampleVibSpeed = event.inst;
  1504. chnState.sampleVibDepth = event.param;
  1505. break;
  1506. // sample effects
  1507. case SymEvent::FromAndPitch:
  1508. chnState.lastNote = note;
  1509. m.instr = chnState.lastInst = mappedInst;
  1510. [[fallthrough]];
  1511. case SymEvent::ReplayFrom:
  1512. m.note = chnState.lastNote;
  1513. if(note >= 0)
  1514. m.instr = chnState.lastInst = mappedInst;
  1515. if(event.command == SymEvent::ReplayFrom)
  1516. {
  1517. m.volcmd = VOLCMD_TONEPORTAMENTO;
  1518. m.vol = 1;
  1519. }
  1520. // don't always add the command, because often FromAndPitch is used with offset 0
  1521. // to act as a key-on which doesn't cancel volume slides, etc
  1522. if(event.param || chnState.fromAdd || chnState.sampleVibDepth)
  1523. {
  1524. double sampleVib = 0.0;
  1525. if(chnState.sampleVibDepth)
  1526. sampleVib = chnState.sampleVibDepth * (std::sin(chnState.sampleVibPhase * (mpt::numbers::pi * 2.0 / 1024.0) + 1.5 * mpt::numbers::pi) - 1.0) / 4.0;
  1527. m.command = CMD_OFFSETPERCENTAGE;
  1528. m.param = mpt::saturate_round<ModCommand::PARAM>(event.param + chnState.fromAdd + sampleVib);
  1529. }
  1530. chnState.tonePortaRemain = 0;
  1531. break;
  1532. }
  1533. // Any event which plays a note should re-enable continuous effects
  1534. if(m.note != NOTE_NONE)
  1535. chnState.stopped = false;
  1536. else if(chnState.stopped)
  1537. continue;
  1538. if(chnState.retriggerRemain)
  1539. {
  1540. chnState.retriggerRemain = std::max(chnState.retriggerRemain, static_cast<uint16>(patternSpeed)) - patternSpeed;
  1541. if(m.command == CMD_NONE)
  1542. {
  1543. m.command = CMD_RETRIG;
  1544. m.param = 0;
  1545. }
  1546. }
  1547. // Handle fractional volume slides
  1548. if(chnState.curVolSlide != 0)
  1549. {
  1550. chnState.curVolSlideAmt += chnState.curVolSlide * patternSpeed;
  1551. if(m.command == CMD_NONE)
  1552. {
  1553. if(patternSpeed > 1 && chnState.curVolSlideAmt >= (patternSpeed - 1))
  1554. {
  1555. uint8 slideAmt = std::min<uint8>(15, mpt::saturate_round<uint8>(chnState.curVolSlideAmt / (patternSpeed - 1)));
  1556. chnState.curVolSlideAmt -= slideAmt * (patternSpeed - 1);
  1557. // normal slide up
  1558. m.command = CMD_CHANNELVOLSLIDE;
  1559. m.param = slideAmt << 4;
  1560. } else if(chnState.curVolSlideAmt >= 1.0f)
  1561. {
  1562. uint8 slideAmt = std::min<uint8>(15, mpt::saturate_round<uint8>(chnState.curVolSlideAmt));
  1563. chnState.curVolSlideAmt -= slideAmt;
  1564. // fine slide up
  1565. m.command = CMD_CHANNELVOLSLIDE;
  1566. m.param = (slideAmt << 4) | 0x0F;
  1567. } else if(patternSpeed > 1 && chnState.curVolSlideAmt <= -(patternSpeed - 1))
  1568. {
  1569. uint8 slideAmt = std::min<uint8>(15, mpt::saturate_round<uint8>(-chnState.curVolSlideAmt / (patternSpeed - 1)));
  1570. chnState.curVolSlideAmt += slideAmt * (patternSpeed - 1);
  1571. // normal slide down
  1572. m.command = CMD_CHANNELVOLSLIDE;
  1573. m.param = slideAmt;
  1574. } else if(chnState.curVolSlideAmt <= -1.0f)
  1575. {
  1576. uint8 slideAmt = std::min<uint8>(14, mpt::saturate_round<uint8>(-chnState.curVolSlideAmt));
  1577. chnState.curVolSlideAmt += slideAmt;
  1578. // fine slide down
  1579. m.command = CMD_CHANNELVOLSLIDE;
  1580. m.param = slideAmt | 0xF0;
  1581. }
  1582. }
  1583. }
  1584. // Handle fractional pitch slides
  1585. if(chnState.curPitchSlide != 0)
  1586. {
  1587. chnState.curPitchSlideAmt += chnState.curPitchSlide * patternSpeed;
  1588. if(m.command == CMD_NONE)
  1589. {
  1590. if(patternSpeed > 1 && chnState.curPitchSlideAmt >= (patternSpeed - 1))
  1591. {
  1592. uint8 slideAmt = std::min<uint8>(0xDF, mpt::saturate_round<uint8>(chnState.curPitchSlideAmt / (patternSpeed - 1)));
  1593. chnState.curPitchSlideAmt -= slideAmt * (patternSpeed - 1);
  1594. // normal slide up
  1595. m.command = CMD_PORTAMENTOUP;
  1596. m.param = slideAmt;
  1597. } else if(chnState.curPitchSlideAmt >= 1.0f)
  1598. {
  1599. uint8 slideAmt = std::min<uint8>(15, mpt::saturate_round<uint8>(chnState.curPitchSlideAmt));
  1600. chnState.curPitchSlideAmt -= slideAmt;
  1601. // fine slide up
  1602. m.command = CMD_PORTAMENTOUP;
  1603. m.param = slideAmt | 0xF0;
  1604. } else if(patternSpeed > 1 && chnState.curPitchSlideAmt <= -(patternSpeed - 1))
  1605. {
  1606. uint8 slideAmt = std::min<uint8>(0xDF, mpt::saturate_round<uint8>(-chnState.curPitchSlideAmt / (patternSpeed - 1)));
  1607. chnState.curPitchSlideAmt += slideAmt * (patternSpeed - 1);
  1608. // normal slide down
  1609. m.command = CMD_PORTAMENTODOWN;
  1610. m.param = slideAmt;
  1611. } else if(chnState.curPitchSlideAmt <= -1.0f)
  1612. {
  1613. uint8 slideAmt = std::min<uint8>(14, mpt::saturate_round<uint8>(-chnState.curPitchSlideAmt));
  1614. chnState.curPitchSlideAmt += slideAmt;
  1615. // fine slide down
  1616. m.command = CMD_PORTAMENTODOWN;
  1617. m.param = slideAmt | 0xF0;
  1618. }
  1619. }
  1620. // TODO: use volume column if effect column is occupied
  1621. else if(m.volcmd == VOLCMD_NONE)
  1622. {
  1623. if(patternSpeed > 1 && chnState.curPitchSlideAmt / 4 >= (patternSpeed - 1))
  1624. {
  1625. uint8 slideAmt = std::min<uint8>(9, mpt::saturate_round<uint8>(chnState.curPitchSlideAmt / (patternSpeed - 1)) / 4);
  1626. chnState.curPitchSlideAmt -= slideAmt * (patternSpeed - 1) * 4;
  1627. m.volcmd = VOLCMD_PORTAUP;
  1628. m.vol = slideAmt;
  1629. } else if(patternSpeed > 1 && chnState.curPitchSlideAmt / 4 <= -(patternSpeed - 1))
  1630. {
  1631. uint8 slideAmt = std::min<uint8>(9, mpt::saturate_round<uint8>(-chnState.curPitchSlideAmt / (patternSpeed - 1)) / 4);
  1632. chnState.curPitchSlideAmt += slideAmt * (patternSpeed - 1) * 4;
  1633. m.volcmd = VOLCMD_PORTADOWN;
  1634. m.vol = slideAmt;
  1635. }
  1636. }
  1637. }
  1638. // Vibrato and Tremolo
  1639. if(m.command == CMD_NONE && chnState.curVibrato != 0)
  1640. {
  1641. m.command = CMD_VIBRATO;
  1642. m.param = chnState.curVibrato;
  1643. }
  1644. if(m.command == CMD_NONE && chnState.curTremolo != 0)
  1645. {
  1646. m.command = CMD_TREMOLO;
  1647. m.param = chnState.curTremolo;
  1648. }
  1649. // Tone Portamento
  1650. if(m.command != CMD_TONEPORTAMENTO && chnState.tonePortaRemain)
  1651. {
  1652. if(m.command == CMD_NONE)
  1653. m.command = CMD_TONEPORTAMENTO;
  1654. else
  1655. m.volcmd = VOLCMD_TONEPORTAMENTO;
  1656. chnState.tonePortaRemain -= std::min(chnState.tonePortaRemain, static_cast<uint16>(chnState.tonePortaAmt * (patternSpeed - 1)));
  1657. }
  1658. chnState.sampleVibPhase = (chnState.sampleVibPhase + chnState.sampleVibSpeed * patternSpeed) & 1023;
  1659. if(!(chn % 2u) && chnState.lastInst && chnState.lastInst <= instruments.size()
  1660. && (instruments[chnState.lastInst - 1].instFlags & SymInstrument::SyncPlay))
  1661. {
  1662. syncPlayCommand = m;
  1663. applySyncPlay = true;
  1664. if(syncPlayCommand.instr && instruments[chnState.lastInst - 1].channel == SymInstrument::StereoL)
  1665. syncPlayCommand.instr++;
  1666. }
  1667. }
  1668. }
  1669. Patterns[patternIndex].WriteEffect(EffectWriter(CMD_SPEED, static_cast<uint8>(pos.speed)).Row(0).RetryNextRow());
  1670. }
  1671. order.insert(order.GetLength(), std::max(pos.loopNum.get(), uint16(1)), patternIndex);
  1672. // Undo transpose tweak
  1673. pos.transpose -= seq.transpose;
  1674. }
  1675. }
  1676. #ifndef NO_PLUGINS
  1677. if(useDSP)
  1678. {
  1679. SNDMIXPLUGIN &plugin = m_MixPlugins[0];
  1680. plugin.Destroy();
  1681. memcpy(&plugin.Info.dwPluginId1, "SymM", 4);
  1682. memcpy(&plugin.Info.dwPluginId2, "Echo", 4);
  1683. plugin.Info.routingFlags = SNDMIXPLUGININFO::irAutoSuspend;
  1684. plugin.Info.mixMode = 0;
  1685. plugin.Info.gain = 10;
  1686. plugin.Info.reserved = 0;
  1687. plugin.Info.dwOutputRouting = 0;
  1688. std::fill(plugin.Info.dwReserved, plugin.Info.dwReserved + std::size(plugin.Info.dwReserved), 0);
  1689. plugin.Info.szName = "Echo";
  1690. plugin.Info.szLibraryName = "SymMOD Echo";
  1691. m_MixPlugins[1].Info.szName = "No Echo";
  1692. }
  1693. #endif // NO_PLUGINS
  1694. // Channel panning
  1695. for(CHANNELINDEX chn = 0; chn < m_nChannels; chn++)
  1696. {
  1697. InitChannel(chn);
  1698. ChnSettings[chn].nPan = (chn & 1) ? 256 : 0;
  1699. ChnSettings[chn].nMixPlugin = useDSP ? 1 : 0; // For MIDI macros controlling the echo DSP
  1700. }
  1701. m_modFormat.formatName = U_("Symphonie");
  1702. m_modFormat.type = U_("symmod");
  1703. if(!isSymphoniePro)
  1704. m_modFormat.madeWithTracker = U_("Symphonie"); // or Symphonie Jr
  1705. else if(instruments.size() <= 128)
  1706. m_modFormat.madeWithTracker = U_("Symphonie Pro");
  1707. else
  1708. m_modFormat.madeWithTracker = U_("Symphonie Pro 256");
  1709. m_modFormat.charset = mpt::Charset::Amiga_no_C1;
  1710. return true;
  1711. }
  1712. OPENMPT_NAMESPACE_END