123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- /*
- * Load_wav.cpp
- * ------------
- * Purpose: WAV importer
- * Notes : This loader converts each WAV channel into a separate mono sample.
- * Authors: Olivier Lapicque
- * OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- #include "stdafx.h"
- #include "Loaders.h"
- #include "WAVTools.h"
- #include "openmpt/soundbase/SampleConvert.hpp"
- #include "openmpt/soundbase/SampleDecode.hpp"
- #include "SampleCopy.h"
- OPENMPT_NAMESPACE_BEGIN
- /////////////////////////////////////////////////////////////
- // WAV file support
- template <typename SampleConversion>
- static bool CopyWavChannel(ModSample &sample, const FileReader &file, size_t channelIndex, size_t numChannels, SampleConversion conv = SampleConversion())
- {
- MPT_ASSERT(sample.GetNumChannels() == 1);
- MPT_ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t));
- const size_t offset = channelIndex * sizeof(typename SampleConversion::input_t) * SampleConversion::input_inc;
- if(sample.AllocateSample() == 0 || !file.CanRead(offset))
- {
- return false;
- }
- const std::byte *inBuf = file.GetRawData<std::byte>().data();
- CopySample<SampleConversion>(reinterpret_cast<typename SampleConversion::output_t*>(sample.samplev()), sample.nLength, 1, inBuf + offset, file.BytesLeft() - offset, numChannels, conv);
- return true;
- }
- CSoundFile::ProbeResult CSoundFile::ProbeFileHeaderWAV(MemoryFileReader file, const uint64 *pfilesize)
- {
- RIFFHeader fileHeader;
- if(!file.ReadStruct(fileHeader))
- {
- return ProbeWantMoreData;
- }
- if((fileHeader.magic != RIFFHeader::idRIFF && fileHeader.magic != RIFFHeader::idLIST)
- || (fileHeader.type != RIFFHeader::idWAVE && fileHeader.type != RIFFHeader::idwave))
- {
- return ProbeFailure;
- }
- MPT_UNREFERENCED_PARAMETER(pfilesize);
- return ProbeSuccess;
- }
- bool CSoundFile::ReadWAV(FileReader &file, ModLoadingFlags loadFlags)
- {
- WAVReader wavFile(file);
- if(!wavFile.IsValid()
- || wavFile.GetNumChannels() == 0
- || wavFile.GetNumChannels() > MAX_BASECHANNELS
- || wavFile.GetNumChannels() >= MAX_SAMPLES
- || wavFile.GetBitsPerSample() == 0
- || wavFile.GetBitsPerSample() > 64
- || (wavFile.GetBitsPerSample() < 32 && wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat)
- || (wavFile.GetSampleFormat() != WAVFormatChunk::fmtPCM && wavFile.GetSampleFormat() != WAVFormatChunk::fmtFloat))
- {
- return false;
- } else if(loadFlags == onlyVerifyHeader)
- {
- return true;
- }
- InitializeGlobals(MOD_TYPE_MPT);
- m_ContainerType = MOD_CONTAINERTYPE_WAV;
- m_nChannels = std::max(wavFile.GetNumChannels(), uint16(2));
- Patterns.ResizeArray(2);
- if(!Patterns.Insert(0, 64) || !Patterns.Insert(1, 64))
- {
- return false;
- }
- m_modFormat.formatName = U_("RIFF WAVE");
- m_modFormat.type = U_("wav");
- m_modFormat.charset = mpt::Charset::Windows1252;
-
- const SmpLength sampleLength = wavFile.GetSampleLength();
- // Setting up module length
- // Calculate sample length in ticks at tempo 125
- const uint32 sampleRate = std::max(uint32(1), wavFile.GetSampleRate());
- const uint32 sampleTicks = mpt::saturate_cast<uint32>(((sampleLength * 50) / sampleRate) + 1);
- uint32 ticksPerRow = std::max((sampleTicks + 63u) / 63u, uint32(1));
- Order().assign(1, 0);
- ORDERINDEX numOrders = 1;
- while(ticksPerRow >= 32 && numOrders < MAX_ORDERS)
- {
- numOrders++;
- ticksPerRow = (sampleTicks + (64 * numOrders - 1)) / (64 * numOrders);
- }
- Order().resize(numOrders, 1);
- m_nSamples = wavFile.GetNumChannels();
- m_nInstruments = 0;
- m_nDefaultSpeed = ticksPerRow;
- m_nDefaultTempo.Set(125);
- m_SongFlags = SONG_LINEARSLIDES;
- for(CHANNELINDEX channel = 0; channel < m_nChannels; channel++)
- {
- ChnSettings[channel].Reset();
- ChnSettings[channel].nPan = (channel % 2u) ? 256 : 0;
- }
- // Setting up pattern
- PatternRow pattern = Patterns[0].GetRow(0);
- pattern[0].note = pattern[1].note = NOTE_MIDDLEC;
- pattern[0].instr = pattern[1].instr = 1;
- const FileReader sampleChunk = wavFile.GetSampleData();
- // Read every channel into its own sample lot.
- for(SAMPLEINDEX channel = 0; channel < GetNumSamples(); channel++)
- {
- pattern[channel].note = pattern[0].note;
- pattern[channel].instr = static_cast<ModCommand::INSTR>(channel + 1);
- ModSample &sample = Samples[channel + 1];
- sample.Initialize();
- sample.uFlags = CHN_PANNING;
- sample.nLength = sampleLength;
- sample.nC5Speed = wavFile.GetSampleRate();
- m_szNames[channel + 1] = "";
- wavFile.ApplySampleSettings(sample, GetCharsetInternal(), m_szNames[channel + 1]);
- if(wavFile.GetNumChannels() > 1)
- {
- // Pan all samples appropriately
- switch(channel)
- {
- case 0:
- sample.nPan = 0;
- break;
- case 1:
- sample.nPan = 256;
- break;
- case 2:
- sample.nPan = (wavFile.GetNumChannels() == 3 ? 128u : 64u);
- pattern[channel].command = CMD_S3MCMDEX;
- pattern[channel].param = 0x91;
- break;
- case 3:
- sample.nPan = 192;
- pattern[channel].command = CMD_S3MCMDEX;
- pattern[channel].param = 0x91;
- break;
- default:
- sample.nPan = 128;
- break;
- }
- }
- if(wavFile.GetBitsPerSample() > 8)
- {
- sample.uFlags.set(CHN_16BIT);
- }
- if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat)
- {
- if(wavFile.GetBitsPerSample() <= 32)
- CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
- else
- CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float64>, SC::DecodeFloat64<littleEndian64>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
- } else
- {
- if(wavFile.GetBitsPerSample() <= 8)
- CopyWavChannel<SC::DecodeUint8>(sample, sampleChunk, channel, wavFile.GetNumChannels());
- else if(wavFile.GetBitsPerSample() <= 16)
- CopyWavChannel<SC::DecodeInt16<0, littleEndian16>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
- else if(wavFile.GetBitsPerSample() <= 24)
- CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
- else if(wavFile.GetBitsPerSample() <= 32)
- CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
- else if(wavFile.GetBitsPerSample() <= 64)
- CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int64>, SC::DecodeInt64<0, littleEndian64>>>(sample, sampleChunk, channel, wavFile.GetNumChannels());
- }
- sample.PrecomputeLoops(*this, false);
- }
- return true;
- }
- OPENMPT_NAMESPACE_END
|