aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/soundlib/S3MTools.cpp
blob: 27be50867a8e6af9279a0101e7ce9fd3b5b22da5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * S3MTools.cpp
 * ------------
 * Purpose: Definition of S3M file structures and helper functions
 * Notes  : (currently none)
 * Authors: OpenMPT Devs
 * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
 */


#include "stdafx.h"
#include "Loaders.h"
#include "S3MTools.h"
#include "../common/mptStringBuffer.h"


OPENMPT_NAMESPACE_BEGIN

// Convert an S3M sample header to OpenMPT's internal sample header.
void S3MSampleHeader::ConvertToMPT(ModSample &mptSmp, bool isST3) const
{
	mptSmp.Initialize(MOD_TYPE_S3M);
	mptSmp.filename = mpt::String::ReadBuf(mpt::String::maybeNullTerminated, filename);

	if(sampleType == typePCM || sampleType == typeNone)
	{
		// Sample Length and Loops
		if(sampleType == typePCM)
		{
			mptSmp.nLength = length;
			mptSmp.nLoopStart = std::min(static_cast<SmpLength>(loopStart), mptSmp.nLength - 1);
			mptSmp.nLoopEnd = std::min(static_cast<SmpLength>(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();
		}
	} else if(sampleType == typeAdMel)
	{
		OPLPatch patch;
		std::memcpy(patch.data() + 0, mpt::as_raw_memory(length).data(), 4);
		std::memcpy(patch.data() + 4, mpt::as_raw_memory(loopStart).data(), 4);
		std::memcpy(patch.data() + 8, mpt::as_raw_memory(loopEnd).data(), 4);
		mptSmp.SetAdlib(true, patch);
	}

	// Volume / Panning
	mptSmp.nVolume = std::min(defaultVolume.get(), uint8(64)) * 4;

	// C-5 frequency
	mptSmp.nC5Speed = c5speed;
	if(isST3)
	{
		// ST3 ignores or clamps the high 16 bits depending on the instrument type
		if(sampleType == typeAdMel)
			mptSmp.nC5Speed &= 0xFFFF;
		else
			LimitMax(mptSmp.nC5Speed, uint16_max);
	}

	if(mptSmp.nC5Speed == 0)
		mptSmp.nC5Speed = 8363;
	else if(mptSmp.nC5Speed < 1024)
		mptSmp.nC5Speed = 1024;

}


// Convert OpenMPT's internal sample header to an S3M sample header.
SmpLength S3MSampleHeader::ConvertToS3M(const ModSample &mptSmp)
{
	SmpLength smpLength = 0;
	mpt::String::WriteBuf(mpt::String::maybeNullTerminated, filename) = mptSmp.filename;
	memcpy(magic, "SCRS", 4);

	if(mptSmp.uFlags[CHN_ADLIB])
	{
		memcpy(magic, "SCRI", 4);
		sampleType = typeAdMel;
		std::memcpy(mpt::as_raw_memory(length   ).data(), mptSmp.adlib.data() + 0, 4);
		std::memcpy(mpt::as_raw_memory(loopStart).data(), mptSmp.adlib.data() + 4, 4);
		std::memcpy(mpt::as_raw_memory(loopEnd  ).data(), mptSmp.adlib.data() + 8, 4);
	} else if(mptSmp.HasSampleData())
	{
		sampleType = typePCM;
		length = mpt::saturate_cast<uint32>(mptSmp.nLength);
		loopStart = mpt::saturate_cast<uint32>(mptSmp.nLoopStart);
		loopEnd = mpt::saturate_cast<uint32>(mptSmp.nLoopEnd);

		smpLength = length;

		flags = (mptSmp.uFlags[CHN_LOOP] ? smpLoop : 0);
		if(mptSmp.uFlags[CHN_16BIT])
		{
			flags |= smp16Bit;
		}
		if(mptSmp.uFlags[CHN_STEREO])
		{
			flags |= smpStereo;
		}
	} else
	{
		sampleType = typeNone;
	}

	defaultVolume = static_cast<uint8>(std::min(static_cast<uint16>(mptSmp.nVolume / 4), uint16(64)));
	if(mptSmp.nC5Speed != 0)
	{
		c5speed = mptSmp.nC5Speed;
	} else
	{
		c5speed = ModSample::TransposeToFrequency(mptSmp.RelativeTone, mptSmp.nFineTune);
	}

	return smpLength;
}


// 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);
	}
}


// Calculate the sample position in file
uint32 S3MSampleHeader::GetSampleOffset() const
{
	return (dataPointer[1] << 4) | (dataPointer[2] << 12) | (dataPointer[0] << 20);
}


OPENMPT_NAMESPACE_END