1 /** 2 * Copyright: Copyright Auburn Sounds 2016 3 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 4 * Authors: Guillaume Piolat 5 */ 6 module dplug.audio.sound; 7 8 9 /** 10 * This module defines the interfaces that describe a "sound". 11 * A sound is a multi-channel concept, that can be combined like input-range. 12 * Can represent a buffer, an audio processing block, a sound sample. 13 * For now they only deal with float. 14 */ 15 enum isSound(S) = true; // All Sound capabilities are optional! 16 17 18 /// Duration. 19 /// A sound can optionally have a duration. 20 template hasDuration(S) 21 { 22 enum bool hasDuration = is(typeof( 23 (inout int = 0) 24 { 25 S s = S.init; 26 int d = s.duration; 27 })); 28 } 29 30 /// Is this duration a static property? 31 template hasStaticDuration(S) 32 { 33 enum bool hasStaticDuration = hasDuration!S && __traits(compiles, int[S.duration]); 34 } 35 36 /// Is this duration a runtime property? 37 enum bool hasRuntimeDuration(S) = !hasStaticDuration!S; 38 39 unittest 40 { 41 struct Yes 42 { 43 enum duration = 128; 44 } 45 static assert(hasStaticDuration!Yes); 46 static assert(!hasRuntimeDuration!Yes); 47 48 struct No 49 { 50 int duration = 128; 51 } 52 static assert(!hasStaticDuration!No); 53 static assert(hasRuntimeDuration!Yes); 54 } 55 56 57 /// Number of channels. 58 // A sound can optionally have a duration field. 59 template hasDuration(S) 60 { 61 enum bool hasDuration = is(typeof( 62 (inout int = 0) 63 { 64 S s = S.init; 65 int d = s.duration; 66 })); 67 } 68 69 /// Is this duration a static property? 70 template hasStaticDuration(S) 71 { 72 enum bool hasStaticDuration = hasDuration!S && __traits(compiles, int[S.duration]); 73 } 74 75 /// Is this duration a runtime property? 76 enum bool hasRuntimeDuration(S) = !hasStaticDuration!S; 77 78 79 80 81 /// A Sound can optionally process sample with a `nextSample` function. 82 template hasProcessSample(S) 83 { 84 enum bool hasProcessSample = is(typeof(S.init.processSample)); 85 } 86 87 /// A Sound can optionally process sample with a `nextBuffer` function. 88 template hasProcessBuffer(S) 89 { 90 enum bool hasProcessBuffer = is(typeof(S.init.processSample)); 91 } 92 93 94 95 96 97 98 99 /+ 100 101 /// Renders the sound into an array slice. 102 void renderToSlice(S)(auto ref S sound, float[] outBuffer) if (isSound!S) 103 { 104 // Must be mono 105 static assert(sound.channels == 1); 106 107 // TODO: allow to render to static array if 108 static if (hasDuration!D) 109 assert(outBuffer.length == sound.duration); 110 111 static if (hasProcessSample) 112 113 } 114 115 float{ubyte[] toPNG(SRC)(auto ref SRC src) 116 if (isView!SRC) 117 { 118 119 120 enum isView(T) = 121 is(typeof(T.init.w) : size_t) && // width 122 is(typeof(T.init.h) : size_t) && // height 123 is(typeof(T.init[0, 0]) ); // color information 124 125 /// Returns the color type of the specified view. 126 /// By convention, colors are structs with numeric 127 /// fields named after the channel they indicate. 128 alias ViewColor(T) = typeof(T.init[0, 0]); 129 130 /// Views can be read-only or writable. 131 enum isWritableView(T) = 132 isView!T && 133 is(typeof(T.init[0, 0] = ViewColor!T.init)); 134 135 /// Optionally, a view can also provide direct pixel 136 /// access. We call these "direct views". 137 enum isDirectView(T) = 138 isView!T && 139 is(typeof(T.init.scanline(0)) : ViewColor!T[]); 140 141 +/