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