1 /** 2 * Write support for the RIFF file format (used in .wav files). 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.sound.riff.writer; 15 16 import std.algorithm; 17 import std.conv; 18 import std.range; 19 20 import ae.utils.sound.riff.common; 21 import ae.utils.array : staticArray; 22 23 struct ValueReprRange(T) 24 { 25 ubyte[T.sizeof] bytes; 26 size_t p; 27 28 this(ref T t) 29 { 30 bytes[] = (cast(ubyte[])((&t)[0..1]))[]; 31 } 32 33 @property ubyte front() { return bytes[p]; } 34 void popFront() { p++; } 35 @property bool empty() { return p == T.sizeof; } 36 @property size_t length() { return T.sizeof - p; } 37 } 38 39 auto valueReprRange(T)(auto ref T t) { return ValueReprRange!T(t); } 40 41 auto fourCC(char[4] name) 42 { 43 return valueReprRange(name); 44 } 45 46 auto riffChunk(R)(char[4] name, R data) 47 { 48 return chain( 49 fourCC(name), 50 valueReprRange(data.length.to!uint), 51 data 52 ); 53 } 54 55 auto makeRiff(R)(R r, uint sampleRate = 44100) 56 { 57 alias Sample = typeof(r.front); 58 static if (!is(Sample C : C[channels_], size_t channels_)) 59 return makeRiff(r.map!(s => [s].staticArray), sampleRate); 60 else 61 { 62 enum numChannels = r.front.length; 63 auto bytesPerSample = r.front[0].sizeof; 64 auto bitsPerSample = bytesPerSample * 8; 65 66 return riffChunk("RIFF", 67 chain( 68 fourCC("WAVE"), 69 riffChunk("fmt ", 70 valueReprRange(WaveFmt( 71 1, // PCM 72 to!ushort(numChannels), 73 sampleRate, 74 to!uint (sampleRate * bytesPerSample * numChannels), 75 to!ushort(bytesPerSample * numChannels), 76 to!ushort(bitsPerSample), 77 )), 78 ), 79 riffChunk("data", 80 r.map!(s => valueReprRange(s)).joiner.takeExactly(r.length * r.front.sizeof), 81 ), 82 ), 83 ); 84 } 85 }