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 }