Load_wav.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /*
  2. * Load_wav.cpp
  3. * ------------
  4. * Purpose: WAV importer
  5. * Notes : This loader converts each WAV channel into a separate mono sample.
  6. * Authors: Olivier Lapicque
  7. * OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #include "stdafx.h"
  11. #include "Loaders.h"
  12. #include "WAVTools.h"
  13. #include "openmpt/soundbase/SampleConvert.hpp"
  14. #include "openmpt/soundbase/SampleDecode.hpp"
  15. #include "SampleCopy.h"
  16. OPENMPT_NAMESPACE_BEGIN
  17. /////////////////////////////////////////////////////////////
  18. // WAV file support
  19. template <typename SampleConversion>
  20. static bool CopyWavChannel(ModSample &sample, const FileReader &file, size_t channelIndex, size_t numChannels, SampleConversion conv = SampleConversion())
  21. {
  22. MPT_ASSERT(sample.GetNumChannels() == 1);
  23. MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
  24. const size_t offset = channelIndex * sizeof(typename SampleConversion::input_t) * SampleConversion::input_inc;
  25. if(sample.AllocateSample() == 0 || !file.CanRead(offset))
  26. {
  27. return false;
  28. }
  29. const std::byte *inBuf = file.GetRawData<std::byte>().data();
  30. CopySample<SampleConversion>(reinterpret_cast<typename SampleConversion::output_t*>(sample.samplev()), sample.nLength, 1, inBuf + offset, file.BytesLeft() - offset, numChannels, conv);
  31. return true;
  32. }
  33. CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderWAV(MemoryFileReader file, const uint64 *pfilesize)
  34. {
  35. RIFFHeader fileHeader;
  36. if(!file.ReadStruct(fileHeader))
  37. {
  38. return ProbeWantMoreData;
  39. }
  40. if((fileHeader.magic != RIFFHeader::idRIFF && fileHeader.magic != RIFFHeader::idLIST)
  41. || (fileHeader.type != RIFFHeader::idWAVE && fileHeader.type != RIFFHeader::idwave))
  42. {
  43. return ProbeFailure;
  44. }
  45. MPT_UNREFERENCED_PARAMETER(pfilesize);
  46. return ProbeSuccess;
  47. }
  48. bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags)
  49. {
  50. WAVReader wavFile(file);
  51. if(!wavFile.IsValid()
  52. || wavFile.GetNumChannels() == 0
  53. || wavFile.GetNumChannels() > MAX_BASECHANNELS
  54. || wavFile.GetNumChannels() >= MAX_SAMPLES
  55. || wavFile.GetBitsPerSample() == 0
  56. || wavFile.GetBitsPerSample() > 64
  57. || (wavFile.GetBitsPerSample() < 32 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat)
  58. || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat))
  59. {
  60. return false;
  61. } else if(loadFlags == onlyVerifyHeader)
  62. {
  63. return true;
  64. }
  65. InitializeGlobals(MOD_TYPE_MPT);
  66. m_ContainerType = MOD_CONTAINERTYPE_WAV;
  67. m_nChannels = std::max(wavFile.GetNumChannels(), uint16(2));
  68. Patterns.ResizeArray(2);
  69. if(!Patterns.Insert(0, 64) || !Patterns.Insert(1, 64))
  70. {
  71. return false;
  72. }
  73. m_modFormat.formatName = U_("RIFF WAVE");
  74. m_modFormat.type = U_("wav");
  75. m_modFormat.charset = mpt::Charset::Windows1252;
  76. const SmpLength sampleLength = wavFile.GetSampleLength();
  77. // Setting up module length
  78. // Calculate sample length in ticks at tempo 125
  79. const uint32 sampleRate = std::max(uint32(1), wavFile.GetSampleRate());
  80. const uint32 sampleTicks = mpt::saturate_cast<uint32>(((sampleLength * 50) / sampleRate) + 1);
  81. uint32 ticksPerRow = std::max((sampleTicks + 63u) / 63u, uint32(1));
  82. Order().assign(1, 0);
  83. ORDERINDEX numOrders = 1;
  84. while(ticksPerRow >= 32 && numOrders < MAX_ORDERS)
  85. {
  86. numOrders++;
  87. ticksPerRow = (sampleTicks + (64 * numOrders - 1)) / (64 * numOrders);
  88. }
  89. Order().resize(numOrders, 1);
  90. m_nSamples = wavFile.GetNumChannels();
  91. m_nInstruments = 0;
  92. m_nDefaultSpeed = ticksPerRow;
  93. m_nDefaultTempo.Set(125);
  94. m_SongFlags = SONG_LINEARSLIDES;
  95. for(CHANNELINDEX channel = 0; channel < m_nChannels; channel++)
  96. {
  97. ChnSettings[channel].Reset();
  98. ChnSettings[channel].nPan = (channel % 2u) ? 256 : 0;
  99. }
  100. // Setting up pattern
  101. PatternRow pattern = Patterns[0].GetRow(0);
  102. pattern[0].note = pattern[1].note = NOTE_MIDDLEC;
  103. pattern[0].instr = pattern[1].instr = 1;
  104. const FileReader sampleChunk = wavFile.GetSampleData();
  105. // Read every channel into its own sample lot.
  106. for(SAMPLEINDEX channel = 0; channel < GetNumSamples(); channel++)
  107. {
  108. pattern[channel].note = pattern[0].note;
  109. pattern[channel].instr = static_cast<ModCommand::INSTR>(channel + 1);
  110. ModSample &sample = Samples[channel + 1];
  111. sample.Initialize();
  112. sample.uFlags = CHN_PANNING;
  113. sample.nLength = sampleLength;
  114. sample.nC5Speed = wavFile.GetSampleRate();
  115. m_szNames[channel + 1] = "";
  116. wavFile.ApplySampleSettings(sample, GetCharsetInternal(), m_szNames[channel + 1]);
  117. if(wavFile.GetNumChannels() > 1)
  118. {
  119. // Pan all samples appropriately
  120. switch(channel)
  121. {
  122. case 0:
  123. sample.nPan = 0;
  124. break;
  125. case 1:
  126. sample.nPan = 256;
  127. break;
  128. case 2:
  129. sample.nPan = (wavFile.GetNumChannels() == 3 ? 128u : 64u);
  130. pattern[channel].command = CMD_S3MCMDEX;
  131. pattern[channel].param = 0x91;
  132. break;
  133. case 3:
  134. sample.nPan = 192;
  135. pattern[channel].command = CMD_S3MCMDEX;
  136. pattern[channel].param = 0x91;
  137. break;
  138. default:
  139. sample.nPan = 128;
  140. break;
  141. }
  142. }
  143. if(wavFile.GetBitsPerSample() > 8)
  144. {
  145. sample.uFlags.set(CHN_16BIT);
  146. }
  147. if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat)
  148. {
  149. if(wavFile.GetBitsPerSample() <= 32)
  150. CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
  151. else
  152. CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float64>, SC::DecodeFloat64<littleEndian64>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
  153. } else
  154. {
  155. if(wavFile.GetBitsPerSample() <= 8)
  156. CopyWavChannel<SC::DecodeUint8>(sample, sampleChunk, channel, wavFile.GetNumChannels());
  157. else if(wavFile.GetBitsPerSample() <= 16)
  158. CopyWavChannel<SC::DecodeInt16<0, littleEndian16>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
  159. else if(wavFile.GetBitsPerSample() <= 24)
  160. CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
  161. else if(wavFile.GetBitsPerSample() <= 32)
  162. CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
  163. else if(wavFile.GetBitsPerSample() <= 64)
  164. CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int64>, SC::DecodeInt64<0, littleEndian64>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
  165. }
  166. sample.PrecomputeLoops(*this, false);
  167. }
  168. return true;
  169. }
  170. OPENMPT_NAMESPACE_END