1 /**
2 * Play waves using ALSA command-line tools
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.asound;
15
16 import std.conv;
17 import std.exception;
18 import std.process;
19 import std.range;
20 import std.traits;
21
22 /// Return the ALSA format name corresponding to the given type.
23 template aSoundFormat(T)
24 {
25 version(LittleEndian)
26 enum aSoundEndianness = "_LE";
27 else
28 enum aSoundEndianness = "_BE";
29
30 static if (is(T==ubyte))
31 enum aSoundFormat = "U8";
32 else
33 static if (is(T==byte))
34 enum aSoundFormat = "S8";
35 else
36 static if (is(T==ushort))
37 enum aSoundFormat = "U16" ~ aSoundEndianness;
38 else
39 static if (is(T==short))
40 enum aSoundFormat = "S16" ~ aSoundEndianness;
41 else
42 static if (is(T==uint))
43 enum aSoundFormat = "U32" ~ aSoundEndianness;
44 else
45 static if (is(T==int))
46 enum aSoundFormat = "S32" ~ aSoundEndianness;
47 else
48 static if (is(T==float))
49 enum aSoundFormat = "FLOAT" ~ aSoundEndianness;
50 else
51 static if (is(T==double))
52 enum aSoundFormat = "FLOAT64" ~ aSoundEndianness;
53 else
54 static assert(false, "Can't represent sample type in asound format: " ~ T.stringof);
55 }
56
57 void playWave(Wave)(Wave wave, int sampleRate = 44100)
58 {
59 alias Sample = typeof(wave.front);
60 auto p = pipe();
61 auto pid = spawnProcess([
62 "aplay",
63 "--format", aSoundFormat!Sample,
64 "--rate", text(sampleRate),
65 ], p.readEnd());
66 while (!wave.empty)
67 {
68 Sample[1] s;
69 s[0] = wave.front;
70 wave.popFront();
71 p.writeEnd.rawWrite(s[]);
72 }
73 p.writeEnd.close();
74 enforce(pid.wait() == 0, "aplay failed");
75 }
76
77 unittest
78 {
79 if (false)
80 playWave(iota(100));
81 }