1 /**
2  * Some simple wave generator functions.
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 <ae@cy.md>
12  */
13 
14 module ae.utils.sound.wave;
15 
16 import std.algorithm;
17 import std.conv;
18 import std.math;
19 import std.range;
20 
21 import ae.utils.math;
22 import ae.utils.range;
23 
24 enum sampleMax(T) = is(T : long) ? T.max : T(1);
25 
26 /// Simple wave generator.
27 auto squareWave(T)(real interval)
28 {
29 	return infiniteIota!size_t
30 		.map!(n => cast(T)(sampleMax!T + cast(int)(n * 2 / interval) % 2));
31 }
32 
33 /// ditto
34 auto sawToothWave(T)(real interval)
35 {
36 	return infiniteIota!size_t
37 		.map!(n => cast(T)((n % interval * 2 - interval) * sampleMax!T / interval));
38 }
39 
40 /// ditto
41 auto triangleWave(T)(real interval)
42 {
43 	return infiniteIota!size_t
44 		.map!(n => cast(T)((abs(n % interval * 2 - interval) * 2 - interval) * sampleMax!T / interval));
45 }
46 
47 /// ditto
48 auto sineWave(T)(real interval)
49 {
50 	return infiniteIota!size_t
51 		.map!(n => (sin(n * 2 * PI / interval) * sampleMax!T).to!T);
52 }
53 
54 /// ditto
55 auto whiteNoise(T)()
56 {
57 	import std.random;
58 	return infiniteIota!size_t
59 		.map!(n => cast(T)Xorshift(cast(uint)n).front);
60 }
61 
62 /// ditto
63 auto whiteNoiseSqr(T)()
64 {
65 	import std.random;
66 	return infiniteIota!size_t
67 		.map!(n => Xorshift(cast(uint)n).front % 2 ? sampleMax!T : T.min);
68 }
69 
70 /// Fade out this wave (multiply samples by a linearly descending factor).
71 auto fade(W)(W w)
72 {
73 	alias T = typeof(w.front);
74 	sizediff_t dur = w.length;
75 	return dur.iota.map!(p => cast(T)(w[p] * (dur-p) / dur));
76 }
77 
78 /// Stretch a wave with linear interpolation.
79 auto stretch(W)(W wave, real factor)
80 {
81 	static if (is(typeof(wave.length)))
82 	{
83 		auto length = cast(size_t)(wave.length * factor);
84 		auto baseRange = length.iota;
85 	}
86 	else
87 		auto baseRange = infiniteIota!size_t;
88 	return baseRange
89 		.map!((n) {
90 				auto p = n / factor;
91 				auto ip = cast(size_t)p;
92 				return cast(typeof(wave.front))itpl(wave[ip], wave[ip+1], p, ip, ip+1);
93 		});
94 }