| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  audio_stream_opus.cpp                                                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							| 
									
										
										
										
											2017-08-27 14:16:55 +02:00
										 |  |  | /*                      https://godotengine.org                          */ | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2019-01-01 12:53:14 +01:00
										 |  |  | /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */ | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03: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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | #include "audio_stream_opus.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | /**
 | 
					
						
							|  |  |  | 	@author George Marques <george@gmarqu.es> | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | const float AudioStreamPlaybackOpus::osrate = 48000.0f; | 
					
						
							| 
									
										
										
										
											2015-10-03 00:38:43 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | int AudioStreamPlaybackOpus::_op_read_func(void *_stream, unsigned char *_ptr, int _nbytes) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	FileAccess *fa = (FileAccess *)_stream; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (fa->eof_reached()) | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	uint8_t *dst = (uint8_t *)_ptr; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int read = fa->get_buffer(dst, _nbytes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return read; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | int AudioStreamPlaybackOpus::_op_seek_func(void *_stream, opus_int64 _offset, int _whence) { | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef SEEK_SET
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	FileAccess *fa = (FileAccess *)_stream; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (_whence) { | 
					
						
							|  |  |  | 		case SEEK_SET: { | 
					
						
							|  |  |  | 			fa->seek(_offset); | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		case SEEK_CUR: { | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 			fa->seek(fa->get_position() + _offset); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case SEEK_END: { | 
					
						
							|  |  |  | 			fa->seek_end(_offset); | 
					
						
							|  |  |  | 		} break; | 
					
						
							|  |  |  | 		default: { | 
					
						
							| 
									
										
										
										
											2017-12-05 15:41:38 +01:00
										 |  |  | 			ERR_PRINT("Opus seek function failure: Unexpected value in _whence\n"); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	int ret = fa->eof_reached() ? -1 : 0; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	return -1; // no seeking
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int AudioStreamPlaybackOpus::_op_close_func(void *_stream) { | 
					
						
							|  |  |  | 	if (!_stream) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	FileAccess *fa = (FileAccess *)_stream; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	if (fa->is_open()) | 
					
						
							|  |  |  | 		fa->close(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | opus_int64 AudioStreamPlaybackOpus::_op_tell_func(void *_stream) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	FileAccess *_fa = (FileAccess *)_stream; | 
					
						
							| 
									
										
										
										
											2017-09-10 15:37:49 +02:00
										 |  |  | 	return (opus_int64)_fa->get_position(); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlaybackOpus::_clear_stream() { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (!stream_loaded) | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	op_free(opus_file); | 
					
						
							|  |  |  | 	_close_file(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	stream_loaded = false; | 
					
						
							|  |  |  | 	stream_channels = 1; | 
					
						
							|  |  |  | 	playing = false; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlaybackOpus::_close_file() { | 
					
						
							|  |  |  | 	if (f) { | 
					
						
							|  |  |  | 		memdelete(f); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		f = NULL; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error AudioStreamPlaybackOpus::_load_stream() { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	ERR_FAIL_COND_V(!stream_valid, ERR_UNCONFIGURED); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	_clear_stream(); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (file == "") | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		return ERR_INVALID_DATA; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Error err; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	f = FileAccess::open(file, FileAccess::READ, &err); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 10:28:50 +02:00
										 |  |  | 	ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + file + "'."); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int _err = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &_err); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (_err) { | 
					
						
							|  |  |  | 		case OP_EREAD: { // - Can't read the file.
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			memdelete(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_FILE_CANT_READ); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case OP_EVERSION: // - Unrecognized version number.
 | 
					
						
							|  |  |  | 		case OP_ENOTFORMAT: // - Stream is not Opus data.
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		case OP_EIMPL: { // - Stream used non-implemented feature.
 | 
					
						
							|  |  |  | 			memdelete(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case OP_EBADLINK: // - Failed to find old data after seeking.
 | 
					
						
							|  |  |  | 		case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
 | 
					
						
							| 
									
										
										
										
											2018-09-12 21:38:39 -04:00
										 |  |  | 		case OP_EBADHEADER: { // - Invalid or missing Opus bitstream header.
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			memdelete(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_FILE_CORRUPT); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			memdelete(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_BUG); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	repeats = 0; | 
					
						
							|  |  |  | 	stream_loaded = true; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioStreamPlaybackOpus::AudioStreamPlaybackOpus() { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	loops = false; | 
					
						
							|  |  |  | 	playing = false; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	f = NULL; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	stream_loaded = false; | 
					
						
							|  |  |  | 	stream_valid = false; | 
					
						
							|  |  |  | 	repeats = 0; | 
					
						
							|  |  |  | 	paused = true; | 
					
						
							|  |  |  | 	stream_channels = 0; | 
					
						
							|  |  |  | 	current_section = 0; | 
					
						
							|  |  |  | 	length = 0; | 
					
						
							|  |  |  | 	loop_restart_time = 0; | 
					
						
							|  |  |  | 	pre_skip = 0; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	_op_callbacks.read = _op_read_func; | 
					
						
							|  |  |  | 	_op_callbacks.seek = _op_seek_func; | 
					
						
							|  |  |  | 	_op_callbacks.tell = _op_tell_func; | 
					
						
							|  |  |  | 	_op_callbacks.close = _op_close_func; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Error AudioStreamPlaybackOpus::set_file(const String &p_file) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	file = p_file; | 
					
						
							|  |  |  | 	stream_valid = false; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	Error err; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	f = FileAccess::open(file, FileAccess::READ, &err); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 10:28:50 +02:00
										 |  |  | 	ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + file + "'."); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int _err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &_err); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (_err) { | 
					
						
							|  |  |  | 		case OP_EREAD: { // - Can't read the file.
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			memdelete(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_FILE_CANT_READ); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case OP_EVERSION: // - Unrecognized version number.
 | 
					
						
							|  |  |  | 		case OP_ENOTFORMAT: // - Stream is not Opus data.
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		case OP_EIMPL: { // - Stream used non-implemented feature.
 | 
					
						
							|  |  |  | 			memdelete(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case OP_EBADLINK: // - Failed to find old data after seeking.
 | 
					
						
							|  |  |  | 		case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
 | 
					
						
							| 
									
										
										
										
											2018-09-12 21:38:39 -04:00
										 |  |  | 		case OP_EBADHEADER: { // - Invalid or missing Opus bitstream header.
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			memdelete(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_FILE_CORRUPT); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 		case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			memdelete(f); | 
					
						
							|  |  |  | 			f = NULL; | 
					
						
							|  |  |  | 			ERR_FAIL_V(ERR_BUG); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		} break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	const OpusHead *oinfo = op_head(opus_file, -1); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	stream_channels = oinfo->channel_count; | 
					
						
							|  |  |  | 	pre_skip = oinfo->pre_skip; | 
					
						
							|  |  |  | 	frames_mixed = pre_skip; | 
					
						
							|  |  |  | 	ogg_int64_t len = op_pcm_total(opus_file, -1); | 
					
						
							|  |  |  | 	if (len < 0) { | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		length = 0; | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		length = (len / osrate); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	op_free(opus_file); | 
					
						
							|  |  |  | 	memdelete(f); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	f = NULL; | 
					
						
							|  |  |  | 	stream_valid = true; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlaybackOpus::play(float p_from) { | 
					
						
							|  |  |  | 	if (playing) | 
					
						
							|  |  |  | 		stop(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (_load_stream() != OK) | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	frames_mixed = pre_skip; | 
					
						
							|  |  |  | 	playing = true; | 
					
						
							|  |  |  | 	if (p_from > 0) { | 
					
						
							| 
									
										
										
										
											2017-09-21 00:31:36 -03:00
										 |  |  | 		seek(p_from); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AudioStreamPlaybackOpus::stop() { | 
					
						
							|  |  |  | 	_clear_stream(); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	playing = false; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 00:31:36 -03:00
										 |  |  | void AudioStreamPlaybackOpus::seek(float p_time) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (!playing) return; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	ogg_int64_t pcm_offset = (ogg_int64_t)(p_time * osrate); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	bool ok = op_pcm_seek(opus_file, pcm_offset) == 0; | 
					
						
							|  |  |  | 	if (!ok) { | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		ERR_PRINT("Seek time over stream size."); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	frames_mixed = osrate * p_time; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 19:04:25 +07:00
										 |  |  | int AudioStreamPlaybackOpus::mix(int16_t *p_buffer, int p_frames) { | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	if (!playing) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	int total = p_frames; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	while (true) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		int todo = p_frames; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-07 23:08:51 +02:00
										 |  |  | 		if (todo < MIN_MIX) { | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 19:04:25 +07:00
										 |  |  | 		int ret = op_read(opus_file, (opus_int16 *)p_buffer, todo * stream_channels, ¤t_section); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		if (ret < 0) { | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 			playing = false; | 
					
						
							| 
									
										
										
										
											2019-08-11 10:49:53 +02:00
										 |  |  | 			ERR_BREAK_MSG(ret < 0, "Error reading Opus file: " + file + "."); | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		} else if (ret == 0) { // end of song, reload?
 | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 			op_free(opus_file); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			_close_file(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			f = FileAccess::open(file, FileAccess::READ); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			int errv = 0; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 			opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &errv); | 
					
						
							|  |  |  | 			if (errv != 0) { | 
					
						
							|  |  |  | 				playing = false; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 				break; // :(
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!has_loop()) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				playing = false; | 
					
						
							|  |  |  | 				repeats = 1; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (loop_restart_time) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				bool ok = op_pcm_seek(opus_file, (loop_restart_time * osrate) + pre_skip) == 0; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 				if (!ok) { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 					playing = false; | 
					
						
							| 
									
										
										
										
											2019-06-11 14:49:34 +02:00
										 |  |  | 					ERR_PRINT("Loop restart time rejected"); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				frames_mixed = (loop_restart_time * osrate) + pre_skip; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 				frames_mixed = pre_skip; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			repeats++; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		stream_channels = op_head(opus_file, current_section)->channel_count; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		frames_mixed += ret; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-28 19:04:25 +07:00
										 |  |  | 		p_buffer += ret * stream_channels; | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		p_frames -= ret; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	return total - p_frames; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | float AudioStreamPlaybackOpus::get_length() const { | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (!stream_loaded) { | 
					
						
							|  |  |  | 		if (const_cast<AudioStreamPlaybackOpus *>(this)->_load_stream() != OK) | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 			return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return length; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 00:31:36 -03:00
										 |  |  | float AudioStreamPlaybackOpus::get_playback_position() const { | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	int32_t frames = int32_t(frames_mixed); | 
					
						
							|  |  |  | 	if (frames < 0) | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		frames = 0; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	return double(frames) / osrate; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int AudioStreamPlaybackOpus::get_minimum_buffer_size() const { | 
					
						
							|  |  |  | 	return MIN_MIX; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AudioStreamPlaybackOpus::~AudioStreamPlaybackOpus() { | 
					
						
							|  |  |  | 	_clear_stream(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | RES ResourceFormatLoaderAudioStreamOpus::load(const String &p_path, const String &p_original_path, Error *r_error) { | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 	if (r_error) | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		*r_error = OK; | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	AudioStreamOpus *opus_stream = memnew(AudioStreamOpus); | 
					
						
							|  |  |  | 	opus_stream->set_file(p_path); | 
					
						
							|  |  |  | 	return Ref<AudioStreamOpus>(opus_stream); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ResourceFormatLoaderAudioStreamOpus::get_recognized_extensions(List<String> *p_extensions) const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	p_extensions->push_back("opus"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | String ResourceFormatLoaderAudioStreamOpus::get_resource_type(const String &p_path) const { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	if (p_path.get_extension().to_lower() == "opus") | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | 		return "AudioStreamOpus"; | 
					
						
							|  |  |  | 	return ""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | bool ResourceFormatLoaderAudioStreamOpus::handles_type(const String &p_type) const { | 
					
						
							|  |  |  | 	return (p_type == "AudioStream" || p_type == "AudioStreamOpus"); | 
					
						
							| 
									
										
										
										
											2015-10-02 14:20:50 -03:00
										 |  |  | } |