// Retrieve the internal sample format flags for this instrument. SampleIO XMSample::GetSampleFormat() const //---------------------------------------- { if(reserved == sampleADPCM && !(flags & (XMSample::sample16Bit | XMSample::sampleStereo))) { // MODPlugin :( return SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::ADPCM); } return SampleIO( (flags & XMSample::sample16Bit) ? SampleIO::_16bit : SampleIO::_8bit, (flags & XMSample::sampleStereo) ? SampleIO::stereoSplit : SampleIO::mono, SampleIO::littleEndian, SampleIO::deltaPCM); }
// Retrieve the internal sample format flags for this sample. SampleIO S3MSampleHeader::GetSampleFormat(bool signedSamples) const //----------------------------------------------------------------- { if(pack == S3MSampleHeader::pADPCM && !(flags & S3MSampleHeader::smp16Bit) && !(flags & S3MSampleHeader::smpStereo)) { // MODPlugin :( return SampleIO(SampleIO::_8bit, SampleIO::mono, SampleIO::littleEndian, SampleIO::ADPCM); } else { return SampleIO( (flags & S3MSampleHeader::smp16Bit) ? SampleIO::_16bit : SampleIO::_8bit, (flags & S3MSampleHeader::smpStereo) ? SampleIO::stereoSplit : SampleIO::mono, SampleIO::littleEndian, signedSamples ? SampleIO::signedPCM : SampleIO::unsignedPCM); } }
OPENMPT_NAMESPACE_BEGIN #if MPT_COMPILER_GCC #if MPT_GCC_AT_LEAST(4,6,0) #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wswitch" #elif MPT_COMPILER_CLANG #pragma clang diagnostic push #if MPT_CLANG_AT_LEAST(3,3,0) #pragma clang diagnostic ignored "-Wswitch" #else #pragma clang diagnostic ignored "-Wswitch-enum" #endif #endif // Read a sample from memory size_t SampleIO::ReadSample(ModSample &sample, FileReader &file) const //-------------------------------------------------------------------- { if(sample.nLength < 1 || !file.IsValid()) { return 0; } LimitMax(sample.nLength, MAX_SAMPLE_LENGTH); const char * const sourceBuf = file.GetRawData(); const FileReader::off_t fileSize = file.BytesLeft(), filePosition = file.GetPosition(); FileReader::off_t bytesRead = 0; // Amount of memory that has been read from file sample.uFlags.set(CHN_16BIT, GetBitDepth() >= 16); sample.uFlags.set(CHN_STEREO, GetChannelFormat() != mono); size_t sampleSize = sample.AllocateSample(); // Target sample size in bytes if(sampleSize == 0) { sample.nLength = 0; return 0; } ASSERT(sampleSize >= sample.GetSampleSizeInBytes()); ////////////////////////////////////////////////////// // 8-Bit / Mono / PCM if(GetBitDepth() == 8 && GetChannelFormat() == mono) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Mono / Signed / PCM bytesRead = CopyMonoSample<SC::DecodeInt8>(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Mono / Unsigned / PCM bytesRead = CopyMonoSample<SC::DecodeUint8>(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Mono / Delta / PCM case MT2: bytesRead = CopyMonoSample<SC::DecodeInt8Delta>(sample, sourceBuf, fileSize); break; case PCM7to8: // 7 Bit stored as 8-Bit with highest bit unused / Mono / Signed / PCM bytesRead = CopyMonoSample<SC::DecodeInt7>(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 8-Bit / Stereo Split / PCM else if(GetBitDepth() == 8 && GetChannelFormat() == stereoSplit) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt8>(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample<SC::DecodeUint8>(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Stereo Split / Delta / PCM case MT2: bytesRead = CopyStereoSplitSample<SC::DecodeInt8Delta>(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 8-Bit / Stereo Interleaved / PCM else if(GetBitDepth() == 8 && GetChannelFormat() == stereoInterleaved) { switch(GetEncoding()) { case signedPCM: // 8-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt8>(sample, sourceBuf, fileSize); break; case unsignedPCM: // 8-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeUint8>(sample, sourceBuf, fileSize); break; case deltaPCM: // 8-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt8Delta>(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Mono / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == mono && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyMonoSample<SC::DecodeInt16<0, littleEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyMonoSample<SC::DecodeInt16<0x8000u, littleEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM case MT2: bytesRead = CopyMonoSample<SC::DecodeInt16Delta<littleEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Mono / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == mono && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Mono / Signed / PCM bytesRead = CopyMonoSample<SC::DecodeInt16<0, bigEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Mono / Unsigned / PCM bytesRead = CopyMonoSample<SC::DecodeInt16<0x8000u, bigEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Mono / Delta / PCM bytesRead = CopyMonoSample<SC::DecodeInt16Delta<bigEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Split / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoSplit && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16<0, littleEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16<0x8000u, littleEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Split / Delta / PCM case MT2: bytesRead = CopyStereoSplitSample<SC::DecodeInt16Delta<littleEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Split / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoSplit && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Split / Signed / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16<0, bigEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Split / Unsigned / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16<0x8000u, bigEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Split / Delta / PCM bytesRead = CopyStereoSplitSample<SC::DecodeInt16Delta<bigEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Interleaved / Little Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEndianness() == littleEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16<0, littleEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16<0x8000u, littleEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16Delta<littleEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 16-Bit / Stereo Interleaved / Big Endian / PCM else if(GetBitDepth() == 16 && GetChannelFormat() == stereoInterleaved && GetEndianness() == bigEndian) { switch(GetEncoding()) { case signedPCM: // 16-Bit / Stereo Interleaved / Signed / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16<0, bigEndian16> >(sample, sourceBuf, fileSize); break; case unsignedPCM: // 16-Bit / Stereo Interleaved / Unsigned / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16<0x8000u, bigEndian16> >(sample, sourceBuf, fileSize); break; case deltaPCM: // 16-Bit / Stereo Interleaved / Delta / PCM bytesRead = CopyStereoInterleavedSample<SC::DecodeInt16Delta<bigEndian16> >(sample, sourceBuf, fileSize); break; } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Mono / PCM else if(GetBitDepth() == 24 && GetChannelFormat() == mono && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Stereo Interleaved / PCM else if(GetBitDepth() == 24 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Mono / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Stereo Interleaved / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize); } else { bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize); } } ////////////////////////////////////////////////////// // 24-Bit / Signed / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 24 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCMnormalize) { // Normalize to 16-Bit uint32 srcPeak = uint32(1)<<31; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = static_cast<uint16>(Clamp(Util::muldivr_unsigned(sample.nGlobalVol, srcPeak, uint32(1)<<31), uint32(1), uint32(64))); } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCMnormalize) { // Normalize to 16-Bit uint32 srcPeak = uint32(1)<<31; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = static_cast<uint16>(Clamp(Util::muldivr_unsigned(sample.nGlobalVol, srcPeak, uint32(1)<<31), uint32(1), uint32(64))); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono, Stereo Interleaved / PCM else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == floatPCMnormalize) { // Normalize to 16-Bit float32 srcPeak = 1.0f; if(GetEndianness() == littleEndian) { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } else { bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } if(bytesRead) { // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. sample.nGlobalVol = Util::Round<uint16>(Clamp(sample.nGlobalVol * srcPeak, 1.0f, 64.0f)); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono / PCM / full scale 2^15 else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM15) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<15))) ); } else { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<15))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^15 else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM15) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<15))) ); } else { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<15))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^23 else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM23) { if(GetEndianness() == littleEndian) { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<23))) ); } else { bytesRead = CopyMonoSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<23))) ); } } ////////////////////////////////////////////////////// // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^23 else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM23) { if(GetEndianness() == littleEndian) { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<23))) ); } else { bytesRead = CopyStereoInterleavedSample (sample, sourceBuf, fileSize, SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<23))) ); } } ////////////////////////////////////////////////////// // Compressed samples if(*this == SampleIO(_8bit, mono, littleEndian, ADPCM)) { // 4-Bit ADPCM data int8 compressionTable[16]; // ADPCM Compression LUT if(file.ReadArray(compressionTable)) { size_t readLength = (sample.nLength + 1) / 2; LimitMax(readLength, file.BytesLeft()); const uint8 *inBuf = reinterpret_cast<const uint8*>(sourceBuf) + sizeof(compressionTable); int8 *outBuf = static_cast<int8 *>(sample.pSample); int8 delta = 0; for(size_t i = readLength; i != 0; i--) { delta += compressionTable[*inBuf & 0x0F]; *(outBuf++) = delta; delta += compressionTable[(*inBuf >> 4) & 0x0F]; *(outBuf++) = delta; inBuf++; } bytesRead = sizeof(compressionTable) + readLength; }