WAVTools.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. * WAVTools.h
  3. * ----------
  4. * Purpose: Definition of WAV file structures and helper functions
  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. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "mpt/uuid/uuid.hpp"
  12. #include "../common/FileReader.h"
  13. #include "Loaders.h"
  14. #ifndef MODPLUG_NO_FILESAVE
  15. #include "mpt/io/io.hpp"
  16. #include "mpt/io/io_virtual_wrapper.hpp"
  17. #endif
  18. OPENMPT_NAMESPACE_BEGIN
  19. struct FileTags;
  20. // RIFF header
  21. struct RIFFHeader
  22. {
  23. // 32-Bit chunk identifiers
  24. enum RIFFMagic
  25. {
  26. idRIFF = MagicLE("RIFF"), // magic for WAV files
  27. idLIST = MagicLE("LIST"), // magic for samples in DLS banks
  28. idWAVE = MagicLE("WAVE"), // type for WAV files
  29. idwave = MagicLE("wave"), // type for samples in DLS banks
  30. };
  31. uint32le magic; // RIFF (in WAV files) or LIST (in DLS banks)
  32. uint32le length; // Size of the file, not including magic and length
  33. uint32le type; // WAVE (in WAV files) or wave (in DLS banks)
  34. };
  35. MPT_BINARY_STRUCT(RIFFHeader, 12)
  36. // General RIFF Chunk header
  37. struct RIFFChunk
  38. {
  39. // 32-Bit chunk identifiers
  40. enum ChunkIdentifiers
  41. {
  42. idfmt_ = MagicLE("fmt "), // Sample format information
  43. iddata = MagicLE("data"), // Sample data
  44. idpcm_ = MagicLE("pcm "), // IMA ADPCM samples
  45. idfact = MagicLE("fact"), // Compressed samples
  46. idsmpl = MagicLE("smpl"), // Sampler and loop information
  47. idinst = MagicLE("inst"), // Instrument information
  48. idLIST = MagicLE("LIST"), // List of chunks
  49. idxtra = MagicLE("xtra"), // OpenMPT extra infomration
  50. idcue_ = MagicLE("cue "), // Cue points
  51. idwsmp = MagicLE("wsmp"), // DLS bank samples
  52. idCSET = MagicLE("CSET"), // Character Set
  53. id____ = 0x00000000, // Found when loading buggy MPT samples
  54. // Identifiers in "LIST" chunk
  55. idINAM = MagicLE("INAM"), // title
  56. idISFT = MagicLE("ISFT"), // software
  57. idICOP = MagicLE("ICOP"), // copyright
  58. idIART = MagicLE("IART"), // artist
  59. idIPRD = MagicLE("IPRD"), // product (album)
  60. idICMT = MagicLE("ICMT"), // comment
  61. idIENG = MagicLE("IENG"), // engineer
  62. idISBJ = MagicLE("ISBJ"), // subject
  63. idIGNR = MagicLE("IGNR"), // genre
  64. idICRD = MagicLE("ICRD"), // date created
  65. idYEAR = MagicLE("YEAR"), // year
  66. idTRCK = MagicLE("TRCK"), // track number
  67. idTURL = MagicLE("TURL"), // url
  68. };
  69. uint32le id; // See ChunkIdentifiers
  70. uint32le length; // Chunk size without header
  71. size_t GetLength() const
  72. {
  73. return length;
  74. }
  75. ChunkIdentifiers GetID() const
  76. {
  77. return static_cast<ChunkIdentifiers>(id.get());
  78. }
  79. };
  80. MPT_BINARY_STRUCT(RIFFChunk, 8)
  81. // Format Chunk
  82. struct WAVFormatChunk
  83. {
  84. // Sample formats
  85. enum SampleFormats
  86. {
  87. fmtPCM = 1,
  88. fmtFloat = 3,
  89. fmtALaw = 6,
  90. fmtULaw = 7,
  91. fmtIMA_ADPCM = 17,
  92. fmtMP3 = 85,
  93. fmtExtensible = 0xFFFE,
  94. };
  95. uint16le format; // Sample format, see SampleFormats
  96. uint16le numChannels; // Number of audio channels
  97. uint32le sampleRate; // Sample rate in Hz
  98. uint32le byteRate; // Bytes per second (should be freqHz * blockAlign)
  99. uint16le blockAlign; // Size of a sample, in bytes (do not trust this value, it's incorrect in some files)
  100. uint16le bitsPerSample; // Bits per sample
  101. };
  102. MPT_BINARY_STRUCT(WAVFormatChunk, 16)
  103. // Extension of the WAVFormatChunk structure, used if format == formatExtensible
  104. struct WAVFormatChunkExtension
  105. {
  106. uint16le size;
  107. uint16le validBitsPerSample;
  108. uint32le channelMask;
  109. mpt::GUIDms subFormat;
  110. };
  111. MPT_BINARY_STRUCT(WAVFormatChunkExtension, 24)
  112. // Sample information chunk
  113. struct WAVSampleInfoChunk
  114. {
  115. uint32le manufacturer;
  116. uint32le product;
  117. uint32le samplePeriod; // 1000000000 / sampleRate
  118. uint32le baseNote; // MIDI base note of sample
  119. uint32le pitchFraction;
  120. uint32le SMPTEFormat;
  121. uint32le SMPTEOffset;
  122. uint32le numLoops; // number of loops
  123. uint32le samplerData;
  124. // Set up information
  125. void ConvertToWAV(uint32 freq, uint8 rootNote)
  126. {
  127. manufacturer = 0;
  128. product = 0;
  129. samplePeriod = 1000000000 / freq;
  130. if(rootNote != 0)
  131. baseNote = rootNote - NOTE_MIN;
  132. else
  133. baseNote = NOTE_MIDDLEC - NOTE_MIN;
  134. pitchFraction = 0;
  135. SMPTEFormat = 0;
  136. SMPTEOffset = 0;
  137. numLoops = 0;
  138. samplerData = 0;
  139. }
  140. };
  141. MPT_BINARY_STRUCT(WAVSampleInfoChunk, 36)
  142. // Sample loop information chunk (found after WAVSampleInfoChunk in "smpl" chunk)
  143. struct WAVSampleLoop
  144. {
  145. // Sample Loop Types
  146. enum LoopType
  147. {
  148. loopForward = 0,
  149. loopBidi = 1,
  150. loopBackward = 2,
  151. };
  152. uint32le identifier;
  153. uint32le loopType; // See LoopType
  154. uint32le loopStart; // Loop start in samples
  155. uint32le loopEnd; // Loop end in samples
  156. uint32le fraction;
  157. uint32le playCount; // Loop Count, 0 = infinite
  158. // Apply WAV loop information to a mod sample.
  159. void ApplyToSample(SmpLength &start, SmpLength &end, SmpLength sampleLength, SampleFlags &flags, ChannelFlags enableFlag, ChannelFlags bidiFlag, bool mptLoopFix) const;
  160. // Convert internal loop information into a WAV loop.
  161. void ConvertToWAV(SmpLength start, SmpLength end, bool bidi);
  162. };
  163. MPT_BINARY_STRUCT(WAVSampleLoop, 24)
  164. // Instrument information chunk
  165. struct WAVInstrumentChunk
  166. {
  167. uint8 unshiftedNote; // Root key of sample, 0...127
  168. int8 finetune; // Finetune of root key in cents
  169. int8 gain; // in dB
  170. uint8 lowNote; // Note range, 0...127
  171. uint8 highNote;
  172. uint8 lowVelocity; // Velocity range, 0...127
  173. uint8 highVelocity;
  174. };
  175. MPT_BINARY_STRUCT(WAVInstrumentChunk, 7)
  176. // MPT-specific "xtra" chunk
  177. struct WAVExtraChunk
  178. {
  179. enum Flags
  180. {
  181. setPanning = 0x20,
  182. };
  183. uint32le flags;
  184. uint16le defaultPan;
  185. uint16le defaultVolume;
  186. uint16le globalVolume;
  187. uint16le reserved;
  188. uint8le vibratoType;
  189. uint8le vibratoSweep;
  190. uint8le vibratoDepth;
  191. uint8le vibratoRate;
  192. // Set up sample information
  193. void ConvertToWAV(const ModSample &sample, MODTYPE modType)
  194. {
  195. if(sample.uFlags[CHN_PANNING])
  196. {
  197. flags = WAVExtraChunk::setPanning;
  198. } else
  199. {
  200. flags = 0;
  201. }
  202. defaultPan = sample.nPan;
  203. defaultVolume = sample.nVolume;
  204. globalVolume = sample.nGlobalVol;
  205. vibratoType = sample.nVibType;
  206. vibratoSweep = sample.nVibSweep;
  207. vibratoDepth = sample.nVibDepth;
  208. vibratoRate = sample.nVibRate;
  209. if((modType & MOD_TYPE_XM) && (vibratoDepth | vibratoRate))
  210. {
  211. // XM vibrato is upside down
  212. vibratoSweep = 255 - vibratoSweep;
  213. }
  214. }
  215. };
  216. MPT_BINARY_STRUCT(WAVExtraChunk, 16)
  217. // Sample cue point structure for the "cue " chunk
  218. struct WAVCuePoint
  219. {
  220. uint32le id; // Unique identification value
  221. uint32le position; // Play order position
  222. uint32le riffChunkID; // RIFF ID of corresponding data chunk
  223. uint32le chunkStart; // Byte Offset of Data Chunk
  224. uint32le blockStart; // Byte Offset to sample of First Channel
  225. uint32le offset; // Byte Offset to sample byte of First Channel
  226. // Set up sample information
  227. void ConvertToWAV(uint32 id_, SmpLength offset_)
  228. {
  229. id = id_;
  230. position = offset_;
  231. riffChunkID = static_cast<uint32>(RIFFChunk::iddata);
  232. chunkStart = 0; // we use no Wave List Chunk (wavl) as we have only one data block, so this should be 0.
  233. blockStart = 0; // ditto
  234. offset = offset_;
  235. }
  236. };
  237. MPT_BINARY_STRUCT(WAVCuePoint, 24)
  238. class WAVReader
  239. {
  240. protected:
  241. FileReader file;
  242. FileReader sampleData, smplChunk, instChunk, xtraChunk, wsmpChunk, cueChunk;
  243. FileReader::ChunkList<RIFFChunk> infoChunk;
  244. FileReader::off_t sampleLength;
  245. WAVFormatChunk formatInfo;
  246. uint16 subFormat;
  247. uint16 codePage;
  248. bool isDLS;
  249. bool mayBeCoolEdit16_8;
  250. uint16 GetFileCodePage(FileReader::ChunkList<RIFFChunk> &chunks);
  251. public:
  252. WAVReader(FileReader &inputFile);
  253. bool IsValid() const { return sampleData.IsValid(); }
  254. void FindMetadataChunks(FileReader::ChunkList<RIFFChunk> &chunks);
  255. // Self-explanatory getters.
  256. WAVFormatChunk::SampleFormats GetSampleFormat() const { return IsExtensibleFormat() ? static_cast<WAVFormatChunk::SampleFormats>(subFormat) : static_cast<WAVFormatChunk::SampleFormats>(formatInfo.format.get()); }
  257. uint16 GetNumChannels() const { return formatInfo.numChannels; }
  258. uint16 GetBitsPerSample() const { return formatInfo.bitsPerSample; }
  259. uint32 GetSampleRate() const { return formatInfo.sampleRate; }
  260. uint16 GetBlockAlign() const { return formatInfo.blockAlign; }
  261. FileReader GetSampleData() const { return sampleData; }
  262. FileReader GetWsmpChunk() const { return wsmpChunk; }
  263. bool IsExtensibleFormat() const { return formatInfo.format == WAVFormatChunk::fmtExtensible; }
  264. bool MayBeCoolEdit16_8() const { return mayBeCoolEdit16_8; }
  265. // Get size of a single sample point, in bytes.
  266. uint16 GetSampleSize() const { return static_cast<uint16>(((static_cast<uint32>(GetNumChannels()) * static_cast<uint32>(GetBitsPerSample())) + 7) / 8); }
  267. // Get sample length (in samples)
  268. SmpLength GetSampleLength() const { return mpt::saturate_cast<SmpLength>(sampleLength); }
  269. // Apply sample settings from file (loop points, MPT extra settings, ...) to a sample.
  270. void ApplySampleSettings(ModSample &sample, mpt::Charset sampleCharset, mpt::charbuf<MAX_SAMPLENAME> &sampleName);
  271. };
  272. #ifndef MODPLUG_NO_FILESAVE
  273. class WAVWriter
  274. {
  275. protected:
  276. // Output stream
  277. mpt::IO::OFileBase &s;
  278. // Cursor position
  279. std::size_t position = 0;
  280. // Total number of bytes written to file / memory
  281. std::size_t totalSize = 0;
  282. // Currently written chunk
  283. std::size_t chunkStartPos = 0;
  284. RIFFChunk chunkHeader;
  285. bool finalized = false;
  286. public:
  287. // Output to stream
  288. WAVWriter(mpt::IO::OFileBase &stream);
  289. ~WAVWriter();
  290. // Finalize the file by closing the last open chunk and updating the file header. Returns total size of file.
  291. std::size_t Finalize();
  292. // Begin writing a new chunk to the file.
  293. void StartChunk(RIFFChunk::ChunkIdentifiers id);
  294. // Skip some bytes... For example after writing sample data.
  295. void Skip(size_t numBytes) { Seek(position + numBytes); }
  296. // Get position in file (not counting any changes done to the file from outside this class, i.e. through GetFile())
  297. std::size_t GetPosition() const { return position; }
  298. // Write some data to the file.
  299. template<typename T>
  300. void Write(const T &data)
  301. {
  302. Write(mpt::as_raw_memory(data));
  303. }
  304. // Write a buffer to the file.
  305. void Write(mpt::const_byte_span data);
  306. // Use before writing raw data directly to the underlying stream s
  307. void WriteBeforeDirect();
  308. // Use after writing raw data directly to the underlying stream s
  309. void WriteAfterDirect(bool success, std::size_t count);
  310. // Write the WAV format to the file.
  311. void WriteFormat(uint32 sampleRate, uint16 bitDepth, uint16 numChannels, WAVFormatChunk::SampleFormats encoding);
  312. // Write text tags to the file.
  313. void WriteMetatags(const FileTags &tags);
  314. // Write a sample loop information chunk to the file.
  315. void WriteLoopInformation(const ModSample &sample);
  316. // Write a sample's cue points to the file.
  317. void WriteCueInformation(const ModSample &sample);
  318. // Write MPT's sample information chunk to the file.
  319. void WriteExtraInformation(const ModSample &sample, MODTYPE modType, const char *sampleName = nullptr);
  320. protected:
  321. // Seek to a position in file.
  322. void Seek(std::size_t pos);
  323. // End current chunk by updating the chunk header and writing a padding byte if necessary.
  324. void FinalizeChunk();
  325. // Write a single tag into a open idLIST chunk
  326. void WriteTag(RIFFChunk::ChunkIdentifiers id, const mpt::ustring &utext);
  327. };
  328. #endif // MODPLUG_NO_FILESAVE
  329. OPENMPT_NAMESPACE_END