1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or
5  *  (at your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *  GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  */
16 
17 #include <assert.h>
18 #include <string.h>
19 #include <stdlib.h>
20 		// for abs()
21 #include "sound.h"
22 #include "sndintrn.h"
23 #include "libs/tasklib.h"
24 #include "libs/timelib.h"
25 #include "libs/threadlib.h"
26 #include "libs/log.h"
27 #include "libs/memlib.h"
28 
29 
30 static Task decoderTask;
31 
32 static TimeCount musicFadeStartTime;
33 static sint32 musicFadeInterval;
34 static int musicFadeStartVolume;
35 static int musicFadeDelta;
36 // Mutex protects fade structures
37 static Mutex fade_mutex;
38 
39 static void add_scope_data (TFB_SoundSource *source, uint32 bytes);
40 
41 
42 void
PlayStream(TFB_SoundSample * sample,uint32 source,bool looping,bool scope,bool rewind)43 PlayStream (TFB_SoundSample *sample, uint32 source, bool looping, bool scope,
44 		bool rewind)
45 {
46 	uint32 i;
47 	sint32 offset;
48 	TFB_SoundDecoder *decoder;
49 
50 	if (!sample)
51 		return;
52 
53 	StopStream (source);
54 	if (sample->callbacks.OnStartStream &&
55 		!sample->callbacks.OnStartStream (sample))
56 		return; // callback failed
57 
58 	if (sample->buffer_tag)
59 		memset (sample->buffer_tag, 0,
60 				sample->num_buffers * sizeof (sample->buffer_tag[0]));
61 
62 	decoder = sample->decoder;
63 	offset = sample->offset;
64 	if (rewind)
65 		SoundDecoder_Rewind (decoder);
66 	else
67 		offset += (sint32)(SoundDecoder_GetTime (decoder) * ONE_SECOND);
68 
69 	soundSource[source].sample = sample;
70 	decoder->looping = looping;
71 	audio_Sourcei (soundSource[source].handle, audio_LOOPING, false);
72 
73 	if (scope)
74 	{	// Prealloc the scope buffer in advance so that we do not
75 		// realloc it a zillion times
76 		soundSource[source].sbuf_size = sample->num_buffers *
77 				decoder->buffer_size + PAD_SCOPE_BYTES;
78 		soundSource[source].sbuffer = HCalloc (soundSource[source].sbuf_size);
79 	}
80 
81 	for (i = 0; i < sample->num_buffers; ++i)
82 	{
83 		uint32 decoded_bytes;
84 
85 		decoded_bytes = SoundDecoder_Decode (decoder);
86 #if 0
87 		log_add (log_Debug, "PlayStream(): source:%d filename:%s start:%d "
88 				"position:%d bytes:%d\n",
89 				source, decoder->filename, decoder->start_sample,
90 				decoder->pos, decoded_bytes);
91 #endif
92 		if (decoded_bytes == 0)
93 			break;
94 
95 		audio_BufferData (sample->buffer[i], decoder->format,
96 				decoder->buffer, decoded_bytes, decoder->frequency);
97 		audio_SourceQueueBuffers (soundSource[source].handle, 1,
98 				&sample->buffer[i]);
99 		if (sample->callbacks.OnQueueBuffer)
100 			sample->callbacks.OnQueueBuffer (sample, sample->buffer[i]);
101 
102 		if (scope)
103 			add_scope_data (&soundSource[source], decoded_bytes);
104 
105 		if (decoder->error != SOUNDDECODER_OK)
106 		{
107 			if (decoder->error != SOUNDDECODER_EOF ||
108 					!sample->callbacks.OnEndChunk ||
109 					!sample->callbacks.OnEndChunk (sample, sample->buffer[i]))
110 			{	// Decoder probably run out of data before we could fill
111 				// all buffers, and OnEndChunk() did not set a new one
112 				break;
113 			}
114 			else
115 			{	// OnEndChunk() probably set a new decoder, get it
116 				decoder = sample->decoder;
117 			}
118 		}
119 	}
120 
121 	soundSource[source].sbuf_lasttime = GetTimeCounter ();
122 	// Adjust the start time so it looks like the stream has been playing
123 	// from the very beginning
124 	soundSource[source].start_time = GetTimeCounter () - offset;
125 	soundSource[source].pause_time = 0;
126 	soundSource[source].stream_should_be_playing = TRUE;
127 	audio_SourcePlay (soundSource[source].handle);
128 }
129 
130 void
StopStream(uint32 source)131 StopStream (uint32 source)
132 {
133 	StopSource (source);
134 
135 	soundSource[source].stream_should_be_playing = FALSE;
136 	soundSource[source].sample = NULL;
137 
138 	if (soundSource[source].sbuffer)
139 	{
140 		void *sbuffer = soundSource[source].sbuffer;
141 		soundSource[source].sbuffer = NULL;
142 		HFree (sbuffer);
143 	}
144 	soundSource[source].sbuf_size = 0;
145 	soundSource[source].sbuf_head = 0;
146 	soundSource[source].sbuf_tail = 0;
147 	soundSource[source].pause_time = 0;
148 }
149 
150 void
PauseStream(uint32 source)151 PauseStream (uint32 source)
152 {
153 	soundSource[source].stream_should_be_playing = FALSE;
154 	if (!soundSource[source].pause_time)
155 		soundSource[source].pause_time = GetTimeCounter ();
156 	audio_SourcePause (soundSource[source].handle);
157 }
158 
159 void
ResumeStream(uint32 source)160 ResumeStream (uint32 source)
161 {
162 	if (soundSource[source].pause_time)
163 	{	// Adjust the start time so it looks like the stream has
164 		// been playing all this time non-stop
165 		soundSource[source].start_time += GetTimeCounter ()
166 				- soundSource[source].pause_time;
167 	}
168 	soundSource[source].pause_time = 0;
169 	soundSource[source].stream_should_be_playing = TRUE;
170 	audio_SourcePlay (soundSource[source].handle);
171 }
172 
173 void
SeekStream(uint32 source,uint32 pos)174 SeekStream (uint32 source, uint32 pos)
175 {
176 	TFB_SoundSample* sample = soundSource[source].sample;
177 	bool looping;
178 	bool scope;
179 
180 	if (!sample)
181 		return;
182 	looping = sample->decoder->looping;
183 	scope = soundSource[source].sbuffer != NULL;
184 
185 	StopSource (source);
186 	SoundDecoder_Seek (sample->decoder, pos);
187 	PlayStream (sample, source, looping, scope, false);
188 }
189 
190 BOOLEAN
PlayingStream(uint32 source)191 PlayingStream (uint32 source)
192 {
193 	return soundSource[source].stream_should_be_playing;
194 }
195 
196 
197 TFB_SoundSample *
TFB_CreateSoundSample(TFB_SoundDecoder * decoder,uint32 num_buffers,const TFB_SoundCallbacks * pcbs)198 TFB_CreateSoundSample (TFB_SoundDecoder *decoder, uint32 num_buffers,
199 		const TFB_SoundCallbacks *pcbs /* can be NULL */)
200 {
201 	TFB_SoundSample *sample;
202 
203 	sample = HCalloc (sizeof (*sample));
204 	sample->decoder = decoder;
205 	sample->num_buffers = num_buffers;
206 	sample->buffer = HCalloc (sizeof (audio_Object) * num_buffers);
207 	audio_GenBuffers (num_buffers, sample->buffer);
208 	if (pcbs)
209 		sample->callbacks = *pcbs;
210 
211 	return sample;
212 }
213 
214 // Deletes all TFB_SoundSample data structures, except decoder
215 void
TFB_DestroySoundSample(TFB_SoundSample * sample)216 TFB_DestroySoundSample (TFB_SoundSample *sample)
217 {
218 	if (sample->buffer)
219 	{
220 		audio_DeleteBuffers (sample->num_buffers, sample->buffer);
221 		HFree (sample->buffer);
222 	}
223 	HFree (sample->buffer_tag);
224 	HFree (sample);
225 }
226 
227 void
TFB_SetSoundSampleData(TFB_SoundSample * sample,void * data)228 TFB_SetSoundSampleData (TFB_SoundSample *sample, void* data)
229 {
230 	sample->data = data;
231 }
232 
233 void*
TFB_GetSoundSampleData(TFB_SoundSample * sample)234 TFB_GetSoundSampleData (TFB_SoundSample *sample)
235 {
236 	return sample->data;
237 }
238 
239 void
TFB_SetSoundSampleCallbacks(TFB_SoundSample * sample,const TFB_SoundCallbacks * pcbs)240 TFB_SetSoundSampleCallbacks (TFB_SoundSample *sample,
241 		const TFB_SoundCallbacks *pcbs /* can be NULL */)
242 {
243 	if (pcbs)
244 		sample->callbacks = *pcbs;
245 	else
246 		memset (&sample->callbacks, 0, sizeof (sample->callbacks));
247 }
248 
249 TFB_SoundDecoder*
TFB_GetSoundSampleDecoder(TFB_SoundSample * sample)250 TFB_GetSoundSampleDecoder (TFB_SoundSample *sample)
251 {
252 	return sample->decoder;
253 }
254 
255 TFB_SoundTag*
TFB_FindTaggedBuffer(TFB_SoundSample * sample,audio_Object buffer)256 TFB_FindTaggedBuffer (TFB_SoundSample *sample, audio_Object buffer)
257 {
258 	uint32 buf_num;
259 
260 	if (!sample->buffer_tag)
261 		return NULL; // do not have any tags
262 
263 	for (buf_num = 0;
264 			buf_num < sample->num_buffers &&
265 			(!sample->buffer_tag[buf_num].in_use ||
266 			 sample->buffer_tag[buf_num].buf_name != buffer
267 			);
268 			buf_num++)
269 		;
270 
271 	return buf_num < sample->num_buffers ?
272 			&sample->buffer_tag[buf_num] : NULL;
273 }
274 
275 bool
TFB_TagBuffer(TFB_SoundSample * sample,audio_Object buffer,intptr_t data)276 TFB_TagBuffer (TFB_SoundSample *sample, audio_Object buffer, intptr_t data)
277 {
278 	uint32 buf_num;
279 
280 	if (!sample->buffer_tag)
281 		sample->buffer_tag = HCalloc (sizeof (TFB_SoundTag) *
282 				sample->num_buffers);
283 
284 	for (buf_num = 0;
285 			buf_num < sample->num_buffers &&
286 			sample->buffer_tag[buf_num].in_use &&
287 			sample->buffer_tag[buf_num].buf_name != buffer;
288 			buf_num++)
289 		;
290 
291 	if (buf_num >= sample->num_buffers)
292 		return false; // no empty slot
293 
294 	sample->buffer_tag[buf_num].in_use = 1;
295 	sample->buffer_tag[buf_num].buf_name = buffer;
296 	sample->buffer_tag[buf_num].data = data;
297 
298 	return true;
299 }
300 
301 void
TFB_ClearBufferTag(TFB_SoundTag * ptag)302 TFB_ClearBufferTag (TFB_SoundTag *ptag)
303 {
304 	ptag->in_use = 0;
305 	ptag->buf_name = 0;
306 }
307 
308 static void
remove_scope_data(TFB_SoundSource * source,audio_Object buffer)309 remove_scope_data (TFB_SoundSource *source, audio_Object buffer)
310 {
311 	audio_IntVal buf_size;
312 
313 	audio_GetBufferi (buffer, audio_SIZE, &buf_size);
314 	source->sbuf_head += buf_size;
315 	// the buffer is cyclic
316 	source->sbuf_head %= source->sbuf_size;
317 
318 	source->sbuf_lasttime = GetTimeCounter ();
319 }
320 
321 static void
add_scope_data(TFB_SoundSource * source,uint32 bytes)322 add_scope_data (TFB_SoundSource *source, uint32 bytes)
323 {
324 	uint8 *sbuffer = source->sbuffer;
325 	uint8 *dec_buf = source->sample->decoder->buffer;
326 	uint32 tail_bytes;
327 	uint32 wrap_bytes;
328 
329 	if (source->sbuf_tail + bytes > source->sbuf_size)
330 	{	// does not fit at the tail, have to split it up
331 		tail_bytes = source->sbuf_size - source->sbuf_tail;
332 		wrap_bytes = bytes - tail_bytes;
333 	}
334 	else
335 	{	// all fits at the tail
336 		tail_bytes = bytes;
337 		wrap_bytes = 0;
338 	}
339 
340 	if (tail_bytes)
341 	{
342 		memcpy (sbuffer + source->sbuf_tail, dec_buf, tail_bytes);
343 		source->sbuf_tail += tail_bytes;
344 	}
345 
346 	if (wrap_bytes)
347 	{
348 		memcpy (sbuffer, dec_buf + tail_bytes, wrap_bytes);
349 		source->sbuf_tail = wrap_bytes;
350 	}
351 }
352 
353 static void
process_stream(TFB_SoundSource * source)354 process_stream (TFB_SoundSource *source)
355 {
356 	TFB_SoundSample *sample = source->sample;
357 	TFB_SoundDecoder *decoder = sample->decoder;
358 	bool end_chunk_failed = false;
359 	audio_IntVal processed;
360 	audio_IntVal queued;
361 
362 	audio_GetSourcei (source->handle, audio_BUFFERS_PROCESSED, &processed);
363 	audio_GetSourcei (source->handle, audio_BUFFERS_QUEUED, &queued);
364 
365 	if (processed == 0)
366 	{	// Nothing was played
367 		audio_IntVal state;
368 
369 		audio_GetSourcei (source->handle, audio_SOURCE_STATE, &state);
370 		if (state != audio_PLAYING)
371 		{
372 			if (queued == 0 && decoder->error == SOUNDDECODER_EOF)
373 			{	// The stream has reached the end
374 				log_add (log_Info, "StreamDecoderTaskFunc(): "
375 						"finished playing %s", decoder->filename);
376 				source->stream_should_be_playing = FALSE;
377 
378 				if (sample->callbacks.OnEndStream)
379 					sample->callbacks.OnEndStream (sample);
380  			}
381 			else
382  			{
383 				log_add (log_Warning, "StreamDecoderTaskFunc(): "
384 						"buffer underrun playing %s", decoder->filename);
385 				audio_SourcePlay (source->handle);
386 			}
387 		}
388 	}
389 
390 	// Unqueue processed buffers and replace them with new ones
391 	for (; processed > 0; --processed)
392 	{
393 		uint32 error;
394 		audio_Object buffer;
395 		uint32 decoded_bytes;
396 
397 		audio_GetError (); // clear error state
398 
399 		// Get the buffer that finished playing
400 		audio_SourceUnqueueBuffers (source->handle, 1, &buffer);
401 		error = audio_GetError();
402 		if (error != audio_NO_ERROR)
403 		{
404 			log_add (log_Warning, "StreamDecoderTaskFunc(): "
405 					"error after audio_SourceUnqueueBuffers: %x, file %s",
406 					error, decoder->filename);
407 			break;
408 		}
409 
410 		// Process a callback on a tagged buffer, if any
411 		if (sample->callbacks.OnTaggedBuffer)
412 		{
413 			TFB_SoundTag* tag = TFB_FindTaggedBuffer (sample, buffer);
414 			if (tag)
415 				sample->callbacks.OnTaggedBuffer (sample, tag);
416 		}
417 
418 		if (source->sbuffer)
419 			remove_scope_data (source, buffer);
420 
421 		// See what state the decoder was left in last time around
422 		if (decoder->error != SOUNDDECODER_OK)
423 		{
424 			if (decoder->error == SOUNDDECODER_EOF)
425 			{
426 				if (end_chunk_failed)
427 					continue; // should not do it again
428 
429 				if (!sample->callbacks.OnEndChunk ||
430 						!sample->callbacks.OnEndChunk (sample, source->last_q_buf))
431 				{	// Reached the end of the current stream and we did not
432 					// get another sample to play (relevant for Trackplayer)
433 					end_chunk_failed = true;
434 					continue;
435 				}
436 				else
437 				{	// OnEndChunk succeeded, so someone (read: Trackplayer)
438 					// wants to keep going, probably with a new decoder.
439 					// Get the new decoder
440 					decoder = sample->decoder;
441 				}
442 			}
443 			else
444 			{	// Decoder returned a real error, keep going
445 #if 0
446 				log_add (log_Debug, "StreamDecoderTaskFunc(): "
447 						"decoder->error is %d for %s", decoder->error,
448 						decoder->filename);
449 #endif
450 				continue;
451 			}
452 		}
453 
454 		// Now replace the unqueued buffer with a new one
455 		decoded_bytes = SoundDecoder_Decode (decoder);
456 		if (decoder->error == SOUNDDECODER_ERROR)
457 		{
458 			log_add (log_Warning, "StreamDecoderTaskFunc(): "
459 					"SoundDecoder_Decode error %d, file %s",
460 					decoder->error, decoder->filename);
461 			source->stream_should_be_playing = FALSE;
462 			continue;
463 		}
464 
465 		if (decoded_bytes == 0)
466 		{	// Nothing was decoded, keep going
467 			continue;
468 			// This loses a stream buffer, which we cannot get back
469 			// w/o restarting the stream, but we should never get here.
470 		}
471 
472 		// And a new buffer is born
473 		audio_BufferData (buffer, decoder->format, decoder->buffer,
474 				decoded_bytes, decoder->frequency);
475 		error = audio_GetError();
476 		if (error != audio_NO_ERROR)
477 		{
478 			log_add (log_Warning, "StreamDecoderTaskFunc(): "
479 					"error after audio_BufferData: %x, file %s, decoded %d",
480 					error, decoder->filename, decoded_bytes);
481 			continue;
482 		}
483 
484 		// Now queue the buffer
485 		audio_SourceQueueBuffers (source->handle, 1, &buffer);
486 		error = audio_GetError();
487 		if (error != audio_NO_ERROR)
488 		{
489 			log_add (log_Warning, "StreamDecoderTaskFunc(): "
490 					"error after audio_SourceQueueBuffers: %x, file %s, "
491 					"decoded %d", error, decoder->filename, decoded_bytes);
492 			continue;
493 		}
494 
495 		// Remember the last queued buffer so we can pass it to callbacks
496 		source->last_q_buf = buffer;
497 		if (sample->callbacks.OnQueueBuffer)
498 			sample->callbacks.OnQueueBuffer (sample, buffer);
499 
500 		if (source->sbuffer)
501 			add_scope_data (source, decoded_bytes);
502 	}
503 }
504 
505 static void
processMusicFade(void)506 processMusicFade (void)
507 {
508 	TimeCount Now;
509 	sint32 elapsed;
510 	int newVolume;
511 
512 	LockMutex (fade_mutex);
513 
514 	if (!musicFadeInterval)
515 	{	// there is no fade set
516 		UnlockMutex (fade_mutex);
517 		return;
518 	}
519 
520 	Now = GetTimeCounter ();
521 	elapsed = Now - musicFadeStartTime;
522 	if (elapsed > musicFadeInterval)
523 		elapsed = musicFadeInterval;
524 
525 	newVolume = musicFadeStartVolume + (long)musicFadeDelta * elapsed
526 			/ musicFadeInterval;
527 	SetMusicVolume (newVolume);
528 
529 	if (elapsed >= musicFadeInterval)
530 		musicFadeInterval = 0; // fade is over
531 
532 	UnlockMutex (fade_mutex);
533 }
534 
535 static int
StreamDecoderTaskFunc(void * data)536 StreamDecoderTaskFunc (void *data)
537 {
538 	Task task = (Task)data;
539 	int active_streams;
540 	int i;
541 
542 	while (!Task_ReadState (task, TASK_EXIT))
543 	{
544 		active_streams = 0;
545 
546 		processMusicFade ();
547 
548 		for (i = MUSIC_SOURCE; i < NUM_SOUNDSOURCES; ++i)
549 		{
550 			TFB_SoundSource *source = &soundSource[i];
551 
552 			LockMutex (source->stream_mutex);
553 
554 			if (!source->sample ||
555 				!source->sample->decoder ||
556 				!source->stream_should_be_playing ||
557 				source->sample->decoder->error == SOUNDDECODER_ERROR)
558 			{
559 				UnlockMutex (source->stream_mutex);
560 				continue;
561 			}
562 
563 			process_stream (source);
564 			active_streams++;
565 
566 			UnlockMutex (source->stream_mutex);
567 		}
568 
569 		if (active_streams == 0)
570 		{	// Throttle down the thread when there are no active streams
571 			HibernateThread (ONE_SECOND / 10);
572 		}
573 		else
574 			TaskSwitch ();
575 	}
576 
577 	FinishTask (task);
578 	return 0;
579 }
580 
581 static inline sint32
readSoundSample(void * ptr,int sample_size)582 readSoundSample (void *ptr, int sample_size)
583 {
584 	if (sample_size == sizeof (uint8))
585 		return (*(uint8*)ptr - 128) << 8;
586 	else
587 		return *(sint16*)ptr;
588 }
589 
590 // Graphs the current sound data for the oscilloscope.
591 // Includes a rudimentary automatic gain control (AGC) to properly graph
592 // the streams at different gain levels (based on running average).
593 // We use AGC because different pieces of music and speech can easily be
594 // at very different gain levels, because the game is moddable.
595 int
GraphForegroundStream(uint8 * data,sint32 width,sint32 height,bool wantSpeech)596 GraphForegroundStream (uint8 *data, sint32 width, sint32 height,
597 		bool wantSpeech)
598 {
599 	int source_num;
600 	TFB_SoundSource *source;
601 	TFB_SoundDecoder *decoder;
602 	int channels;
603 	int sample_size;
604 	int full_sample;
605 	int step;
606 	long played_time;
607 	long delta;
608 	uint8 *sbuffer;
609 	unsigned long pos;
610 	int scale;
611 	sint32 i;
612 	// AGC variables
613 #define DEF_PAGE_MAX    28000
614 #define AGC_PAGE_COUNT  16
615 	static int page_sum = DEF_PAGE_MAX * AGC_PAGE_COUNT;
616 	static int pages[AGC_PAGE_COUNT] =
617 	{
618 		DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX,
619 		DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX,
620 		DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX,
621 		DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX, DEF_PAGE_MAX,
622 	};
623 	static int page_head;
624 #define AGC_FRAME_COUNT  8
625 	static int frame_sum;
626 	static int frames;
627 	static int avg_amp = DEF_PAGE_MAX; // running amplitude (sort of) average
628 	int target_amp;
629 	int max_a;
630 #define VAD_MIN_ENERGY  100
631 	long energy;
632 
633 
634 	// Prefer speech to music
635 	source_num = SPEECH_SOURCE;
636 	source = &soundSource[source_num];
637 	LockMutex (source->stream_mutex);
638 	if (wantSpeech && (!source->sample ||
639 			!source->sample->decoder || !source->sample->decoder->is_null))
640 	{	// Use speech waveform, since it's available
641 		// Step is picked experimentally. Using step of 1 sample at 11025Hz,
642 		// because human speech is mostly in the low frequencies, and it looks
643 		// better this way.
644 		step = 1;
645 	}
646 	else
647 	{	// We do not have speech -- use music waveform
648 		UnlockMutex (source->stream_mutex);
649 
650 		source_num = MUSIC_SOURCE;
651 		source = &soundSource[source_num];
652 		LockMutex (source->stream_mutex);
653 
654 		// Step is picked experimentally. Using step of 4 samples at 11025Hz.
655 		// It looks better this way.
656 		step = 4;
657 	}
658 
659 	if (!PlayingStream (source_num) || !source->sample
660 			|| !source->sample->decoder || !source->sbuffer
661 			|| source->sbuf_size == 0)
662 	{	// We don't have data to return, oh well.
663 		UnlockMutex (source->stream_mutex);
664 		return 0;
665 	}
666 	decoder = source->sample->decoder;
667 
668 	if (!audio_GetFormatInfo (decoder->format, &channels, &sample_size))
669 	{
670 		UnlockMutex (source->stream_mutex);
671 		log_add (log_Debug, "GraphForegroundStream(): uknown format %u",
672 				(unsigned)decoder->format);
673 		return 0;
674 	}
675 	full_sample = channels * sample_size;
676 
677 	// See how far into the buffer we should be now
678 	played_time = GetTimeCounter () - source->sbuf_lasttime;
679 	delta = played_time * decoder->frequency * full_sample / ONE_SECOND;
680 	// align delta to sample start
681 	delta = delta & ~(full_sample - 1);
682 
683 	if (delta < 0)
684 	{
685 		log_add (log_Debug, "GraphForegroundStream(): something is messed"
686 				" with timing, delta %ld", delta);
687 		delta = 0;
688 	}
689 	else if (delta > (long)source->sbuf_size)
690 	{	// Stream decoder task has just had a heart attack, not much we can do
691 		delta = 0;
692 	}
693 
694 	// Step is in 11025 Hz units, so we need to adjust to source frequency
695 	step = decoder->frequency * step / 11025;
696 	if (step == 0)
697 		step = 1;
698 	step *= full_sample;
699 
700 	sbuffer = source->sbuffer;
701 	pos = source->sbuf_head + delta;
702 
703 	// We are not basing the scaling factor on signal energy, because we
704 	// want it to *look* pretty instead of sounding nice and even
705 	target_amp = (height >> 1) >> 1;
706 	scale = avg_amp / target_amp;
707 
708 	max_a = 0;
709 	energy = 0;
710 	for (i = 0; i < width; ++i, pos += step)
711 	{
712 		sint32 s;
713 		int t;
714 
715 		pos %= source->sbuf_size;
716 
717 		s = readSoundSample (sbuffer + pos, sample_size);
718 		if (channels > 1)
719 			s += readSoundSample (sbuffer + pos + sample_size, sample_size);
720 
721 		energy += (s * s) / 0x10000;
722 		t = abs(s);
723 		if (t > max_a)
724 			max_a = t;
725 
726 		s = (s / scale) + (height >> 1);
727 		if (s < 0)
728 			s = 0;
729 		else if (s > height - 1)
730 			s = height - 1;
731 
732 		data[i] = s;
733 	}
734 	energy /= width;
735 
736 	// Very basic VAD. We don't want to count speech pauses in the average
737 	if (energy > VAD_MIN_ENERGY)
738 	{
739 		// Record the maximum amplitude (sort of)
740 		frame_sum += max_a;
741 		++frames;
742 		if (frames == AGC_FRAME_COUNT)
743 		{	// Got a full page
744 			frame_sum /= AGC_FRAME_COUNT;
745 			// Record the page
746 			page_sum -= pages[page_head];
747 			page_sum += frame_sum;
748 			pages[page_head] = frame_sum;
749 			page_head = (page_head + 1) % AGC_PAGE_COUNT;
750 
751 			frame_sum = 0;
752 			frames = 0;
753 
754 			avg_amp = page_sum / AGC_PAGE_COUNT;
755 		}
756 	}
757 
758 	UnlockMutex (source->stream_mutex);
759 	return 1;
760 }
761 
762 // This function is normally called on the Starcon2Main thread
763 bool
SetMusicStreamFade(sint32 howLong,int endVolume)764 SetMusicStreamFade (sint32 howLong, int endVolume)
765 {
766 	bool ret = true;
767 
768 	LockMutex (fade_mutex);
769 
770 	if (howLong < 0)
771 		howLong = 0;
772 
773 	musicFadeStartTime = GetTimeCounter ();
774 	musicFadeInterval = howLong;
775 	musicFadeStartVolume = musicVolume;
776 	musicFadeDelta = endVolume - musicFadeStartVolume;
777 	if (!musicFadeInterval)
778 		ret = false; // reject
779 
780 	UnlockMutex (fade_mutex);
781 
782 	return ret;
783 }
784 
785 int
InitStreamDecoder(void)786 InitStreamDecoder (void)
787 {
788 	fade_mutex = CreateMutex ("Stream fade mutex", SYNC_CLASS_AUDIO);
789 	if (!fade_mutex)
790 		return -1;
791 
792 	decoderTask = AssignTask (StreamDecoderTaskFunc, 1024,
793 		"audio stream decoder");
794 	if (!decoderTask)
795 		return -1;
796 
797 	return 0;
798 }
799 
800 void
UninitStreamDecoder(void)801 UninitStreamDecoder (void)
802 {
803 	if (decoderTask)
804 	{
805 		ConcludeTask (decoderTask);
806 		decoderTask = NULL;
807 	}
808 
809 	if (fade_mutex)
810 	{
811 		DestroyMutex (fade_mutex);
812 		fade_mutex = NULL;
813 	}
814 }
815