aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/soundlib/ModSample.h
blob: 07a2e1f4a85cbb8ea224f295caef49220919d8de (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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * ModSample.h
 * -----------
 * Purpose: Module Sample header class and helpers
 * Notes  : (currently none)
 * Authors: OpenMPT Devs
 * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
 */


#pragma once

#include "openmpt/all/BuildSettings.hpp"

OPENMPT_NAMESPACE_BEGIN

class CSoundFile;

// Sample Struct
struct ModSample
{
	SmpLength nLength;						// In frames
	SmpLength nLoopStart, nLoopEnd;			// Ditto
	SmpLength nSustainStart, nSustainEnd;	// Ditto
	union
	{
		void  *pSample;						// Pointer to sample data
		int8  *pSample8;					// Pointer to 8-bit sample data
		int16 *pSample16;					// Pointer to 16-bit sample data
	} pData;
	uint32 nC5Speed;						// Frequency of middle-C, in Hz (for IT/S3M/MPTM)
	uint16 nPan;							// Default sample panning (if pan flag is set), 0...256
	uint16 nVolume;							// Default volume, 0...256 (ignored if uFlags[SMP_NODEFAULTVOLUME] is set)
	uint16 nGlobalVol;						// Global volume (sample volume is multiplied by this), 0...64
	SampleFlags uFlags;						// Sample flags (see ChannelFlags enum)
	int8   RelativeTone;					// Relative note to middle c (for MOD/XM)
	int8   nFineTune;						// Finetune period (for MOD/XM), -128...127, unit is 1/128th of a semitone
	VibratoType nVibType;					// Auto vibrato type
	uint8  nVibSweep;						// Auto vibrato sweep (i.e. how long it takes until the vibrato effect reaches its full depth)
	uint8  nVibDepth;						// Auto vibrato depth
	uint8  nVibRate;						// Auto vibrato rate (speed)
	uint8  rootNote;						// For multisample import

	//char name[MAX_SAMPLENAME];			// Maybe it would be nicer to have sample names here, but that would require some refactoring.
	mpt::charbuf<MAX_SAMPLEFILENAME> filename;
	std::string GetFilename() const { return filename; }

	union
	{
		std::array<SmpLength, 9> cues;
		OPLPatch adlib;
	};

	ModSample(MODTYPE type = MOD_TYPE_NONE)
	{
		pData.pSample = nullptr;
		Initialize(type);
	}

	bool HasSampleData() const noexcept
	{
		MPT_ASSERT(!pData.pSample || (pData.pSample && nLength > 0));  // having sample pointer implies non-zero sample length
		return pData.pSample != nullptr && nLength != 0;
	}

	MPT_FORCEINLINE const void *samplev() const noexcept
	{
		return pData.pSample;
	}
	MPT_FORCEINLINE void *samplev() noexcept
	{
		return pData.pSample;
	}
	MPT_FORCEINLINE const std::byte *sampleb() const noexcept
	{
		return mpt::void_cast<const std::byte*>(pData.pSample);
	}
	MPT_FORCEINLINE std::byte *sampleb() noexcept
	{
		return mpt::void_cast<std::byte*>(pData.pSample);
	}
	MPT_FORCEINLINE const int8 *sample8() const noexcept
	{
		MPT_ASSERT(GetElementarySampleSize() == sizeof(int8));
		return pData.pSample8;
	}
	MPT_FORCEINLINE int8 *sample8() noexcept
	{
		MPT_ASSERT(GetElementarySampleSize() == sizeof(int8));
		return pData.pSample8;
	}
	MPT_FORCEINLINE const int16 *sample16() const noexcept
	{
		MPT_ASSERT(GetElementarySampleSize() == sizeof(int16));
		return pData.pSample16;
	}
	MPT_FORCEINLINE int16 *sample16() noexcept
	{
		MPT_ASSERT(GetElementarySampleSize() == sizeof(int16));
		return pData.pSample16;
	}

	// Return the size of one (elementary) sample in bytes.
	uint8 GetElementarySampleSize() const noexcept { return (uFlags & CHN_16BIT) ? 2 : 1; }

	// Return the number of channels in the sample.
	uint8 GetNumChannels() const noexcept { return (uFlags & CHN_STEREO) ? 2 : 1; }

	// Return the number of bytes per frame (Channels * Elementary Sample Size)
	uint8 GetBytesPerSample() const noexcept { return GetElementarySampleSize() * GetNumChannels(); }

	// Return the size which pSample is at least.
	SmpLength GetSampleSizeInBytes() const noexcept { return nLength * GetBytesPerSample(); }

	// Returns sample rate of the sample. The argument is needed because
	// the sample rate is obtained differently for different module types.
	uint32 GetSampleRate(const MODTYPE type) const;

	// Translate sample properties between two given formats.
	void Convert(MODTYPE fromType, MODTYPE toType);

	// Initialize sample slot with default values.
	void Initialize(MODTYPE type = MOD_TYPE_NONE);

	// Copies sample data from another sample slot and ensures that the 16-bit/stereo flags are set accordingly.
	bool CopyWaveform(const ModSample &smpFrom);

	// Allocate sample based on a ModSample's properties.
	// Returns number of bytes allocated, 0 on failure.
	size_t AllocateSample();
	// Allocate sample memory. On sucess, a pointer to the silenced sample buffer is returned. On failure, nullptr is returned.
	static void *AllocateSample(SmpLength numFrames, size_t bytesPerSample);
	// Compute sample buffer size in bytes, including any overhead introduced by pre-computed loops and such. Returns 0 if sample is too big.
	static size_t GetRealSampleBufferSize(SmpLength numSamples, size_t bytesPerSample);

	void FreeSample();
	static void FreeSample(void *samplePtr);

	// Set loop points and update loop wrap-around buffer
	void SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile);
	// Set sustain loop points and update loop wrap-around buffer
	void SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile);
	// Update loop wrap-around buffer
	void PrecomputeLoops(CSoundFile &sndFile, bool updateChannels = true);

	constexpr bool HasLoop() const noexcept { return uFlags[CHN_LOOP] && nLoopEnd > nLoopStart; }
	constexpr bool HasSustainLoop() const noexcept { return uFlags[CHN_SUSTAINLOOP] && nSustainEnd > nSustainStart; }
	constexpr bool HasPingPongLoop() const noexcept { return uFlags.test_all(CHN_LOOP | CHN_PINGPONGLOOP) && nLoopEnd > nLoopStart; }
	constexpr bool HasPingPongSustainLoop() const noexcept { return uFlags.test_all(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN) && nSustainEnd > nSustainStart; }

	// Remove loop points if they're invalid.
	void SanitizeLoops();

	// Transpose <-> Frequency conversions
	static uint32 TransposeToFrequency(int transpose, int finetune = 0);
	void TransposeToFrequency();
	static std::pair<int8, int8> FrequencyToTranspose(uint32 freq);
	void FrequencyToTranspose();

	// Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up)
	void Transpose(double amount);

	// Check if the sample has any valid cue points
	bool HasAnyCuePoints() const;
	// Check if the sample's cue points are the default cue point set.
	bool HasCustomCuePoints() const;
	void SetDefaultCuePoints();
	// Set cue points so that they are suitable for regular offset command extension
	void Set16BitCuePoints();
	void RemoveAllCuePoints();

	void SetAdlib(bool enable, OPLPatch patch = OPLPatch{{}});
};

OPENMPT_NAMESPACE_END