1 /*************************************************************************/
2 /*  audio_effect_record.cpp                                              */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "audio_effect_record.h"
32 
process(const AudioFrame * p_src_frames,AudioFrame * p_dst_frames,int p_frame_count)33 void AudioEffectRecordInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
34 	if (!is_recording) {
35 		for (int i = 0; i < p_frame_count; i++) {
36 			p_dst_frames[i] = p_src_frames[i];
37 		}
38 		return;
39 	}
40 
41 	//Add incoming audio frames to the IO ring buffer
42 	const AudioFrame *src = p_src_frames;
43 	AudioFrame *rb_buf = ring_buffer.ptrw();
44 	for (int i = 0; i < p_frame_count; i++) {
45 		p_dst_frames[i] = p_src_frames[i];
46 		rb_buf[ring_buffer_pos & ring_buffer_mask] = src[i];
47 		ring_buffer_pos++;
48 	}
49 }
50 
_update_buffer()51 void AudioEffectRecordInstance::_update_buffer() {
52 	//Case: Frames are remaining in the buffer
53 	while (ring_buffer_read_pos < ring_buffer_pos) {
54 		//Read from the buffer into recording_data
55 		_io_store_buffer();
56 	}
57 }
58 
_update(void * userdata)59 void AudioEffectRecordInstance::_update(void *userdata) {
60 	AudioEffectRecordInstance *ins = (AudioEffectRecordInstance *)userdata;
61 	ins->_update_buffer();
62 }
63 
process_silence() const64 bool AudioEffectRecordInstance::process_silence() const {
65 	return true;
66 }
67 
_io_thread_process()68 void AudioEffectRecordInstance::_io_thread_process() {
69 	thread_active = true;
70 
71 	while (is_recording) {
72 		//Check: The current recording has been requested to stop
73 		if (!base->recording_active) {
74 			is_recording = false;
75 		}
76 
77 		_update_buffer();
78 
79 		if (is_recording) {
80 			//Wait to avoid too much busy-wait
81 			OS::get_singleton()->delay_usec(500);
82 		}
83 	}
84 
85 	thread_active = false;
86 }
87 
_io_store_buffer()88 void AudioEffectRecordInstance::_io_store_buffer() {
89 	int to_read = ring_buffer_pos - ring_buffer_read_pos;
90 
91 	AudioFrame *rb_buf = ring_buffer.ptrw();
92 
93 	while (to_read) {
94 		AudioFrame buffered_frame = rb_buf[ring_buffer_read_pos & ring_buffer_mask];
95 		recording_data.push_back(buffered_frame.l);
96 		recording_data.push_back(buffered_frame.r);
97 
98 		ring_buffer_read_pos++;
99 		to_read--;
100 	}
101 }
102 
_thread_callback(void * _instance)103 void AudioEffectRecordInstance::_thread_callback(void *_instance) {
104 
105 	AudioEffectRecordInstance *aeri = reinterpret_cast<AudioEffectRecordInstance *>(_instance);
106 
107 	aeri->_io_thread_process();
108 }
109 
init()110 void AudioEffectRecordInstance::init() {
111 	//Reset recorder status
112 	ring_buffer_pos = 0;
113 	ring_buffer_read_pos = 0;
114 
115 	//We start a new recording
116 	recording_data.resize(0); //Clear data completely and reset length
117 	is_recording = true;
118 
119 #ifdef NO_THREADS
120 	AudioServer::get_singleton()->add_update_callback(&AudioEffectRecordInstance::_update, this);
121 #else
122 	io_thread = Thread::create(_thread_callback, this);
123 #endif
124 }
125 
finish()126 void AudioEffectRecordInstance::finish() {
127 
128 #ifdef NO_THREADS
129 	AudioServer::get_singleton()->remove_update_callback(&AudioEffectRecordInstance::_update, this);
130 #else
131 	if (thread_active) {
132 		Thread::wait_to_finish(io_thread);
133 	}
134 #endif
135 }
136 
~AudioEffectRecordInstance()137 AudioEffectRecordInstance::~AudioEffectRecordInstance() {
138 
139 	finish();
140 }
141 
instance()142 Ref<AudioEffectInstance> AudioEffectRecord::instance() {
143 	Ref<AudioEffectRecordInstance> ins;
144 	ins.instance();
145 	ins->base = Ref<AudioEffectRecord>(this);
146 	ins->is_recording = false;
147 
148 	//Re-using the buffer size calculations from audio_effect_delay.cpp
149 	float ring_buffer_max_size = IO_BUFFER_SIZE_MS;
150 	ring_buffer_max_size /= 1000.0; //convert to seconds
151 	ring_buffer_max_size *= AudioServer::get_singleton()->get_mix_rate();
152 
153 	int ringbuff_size = ring_buffer_max_size;
154 
155 	int bits = 0;
156 
157 	while (ringbuff_size > 0) {
158 		bits++;
159 		ringbuff_size /= 2;
160 	}
161 
162 	ringbuff_size = 1 << bits;
163 	ins->ring_buffer_mask = ringbuff_size - 1;
164 	ins->ring_buffer_pos = 0;
165 
166 	ins->ring_buffer.resize(ringbuff_size);
167 
168 	ins->ring_buffer_read_pos = 0;
169 
170 	ensure_thread_stopped();
171 	current_instance = ins;
172 	if (recording_active) {
173 		ins->init();
174 	}
175 
176 	return ins;
177 }
178 
ensure_thread_stopped()179 void AudioEffectRecord::ensure_thread_stopped() {
180 	recording_active = false;
181 	if (current_instance != 0) {
182 		current_instance->finish();
183 	}
184 }
185 
set_recording_active(bool p_record)186 void AudioEffectRecord::set_recording_active(bool p_record) {
187 	if (p_record) {
188 		if (current_instance == 0) {
189 			WARN_PRINTS("Recording should not be set as active before Godot has initialized.");
190 			recording_active = false;
191 			return;
192 		}
193 
194 		ensure_thread_stopped();
195 		recording_active = true;
196 		current_instance->init();
197 	} else {
198 		recording_active = false;
199 	}
200 }
201 
is_recording_active() const202 bool AudioEffectRecord::is_recording_active() const {
203 	return recording_active;
204 }
205 
set_format(AudioStreamSample::Format p_format)206 void AudioEffectRecord::set_format(AudioStreamSample::Format p_format) {
207 	format = p_format;
208 }
209 
get_format() const210 AudioStreamSample::Format AudioEffectRecord::get_format() const {
211 	return format;
212 }
213 
get_recording() const214 Ref<AudioStreamSample> AudioEffectRecord::get_recording() const {
215 	AudioStreamSample::Format dst_format = format;
216 	bool stereo = true; //forcing mono is not implemented
217 
218 	PoolVector<uint8_t> dst_data;
219 
220 	ERR_FAIL_COND_V(current_instance.is_null(), NULL);
221 	ERR_FAIL_COND_V(current_instance->recording_data.size() == 0, NULL);
222 
223 	if (dst_format == AudioStreamSample::FORMAT_8_BITS) {
224 		int data_size = current_instance->recording_data.size();
225 		dst_data.resize(data_size);
226 		PoolVector<uint8_t>::Write w = dst_data.write();
227 
228 		for (int i = 0; i < data_size; i++) {
229 			int8_t v = CLAMP(current_instance->recording_data[i] * 128, -128, 127);
230 			w[i] = v;
231 		}
232 	} else if (dst_format == AudioStreamSample::FORMAT_16_BITS) {
233 		int data_size = current_instance->recording_data.size();
234 		dst_data.resize(data_size * 2);
235 		PoolVector<uint8_t>::Write w = dst_data.write();
236 
237 		for (int i = 0; i < data_size; i++) {
238 			int16_t v = CLAMP(current_instance->recording_data[i] * 32768, -32768, 32767);
239 			encode_uint16(v, &w[i * 2]);
240 		}
241 	} else if (dst_format == AudioStreamSample::FORMAT_IMA_ADPCM) {
242 		//byte interleave
243 		Vector<float> left;
244 		Vector<float> right;
245 
246 		int tframes = current_instance->recording_data.size() / 2;
247 		left.resize(tframes);
248 		right.resize(tframes);
249 
250 		for (int i = 0; i < tframes; i++) {
251 			left.set(i, current_instance->recording_data[i * 2 + 0]);
252 			right.set(i, current_instance->recording_data[i * 2 + 1]);
253 		}
254 
255 		PoolVector<uint8_t> bleft;
256 		PoolVector<uint8_t> bright;
257 
258 		ResourceImporterWAV::_compress_ima_adpcm(left, bleft);
259 		ResourceImporterWAV::_compress_ima_adpcm(right, bright);
260 
261 		int dl = bleft.size();
262 		dst_data.resize(dl * 2);
263 
264 		PoolVector<uint8_t>::Write w = dst_data.write();
265 		PoolVector<uint8_t>::Read rl = bleft.read();
266 		PoolVector<uint8_t>::Read rr = bright.read();
267 
268 		for (int i = 0; i < dl; i++) {
269 			w[i * 2 + 0] = rl[i];
270 			w[i * 2 + 1] = rr[i];
271 		}
272 	} else {
273 		ERR_PRINT("Format not implemented.");
274 	}
275 
276 	Ref<AudioStreamSample> sample;
277 	sample.instance();
278 	sample->set_data(dst_data);
279 	sample->set_format(dst_format);
280 	sample->set_mix_rate(AudioServer::get_singleton()->get_mix_rate());
281 	sample->set_loop_mode(AudioStreamSample::LOOP_DISABLED);
282 	sample->set_loop_begin(0);
283 	sample->set_loop_end(0);
284 	sample->set_stereo(stereo);
285 
286 	return sample;
287 }
288 
_bind_methods()289 void AudioEffectRecord::_bind_methods() {
290 	ClassDB::bind_method(D_METHOD("set_recording_active", "record"), &AudioEffectRecord::set_recording_active);
291 	ClassDB::bind_method(D_METHOD("is_recording_active"), &AudioEffectRecord::is_recording_active);
292 	ClassDB::bind_method(D_METHOD("set_format", "format"), &AudioEffectRecord::set_format);
293 	ClassDB::bind_method(D_METHOD("get_format"), &AudioEffectRecord::get_format);
294 	ClassDB::bind_method(D_METHOD("get_recording"), &AudioEffectRecord::get_recording);
295 
296 	ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM"), "set_format", "get_format");
297 }
298 
AudioEffectRecord()299 AudioEffectRecord::AudioEffectRecord() {
300 	format = AudioStreamSample::FORMAT_16_BITS;
301 	recording_active = false;
302 }
303