1 /*******************************************************************************
2 * Copyright 2015-2016 Juan Francisco Crespo Galán
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *   http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 ******************************************************************************/
16 
17 #pragma once
18 
19 /**
20 * @file BinauralReader.h
21 * @ingroup fx
22 * The BinauralReader class.
23 */
24 
25 #include "IReader.h"
26 #include "ISound.h"
27 #include "Convolver.h"
28 #include "HRTF.h"
29 #include "Source.h"
30 #include "util/FFTPlan.h"
31 #include "util/ThreadPool.h"
32 
33 #include <memory>
34 #include <vector>
35 #include <future>
36 
37 AUD_NAMESPACE_BEGIN
38 
39 /**
40 * This class represents a reader for a sound that can sound different depending on its realtive position with the listener.
41 */
42 class AUD_API BinauralReader : public IReader
43 {
44 private:
45 	/**
46 	* The current position.
47 	*/
48 	int m_position;
49 
50 	/**
51 	* The reader of the input sound.
52 	*/
53 	std::shared_ptr<IReader> m_reader;
54 
55 	/**
56 	* The HRTF set.
57 	*/
58 	std::shared_ptr<HRTF> m_hrtfs;
59 
60 	/**
61 	* A Source object that will be used to change the source position of the sound.
62 	*/
63 	std::shared_ptr<Source> m_source;
64 
65 	/**
66 	* The intended azimuth.
67 	*/
68 	float m_Azimuth;
69 
70 	/**
71 	* The intended elevation.
72 	*/
73 	float m_Elevation;
74 
75 	/**
76 	* The real azimuth being used.
77 	*/
78 	float m_RealAzimuth;
79 
80 	/**
81 	* The real elevation being used.
82 	*/
83 	float m_RealElevation;
84 
85 	/**
86 	* The FFT size, given by the FFTPlan.
87 	*/
88 	int m_N;
89 
90 	/**
91 	* The length of the impulse response fragments, m_N/2 will be used.
92 	*/
93 	int m_M;
94 
95 	/**
96 	* The max length of the input slices, m_N/2 will be used.
97 	*/
98 	int m_L;
99 
100 	/**
101 	* The array of convolvers that will be used, one per channel.
102 	*/
103 	std::vector<std::unique_ptr<Convolver>> m_convolvers;
104 
105 	/**
106 	* True if a transition is happening.
107 	*/
108 	bool m_transition;
109 
110 	/**
111 	* The position of the current transition (decreasing)
112 	*/
113 	int m_transPos;
114 
115 	/**
116 	* The output buffer in which the convolved data will be written and from which the reader will read.
117 	*/
118 	sample_t* m_outBuffer;
119 
120 	/**
121 	* The input buffer that will hold the data to be convolved.
122 	*/
123 	sample_t* m_inBuffer;
124 
125 	/**
126 	* Current position in which the m_outBuffer is being read.
127 	*/
128 	int m_outBufferPos;
129 
130 	/**
131 	* Length of rhe m_outBuffer.
132 	*/
133 	int m_outBufLen;
134 
135 	/**
136 	* Effective length of rhe m_outBuffer.
137 	*/
138 	int m_eOutBufLen;
139 
140 	/**
141 	* Flag indicating whether the end of the sound has been reached or not.
142 	*/
143 	bool m_eosReader;
144 
145 	/**
146 	* Flag indicating whether the end of the extra data generated in the convolution has been reached or not.
147 	*/
148 	bool m_eosTail;
149 
150 	/**
151 	* A vector of buffers (one per channel) on which the audio signal will be separated per channel so it can be convolved.
152 	*/
153 	std::vector<sample_t*> m_vecOut;
154 
155 	/**
156 	* A shared ptr to a thread pool.
157 	*/
158 	std::shared_ptr<ThreadPool> m_threadPool;
159 
160 	/**
161 	* Length of the input data to be used by the channel threads.
162 	*/
163 	int m_lastLengthIn;
164 
165 	/**
166 	* A vector of futures to sync tasks.
167 	*/
168 	std::vector<std::future<int>> m_futures;
169 
170 	// delete copy constructor and operator=
171 	BinauralReader(const BinauralReader&) = delete;
172 	BinauralReader& operator=(const BinauralReader&) = delete;
173 
174 public:
175 	/**
176 	* Creates a new convolver reader.
177 	* \param reader A reader of the input sound to be assigned to this reader. It must have one channel.
178 	* \param hrtfs A shared pointer to an HRTF object that will be used to get a particular impulse response depending on the source.
179 	* \param source A shared pointer to a Source object that will be used to change the source position of the sound.
180 	* \param threadPool A shared pointer to a ThreadPool object with 1 or more threads.
181 	* \param plan A shared pointer to and FFT plan that will be used for convolution.
182 	* \exception Exception thrown if the specs of the HRTFs and the sound don't match or if the provided HRTF object is empty.
183 	*/
184 	BinauralReader(std::shared_ptr<IReader> reader, std::shared_ptr<HRTF> hrtfs, std::shared_ptr<Source> source, std::shared_ptr<ThreadPool> threadPool, std::shared_ptr<FFTPlan> plan);
185 	virtual ~BinauralReader();
186 
187 	virtual bool isSeekable() const;
188 	virtual void seek(int position);
189 	virtual int getLength() const;
190 	virtual int getPosition() const;
191 	virtual Specs getSpecs() const;
192 	virtual void read(int& length, bool& eos, sample_t* buffer);
193 
194 private:
195 	/**
196 	* Joins several buffers (one per channel) into the m_outBuffer.
197 	* \param start The starting position from which the m_outBuffer will be written.
198 	* \param len The amout of samples that will be joined.
199 	* \param nConvolvers The number of convolvers that have been used. Only use 2 or 4 as possible values.
200 						 If the value is 4 the result will be interpolated.
201 	*/
202 	void joinByChannel(int start, int len, int nConvolvers);
203 
204 	/**
205 	* Loads the m_outBuffer with data.
206 	* \param nConvolvers The number of convolver objects that will be used. Only 2 or 4 should be used.
207 	*/
208 	void loadBuffer(int nConvolvers);
209 
210 	/**
211 	* The function that the threads will run. It will process a subset of channels.
212 	* \param id An id number that will determine which subset of channels will be processed.
213 	* \param input A flag that will indicate if thare is input data.
214 	*		-If true there is new input data.
215 	*		-If false there isn't new input data.
216 	* \return The number of samples obtained.
217 	*/
218 	int threadFunction(int id, bool input);
219 
220 	bool checkSource();
221 };
222 
223 AUD_NAMESPACE_END