| 
									
										
										
										
											2017-03-05 15:47:28 +01:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  audio_stream_sample.cpp                                              */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							| 
									
										
										
										
											2017-08-27 14:16:55 +02:00
										 |  |  | /*                      https://godotengine.org                          */ | 
					
						
							| 
									
										
										
										
											2017-03-05 15:47:28 +01:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2021-01-01 20:13:46 +01:00
										 |  |  | /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */ | 
					
						
							| 
									
										
										
										
											2017-03-05 15:47:28 +01:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | #include "audio_stream_sample.h"
 | 
					
						
							| 
									
										
										
										
											2020-01-26 11:24:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-11 14:51:48 +02:00
										 |  |  | #include "core/io/file_access.h"
 | 
					
						
							| 
									
										
										
										
											2018-09-11 18:13:45 +02:00
										 |  |  | #include "core/io/marshalls.h"
 | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlaybackSample::start(float p_from_pos) { | 
					
						
							| 
									
										
										
										
											2017-11-12 11:11:45 -03:00
										 |  |  | 	if (base->format == AudioStreamSample::FORMAT_IMA_ADPCM) { | 
					
						
							|  |  |  | 		//no seeking in IMA_ADPCM
 | 
					
						
							|  |  |  | 		for (int i = 0; i < 2; i++) { | 
					
						
							|  |  |  | 			ima_adpcm[i].step_index = 0; | 
					
						
							|  |  |  | 			ima_adpcm[i].predictor = 0; | 
					
						
							|  |  |  | 			ima_adpcm[i].loop_step_index = 0; | 
					
						
							|  |  |  | 			ima_adpcm[i].loop_predictor = 0; | 
					
						
							|  |  |  | 			ima_adpcm[i].last_nibble = -1; | 
					
						
							|  |  |  | 			ima_adpcm[i].loop_pos = 0x7FFFFFFF; | 
					
						
							|  |  |  | 			ima_adpcm[i].window_ofs = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		offset = 0; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		seek(p_from_pos); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	sign = 1; | 
					
						
							|  |  |  | 	active = true; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlaybackSample::stop() { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	active = false; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool AudioStreamPlaybackSample::is_playing() const { | 
					
						
							|  |  |  | 	return active; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int AudioStreamPlaybackSample::get_loop_count() const { | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 00:31:36 -03:00
										 |  |  | float AudioStreamPlaybackSample::get_playback_position() const { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	return float(offset >> MIX_FRAC_BITS) / base->mix_rate; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 00:31:36 -03:00
										 |  |  | void AudioStreamPlaybackSample::seek(float p_time) { | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 	if (base->format == AudioStreamSample::FORMAT_IMA_ADPCM) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 		return; //no seeking in ima-adpcm
 | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 20:35:33 +01:00
										 |  |  | 	float max = base->get_length(); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (p_time < 0) { | 
					
						
							|  |  |  | 		p_time = 0; | 
					
						
							|  |  |  | 	} else if (p_time >= max) { | 
					
						
							|  |  |  | 		p_time = max - 0.001; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	offset = uint64_t(p_time * base->mix_rate) << MIX_FRAC_BITS; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | template <class Depth, bool is_stereo, bool is_ima_adpcm> | 
					
						
							|  |  |  | void AudioStreamPlaybackSample::do_resample(const Depth *p_src, AudioFrame *p_dst, int64_t &offset, int32_t &increment, uint32_t amount, IMA_ADPCM_State *ima_adpcm) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	// this function will be compiled branchless by any decent compiler
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	int32_t final, final_r, next, next_r; | 
					
						
							| 
									
										
										
										
											2019-11-20 16:22:16 +01:00
										 |  |  | 	while (amount) { | 
					
						
							|  |  |  | 		amount--; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		int64_t pos = offset >> MIX_FRAC_BITS; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 		if (is_stereo && !is_ima_adpcm) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			pos <<= 1; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (is_ima_adpcm) { | 
					
						
							|  |  |  | 			int64_t sample_pos = pos + ima_adpcm[0].window_ofs; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			while (sample_pos > ima_adpcm[0].last_nibble) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 				static const int16_t _ima_adpcm_step_table[89] = { | 
					
						
							|  |  |  | 					7, 8, 9, 10, 11, 12, 13, 14, 16, 17, | 
					
						
							|  |  |  | 					19, 21, 23, 25, 28, 31, 34, 37, 41, 45, | 
					
						
							|  |  |  | 					50, 55, 60, 66, 73, 80, 88, 97, 107, 118, | 
					
						
							|  |  |  | 					130, 143, 157, 173, 190, 209, 230, 253, 279, 307, | 
					
						
							|  |  |  | 					337, 371, 408, 449, 494, 544, 598, 658, 724, 796, | 
					
						
							|  |  |  | 					876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, | 
					
						
							|  |  |  | 					2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, | 
					
						
							|  |  |  | 					5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, | 
					
						
							|  |  |  | 					15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				static const int8_t _ima_adpcm_index_table[16] = { | 
					
						
							|  |  |  | 					-1, -1, -1, -1, 2, 4, 6, 8, | 
					
						
							|  |  |  | 					-1, -1, -1, -1, 2, 4, 6, 8 | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				for (int i = 0; i < (is_stereo ? 2 : 1); i++) { | 
					
						
							|  |  |  | 					int16_t nibble, diff, step; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					ima_adpcm[i].last_nibble++; | 
					
						
							| 
									
										
										
										
											2017-06-28 17:00:18 -03:00
										 |  |  | 					const uint8_t *src_ptr = (const uint8_t *)base->data; | 
					
						
							|  |  |  | 					src_ptr += AudioStreamSample::DATA_PAD; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					uint8_t nbb = src_ptr[(ima_adpcm[i].last_nibble >> 1) * (is_stereo ? 2 : 1) + i]; | 
					
						
							|  |  |  | 					nibble = (ima_adpcm[i].last_nibble & 1) ? (nbb >> 4) : (nbb & 0xF); | 
					
						
							|  |  |  | 					step = _ima_adpcm_step_table[ima_adpcm[i].step_index]; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					ima_adpcm[i].step_index += _ima_adpcm_index_table[nibble]; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					if (ima_adpcm[i].step_index < 0) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						ima_adpcm[i].step_index = 0; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					if (ima_adpcm[i].step_index > 88) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						ima_adpcm[i].step_index = 88; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					diff = step >> 3; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					if (nibble & 1) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						diff += step >> 2; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					if (nibble & 2) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						diff += step >> 1; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					if (nibble & 4) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						diff += step; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					if (nibble & 8) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						diff = -diff; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					ima_adpcm[i].predictor += diff; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					if (ima_adpcm[i].predictor < -0x8000) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						ima_adpcm[i].predictor = -0x8000; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} else if (ima_adpcm[i].predictor > 0x7FFF) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						ima_adpcm[i].predictor = 0x7FFF; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					/* store loop if there */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					if (ima_adpcm[i].last_nibble == ima_adpcm[i].loop_pos) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 						ima_adpcm[i].loop_step_index = ima_adpcm[i].step_index; | 
					
						
							|  |  |  | 						ima_adpcm[i].loop_predictor = ima_adpcm[i].predictor; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					//printf("%i - %i - pred %i\n",int(ima_adpcm[i].last_nibble),int(nibble),int(ima_adpcm[i].predictor));
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			final = ima_adpcm[0].predictor; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				final_r = ima_adpcm[1].predictor; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			final = p_src[pos]; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 			if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				final_r = p_src[pos + 1]; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (sizeof(Depth) == 1) { /* conditions will not exist anymore when compiled! */ | 
					
						
							|  |  |  | 				final <<= 8; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					final_r <<= 8; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				next = p_src[pos + 2]; | 
					
						
							|  |  |  | 				next_r = p_src[pos + 3]; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				next = p_src[pos + 1]; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (sizeof(Depth) == 1) { | 
					
						
							|  |  |  | 				next <<= 8; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					next_r <<= 8; | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			int32_t frac = int64_t(offset & MIX_FRAC_MASK); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			final = final + ((next - final) * frac >> MIX_FRAC_BITS); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 			if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				final_r = final_r + ((next_r - final_r) * frac >> MIX_FRAC_BITS); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			final_r = final; //copy to right channel if stereo
 | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		p_dst->l = final / 32767.0; | 
					
						
							|  |  |  | 		p_dst->r = final_r / 32767.0; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 		p_dst++; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		offset += increment; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-27 10:27:58 -07:00
										 |  |  | int AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	if (!base->data || !active) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		for (int i = 0; i < p_frames; i++) { | 
					
						
							|  |  |  | 			p_buffer[i] = AudioFrame(0, 0); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-27 10:27:58 -07:00
										 |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int len = base->data_bytes; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	switch (base->format) { | 
					
						
							| 
									
										
										
										
											2020-05-10 13:00:47 +02:00
										 |  |  | 		case AudioStreamSample::FORMAT_8_BITS: | 
					
						
							|  |  |  | 			len /= 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_16_BITS: | 
					
						
							|  |  |  | 			len /= 2; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_IMA_ADPCM: | 
					
						
							|  |  |  | 			len *= 2; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (base->stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		len /= 2; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* some 64-bit fixed point precaches */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-15 01:23:10 -03:00
										 |  |  | 	int64_t loop_begin_fp = ((int64_t)base->loop_begin << MIX_FRAC_BITS); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	int64_t loop_end_fp = ((int64_t)base->loop_end << MIX_FRAC_BITS); | 
					
						
							|  |  |  | 	int64_t length_fp = ((int64_t)len << MIX_FRAC_BITS); | 
					
						
							|  |  |  | 	int64_t begin_limit = (base->loop_mode != AudioStreamSample::LOOP_DISABLED) ? loop_begin_fp : 0; | 
					
						
							|  |  |  | 	int64_t end_limit = (base->loop_mode != AudioStreamSample::LOOP_DISABLED) ? loop_end_fp : length_fp; | 
					
						
							|  |  |  | 	bool is_stereo = base->stereo; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	int32_t todo = p_frames; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-28 19:37:14 +01:00
										 |  |  | 	if (base->loop_mode == AudioStreamSample::LOOP_BACKWARD) { | 
					
						
							|  |  |  | 		sign = -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-07 13:46:33 -03:00
										 |  |  | 	float base_rate = AudioServer::get_singleton()->get_mix_rate(); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	float srate = base->mix_rate; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	srate *= p_rate_scale; | 
					
						
							| 
									
										
										
										
											2020-05-07 13:46:33 -03:00
										 |  |  | 	float playback_speed_scale = AudioServer::get_singleton()->get_playback_speed_scale(); | 
					
						
							|  |  |  | 	float fincrement = (srate * playback_speed_scale) / base_rate; | 
					
						
							| 
									
										
										
										
											2020-03-14 13:08:01 +00:00
										 |  |  | 	int32_t increment = int32_t(MAX(fincrement * MIX_FRAC_LEN, 1)); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	increment *= sign; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	//looping
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	AudioStreamSample::LoopMode loop_format = base->loop_mode; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	AudioStreamSample::Format format = base->format; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* audio data */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	uint8_t *dataptr = (uint8_t *)base->data; | 
					
						
							|  |  |  | 	const void *data = dataptr + AudioStreamSample::DATA_PAD; | 
					
						
							|  |  |  | 	AudioFrame *dst_buff = p_buffer; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (format == AudioStreamSample::FORMAT_IMA_ADPCM) { | 
					
						
							|  |  |  | 		if (loop_format != AudioStreamSample::LOOP_DISABLED) { | 
					
						
							|  |  |  | 			ima_adpcm[0].loop_pos = loop_begin_fp >> MIX_FRAC_BITS; | 
					
						
							|  |  |  | 			ima_adpcm[1].loop_pos = loop_begin_fp >> MIX_FRAC_BITS; | 
					
						
							|  |  |  | 			loop_format = AudioStreamSample::LOOP_FORWARD; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	while (todo > 0) { | 
					
						
							|  |  |  | 		int64_t limit = 0; | 
					
						
							|  |  |  | 		int32_t target = 0, aux = 0; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/** LOOP CHECKING **/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		if (increment < 0) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			/* going backwards */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (loop_format != AudioStreamSample::LOOP_DISABLED && offset < loop_begin_fp) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 				/* loopstart reached */ | 
					
						
							| 
									
										
										
										
											2021-10-11 19:27:50 -03:00
										 |  |  | 				if (loop_format == AudioStreamSample::LOOP_PING_PONG) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 					/* bounce ping pong */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					offset = loop_begin_fp + (loop_begin_fp - offset); | 
					
						
							|  |  |  | 					increment = -increment; | 
					
						
							|  |  |  | 					sign *= -1; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					/* go to loop-end */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					offset = loop_end_fp - (loop_begin_fp - offset); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-03-24 21:45:31 +01:00
										 |  |  | 				/* check for sample not reaching beginning */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (offset < 0) { | 
					
						
							|  |  |  | 					active = false; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			/* going forward */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			if (loop_format != AudioStreamSample::LOOP_DISABLED && offset >= loop_end_fp) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 				/* loopend reached */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-11 19:27:50 -03:00
										 |  |  | 				if (loop_format == AudioStreamSample::LOOP_PING_PONG) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 					/* bounce ping pong */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					offset = loop_end_fp - (offset - loop_end_fp); | 
					
						
							|  |  |  | 					increment = -increment; | 
					
						
							|  |  |  | 					sign *= -1; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 				} else { | 
					
						
							|  |  |  | 					/* go to loop-begin */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					if (format == AudioStreamSample::FORMAT_IMA_ADPCM) { | 
					
						
							|  |  |  | 						for (int i = 0; i < 2; i++) { | 
					
						
							|  |  |  | 							ima_adpcm[i].step_index = ima_adpcm[i].loop_step_index; | 
					
						
							|  |  |  | 							ima_adpcm[i].predictor = ima_adpcm[i].loop_predictor; | 
					
						
							|  |  |  | 							ima_adpcm[i].last_nibble = loop_begin_fp >> MIX_FRAC_BITS; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						offset = loop_begin_fp; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 						offset = loop_begin_fp + (offset - loop_end_fp); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				/* no loop, check for end of sample */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				if (offset >= length_fp) { | 
					
						
							|  |  |  | 					active = false; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** MIXCOUNT COMPUTING **/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* next possible limit (looppoints or sample begin/end */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		limit = (increment < 0) ? begin_limit : end_limit; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* compute what is shorter, the todo or the limit? */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		aux = (limit - offset) / increment + 1; | 
					
						
							|  |  |  | 		target = (aux < todo) ? aux : todo; /* mix target is the shorter buffer */ | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* check just in case */ | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		if (target <= 0) { | 
					
						
							|  |  |  | 			active = false; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		todo -= target; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		switch (base->format) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			case AudioStreamSample::FORMAT_8_BITS: { | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					do_resample<int8_t, true, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					do_resample<int8_t, false, false>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 			} break; | 
					
						
							|  |  |  | 			case AudioStreamSample::FORMAT_16_BITS: { | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					do_resample<int16_t, true, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					do_resample<int16_t, false, false>((int16_t *)data, dst_buff, offset, increment, target, ima_adpcm); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			} break; | 
					
						
							|  |  |  | 			case AudioStreamSample::FORMAT_IMA_ADPCM: { | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				if (is_stereo) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					do_resample<int8_t, true, true>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					do_resample<int8_t, false, true>((int8_t *)data, dst_buff, offset, increment, target, ima_adpcm); | 
					
						
							| 
									
										
										
										
											2020-05-14 16:41:43 +02:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			} break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		dst_buff += target; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-12 11:11:45 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (todo) { | 
					
						
							| 
									
										
										
										
											2021-08-27 10:27:58 -07:00
										 |  |  | 		int mixed_frames = p_frames - todo; | 
					
						
							| 
									
										
										
										
											2017-11-12 11:11:45 -03:00
										 |  |  | 		//bit was missing from mix
 | 
					
						
							|  |  |  | 		int todo_ofs = p_frames - todo; | 
					
						
							|  |  |  | 		for (int i = todo_ofs; i < p_frames; i++) { | 
					
						
							|  |  |  | 			p_buffer[i] = AudioFrame(0, 0); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-08-27 10:27:58 -07:00
										 |  |  | 		return mixed_frames; | 
					
						
							| 
									
										
										
										
											2017-11-12 11:11:45 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-08-27 10:27:58 -07:00
										 |  |  | 	return p_frames; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-09 18:24:36 +01:00
										 |  |  | AudioStreamPlaybackSample::AudioStreamPlaybackSample() {} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | /////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamSample::set_format(Format p_format) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	format = p_format; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | AudioStreamSample::Format AudioStreamSample::get_format() const { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	return format; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void AudioStreamSample::set_loop_mode(LoopMode p_loop_mode) { | 
					
						
							|  |  |  | 	loop_mode = p_loop_mode; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | AudioStreamSample::LoopMode AudioStreamSample::get_loop_mode() const { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	return loop_mode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void AudioStreamSample::set_loop_begin(int p_frame) { | 
					
						
							|  |  |  | 	loop_begin = p_frame; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | int AudioStreamSample::get_loop_begin() const { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	return loop_begin; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void AudioStreamSample::set_loop_end(int p_frame) { | 
					
						
							|  |  |  | 	loop_end = p_frame; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | int AudioStreamSample::get_loop_end() const { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	return loop_end; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void AudioStreamSample::set_mix_rate(int p_hz) { | 
					
						
							| 
									
										
										
										
											2019-11-20 16:22:16 +01:00
										 |  |  | 	ERR_FAIL_COND(p_hz == 0); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	mix_rate = p_hz; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | int AudioStreamSample::get_mix_rate() const { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	return mix_rate; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | void AudioStreamSample::set_stereo(bool p_enable) { | 
					
						
							|  |  |  | 	stereo = p_enable; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | bool AudioStreamSample::is_stereo() const { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	return stereo; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-22 20:35:33 +01:00
										 |  |  | float AudioStreamSample::get_length() const { | 
					
						
							|  |  |  | 	int len = data_bytes; | 
					
						
							|  |  |  | 	switch (format) { | 
					
						
							| 
									
										
										
										
											2020-05-10 13:00:47 +02:00
										 |  |  | 		case AudioStreamSample::FORMAT_8_BITS: | 
					
						
							|  |  |  | 			len /= 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_16_BITS: | 
					
						
							|  |  |  | 			len /= 2; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_IMA_ADPCM: | 
					
						
							|  |  |  | 			len *= 2; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2018-01-22 20:35:33 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (stereo) { | 
					
						
							|  |  |  | 		len /= 2; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return float(len) / mix_rate; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-27 21:51:03 -07:00
										 |  |  | bool AudioStreamSample::is_monophonic() const { | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | void AudioStreamSample::set_data(const Vector<uint8_t> &p_data) { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	AudioServer::get_singleton()->lock(); | 
					
						
							|  |  |  | 	if (data) { | 
					
						
							| 
									
										
										
										
											2020-03-27 16:14:19 -03:00
										 |  |  | 		memfree(data); | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 		data = nullptr; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		data_bytes = 0; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int datalen = p_data.size(); | 
					
						
							|  |  |  | 	if (datalen) { | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | 		const uint8_t *r = p_data.ptr(); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		int alloc_len = datalen + DATA_PAD * 2; | 
					
						
							| 
									
										
										
										
											2020-03-27 16:14:19 -03:00
										 |  |  | 		data = memalloc(alloc_len); //alloc with some padding for interpolation
 | 
					
						
							| 
									
										
										
										
											2021-04-27 16:19:21 +02:00
										 |  |  | 		memset(data, 0, alloc_len); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		uint8_t *dataptr = (uint8_t *)data; | 
					
						
							| 
									
										
										
										
											2021-04-27 16:19:21 +02:00
										 |  |  | 		memcpy(dataptr + DATA_PAD, r, datalen); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		data_bytes = datalen; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AudioServer::get_singleton()->unlock(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-05-14 14:29:06 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | Vector<uint8_t> AudioStreamSample::get_data() const { | 
					
						
							|  |  |  | 	Vector<uint8_t> pv; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (data) { | 
					
						
							|  |  |  | 		pv.resize(data_bytes); | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | 			uint8_t *w = pv.ptrw(); | 
					
						
							| 
									
										
										
										
											2017-10-08 15:11:29 -07:00
										 |  |  | 			uint8_t *dataptr = (uint8_t *)data; | 
					
						
							| 
									
										
										
										
											2021-04-27 16:19:21 +02:00
										 |  |  | 			memcpy(w, dataptr + DATA_PAD, data_bytes); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return pv; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-12 15:48:52 +01:00
										 |  |  | Error AudioStreamSample::save_to_wav(const String &p_path) { | 
					
						
							| 
									
										
										
										
											2018-07-23 14:51:23 +02:00
										 |  |  | 	if (format == AudioStreamSample::FORMAT_IMA_ADPCM) { | 
					
						
							| 
									
										
										
										
											2019-11-07 09:44:15 +01:00
										 |  |  | 		WARN_PRINT("Saving IMA_ADPC samples are not supported yet"); | 
					
						
							| 
									
										
										
										
											2019-03-12 15:48:52 +01:00
										 |  |  | 		return ERR_UNAVAILABLE; | 
					
						
							| 
									
										
										
										
											2018-07-23 14:51:23 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int sub_chunk_2_size = data_bytes; //Subchunk2Size = Size of data in bytes
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Format code
 | 
					
						
							|  |  |  | 	// 1:PCM format (for 8 or 16 bit)
 | 
					
						
							|  |  |  | 	// 3:IEEE float format
 | 
					
						
							|  |  |  | 	int format_code = (format == FORMAT_IMA_ADPCM) ? 3 : 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int n_channels = stereo ? 2 : 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	long sample_rate = mix_rate; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int byte_pr_sample = 0; | 
					
						
							|  |  |  | 	switch (format) { | 
					
						
							| 
									
										
										
										
											2020-05-10 13:00:47 +02:00
										 |  |  | 		case AudioStreamSample::FORMAT_8_BITS: | 
					
						
							|  |  |  | 			byte_pr_sample = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_16_BITS: | 
					
						
							|  |  |  | 			byte_pr_sample = 2; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_IMA_ADPCM: | 
					
						
							|  |  |  | 			byte_pr_sample = 4; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2018-07-23 14:51:23 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	String file_path = p_path; | 
					
						
							|  |  |  | 	if (!(file_path.substr(file_path.length() - 4, 4) == ".wav")) { | 
					
						
							|  |  |  | 		file_path += ".wav"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-12 15:48:52 +01:00
										 |  |  | 	FileAccessRef file = FileAccess::open(file_path, FileAccess::WRITE); //Overrides existing file if present
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); | 
					
						
							| 
									
										
										
										
											2018-07-23 14:51:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Create WAV Header
 | 
					
						
							|  |  |  | 	file->store_string("RIFF"); //ChunkID
 | 
					
						
							|  |  |  | 	file->store_32(sub_chunk_2_size + 36); //ChunkSize = 36 + SubChunk2Size (size of entire file minus the 8 bits for this and previous header)
 | 
					
						
							|  |  |  | 	file->store_string("WAVE"); //Format
 | 
					
						
							|  |  |  | 	file->store_string("fmt "); //Subchunk1ID
 | 
					
						
							|  |  |  | 	file->store_32(16); //Subchunk1Size = 16
 | 
					
						
							|  |  |  | 	file->store_16(format_code); //AudioFormat
 | 
					
						
							|  |  |  | 	file->store_16(n_channels); //Number of Channels
 | 
					
						
							|  |  |  | 	file->store_32(sample_rate); //SampleRate
 | 
					
						
							|  |  |  | 	file->store_32(sample_rate * n_channels * byte_pr_sample); //ByteRate
 | 
					
						
							|  |  |  | 	file->store_16(n_channels * byte_pr_sample); //BlockAlign = NumChannels * BytePrSample
 | 
					
						
							|  |  |  | 	file->store_16(byte_pr_sample * 8); //BitsPerSample
 | 
					
						
							|  |  |  | 	file->store_string("data"); //Subchunk2ID
 | 
					
						
							|  |  |  | 	file->store_32(sub_chunk_2_size); //Subchunk2Size
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Add data
 | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | 	Vector<uint8_t> data = get_data(); | 
					
						
							|  |  |  | 	const uint8_t *read_data = data.ptr(); | 
					
						
							| 
									
										
										
										
											2018-07-23 14:51:23 +02:00
										 |  |  | 	switch (format) { | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_8_BITS: | 
					
						
							| 
									
										
										
										
											2018-09-26 17:38:02 +02:00
										 |  |  | 			for (unsigned int i = 0; i < data_bytes; i++) { | 
					
						
							| 
									
										
										
										
											2018-07-23 14:51:23 +02:00
										 |  |  | 				uint8_t data_point = (read_data[i] + 128); | 
					
						
							|  |  |  | 				file->store_8(data_point); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_16_BITS: | 
					
						
							| 
									
										
										
										
											2018-09-26 17:38:02 +02:00
										 |  |  | 			for (unsigned int i = 0; i < data_bytes / 2; i++) { | 
					
						
							| 
									
										
										
										
											2018-07-23 14:51:23 +02:00
										 |  |  | 				uint16_t data_point = decode_uint16(&read_data[i * 2]); | 
					
						
							|  |  |  | 				file->store_16(data_point); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case AudioStreamSample::FORMAT_IMA_ADPCM: | 
					
						
							|  |  |  | 			//Unimplemented
 | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	file->close(); | 
					
						
							| 
									
										
										
										
											2019-03-12 15:48:52 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							| 
									
										
										
										
											2018-01-18 16:03:53 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | Ref<AudioStreamPlayback> AudioStreamSample::instance_playback() { | 
					
						
							|  |  |  | 	Ref<AudioStreamPlaybackSample> sample; | 
					
						
							| 
									
										
										
										
											2021-06-17 16:03:09 -06:00
										 |  |  | 	sample.instantiate(); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	sample->base = Ref<AudioStreamSample>(this); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	return sample; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String AudioStreamSample::get_stream_name() const { | 
					
						
							|  |  |  | 	return ""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamSample::_bind_methods() { | 
					
						
							| 
									
										
										
										
											2018-04-25 21:04:03 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamSample::set_data); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamSample::get_data); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_format", "format"), &AudioStreamSample::set_format); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_format"), &AudioStreamSample::get_format); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_loop_mode", "loop_mode"), &AudioStreamSample::set_loop_mode); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_loop_mode"), &AudioStreamSample::get_loop_mode); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_loop_begin", "loop_begin"), &AudioStreamSample::set_loop_begin); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_loop_begin"), &AudioStreamSample::get_loop_begin); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_loop_end", "loop_end"), &AudioStreamSample::set_loop_end); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_loop_end"), &AudioStreamSample::get_loop_end); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_mix_rate", "mix_rate"), &AudioStreamSample::set_mix_rate); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamSample::get_mix_rate); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("set_stereo", "stereo"), &AudioStreamSample::set_stereo); | 
					
						
							|  |  |  | 	ClassDB::bind_method(D_METHOD("is_stereo"), &AudioStreamSample::is_stereo); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-23 14:51:23 +02:00
										 |  |  | 	ClassDB::bind_method(D_METHOD("save_to_wav", "path"), &AudioStreamSample::save_to_wav); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-17 18:06:54 -03:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data"); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM"), "set_format", "get_format"); | 
					
						
							| 
									
										
										
										
											2018-10-28 19:37:14 +01:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "Disabled,Forward,Ping-Pong,Backward"), "set_loop_mode", "get_loop_mode"); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_begin"), "set_loop_begin", "get_loop_begin"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_end"), "set_loop_end", "get_loop_end"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_rate"), "set_mix_rate", "get_mix_rate"); | 
					
						
							|  |  |  | 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stereo"), "set_stereo", "is_stereo"); | 
					
						
							| 
									
										
										
										
											2017-09-12 22:09:06 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(FORMAT_8_BITS); | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(FORMAT_16_BITS); | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(FORMAT_IMA_ADPCM); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(LOOP_DISABLED); | 
					
						
							|  |  |  | 	BIND_ENUM_CONSTANT(LOOP_FORWARD); | 
					
						
							| 
									
										
										
										
											2021-10-11 19:27:50 -03:00
										 |  |  | 	BIND_ENUM_CONSTANT(LOOP_PING_PONG); | 
					
						
							| 
									
										
										
										
											2018-10-28 19:37:14 +01:00
										 |  |  | 	BIND_ENUM_CONSTANT(LOOP_BACKWARD); | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-09 18:24:36 +01:00
										 |  |  | AudioStreamSample::AudioStreamSample() {} | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-26 11:24:14 +01:00
										 |  |  | AudioStreamSample::~AudioStreamSample() { | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	if (data) { | 
					
						
							| 
									
										
										
										
											2020-03-27 16:14:19 -03:00
										 |  |  | 		memfree(data); | 
					
						
							| 
									
										
										
										
											2020-04-02 01:20:12 +02:00
										 |  |  | 		data = nullptr; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		data_bytes = 0; | 
					
						
							| 
									
										
										
										
											2017-02-02 22:51:26 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |