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