Ejemplo n.º 1
0
// Convert an XMSample to OpenMPT's internal sample representation.
void XMSample::ConvertToMPT(ModSample &mptSmp) const
//--------------------------------------------------
{
	mptSmp.Initialize(MOD_TYPE_XM);

	// Volume
	mptSmp.nVolume = vol * 4;
	LimitMax(mptSmp.nVolume, uint16(256));

	// Panning
	mptSmp.nPan = pan;
	mptSmp.uFlags = CHN_PANNING;

	// Sample Frequency
	mptSmp.nFineTune = finetune;
	mptSmp.RelativeTone = relnote;

	// Sample Length and Loops
	mptSmp.nLength = length;
	mptSmp.nLoopStart = loopStart;
	mptSmp.nLoopEnd = mptSmp.nLoopStart + loopLength;

	if((flags & XMSample::sample16Bit))
	{
		mptSmp.nLength /= 2;
		mptSmp.nLoopStart /= 2;
		mptSmp.nLoopEnd /= 2;
	}

	if((flags & XMSample::sampleStereo))
	{
		mptSmp.nLength /= 2;
		mptSmp.nLoopStart /= 2;
		mptSmp.nLoopEnd /= 2;
	}

	if((flags & (XMSample::sampleLoop | XMSample::sampleBidiLoop)) && mptSmp.nLoopStart < mptSmp.nLength && mptSmp.nLoopEnd > mptSmp.nLoopStart)
	{
		mptSmp.uFlags.set(CHN_LOOP);
		if((flags & XMSample::sampleBidiLoop))
		{
			mptSmp.uFlags.set(CHN_PINGPONGLOOP);
		}
	}

	mptSmp.SanitizeLoops();

	strcpy(mptSmp.filename, "");
}
Ejemplo n.º 2
0
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.pSample), sample.nLength, 1, inBuf + offset, file.BytesLeft() - offset, numChannels, conv);
	return true;
}
Ejemplo n.º 3
0
SmpLength InsertSilence(ModSample &smp, const SmpLength nSilenceLength, const SmpLength nStartFrom, CSoundFile &sndFile)
//----------------------------------------------------------------------------------------------------------------------
{
	if(nSilenceLength == 0 || nSilenceLength > MAX_SAMPLE_LENGTH || smp.nLength > MAX_SAMPLE_LENGTH - nSilenceLength || nStartFrom > smp.nLength)
		return smp.nLength;

	const bool wasEmpty = smp.nLength == 0 || smp.pSample == nullptr;
	const SmpLength newLength = smp.nLength + nSilenceLength;

	char *pNewSmp = nullptr;

	pNewSmp = static_cast<char *>(ModSample::AllocateSample(newLength, smp.GetBytesPerSample()));
	if(pNewSmp == nullptr)
		return smp.nLength; //Sample allocation failed.

	if(!wasEmpty)
	{
		// Copy over old sample
		const SmpLength silenceOffset = nStartFrom * smp.GetBytesPerSample();
		const SmpLength silenceBytes = nSilenceLength * smp.GetBytesPerSample();
		if(nStartFrom > 0)
		{
			memcpy(pNewSmp, smp.pSample, silenceOffset);
		}
		if(nStartFrom < smp.nLength)
		{
			memcpy(pNewSmp + silenceOffset + silenceBytes, static_cast<const char *>(smp.pSample) + silenceOffset, smp.GetSampleSizeInBytes() - silenceOffset);
		}

		// Update loop points if necessary.
		if(smp.nLoopStart >= nStartFrom) smp.nLoopStart += nSilenceLength;
		if(smp.nLoopEnd >= nStartFrom) smp.nLoopEnd += nSilenceLength;
	} else
	{
		// Set loop points automatically
		smp.nLoopStart = 0;
		smp.nLoopEnd = newLength;
		smp.uFlags.set(CHN_LOOP);
	}

	ReplaceSample(smp, pNewSmp, newLength, sndFile);
	PrecomputeLoops(smp, sndFile, true);

	return smp.nLength;
}
Ejemplo n.º 4
0
SmpLength ResizeSample(ModSample &smp, const SmpLength nNewLength, CSoundFile &sndFile)
//-------------------------------------------------------------------------------------
{
	// Invalid sample size
	if(nNewLength > MAX_SAMPLE_LENGTH || nNewLength == smp.nLength)
		return smp.nLength;

	// New sample will be bigger so we'll just use "InsertSilence" as it's already there.
	if(nNewLength > smp.nLength)
		return InsertSilence(smp, nNewLength - smp.nLength, smp.nLength, sndFile);

	// Else: Shrink sample

	const SmpLength nNewSmpBytes = nNewLength * smp.GetBytesPerSample();

	void *pNewSmp = ModSample::AllocateSample(nNewLength, smp.GetBytesPerSample());
	if(pNewSmp == nullptr)
		return smp.nLength; //Sample allocation failed.

	// Copy over old data and replace sample by the new one
	memcpy(pNewSmp, smp.pSample, nNewSmpBytes);
	ReplaceSample(smp, pNewSmp, nNewLength, sndFile);

	// Adjust loops
	if(smp.nLoopStart > nNewLength)
	{
		smp.nLoopStart = smp.nLoopEnd = 0;
		smp.uFlags.reset(CHN_LOOP);
	}
	if(smp.nLoopEnd > nNewLength) smp.nLoopEnd = nNewLength;
	if(smp.nSustainStart > nNewLength)
	{
		smp.nSustainStart = smp.nSustainEnd = 0;
		smp.uFlags.reset(CHN_SUSTAINLOOP);
	}
	if(smp.nSustainEnd > nNewLength) smp.nSustainEnd = nNewLength;

	PrecomputeLoops(smp, sndFile);

	return smp.nLength;
}
Ejemplo n.º 5
0
bool PrecomputeLoops(ModSample &smp, CSoundFile &sndFile, bool updateChannels)
//----------------------------------------------------------------------------
{
	if(smp.nLength == 0 || smp.pSample == nullptr)
		return false;

	smp.SanitizeLoops();

	// Update channels with possibly changed loop values
	if(updateChannels)
	{
		UpdateLoopPoints(smp, sndFile);
	}

	if(smp.GetElementarySampleSize() == 2)
		PrecomputeLoopsImpl<int16>(smp, sndFile);
	else if(smp.GetElementarySampleSize() == 1)
		PrecomputeLoopsImpl<int8>(smp, sndFile);

	return true;
}
Ejemplo n.º 6
0
// Convert an S3M sample header to OpenMPT's internal sample header.
void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp) const
//---------------------------------------------------------
{
	mptSmp.Initialize(MOD_TYPE_S3M);
	mpt::String::Read<mpt::String::maybeNullTerminated>(mptSmp.filename, filename);

	if((sampleType == typePCM || sampleType == typeNone) && !memcmp(magic, "SCRS", 4))
	{
		// Sample Length and Loops
		if(sampleType == typePCM)
		{
			mptSmp.nLength = length;
			mptSmp.nLoopStart = MIN(loopStart, mptSmp.nLength - 1);
			mptSmp.nLoopEnd = MIN(loopEnd, mptSmp.nLength);
			mptSmp.uFlags.set(CHN_LOOP, (flags & smpLoop) != 0);
		}

		if(mptSmp.nLoopEnd < 2 || mptSmp.nLoopStart >= mptSmp.nLoopEnd || mptSmp.nLoopEnd - mptSmp.nLoopStart < 1)
		{
			mptSmp.nLoopStart = mptSmp.nLoopEnd = 0;
			mptSmp.uFlags.reset();
		}

		// Volume / Panning
		mptSmp.nVolume = MIN(defaultVolume, 64) * 4;

		// C-5 frequency
		mptSmp.nC5Speed = c5speed;
		if(mptSmp.nC5Speed == 0)
		{
			mptSmp.nC5Speed = 8363;
		} else if(mptSmp.nC5Speed < 1024)
		{
			mptSmp.nC5Speed = 1024;
		}
	}
}
Ejemplo n.º 7
0
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;
		}
