1 /*************************************************************************/
2 /*  audio_stream_generator.cpp                                           */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
10 /*                                                                       */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the       */
13 /* "Software"), to deal in the Software without restriction, including   */
14 /* without limitation the rights to use, copy, modify, merge, publish,   */
15 /* distribute, sublicense, and/or sell copies of the Software, and to    */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions:                                             */
18 /*                                                                       */
19 /* The above copyright notice and this permission notice shall be        */
20 /* included in all copies or substantial portions of the Software.       */
21 /*                                                                       */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
29 /*************************************************************************/
30 
31 #include "audio_stream_generator.h"
32 
set_mix_rate(float p_mix_rate)33 void AudioStreamGenerator::set_mix_rate(float p_mix_rate) {
34 	mix_rate = p_mix_rate;
35 }
36 
get_mix_rate() const37 float AudioStreamGenerator::get_mix_rate() const {
38 
39 	return mix_rate;
40 }
41 
set_buffer_length(float p_seconds)42 void AudioStreamGenerator::set_buffer_length(float p_seconds) {
43 
44 	buffer_len = p_seconds;
45 }
get_buffer_length() const46 float AudioStreamGenerator::get_buffer_length() const {
47 
48 	return buffer_len;
49 }
50 
instance_playback()51 Ref<AudioStreamPlayback> AudioStreamGenerator::instance_playback() {
52 
53 	Ref<AudioStreamGeneratorPlayback> playback;
54 	playback.instance();
55 	playback->generator = this;
56 	int target_buffer_size = mix_rate * buffer_len;
57 	playback->buffer.resize(nearest_shift(target_buffer_size));
58 	playback->buffer.clear();
59 	return playback;
60 }
get_stream_name() const61 String AudioStreamGenerator::get_stream_name() const {
62 
63 	return "UserFeed";
64 }
65 
get_length() const66 float AudioStreamGenerator::get_length() const {
67 	return 0;
68 }
69 
_bind_methods()70 void AudioStreamGenerator::_bind_methods() {
71 	ClassDB::bind_method(D_METHOD("set_mix_rate", "hz"), &AudioStreamGenerator::set_mix_rate);
72 	ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamGenerator::get_mix_rate);
73 
74 	ClassDB::bind_method(D_METHOD("set_buffer_length", "seconds"), &AudioStreamGenerator::set_buffer_length);
75 	ClassDB::bind_method(D_METHOD("get_buffer_length"), &AudioStreamGenerator::get_buffer_length);
76 
77 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "mix_rate", PROPERTY_HINT_RANGE, "20,192000,1"), "set_mix_rate", "get_mix_rate");
78 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "buffer_length", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_buffer_length", "get_buffer_length");
79 }
80 
AudioStreamGenerator()81 AudioStreamGenerator::AudioStreamGenerator() {
82 	mix_rate = 44100;
83 	buffer_len = 0.5;
84 }
85 
86 ////////////////
87 
push_frame(const Vector2 & p_frame)88 bool AudioStreamGeneratorPlayback::push_frame(const Vector2 &p_frame) {
89 	if (buffer.space_left() < 1) {
90 		return false;
91 	}
92 
93 	AudioFrame f = p_frame;
94 
95 	buffer.write(&f, 1);
96 	return true;
97 }
98 
can_push_buffer(int p_frames) const99 bool AudioStreamGeneratorPlayback::can_push_buffer(int p_frames) const {
100 	return buffer.space_left() >= p_frames;
101 }
push_buffer(const PoolVector2Array & p_frames)102 bool AudioStreamGeneratorPlayback::push_buffer(const PoolVector2Array &p_frames) {
103 
104 	int to_write = p_frames.size();
105 	if (buffer.space_left() < to_write) {
106 		return false;
107 	}
108 
109 	PoolVector2Array::Read r = p_frames.read();
110 	if (sizeof(real_t) == 4) {
111 		//write directly
112 		buffer.write((const AudioFrame *)r.ptr(), to_write);
113 	} else {
114 		//convert from double
115 		AudioFrame buf[2048];
116 		int ofs = 0;
117 		while (to_write) {
118 
119 			int w = MIN(to_write, 2048);
120 			for (int i = 0; i < w; i++) {
121 				buf[i] = r[i + ofs];
122 			}
123 			buffer.write(buf, w);
124 			ofs += w;
125 			to_write -= w;
126 		}
127 	}
128 	return true;
129 }
130 
get_frames_available() const131 int AudioStreamGeneratorPlayback::get_frames_available() const {
132 	return buffer.space_left();
133 }
134 
get_skips() const135 int AudioStreamGeneratorPlayback::get_skips() const {
136 	return skips;
137 }
138 
clear_buffer()139 void AudioStreamGeneratorPlayback::clear_buffer() {
140 	ERR_FAIL_COND(active);
141 	buffer.clear();
142 	mixed = 0;
143 }
144 
_mix_internal(AudioFrame * p_buffer,int p_frames)145 void AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_frames) {
146 
147 	int read_amount = buffer.data_left();
148 	if (p_frames < read_amount) {
149 		read_amount = p_frames;
150 	}
151 
152 	buffer.read(p_buffer, read_amount);
153 
154 	if (read_amount < p_frames) {
155 		//skipped, not ideal
156 		for (int i = read_amount; i < p_frames; i++) {
157 			p_buffer[i] = AudioFrame(0, 0);
158 		}
159 
160 		skips++;
161 	}
162 
163 	mixed += p_frames / generator->get_mix_rate();
164 }
get_stream_sampling_rate()165 float AudioStreamGeneratorPlayback::get_stream_sampling_rate() {
166 	return generator->get_mix_rate();
167 }
168 
start(float p_from_pos)169 void AudioStreamGeneratorPlayback::start(float p_from_pos) {
170 
171 	if (mixed == 0.0) {
172 		_begin_resample();
173 	}
174 	skips = 0;
175 	active = true;
176 	mixed = 0.0;
177 }
178 
stop()179 void AudioStreamGeneratorPlayback::stop() {
180 	active = false;
181 }
is_playing() const182 bool AudioStreamGeneratorPlayback::is_playing() const {
183 
184 	return active; //always playing, can't be stopped
185 }
186 
get_loop_count() const187 int AudioStreamGeneratorPlayback::get_loop_count() const {
188 	return 0;
189 }
190 
get_playback_position() const191 float AudioStreamGeneratorPlayback::get_playback_position() const {
192 	return mixed;
193 }
seek(float p_time)194 void AudioStreamGeneratorPlayback::seek(float p_time) {
195 	//no seek possible
196 }
197 
_bind_methods()198 void AudioStreamGeneratorPlayback::_bind_methods() {
199 	ClassDB::bind_method(D_METHOD("push_frame", "frame"), &AudioStreamGeneratorPlayback::push_frame);
200 	ClassDB::bind_method(D_METHOD("can_push_buffer", "amount"), &AudioStreamGeneratorPlayback::can_push_buffer);
201 	ClassDB::bind_method(D_METHOD("push_buffer", "frames"), &AudioStreamGeneratorPlayback::push_buffer);
202 	ClassDB::bind_method(D_METHOD("get_frames_available"), &AudioStreamGeneratorPlayback::get_frames_available);
203 	ClassDB::bind_method(D_METHOD("get_skips"), &AudioStreamGeneratorPlayback::get_skips);
204 	ClassDB::bind_method(D_METHOD("clear_buffer"), &AudioStreamGeneratorPlayback::clear_buffer);
205 }
206 
AudioStreamGeneratorPlayback()207 AudioStreamGeneratorPlayback::AudioStreamGeneratorPlayback() {
208 	generator = NULL;
209 	skips = 0;
210 	active = false;
211 	mixed = 0;
212 }
213