1 /** 2 * ae.ui.audio.mixer.software 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.ui.audio.mixer.software; 15 16 import std.algorithm.mutation; 17 18 import ae.ui.audio.mixer.base; 19 import ae.ui.audio.source.base; 20 21 class SoftwareMixer : Mixer 22 { 23 struct Stream 24 { 25 SoundSource source; 26 size_t pos; 27 } 28 Stream[] streams; 29 30 override void playSound(SoundSource sound) 31 { 32 // Note: sounds will begin to play on the next sound frame 33 // (fillBuffer invocation), so any two sounds' start time will 34 // always be a multiple of the buffer length apart. 35 streams ~= Stream(sound, 0); 36 37 // TODO: check sample rate 38 } 39 40 // Temporary storage of procedural streams 41 private SoundSample[] streamBuffer; 42 43 // TODO: multiple channels 44 override void fillBuffer(SoundSample[] buffer) nothrow 45 { 46 buffer[] = 0; 47 48 foreach_reverse (i, ref stream; streams) 49 { 50 foreach (channel; 0..1) 51 { 52 const(SoundSample)[] samples; 53 if (stream.source.procedural) 54 { 55 if (streamBuffer.length < buffer.length) 56 streamBuffer.length = buffer.length; 57 auto copiedSamples = stream.source.copySamples(channel, stream.pos, streamBuffer); 58 samples = streamBuffer[0..copiedSamples]; 59 } 60 else 61 samples = stream.source.getSamples(channel, stream.pos, buffer.length); 62 63 buffer[0..samples.length] += samples[]; // Fast vector math! 64 65 if (samples.length < buffer.length) // EOF? 66 streams = streams.remove(i); 67 } 68 stream.pos += buffer.length; 69 } 70 } 71 }