1 /*
2  * PluginMixBuffer.h
3  * -----------------
4  * Purpose: Helper class for managing plugin audio input and output buffers.
5  * Notes  : (currently none)
6  * Authors: OpenMPT Devs
7  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8  */
9 
10 
11 #pragma once
12 
13 #include "openmpt/all/BuildSettings.hpp"
14 
15 #include <algorithm>
16 #include <array>
17 
18 #if defined(MPT_ENABLE_ARCH_INTRINSICS) || defined(MPT_WITH_VST)
19 #include "mpt/base/aligned_array.hpp"
20 #endif // MPT_ENABLE_ARCH_INTRINSICS || MPT_WITH_VST
21 
22 
23 OPENMPT_NAMESPACE_BEGIN
24 
25 
26 // At least this part of the code is ready for double-precision rendering... :>
27 // buffer_t: Sample buffer type (float, double, ...)
28 // bufferSize: Buffer size in samples
29 template<typename buffer_t, uint32 bufferSize>
30 class PluginMixBuffer
31 {
32 
33 private:
34 
35 #if defined(MPT_ENABLE_ARCH_INTRINSICS) || defined(MPT_WITH_VST)
36 	static constexpr std::align_val_t alignment = std::align_val_t{16};
37 	static_assert(sizeof(mpt::aligned_array<buffer_t, bufferSize, alignment>) == sizeof(std::array<buffer_t, bufferSize>));
38 	static_assert(alignof(mpt::aligned_array<buffer_t, bufferSize, alignment>) == static_cast<std::size_t>(alignment));
39 #endif // MPT_ENABLE_ARCH_INTRINSICS || MPT_WITH_VST
40 
41 protected:
42 
43 #if defined(MPT_ENABLE_ARCH_INTRINSICS) || defined(MPT_WITH_VST)
44 	std::vector<mpt::aligned_array<buffer_t, bufferSize, alignment>> inputs;
45 	std::vector<mpt::aligned_array<buffer_t, bufferSize, alignment>> outputs;
46 #else // !(MPT_ENABLE_ARCH_INTRINSICS || MPT_WITH_VST)
47 	std::vector<std::array<buffer_t, bufferSize>> inputs;
48 	std::vector<std::array<buffer_t, bufferSize>> outputs;
49 #endif // MPT_ENABLE_ARCH_INTRINSICS || MPT_WITH_VST
50 	std::vector<buffer_t*> inputsarray;
51 	std::vector<buffer_t*> outputsarray;
52 
53 public:
54 
55 	// Allocate input and output buffers
Initialize(uint32 numInputs,uint32 numOutputs)56 	bool Initialize(uint32 numInputs, uint32 numOutputs)
57 	{
58 		// Short cut - we do not need to recreate the buffers.
59 		if(inputs.size() == numInputs && outputs.size() == numOutputs)
60 		{
61 			return true;
62 		}
63 
64 		try
65 		{
66 			inputs.resize(numInputs);
67 			outputs.resize(numOutputs);
68 			inputsarray.resize(numInputs);
69 			outputsarray.resize(numOutputs);
70 		} catch(mpt::out_of_memory e)
71 		{
72 			mpt::delete_out_of_memory(e);
73 			inputs.clear();
74 			inputs.shrink_to_fit();
75 			outputs.clear();
76 			outputs.shrink_to_fit();
77 			inputsarray.clear();
78 			inputsarray.shrink_to_fit();
79 			outputsarray.clear();
80 			outputsarray.shrink_to_fit();
81 			return false;
82 		}
83 
84 		for(uint32 i = 0; i < numInputs; i++)
85 		{
86 			inputsarray[i] = inputs[i].data();
87 		}
88 
89 		for(uint32 i = 0; i < numOutputs; i++)
90 		{
91 			outputsarray[i] = outputs[i].data();
92 		}
93 
94 		return true;
95 	}
96 
97 	// Silence all input buffers.
ClearInputBuffers(uint32 numSamples)98 	void ClearInputBuffers(uint32 numSamples)
99 	{
100 		MPT_ASSERT(numSamples <= bufferSize);
101 		for(size_t i = 0; i < inputs.size(); i++)
102 		{
103 			std::fill(inputs[i].data(), inputs[i].data() + numSamples, buffer_t{0});
104 		}
105 	}
106 
107 	// Silence all output buffers.
ClearOutputBuffers(uint32 numSamples)108 	void ClearOutputBuffers(uint32 numSamples)
109 	{
110 		MPT_ASSERT(numSamples <= bufferSize);
111 		for(size_t i = 0; i < outputs.size(); i++)
112 		{
113 			std::fill(outputs[i].data(), outputs[i].data() + numSamples, buffer_t{0});
114 		}
115 	}
116 
PluginMixBuffer()117 	PluginMixBuffer()
118 	{
119 		Initialize(2, 0);
120 	}
121 
122 	// Return pointer to a given input or output buffer
GetInputBuffer(uint32 index)123 	const buffer_t *GetInputBuffer(uint32 index) const { return inputs[index].data(); }
GetOutputBuffer(uint32 index)124 	const buffer_t *GetOutputBuffer(uint32 index) const { return outputs[index].data(); }
GetInputBuffer(uint32 index)125 	buffer_t *GetInputBuffer(uint32 index) { return inputs[index].data(); }
GetOutputBuffer(uint32 index)126 	buffer_t *GetOutputBuffer(uint32 index) { return outputs[index].data(); }
127 
128 	// Return pointer array to all input or output buffers
GetInputBufferArray()129 	buffer_t **GetInputBufferArray() { return inputs.empty() ? nullptr : inputsarray.data(); }
GetOutputBufferArray()130 	buffer_t **GetOutputBufferArray() { return outputs.empty() ? nullptr : outputsarray.data(); }
131 
Ok()132 	bool Ok() const { return (inputs.size() + outputs.size()) > 0; }
133 
134 };
135 
136 
137 OPENMPT_NAMESPACE_END
138