1
0

S3MTools.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * S3MTools.cpp
  3. * ------------
  4. * Purpose: Definition of S3M file structures and helper functions
  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 "Loaders.h"
  11. #include "S3MTools.h"
  12. #include "../common/mptStringBuffer.h"
  13. OPENMPT_NAMESPACE_BEGIN
  14. // Convert an S3M sample header to OpenMPT's internal sample header.
  15. void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp, bool isST3) const
  16. {
  17. mptSmp.Initialize(MOD_TYPE_S3M);
  18. mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, filename);
  19. if(sampleType == typePCM || sampleType == typeNone)
  20. {
  21. // Sample Length and Loops
  22. if(sampleType == typePCM)
  23. {
  24. mptSmp.nLength = length;
  25. mptSmp.nLoopStart = std::min(static_cast<SmpLength>(loopStart), mptSmp.nLength - 1);
  26. mptSmp.nLoopEnd = std::min(static_cast<SmpLength>(loopEnd), mptSmp.nLength);
  27. mptSmp.uFlags.set(CHN_LOOP, (flags & smpLoop) != 0);
  28. }
  29. if(mptSmp.nLoopEnd < 2 || mptSmp.nLoopStart >= mptSmp.nLoopEnd || mptSmp.nLoopEnd - mptSmp.nLoopStart < 1)
  30. {
  31. mptSmp.nLoopStart = mptSmp.nLoopEnd = 0;
  32. mptSmp.uFlags.reset();
  33. }
  34. } else if(sampleType == typeAdMel)
  35. {
  36. OPLPatch patch;
  37. std::memcpy(patch.data() + 0, mpt::as_raw_memory(length).data(), 4);
  38. std::memcpy(patch.data() + 4, mpt::as_raw_memory(loopStart).data(), 4);
  39. std::memcpy(patch.data() + 8, mpt::as_raw_memory(loopEnd).data(), 4);
  40. mptSmp.SetAdlib(true, patch);
  41. }
  42. // Volume / Panning
  43. mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4;
  44. // C-5 frequency
  45. mptSmp.nC5Speed = c5speed;
  46. if(isST3)
  47. {
  48. // ST3 ignores or clamps the high 16 bits depending on the instrument type
  49. if(sampleType == typeAdMel)
  50. mptSmp.nC5Speed &= 0xFFFF;
  51. else
  52. LimitMax(mptSmp.nC5Speed, uint16_max);
  53. }
  54. if(mptSmp.nC5Speed == 0)
  55. mptSmp.nC5Speed = 8363;
  56. else if(mptSmp.nC5Speed < 1024)
  57. mptSmp.nC5Speed = 1024;
  58. }
  59. // Convert OpenMPT's internal sample header to an S3M sample header.
  60. SmpLength S3MSampleHeader::ConvertToS3M(const ModSample &mptSmp)
  61. {
  62. SmpLength smpLength = 0;
  63. mpt::String::WriteBuf(mpt::String::maybeNullTerminated, filename) = mptSmp.filename;
  64. memcpy(magic, "SCRS", 4);
  65. if(mptSmp.uFlags[CHN_ADLIB])
  66. {
  67. memcpy(magic, "SCRI", 4);
  68. sampleType = typeAdMel;
  69. std::memcpy(mpt::as_raw_memory(length ).data(), mptSmp.adlib.data() + 0, 4);
  70. std::memcpy(mpt::as_raw_memory(loopStart).data(), mptSmp.adlib.data() + 4, 4);
  71. std::memcpy(mpt::as_raw_memory(loopEnd ).data(), mptSmp.adlib.data() + 8, 4);
  72. } else if(mptSmp.HasSampleData())
  73. {
  74. sampleType = typePCM;
  75. length = mpt::saturate_cast<uint32>(mptSmp.nLength);
  76. loopStart = mpt::saturate_cast<uint32>(mptSmp.nLoopStart);
  77. loopEnd = mpt::saturate_cast<uint32>(mptSmp.nLoopEnd);
  78. smpLength = length;
  79. flags = (mptSmp.uFlags[CHN_LOOP] ? smpLoop : 0);
  80. if(mptSmp.uFlags[CHN_16BIT])
  81. {
  82. flags |= smp16Bit;
  83. }
  84. if(mptSmp.uFlags[CHN_STEREO])
  85. {
  86. flags |= smpStereo;
  87. }
  88. } else
  89. {
  90. sampleType = typeNone;
  91. }
  92. defaultVolume = static_cast<uint8>(std::min(static_cast<uint16>(mptSmp.nVolume / 4), uint16(64)));
  93. if(mptSmp.nC5Speed != 0)
  94. {
  95. c5speed = mptSmp.nC5Speed;
  96. } else
  97. {
  98. c5speed = ModSample::TransposeToFrequency(mptSmp.RelativeTone, mptSmp.nFineTune);
  99. }
  100. return smpLength;
  101. }
  102. // Retrieve the internal sample format flags for this sample.
  103. SampleIO S3MSampleHeader::GetSampleFormat(bool signedSamples) const
  104. {
  105. if(pack == S3MSampleHeader::pADPCM && !(flags & S3MSampleHeader::smp16Bit) && !(flags & S3MSampleHeader::smpStereo))
  106. {
  107. // MODPlugin :(
  108. return SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::ADPCM);
  109. } else
  110. {
  111. return SampleIO(
  112. (flags & S3MSampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit,
  113. (flags & S3MSampleHeader::smpStereo) ? SampleIO::stereoSplit : SampleIO::mono,
  114. SampleIO::littleEndian,
  115. signedSamples ? SampleIO::signedPCM : SampleIO::unsignedPCM);
  116. }
  117. }
  118. // Calculate the sample position in file
  119. uint32 S3MSampleHeader::GetSampleOffset() const
  120. {
  121. return (dataPointer[1] << 4) | (dataPointer[2] << 12) | (dataPointer[0] << 20);
  122. }
  123. OPENMPT_NAMESPACE_END