Ejemplo n.º 8
0
bool ModModule::load(Stream* stream, int loadMode)
{
    noConstMetaInfo().filename = stream->name();
    setTempo(125);
    setSpeed(6);
    state().globalVolume = 0x40;
    char modName[20];
    stream->read(modName, 20);
    noConstMetaInfo().title = stringncpy(modName, 20);
    const IdMetaInfo* meta = nullptr;
    if(loadMode != LoadingMode::Smp15)
    {
        // check 31-sample mod
        logger()->info(L4CXX_LOCATION, "Probing meta-info for 31-sample mod...");
        stream->seek(0x438);
        meta = findMeta(stream);
        if(meta == nullptr)
        {
            logger()->warn(L4CXX_LOCATION, "Could not find a valid module ID");
            return false;
        }
    }
    else
    {
        logger()->info(L4CXX_LOCATION, "Trying to load 15-sample mod...");
        meta = &smp15MetaInfo;
    }
    logger()->debug(L4CXX_LOCATION, "%d-channel, ID '%s', Tracker '%s'", int(meta->channels), meta->id, meta->tracker);
    noConstMetaInfo().trackerInfo = meta->tracker;
    for(int i = 0; i < meta->channels; i++)
    {
        m_channels.emplace_back(new ModChannel(this, ((i + 1) & 2) == 0));
    }
    stream->seek(20);
    const int numSamples = loadMode == LoadingMode::Smp15 ? 15 : 31;
    for(int i = 0; i < numSamples; i++)
    {
        ModSample* smp = new ModSample();
        m_samples.push_back(smp);
        if(!smp->loadHeader(stream))
        {
            logger()->warn(L4CXX_LOCATION, "Sample header could not be loaded");
            return false;
        }
    }
    uint8_t maxPatNum = 0;
    {
        // load orders
        uint8_t songLen;
        *stream >> songLen;
        if(songLen > 128)
        {
            songLen = 128;
        }
        logger()->debug(L4CXX_LOCATION, "Song length: %d", int(songLen));
        uint8_t tmp;
        *stream >> tmp; // skip the restart pos
        for(uint_fast8_t i = 0; i < songLen; i++)
        {
            *stream >> tmp;
            if(tmp >= 64)
            {
                continue;
            }
            if(tmp > maxPatNum)
            {
                maxPatNum = tmp;
            }
            logger()->trace(L4CXX_LOCATION, "Order %d index: %d", int(i), int(tmp));
            addOrder(std::make_unique<OrderEntry>(tmp));
        }
        if(loadMode != LoadingMode::Smp31Malformed)
        {
            while(songLen++ < 128)
            {
                *stream >> tmp;
                if(tmp >= 64)
                {
                    continue;
                }
                if(tmp > maxPatNum)
                {
                    maxPatNum = tmp;
                }
            }
        }
        else
        {
            stream->seekrel(128 - songLen);
        }
    }
Ejemplo n.º 9
0
// Remove DC offset
float RemoveDCOffset(ModSample &smp,
					 SmpLength iStart,
					 SmpLength iEnd,
					 const MODTYPE modtype,
					 CSoundFile &sndFile)
//---------------------------------------
{
	if(smp.pSample == nullptr || smp.nLength < 1)
		return 0;

	if (iEnd > smp.nLength) iEnd = smp.nLength;
	if (iStart > iEnd) iStart = iEnd;
	if (iStart == iEnd)
	{
		iStart = 0;
		iEnd = smp.nLength;
	}

	iStart *= smp.GetNumChannels();
	iEnd *= smp.GetNumChannels();

	const double dMaxAmplitude = (smp.GetElementarySampleSize() == 2) ? GetMaxAmplitude<int16>() : GetMaxAmplitude<int8>();

	// step 1: Calculate offset.
	OffsetData oData = {0,0,0};
	if(smp.GetElementarySampleSize() == 2)
		oData = CalculateOffset(static_cast<int16 *>(smp.pSample) + iStart, iEnd - iStart);
	else if(smp.GetElementarySampleSize() == 1)
		oData = CalculateOffset(static_cast<int8*>(smp.pSample) + iStart, iEnd - iStart);

	double dMin = oData.dMin, dMax = oData.dMax, dOffset = oData.dOffset;

	const float fReportOffset = (float)dOffset;

	if((int)(dOffset * dMaxAmplitude) == 0)
		return 0;

	// those will be changed...
	dMax += dOffset;
	dMin += dOffset;

	// ... and that might cause distortion, so we will normalize this.
	const double dAmplify = 1 / MAX(dMax, -dMin);

	// step 2: centralize + normalize sample
	dOffset *= dMaxAmplitude * dAmplify;
	if(smp.GetElementarySampleSize() == 2)
		RemoveOffsetAndNormalize( static_cast<int16 *>(smp.pSample) + iStart, iEnd - iStart, dOffset, dAmplify);
	else if(smp.GetElementarySampleSize() == 1)
		RemoveOffsetAndNormalize( static_cast<int8 *>(smp.pSample) + iStart, iEnd - iStart, dOffset, dAmplify);

	// step 3: adjust global vol (if available)
	if((modtype & (MOD_TYPE_IT | MOD_TYPE_MPT)) && (iStart == 0) && (iEnd == smp.nLength * smp.GetNumChannels()))
	{
		CriticalSection cs;

		smp.nGlobalVol = std::min((uint16)(smp.nGlobalVol / dAmplify), uint16(64));
		for (CHANNELINDEX i = 0; i < MAX_CHANNELS; i++)
		{
			if(sndFile.m_PlayState.Chn[i].pModSample == &smp)
			{
				sndFile.m_PlayState.Chn[i].nInsVol = smp.nGlobalVol;
				if(sndFile.m_PlayState.Chn[i].pModInstrument)
				{
					sndFile.m_PlayState.Chn[i].nInsVol = (smp.nGlobalVol * sndFile.m_PlayState.Chn[i].pModInstrument->nGlobalVol) >> 6;
				}
			}