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 }