#include "stdafx.h"
#include "Loaders.h"
#include "WAVTools.h"
#include "../soundbase/SampleFormatConverters.h"
#include "../soundbase/SampleFormatCopy.h"
OPENMPT_NAMESPACE_BEGIN
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 mpt::byte *inBuf = file.GetRawData<mpt::byte>();
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.GetBitsPerSample() == 0
|| wavFile.GetBitsPerSample() > 32
|| (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::CharsetWindows1252;
const SmpLength sampleLength = wavFile.GetSampleLength();
const uint32 sampleRate = std::max(uint32(1), wavFile.GetSampleRate());
const uint32 sampleTicks = mpt::saturate_cast<uint32>(((sampleLength * 50) / sampleRate) + 1);
uint32 ticksPerRow = std::max<uint32>((sampleTicks + 63u) / 63u, 1u);
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;
}
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();
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();
strcpy(m_szNames[channel + 1], "");
wavFile.ApplySampleSettings(sample, GetCharsetInternal(), m_szNames[channel + 1]);
if(wavFile.GetNumChannels() > 1)
{
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)
{
CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(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());
}
}
sample.PrecomputeLoops(*this, false);
}
return true;
}
OPENMPT_NAMESPACE_END