1 /* 2 * ModSample.h 3 * ----------- 4 * Purpose: Module Sample header class and helpers 5 * Notes : (currently none) 6 * Authors: OpenMPT Devs 7 * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. 8 */ 9 10 11 #pragma once 12 13 #include "openmpt/all/BuildSettings.hpp" 14 15 OPENMPT_NAMESPACE_BEGIN 16 17 class CSoundFile; 18 19 // Sample Struct 20 struct ModSample 21 { 22 SmpLength nLength; // In frames 23 SmpLength nLoopStart, nLoopEnd; // Ditto 24 SmpLength nSustainStart, nSustainEnd; // Ditto 25 union 26 { 27 void *pSample; // Pointer to sample data 28 int8 *pSample8; // Pointer to 8-bit sample data 29 int16 *pSample16; // Pointer to 16-bit sample data 30 } pData; 31 uint32 nC5Speed; // Frequency of middle-C, in Hz (for IT/S3M/MPTM) 32 uint16 nPan; // Default sample panning (if pan flag is set), 0...256 33 uint16 nVolume; // Default volume, 0...256 (ignored if uFlags[SMP_NODEFAULTVOLUME] is set) 34 uint16 nGlobalVol; // Global volume (sample volume is multiplied by this), 0...64 35 SampleFlags uFlags; // Sample flags (see ChannelFlags enum) 36 int8 RelativeTone; // Relative note to middle c (for MOD/XM) 37 int8 nFineTune; // Finetune period (for MOD/XM), -128...127, unit is 1/128th of a semitone 38 VibratoType nVibType; // Auto vibrato type 39 uint8 nVibSweep; // Auto vibrato sweep (i.e. how long it takes until the vibrato effect reaches its full depth) 40 uint8 nVibDepth; // Auto vibrato depth 41 uint8 nVibRate; // Auto vibrato rate (speed) 42 uint8 rootNote; // For multisample import 43 44 //char name[MAX_SAMPLENAME]; // Maybe it would be nicer to have sample names here, but that would require some refactoring. 45 mpt::charbuf<MAX_SAMPLEFILENAME> filename; GetFilenameModSample46 std::string GetFilename() const { return filename; } 47 48 union 49 { 50 std::array<SmpLength, 9> cues; 51 OPLPatch adlib; 52 }; 53 54 ModSample(MODTYPE type = MOD_TYPE_NONE) 55 { 56 pData.pSample = nullptr; 57 Initialize(type); 58 } 59 HasSampleDataModSample60 bool HasSampleData() const noexcept 61 { 62 MPT_ASSERT(!pData.pSample || (pData.pSample && nLength > 0)); // having sample pointer implies non-zero sample length 63 return pData.pSample != nullptr && nLength != 0; 64 } 65 samplevModSample66 MPT_FORCEINLINE const void *samplev() const noexcept 67 { 68 return pData.pSample; 69 } samplevModSample70 MPT_FORCEINLINE void *samplev() noexcept 71 { 72 return pData.pSample; 73 } samplebModSample74 MPT_FORCEINLINE const std::byte *sampleb() const noexcept 75 { 76 return mpt::void_cast<const std::byte*>(pData.pSample); 77 } samplebModSample78 MPT_FORCEINLINE std::byte *sampleb() noexcept 79 { 80 return mpt::void_cast<std::byte*>(pData.pSample); 81 } sample8ModSample82 MPT_FORCEINLINE const int8 *sample8() const noexcept 83 { 84 MPT_ASSERT(GetElementarySampleSize() == sizeof(int8)); 85 return pData.pSample8; 86 } sample8ModSample87 MPT_FORCEINLINE int8 *sample8() noexcept 88 { 89 MPT_ASSERT(GetElementarySampleSize() == sizeof(int8)); 90 return pData.pSample8; 91 } sample16ModSample92 MPT_FORCEINLINE const int16 *sample16() const noexcept 93 { 94 MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); 95 return pData.pSample16; 96 } sample16ModSample97 MPT_FORCEINLINE int16 *sample16() noexcept 98 { 99 MPT_ASSERT(GetElementarySampleSize() == sizeof(int16)); 100 return pData.pSample16; 101 } 102 103 // Return the size of one (elementary) sample in bytes. GetElementarySampleSizeModSample104 uint8 GetElementarySampleSize() const noexcept { return (uFlags & CHN_16BIT) ? 2 : 1; } 105 106 // Return the number of channels in the sample. GetNumChannelsModSample107 uint8 GetNumChannels() const noexcept { return (uFlags & CHN_STEREO) ? 2 : 1; } 108 109 // Return the number of bytes per frame (Channels * Elementary Sample Size) GetBytesPerSampleModSample110 uint8 GetBytesPerSample() const noexcept { return GetElementarySampleSize() * GetNumChannels(); } 111 112 // Return the size which pSample is at least. GetSampleSizeInBytesModSample113 SmpLength GetSampleSizeInBytes() const noexcept { return nLength * GetBytesPerSample(); } 114 115 // Returns sample rate of the sample. The argument is needed because 116 // the sample rate is obtained differently for different module types. 117 uint32 GetSampleRate(const MODTYPE type) const; 118 119 // Translate sample properties between two given formats. 120 void Convert(MODTYPE fromType, MODTYPE toType); 121 122 // Initialize sample slot with default values. 123 void Initialize(MODTYPE type = MOD_TYPE_NONE); 124 125 // Copies sample data from another sample slot and ensures that the 16-bit/stereo flags are set accordingly. 126 bool CopyWaveform(const ModSample &smpFrom); 127 128 // Allocate sample based on a ModSample's properties. 129 // Returns number of bytes allocated, 0 on failure. 130 size_t AllocateSample(); 131 // Allocate sample memory. On sucess, a pointer to the silenced sample buffer is returned. On failure, nullptr is returned. 132 static void *AllocateSample(SmpLength numFrames, size_t bytesPerSample); 133 // Compute sample buffer size in bytes, including any overhead introduced by pre-computed loops and such. Returns 0 if sample is too big. 134 static size_t GetRealSampleBufferSize(SmpLength numSamples, size_t bytesPerSample); 135 136 void FreeSample(); 137 static void FreeSample(void *samplePtr); 138 139 // Set loop points and update loop wrap-around buffer 140 void SetLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile); 141 // Set sustain loop points and update loop wrap-around buffer 142 void SetSustainLoop(SmpLength start, SmpLength end, bool enable, bool pingpong, CSoundFile &sndFile); 143 // Update loop wrap-around buffer 144 void PrecomputeLoops(CSoundFile &sndFile, bool updateChannels = true); 145 HasLoopModSample146 constexpr bool HasLoop() const noexcept { return uFlags[CHN_LOOP] && nLoopEnd > nLoopStart; } HasSustainLoopModSample147 constexpr bool HasSustainLoop() const noexcept { return uFlags[CHN_SUSTAINLOOP] && nSustainEnd > nSustainStart; } HasPingPongLoopModSample148 constexpr bool HasPingPongLoop() const noexcept { return uFlags.test_all(CHN_LOOP | CHN_PINGPONGLOOP) && nLoopEnd > nLoopStart; } HasPingPongSustainLoopModSample149 constexpr bool HasPingPongSustainLoop() const noexcept { return uFlags.test_all(CHN_SUSTAINLOOP | CHN_PINGPONGSUSTAIN) && nSustainEnd > nSustainStart; } 150 151 // Remove loop points if they're invalid. 152 void SanitizeLoops(); 153 154 // Transpose <-> Frequency conversions 155 static uint32 TransposeToFrequency(int transpose, int finetune = 0); 156 void TransposeToFrequency(); 157 static std::pair<int8, int8> FrequencyToTranspose(uint32 freq); 158 void FrequencyToTranspose(); 159 160 // Transpose the sample by amount specified in octaves (i.e. amount=1 transposes one octave up) 161 void Transpose(double amount); 162 163 // Check if the sample's cue points are the default cue point set. 164 bool HasCustomCuePoints() const; 165 void SetDefaultCuePoints(); 166 // Set cue points so that they are suitable for regular offset command extension 167 void Set16BitCuePoints(); 168 169 void SetAdlib(bool enable, OPLPatch patch = OPLPatch{{}}); 170 }; 171 172 OPENMPT_NAMESPACE_END 173