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 <ae@cy.md> 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 /// 26 version(LittleEndian) 27 enum aSoundEndianness = "_LE"; 28 else 29 enum aSoundEndianness = "_BE"; 30 31 /// 32 static if (is(T==ubyte)) 33 enum aSoundFormat = "U8"; 34 else 35 static if (is(T==byte)) 36 enum aSoundFormat = "S8"; 37 else 38 static if (is(T==ushort)) 39 enum aSoundFormat = "U16" ~ aSoundEndianness; 40 else 41 static if (is(T==short)) 42 enum aSoundFormat = "S16" ~ aSoundEndianness; 43 else 44 static if (is(T==uint)) 45 enum aSoundFormat = "U32" ~ aSoundEndianness; 46 else 47 static if (is(T==int)) 48 enum aSoundFormat = "S32" ~ aSoundEndianness; 49 else 50 static if (is(T==float)) 51 enum aSoundFormat = "FLOAT" ~ aSoundEndianness; 52 else 53 static if (is(T==double)) 54 enum aSoundFormat = "FLOAT64" ~ aSoundEndianness; 55 else 56 static assert(false, "Can't represent sample type in asound format: " ~ T.stringof); 57 } 58 59 /// Play a wave (range of samples) using `aplay`. 60 void playWave(Wave)(Wave wave, int sampleRate = 44100) 61 { 62 alias Sample = typeof(wave.front); 63 static if (is(Sample C : C[channels_], size_t channels_)) 64 { 65 alias ChannelSample = C; 66 enum channels = channels_; 67 } 68 else 69 { 70 alias ChannelSample = Sample; 71 enum channels = 1; 72 } 73 auto p = pipe(); 74 auto pid = spawnProcess([ 75 "aplay", 76 "--format", aSoundFormat!ChannelSample, 77 "--channels", text(channels), 78 "--rate", text(sampleRate), 79 ], p.readEnd()); 80 while (!wave.empty) 81 { 82 Sample[1] s; 83 s[0] = wave.front; 84 wave.popFront(); 85 p.writeEnd.rawWrite(s[]); 86 } 87 p.writeEnd.close(); 88 enforce(pid.wait() == 0, "aplay failed"); 89 } 90 91 unittest 92 { 93 if (false) 94 playWave(iota(100)); 95 }