1 /*************************************************************************/
2 /*  gibberish_stream.cpp                                                 */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 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 #include "gibberish_stream.h"
31 #include "servers/audio_server.h"
32 
33 //TODO: This class needs to be adapted to the new AudioStream API,
34 // or dropped if nobody cares about fixing it :) (GH-3307)
35 
36 #if 0
37 
38 int AudioStreamGibberish::get_channel_count() const {
39 
40 	return 1;
41 }
42 
43 
44 static float _get_vol_at_pos(int p_pos, int p_len, int p_x_fade) {
45 
46 	if (p_pos < p_x_fade)
47 		return float(p_pos)/p_x_fade;
48 	else if (p_pos>(p_len-p_x_fade))
49 		return float(p_len-p_pos)/p_x_fade;
50 	else
51 		return 1.0;
52 
53 }
54  int AudioStreamGibberish::randomize() {
55 
56 	if (rand_idx==_rand_pool.size()) {
57 
58 		for(int i=0;i<_rand_pool.size();i++) {
59 
60 			SWAP(_rand_pool[i],_rand_pool[Math::rand()%_rand_pool.size()]);
61 		}
62 		rand_idx=0;
63 	}
64 
65 	return _rand_pool[rand_idx++];
66 }
67 
68 bool AudioStreamGibberish::mix(int32_t *p_buffer, int p_frames) {
69 
70 	if (!active)
71 		return false;
72 
73 	zeromem(p_buffer,p_frames*sizeof(int32_t));
74 
75 	if (!paused && active_voices==0) {
76 
77 		active_voices=1;
78 		playback[0].idx=randomize();
79 		playback[0].fp_pos=0;
80 		playback[0].scale=Math::random(1,1+pitch_random_scale);
81 	}
82 
83 	for(int i=0;i<active_voices;i++) {
84 
85 		RID s = _samples[playback[i].idx]->get_rid();
86 
87 		uint64_t fp_pos=playback[i].fp_pos;
88 		const void *data = AudioServer::get_singleton()->sample_get_data_ptr(s);
89 		bool is16 = AudioServer::get_singleton()->sample_get_format(s)==AudioServer::SAMPLE_FORMAT_PCM16;
90 		int skip = AudioServer::get_singleton()->sample_is_stereo(s) ? 1: 0;
91 		uint64_t max = AudioServer::get_singleton()->sample_get_length(s) * uint64_t(FP_LEN);
92 		int mrate = AudioServer::get_singleton()->sample_get_mix_rate(s) * pitch_scale * playback[i].scale;
93 		uint64_t increment = uint64_t(mrate) * uint64_t(FP_LEN) / get_mix_rate();
94 
95 
96 		float vol_begin = _get_vol_at_pos(fp_pos>>FP_BITS,max>>FP_BITS,xfade_time*mrate);
97 		float vol_end = _get_vol_at_pos((fp_pos+p_frames*increment)>>FP_BITS,max>>FP_BITS,xfade_time*mrate);
98 
99 		int32_t vol = CLAMP(int32_t(vol_begin * 65535),0,65535);
100 		int32_t vol_to = CLAMP(int32_t(vol_end * 65535),0,65535);
101 		int32_t vol_inc = (vol_to-vol)/p_frames;
102 
103 		bool done=false;
104 
105 		if (is16) {
106 
107 			const int16_t *smp = (int16_t*)data;
108 			for(int i=0;i<p_frames;i++) {
109 
110 				if (fp_pos >= max) {
111 					done=true;
112 					break;
113 				}
114 
115 				int idx = (fp_pos>>FP_BITS)<<skip;
116 				p_buffer[i]+=int32_t(smp[idx])*vol;
117 				vol+=vol_inc;
118 
119 				fp_pos+=increment;
120 			}
121 		} else {
122 
123 			const int8_t *smp = (int8_t*)data;
124 			for(int i=0;i<p_frames;i++) {
125 
126 				if (fp_pos >= max) {
127 					done=true;
128 					break;
129 				}
130 
131 				int idx = (fp_pos>>FP_BITS)<<skip;
132 				p_buffer[i]+=(int32_t(smp[idx])<<8)*vol;
133 				vol+=vol_inc;
134 				fp_pos+=increment;
135 			}
136 
137 		}
138 
139 		playback[i].fp_pos=fp_pos;
140 		if (!paused && active_voices==1 && (vol_end < vol_begin || done)) {
141 			//xfade to something else i gues
142 			active_voices=2;
143 			playback[1].idx=randomize();
144 			playback[1].fp_pos=0;
145 			playback[1].scale=Math::random(1,1+pitch_random_scale);
146 		}
147 
148 		if (done) {
149 
150 			if (i==0 && active_voices==2) {
151 				playback[0]=playback[1];
152 				i--;
153 			}
154 			active_voices--;
155 
156 		}
157 	}
158 
159 	return true;
160 }
161 
162 
163 void AudioStreamGibberish::play() {
164 	if (active)
165 		stop();
166 
167 
168 	if (!phonemes.is_valid())
169 		return;
170 
171 
172 	List<StringName> slist;
173 	phonemes->get_sample_list(&slist);
174 	if (slist.size()==0)
175 		return;
176 
177 	_samples.resize(slist.size());
178 	_rand_pool.resize(slist.size());
179 
180 	int i=0;
181 	for(List<StringName>::Element *E=slist.front();E;E=E->next()) {
182 
183 		_rand_pool[i]=i;
184 		_samples[i++]=phonemes->get_sample(E->get());
185 	}
186 
187 	rand_idx=0;
188 	active_voices=0;
189 	active=true;
190 }
191 
192 void AudioStreamGibberish::stop(){
193 
194 	active=false;
195 
196 
197 }
198 
199 bool AudioStreamGibberish::is_playing() const {
200 
201 	return active;
202 }
203 
204 
205 void AudioStreamGibberish::set_paused(bool p_paused){
206 
207 	paused=p_paused;
208 }
209 
210 bool AudioStreamGibberish::is_paused(bool p_paused) const{
211 
212 	return paused;
213 }
214 
215 void AudioStreamGibberish::set_loop(bool p_enable){
216 
217 
218 }
219 
220 bool AudioStreamGibberish::has_loop() const{
221 
222 	return false;
223 }
224 
225 
226 float AudioStreamGibberish::get_length() const{
227 
228 	return 0;
229 }
230 
231 
232 String AudioStreamGibberish::get_stream_name() const{
233 
234 	return "Gibberish";
235 }
236 
237 
238 int AudioStreamGibberish::get_loop_count() const{
239 
240 	return 0;
241 }
242 
243 
244 float AudioStreamGibberish::get_pos() const{
245 
246 	return 0;
247 }
248 
249 void AudioStreamGibberish::seek_pos(float p_time){
250 
251 
252 }
253 
254 
255 AudioStream::UpdateMode AudioStreamGibberish::get_update_mode() const{
256 
257 	return AudioStream::UPDATE_NONE;
258 }
259 
260 void AudioStreamGibberish::update(){
261 
262 
263 }
264 
265 
266 void AudioStreamGibberish::set_phonemes(const Ref<SampleLibrary>& p_phonemes) {
267 
268 	phonemes=p_phonemes;
269 
270 }
271 
272 Ref<SampleLibrary> AudioStreamGibberish::get_phonemes() const {
273 
274 	return phonemes;
275 }
276 
277 void AudioStreamGibberish::set_xfade_time(float p_xfade) {
278 
279 	xfade_time=p_xfade;
280 }
281 
282 float AudioStreamGibberish::get_xfade_time() const {
283 
284 	return xfade_time;
285 }
286 
287 void AudioStreamGibberish::set_pitch_scale(float p_scale) {
288 
289 	pitch_scale=p_scale;
290 }
291 
292 float AudioStreamGibberish::get_pitch_scale() const {
293 
294 	return pitch_scale;
295 }
296 
297 void AudioStreamGibberish::set_pitch_random_scale(float p_random_scale) {
298 
299 	pitch_random_scale=p_random_scale;
300 }
301 
302 float AudioStreamGibberish::get_pitch_random_scale() const {
303 
304 	return pitch_random_scale;
305 }
306 
307 void AudioStreamGibberish::_bind_methods() {
308 
309 	ObjectTypeDB::bind_method(_MD("set_phonemes","phonemes"),&AudioStreamGibberish::set_phonemes);
310 	ObjectTypeDB::bind_method(_MD("get_phonemes"),&AudioStreamGibberish::get_phonemes);
311 
312 	ObjectTypeDB::bind_method(_MD("set_pitch_scale","pitch_scale"),&AudioStreamGibberish::set_pitch_scale);
313 	ObjectTypeDB::bind_method(_MD("get_pitch_scale"),&AudioStreamGibberish::get_pitch_scale);
314 
315 	ObjectTypeDB::bind_method(_MD("set_pitch_random_scale","pitch_random_scale"),&AudioStreamGibberish::set_pitch_random_scale);
316 	ObjectTypeDB::bind_method(_MD("get_pitch_random_scale"),&AudioStreamGibberish::get_pitch_random_scale);
317 
318 	ObjectTypeDB::bind_method(_MD("set_xfade_time","sec"),&AudioStreamGibberish::set_xfade_time);
319 	ObjectTypeDB::bind_method(_MD("get_xfade_time"),&AudioStreamGibberish::get_xfade_time);
320 
321 	ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"phonemes",PROPERTY_HINT_RESOURCE_TYPE,"SampleLibrary"),_SCS("set_phonemes"),_SCS("get_phonemes"));
322 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"pitch_scale",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_pitch_scale"),_SCS("get_pitch_scale"));
323 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"pitch_random_scale",PROPERTY_HINT_RANGE,"0,64,0.01"),_SCS("set_pitch_random_scale"),_SCS("get_pitch_random_scale"));
324 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"xfade_sec",PROPERTY_HINT_RANGE,"0.001,0.5,0.001"),_SCS("set_xfade_time"),_SCS("get_xfade_time"));
325 
326 }
327 
328 AudioStreamGibberish::AudioStreamGibberish() {
329 
330 	xfade_time=0.1;
331 	pitch_scale=1;
332 	pitch_random_scale=0;
333 	active=false;
334 	paused=false;
335 	active_voices=0;
336 }
337 #endif
338