1 /*(LGPL)
2 ---------------------------------------------------------------------------
3 	a_wave.c - Wava Data Manager
4 ---------------------------------------------------------------------------
5  * Copyright (C) 2001-2003, 2007 David Olofson
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or (at
10  * your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 
26 #include "kobolog.h"
27 #include "a_globals.h"
28 #include "a_wave.h"
29 #include "a_struct.h"
30 #include "a_math.h"
31 #include "a_tools.h"
32 #include "a_agw.h"
33 #include "eel.h"
34 
35 static int _was_init = 0;
36 
audio_wave_open(void)37 void audio_wave_open(void)
38 {
39 	if(_was_init)
40 		return;
41 
42 	memset(wavetab, 0, sizeof(wavetab));
43 	_was_init = 1;
44 }
45 
audio_wave_close(void)46 void audio_wave_close(void)
47 {
48 	if(!_was_init)
49 		return;
50 
51 	audio_wave_free(-1);
52 
53 	_was_init = 0;
54 }
55 
56 #define	CHECKINIT	if(!_was_init) audio_wave_open();
57 
58 
59 /*----------------------------------------------------------
60 	Internal Tools
61 ----------------------------------------------------------*/
62 
63 /*
64  * Fill in the loop/interpolation extension zone with the right
65  * data, depending on whether the waveform is looped or not.
66  *
67  * (This should probably be replaced with smarter mixers. Cheap
68  * sample players like the EMU8000 chips, have the same problem
69  * with interpolation over loop wraps, which causes various
70  * problems with anything but plain "loop forever" samples.)
71  */
_render_extension(int wid)72 static void _render_extension(int wid)
73 {
74 	Sint8 *eos;
75 	if(AF_MIDI == wavetab[wid].format)
76 		return;
77 
78 	eos = wavetab[wid].data.si8 + wavetab[wid].size;
79 	if(wavetab[wid].looped)
80 	{
81 		unsigned s, from = 0;
82 		for(s = 0; s < wavetab[wid].xsize; ++s)
83 		{
84 			eos[s] = wavetab[wid].data.si8[from++];
85 			if(from >= wavetab[wid].size)
86 				from = 0;
87 		}
88 	}
89 	else
90 		memset(eos, 0, wavetab[wid].xsize);
91 }
92 
93 
_calc_info(int wid)94 static void _calc_info(int wid)
95 {
96 	wavetab[wid].speed = (unsigned)((double)wavetab[wid].rate * 65536.0 /
97 			(double)a_settings.samplerate);
98 	switch(wavetab[wid].format)
99 	{
100 	  case AF_MONO8:
101 		wavetab[wid].samples = wavetab[wid].size;
102 		break;
103 	  case AF_STEREO8:
104 	  case AF_MONO16:
105 		wavetab[wid].samples = wavetab[wid].size / 2;
106 		break;
107 	  case AF_STEREO16:
108 	  case AF_MONO32:
109 		wavetab[wid].samples = wavetab[wid].size / 4;
110 		break;
111 	  case AF_STEREO32:
112 		wavetab[wid].samples = wavetab[wid].size / 8;
113 		break;
114 	  case AF_MIDI:
115 		wavetab[wid].samples = 1;
116 		break;
117 	}
118 }
119 
120 
audio_wave_prepare(int wid)121 void audio_wave_prepare(int wid)
122 {
123 	int w, first, last;
124 	if(wid < 0)
125 	{
126 		first = 0;
127 		last = AUDIO_MAX_WAVES - 1;
128 	}
129 	else
130 		first = last = wid;
131 	for(w = first; w <= last; ++w)
132 	{
133 		if(!wavetab[w].allocated)
134 			continue;
135 		_calc_info(w);
136 		_render_extension(w);
137 	}
138 }
139 
140 
_get_free_wid(void)141 static int _get_free_wid(void)
142 {
143 	int w;
144 	for(w = 0; w < AUDIO_MAX_WAVES; ++w)
145 		if(!wavetab[w].allocated)
146 			return w;
147 	return -1;
148 }
149 
150 
151 /*
152  * Flip back and forth between big and little endian,
153  * unless we're on big endian hardware.
154  */
flip_endian(Uint8 * data,Uint32 size,int format)155 static void flip_endian(Uint8 *data, Uint32 size, int format)
156 {
157 #if SDL_BYTEORDER == SDL_LITTLE_ENDIAN
158 	int i, s;
159 	switch(format)
160 	{
161 	  case AF_MIDI:
162 	  case AF_MONO8:
163 	  case AF_STEREO8:
164 		break;
165 	  case AF_MONO16:
166 	  case AF_STEREO16:
167 		for(i = 0; i < size; i += 2)
168 		{
169 			s = data[i];
170 			data[i] = data[i + 1];
171 			data[i + 1] = s;
172 		}
173 		break;
174 	  case AF_MONO32:
175 	  case AF_STEREO32:
176 		for(i = 0; i < size; i += 4)
177 		{
178 			s = data[i];
179 			data[i] = data[i + 3];
180 			data[i + 3] = s;
181 			s = data[i + 1];
182 			data[i + 1] = data[i + 2];
183 			data[i + 2] = s;
184 		}
185 		break;
186 	}
187 #endif
188 }
189 
190 
LoadRAW(const char * name,Uint8 ** data,Uint32 * size,int * format,int * rate,int * loop)191 static int LoadRAW(const char *name, Uint8 ** data, Uint32 * size,
192 		int *format, int *rate, int *loop)
193 {
194 	unsigned char header[8];
195 	int startpos = 0;
196 
197 	FILE *f = fopen(name, "rb");
198 	if(!f)
199 		return -1;
200 
201 	if(fread(header, sizeof(header), 1, f) == 1)
202 	{
203 		if(strncmp("RAW", (char *)header, 3) == 0)
204 		{
205 			const char *fmt;
206 			*format = (int)header[3] & 0x0f;
207 			*loop = (header[3] & 0x80) != 0;
208 			startpos = sizeof(header);
209 			*rate = header[4];
210 			*rate |= header[5] << 8;
211 			*rate |= header[6] << 16;
212 			*rate |= header[7] << 24;
213 			switch (*format)
214 			{
215 			  case AF_MONO8:
216 				fmt = "MONO8";
217 				break;
218 			  case AF_STEREO8:
219 				fmt = "STEREO8";
220 				break;
221 			  case AF_MONO16:
222 				fmt = "MONO16";
223 				break;
224 			  case AF_STEREO16:
225 				fmt = "STEREO16";
226 				break;
227 			  case AF_MONO32:
228 				fmt = "MONO32";
229 				break;
230 			  case AF_STEREO32:
231 				fmt = "STEREO32";
232 				break;
233 			  case AF_MIDI:
234 				fmt = "MIDI (Huh!?)";
235 				break;
236 			  default:
237 				fmt = "Unknown";
238 				break;
239 			}
240 			log_printf(DLOG, "LoadRAW: %s, %d Hz", fmt, *rate);
241 			if(*loop)
242 				log_printf(DLOG, ", looped\n");
243 			else
244 				log_printf(DLOG, ", one-shot\n");
245 		}
246 		else
247 			fseek(f, 0, SEEK_SET);
248 	}
249 
250 	if(fseek(f, 0, SEEK_END) == 0)
251 	{
252 		int s = (int)ftell(f) - startpos;
253 		if(s <= 0)
254 		{
255 			fclose(f);
256 			return -2;
257 		}
258 		*size = (Uint32) s;
259 		if(fseek(f, startpos, SEEK_SET) == 0)
260 		{
261 			*data = malloc(*size);
262 			if(*data)
263 			{
264 				if(fread(*data, *size, 1, f) == 1)
265 				{
266 					fclose(f);
267 					flip_endian(*data, *size, *format);
268 					return 0;
269 				}
270 				free(*data);
271 				*data = NULL;
272 			}
273 		}
274 	}
275 	fclose(f);
276 	return -3;
277 }
278 
279 
SaveRAW(const char * name,void * data,Uint32 size,int format,int rate,int loop)280 static int SaveRAW(const char *name, void *data, Uint32 size,
281 		int format, int rate, int loop)
282 {
283 	unsigned char header[8] = "RAW\0rate";
284 	int result;
285 	FILE *f = fopen(name, "wb");
286 	if(!f)
287 		return -1;
288 	header[3] = (char)format;
289 	if(loop)
290 		header[3] |= 0x80;
291 	header[4] = rate & 0xff;
292 	header[5] = (rate >> 8) & 0xff;
293 	header[6] = (rate >> 16) & 0xff;
294 	header[7] = (rate >> 24) & 0xff;
295 	if(fwrite(header, sizeof(header), 1, f) != 1)
296 		return -2;
297 	flip_endian(data, size, format);
298 	result = fwrite(data, size, 1, f);
299 	flip_endian(data, size, format);
300 	if(result != 1)
301 		return -3;
302 	fclose(f);
303 	return 0;
304 }
305 
306 
307 /*
308  * Calculate waveform memory needed, including the extra bytes
309  * needed for proper end-of-waveform handling. Will set the
310  * 'xsize' and 'play_samples' field.
311  *
312  * Must know sample format and original size!
313  *
314  * Also note that this is heavily dependent on the voice
315  * mixer - that's where the extra samples are needed.
316 FIXME: ...which means that this code probably belongs there,
317 FIXME: or that the voice mixer should set the parameters.
318  *
319  * Returns the total size required in bytes.
320  */
_calc_xsize(int wid)321 static unsigned _calc_xsize(int wid)
322 {
323 	unsigned samples, fsamples;
324 	unsigned bytes_sample = 1;
325 	unsigned ssize = wavetab[wid].size;
326 	switch(wavetab[wid].format)
327 	{
328 	  case AF_MONO8:
329 		bytes_sample = 1;
330 		break;
331 	  case AF_STEREO8:
332 	  case AF_MONO16:
333 		bytes_sample = 2;
334 		ssize >>= 1;
335 		break;
336 	  case AF_STEREO16:
337 	  case AF_MONO32:
338 		bytes_sample = 4;
339 		ssize >>= 2;
340 		break;
341 	  case AF_STEREO32:
342 		bytes_sample = 8;
343 		ssize >>= 3;
344 		break;
345 	  case AF_MIDI:
346 		wavetab[wid].xsize = 0;
347 		return 0;
348 	}
349 
350 	/* Fixed part: */
351 	/*	Looping. */
352 	samples = ssize;
353 	while(samples < MIN_LOOP)
354 		samples <<= 1;
355 	wavetab[wid].play_samples = samples;
356 	samples -= ssize;
357 
358 	/*	Interpolation. */
359 	samples += 3;
360 
361 	/* Freq. ratio dependent part: oversampling and looping */
362 	fsamples = AUDIO_MAX_MIX_RATE / AUDIO_MIN_OUTPUT_RATE;
363 	fsamples *= AUDIO_MAX_OVERSAMPLING;
364 	++fsamples;
365 
366 	wavetab[wid].xsize = bytes_sample * (samples + fsamples);
367 	return wavetab[wid].size + wavetab[wid].xsize;
368 }
369 
370 
371 /*----------------------------------------------------------
372 	Basic Wave API
373 ----------------------------------------------------------*/
374 
audio_wave_alloc(int wid)375 int audio_wave_alloc(int wid)
376 {
377 	CHECKINIT
378 	if(wid >= AUDIO_MAX_WAVES)
379 		return -1;
380 	if(wid < 0)
381 		wid = _get_free_wid();
382 	if(wid < 0)
383 		return -2;
384 
385 	audio_wave_free(wid);
386 	wavetab[wid].allocated = 1;
387 	return wid;
388 }
389 
390 
audio_wave_alloc_range(int first_wid,int last_wid)391 int audio_wave_alloc_range(int first_wid, int last_wid)
392 {
393 	int w, res, last_done;
394 	if(last_wid < first_wid)
395 		return -1;
396 	last_done = -1;
397 	res = 0;
398 	for(w = first_wid; w <= last_wid; ++w)
399 	{
400 		res = audio_wave_alloc(w);
401 		if(res < 0)
402 			break;
403 		last_done = w;
404 	}
405 
406 	if(res < 0)
407 	{
408 		if(last_done >= 0)
409 			for(w = first_wid; w <= last_done; ++w)
410 				audio_wave_free(w);
411 		return -2;
412 	}
413 	else
414 		return first_wid;
415 }
416 
417 
audio_wave_get(int wid)418 audio_wave_t *audio_wave_get(int wid)
419 {
420 	if(wid < 0)
421 		return NULL;
422 	if(wid >= AUDIO_MAX_WAVES)
423 		return NULL;
424 	return &wavetab[wid];
425 }
426 
427 
audio_wave_format(int wid,audio_formats_t fmt,int fs)428 int audio_wave_format(int wid, audio_formats_t fmt, int fs)
429 {
430 	unsigned old_xsize, new_size;
431 	wid = audio_wave_alloc(wid);
432 	if(wid < 0)
433 		return wid;
434 
435 	old_xsize = wavetab[wid].xsize;
436 	wavetab[wid].format = fmt;
437 	wavetab[wid].rate = fs;
438 	if(wavetab[wid].data.si8)
439 	{
440 		new_size = _calc_xsize(wid);
441 		if(wavetab[wid].xsize != old_xsize)
442 		{
443 			void *ndata = realloc(wavetab[wid].data.si8, new_size);
444 			if(!ndata)
445 				return -3;
446 			wavetab[wid].data.si8 = ndata;
447 			_calc_info(wid);
448 		}
449 	}
450 	return wid;
451 }
452 
453 
audio_wave_load_mem(int wid,void * data,unsigned size,int looped)454 int audio_wave_load_mem(int wid, void *data, unsigned size, int looped)
455 {
456 	wid = audio_wave_alloc(wid);
457 	if(wid < 0)
458 		return wid;
459 
460 	wavetab[wid].size = size;
461 	wavetab[wid].looped = looped;
462 	wavetab[wid].data.si8 = (Sint8 *)malloc(_calc_xsize(wid));
463 	wavetab[wid].howtofree = HTF_FREE;
464 	if(!wavetab[wid].data.si8)
465 	{
466 		audio_wave_free(wid);
467 		return -1;
468 	}
469 
470 	if(data)
471 		memcpy(wavetab[wid].data.si8, data, size);
472 	else
473 		memset(wavetab[wid].data.si8, 0, size);
474 
475 #ifdef xDEBUG
476 	{
477 		int i;
478 		int peak = 0;
479 		double avg = 0;
480 		double power = 0;
481 		int iavg, ipower;
482 		for(i = 0; i < size; ++i)
483 		{
484 			int s;
485 			s = wavetab[wid].data.si8[i];
486 			avg += s;
487 			power += labs(s);
488 			if(labs(s) > peak)
489 				peak = labs(s);
490 		}
491 		avg /= size;
492 		power /= size;
493 		iavg = (int)avg;
494 		ipower = (int)power;
495 		log_printf(D3LOG, "audio_wave_load_mem(id=%d): size=%d  peak=%d"
496 				"  average=%d  power=%d\n",
497 				wid, size, peak, iavg, ipower);
498 	}
499 #endif
500 	_calc_info(wid);
501 	return wid;
502 }
503 
504 
audio_wave_blank(int wid,unsigned samples,int looped)505 int audio_wave_blank(int wid, unsigned samples, int looped)
506 {
507 	int bps = 0;
508 
509 	wid = audio_wave_alloc(wid);
510 	if(wid < 0)
511 		return wid;
512 
513 	switch(wavetab[wid].format)
514 	{
515 	  case AF_MONO8:
516 		bps = 1;
517 		break;
518 	  case AF_STEREO8:
519 	  case AF_MONO16:
520 		bps = 2;
521 		break;
522 	  case AF_STEREO16:
523 	  case AF_MONO32:
524 		bps = 4;
525 		break;
526 	  case AF_STEREO32:
527 		bps = 8;
528 		break;
529 	  case AF_MIDI:
530 		return wid;
531 	}
532 	return audio_wave_load_mem(wid, NULL, samples * bps, looped);
533 }
534 
535 
audio_wave_convert(int wid,int new_wid,audio_formats_t fmt,int fs,audio_resample_t resamp)536 int audio_wave_convert(int wid, int new_wid, audio_formats_t fmt,
537 		int fs, audio_resample_t resamp)
538 {
539 	int inplace, private_pool = 0, i;
540 	audio_voice_t resampler;
541 	audio_quality_t	old_quality;
542 	int *bus;
543 	Sint8 *out8;
544 	Sint16 *out16;
545 	float *out32;
546 	unsigned newlen, j;
547 
548 	/* We need this to run the voice mixer... */
549 	if(ptab_init(65536) < 0)
550 	{
551 		log_printf(ELOG, "audio_wave_convert(): ptab_init() failed!\n");
552 		return -20;
553 	}
554 
555 	if(AF_MIDI == fmt)
556 	{
557 		log_printf(ELOG, "audio_wave_convert(): Cannot convert to MIDI!\n");
558 		return -10;
559 	}
560 
561 	if(wid >= AUDIO_MAX_WAVES)
562 		return -1;
563 	if(wid < 0)
564 		return -2;
565 
566 	if(AF_MIDI == wavetab[wid].format)
567 	{
568 		log_printf(ELOG, "audio_wave_convert(): Cannot convert from MIDI!\n");
569 		return -11;
570 	}
571 
572 	if(new_wid == wid)
573 	{
574 		inplace = 1;
575 		new_wid = audio_wave_alloc(-1);
576 		if(new_wid < 0)
577 			return new_wid;
578 	}
579 	else
580 	{
581 		inplace = 0;
582 		new_wid = audio_wave_alloc(new_wid);
583 		if(new_wid < 0)
584 			return new_wid;
585 	}
586 	audio_wave_format(new_wid, fmt, fs);
587 	newlen = (unsigned)ceil((float)wavetab[wid].samples * (float)fs /
588 			(float)wavetab[wid].rate);
589 	audio_wave_blank(new_wid, newlen, wavetab[wid].looped);
590 
591 	/* Must prepare, as we're gonna use the wave mixer! */
592 	audio_wave_prepare(wid);
593 
594 	memset(&resampler, 0, sizeof(resampler));
595 
596 	/* We need to tweak the 'speed' to get the output rate right! */
597 	wavetab[wid].speed = (unsigned)((double)wavetab[wid].rate * 65536.0 /
598 			(double)wavetab[new_wid].rate);
599 
600 	old_quality = a_settings.quality;
601 	a_settings.quality = AQ_VERY_HIGH;
602 
603 	if(!aev_event_pool)
604 	{
605 		private_pool = 1;
606 		aev_open(20);
607 	}
608 
609 	switch(resamp)
610 	{
611 	  case AR_WORST:
612 		resamp = AR_NEAREST;
613 		break;
614 	  case AR_MEDIUM:
615 		resamp = AR_LINEAR_2X_R;
616 		break;
617 	  case AR_BEST:
618 		resamp = AR_CUBIC_R;
619 		break;
620 	  default:
621 		break;
622 	}
623 
624 	aev_timer = 0;
625 	(void)aev_send1(&resampler.port, 0, VE_START, wid);
626 	(void)aev_sendi1(&resampler.port, 0, VE_SET, VC_PITCH, 60<<16);
627 	(void)aev_sendi1(&resampler.port, 0, VE_SET, VC_RESAMPLE, resamp);
628 	(void)aev_sendi1(&resampler.port, 0, VE_SET, VC_SEND_BUS, -1);
629 	(void)aev_sendi2(&resampler.port, 0, VE_IRAMP, VIC_LVOL,
630 			65536 >> (16-VOL_BITS), 0);
631 	(void)aev_sendi2(&resampler.port, 0, VE_IRAMP, VIC_RVOL,
632 			65536 >> (16-VOL_BITS), 0);
633 	bus = malloc(256 * sizeof(int) * 2);
634 	out8 = wavetab[new_wid].data.si8;
635 	out16 = wavetab[new_wid].data.si16;
636 	out32 = wavetab[new_wid].data.f32;
637 	for(i = (int)wavetab[new_wid].samples; i > 0; i -= 256)
638 	{
639 		unsigned frames;
640 		if(i > 256)
641 			frames = 256;
642 		else
643 			frames = (unsigned)i;
644 		s32clear(bus, frames);
645 		voice_process_mix(&resampler, &bus, frames);
646 		switch(wavetab[new_wid].format)
647 		{
648 		  case AF_MONO8:
649 			for(j = 0; j < frames; ++j)
650 				*out8++ = (bus[j<<1] + bus[(j<<1)+1]) >> 9;
651 			break;
652 		  case AF_STEREO8:
653 			for(j = 0; j < frames; ++j)
654 			{
655 				*out8++ = bus[j<<1] >> 8;
656 				*out8++ = bus[(j<<1)+1] >> 8;
657 			}
658 			break;
659 		  case AF_MONO16:
660 			for(j = 0; j < frames; ++j)
661 				*out16++ = (Sint16)(bus[j<<1] +
662 						bus[(j<<1)+1]) >> 1;
663 			break;
664 		  case AF_STEREO16:
665 			for(j = 0; j < frames; ++j)
666 			{
667 				*out16++ = (Sint16)(bus[j<<1]);
668 				*out16++ = (Sint16)(bus[(j<<1)+1]);
669 			}
670 			break;
671 		  case AF_MONO32:
672 			for(j = 0; j < frames; ++j)
673 				*out32++ = (float)(bus[j<<1] +
674 						bus[(j<<1)+1]) * 0.5;
675 			break;
676 		  case AF_STEREO32:
677 			for(j = 0; j < frames; ++j)
678 			{
679 				*out32++ = (float)bus[j<<1];
680 				*out32++ = (float)bus[(j<<1)+1];
681 			}
682 			break;
683 		  case AF_MIDI:	/* whinestopper... */
684 			break;
685 		}
686 	}
687 	free(bus);
688 	_calc_info(new_wid);
689 
690 	voice_kill(&resampler);
691 	a_settings.quality = old_quality;
692 
693 	if(private_pool)
694 		aev_close();
695 
696 	if(inplace)
697 	{
698 		audio_wave_free(wid);
699 		memcpy(wavetab + wid, wavetab + new_wid, sizeof(audio_wave_t));
700 		memset(wavetab + new_wid, 0, sizeof(audio_wave_t));
701 		return wid;
702 	}
703 	else
704 	{
705 		_calc_info(wid);	/* Restore after our tweaking */
706 		return new_wid;
707 	}
708 }
709 
710 
audio_wave_clone(int wid,int new_wid)711 int audio_wave_clone(int wid, int new_wid)
712 {
713 	if(wid >= AUDIO_MAX_WAVES)
714 		return -1;
715 	if(wid < 0)
716 		return -2;
717 	new_wid = audio_wave_format(new_wid, wavetab[wid].format,
718 			wavetab[wid].rate);
719 	if(new_wid < 0)
720 		return new_wid;
721 	return audio_wave_load_mem(new_wid, wavetab[wid].data.si8,
722 			wavetab[wid].size, wavetab[wid].looped);
723 }
724 
725 
726 /* We're simply using the same path for everything. */
audio_set_path(const char * path)727 void audio_set_path(const char *path)
728 {
729 	eel_set_path(path);
730 }
731 
732 
audio_path(void)733 const char *audio_path(void)
734 {
735 	return eel_path();
736 }
737 
738 
load_midi(int wid,const char * name)739 static int load_midi(int wid, const char *name)
740 {
741 	midi_file_t *mf;
742 
743 	wid = audio_wave_alloc(wid);
744 	if(wid < 0)
745 		return wid;
746 
747 	mf = mf_open(name);
748 	if(!mf)
749 	{
750 		log_printf(ELOG, "load_midi(): Failed to load file"
751 				" \"%s\"! (Path = \"%s\")\n", name,
752 				eel_path());
753 		audio_wave_free(wid);
754 		return -1;
755 	}
756 
757 	wavetab[wid].data.midi = mf;
758 
759 	wavetab[wid].size = 1;	/* Duration in ms or something? */
760 	wavetab[wid].xsize = 0;	/* N/A */
761 	wavetab[wid].howtofree = HTF_FREE;
762 
763 	wavetab[wid].format = AF_MIDI;
764 	wavetab[wid].rate = 120;	/* PPQN? */
765 	wavetab[wid].looped = 0;	/* Not yet implemented */
766 
767 	wavetab[wid].speed = 120;	/* ? */
768 	wavetab[wid].samples = 1;	/* Number of events? */
769 
770 	log_printf(DLOG, ".------------------------------------------------------\n");
771 	log_printf(DLOG, "| MIDI File: %s\n", name);
772 	log_printf(DLOG, "|    Format: %u\n", mf->format);
773 	log_printf(DLOG, "|     Title: %s\n", mf->title);
774 	log_printf(DLOG, "|    Author: %s\n", mf->author);
775 	log_printf(DLOG, "|   Remarks: %s\n", mf->remarks);
776 	log_printf(DLOG, "'------------------------------------------------------\n");
777 
778 	return wid;
779 }
780 
781 
audio_wave_load(int wid,const char * name,int looped)782 int audio_wave_load(int wid, const char *name, int looped)
783 {
784 	char buf[1024];
785 	SDL_AudioSpec spec;
786 	Uint8 *data = NULL;
787 	Uint32 size;
788 	int format = -2;
789 	int rate = 0;	/* Warning suppressor */
790 	int res;
791 	int using_loadwav = 0;
792 
793 	/* Prepend path */
794 	strncpy(buf, eel_path(), sizeof(buf));
795 #ifdef WIN32
796 	strncat(buf, "\\", sizeof(buf));
797 #elif defined MACOS
798 	strncat(buf, ":", sizeof(buf));
799 #else
800 	strncat(buf, "/", sizeof(buf));
801 #endif
802 	strncat(buf, name, sizeof(buf));
803 
804 	/* Check extension */
805 	if(strstr(name, ".raw") || strstr(name, ".RAW"))
806 	{
807 		format = -1;
808 		res = LoadRAW(buf, &data, &size, &format, &rate, &looped);
809 		if(res < 0)
810 			format = -1;
811 	}
812 	else if(strstr(name, ".agw") || strstr(name, ".AGW"))
813 		return agw_load(wid, name);	/* No full path here! */
814 	else if(strstr(name, ".mid") || strstr(name, ".MID"))
815 		return load_midi(wid, buf);
816 	else
817 	{
818 		using_loadwav = 1;
819 		res = SDL_LoadWAV(buf, &spec, &data, &size) ? 0 : -1;
820 	}
821 
822 	wid = audio_wave_alloc(wid);
823 	if(wid < 0)
824 		return wid;
825 
826 	if(format >= 0)
827 	{
828 		wavetab[wid].format = format;
829 		wavetab[wid].rate = rate;
830 	}
831 	else if(using_loadwav)
832 	{
833 		switch (spec.format)
834 		{
835 		  case AUDIO_S8:
836 			wavetab[wid].format = AF_MONO8;
837 			break;
838 		  case AUDIO_S16SYS:
839 			wavetab[wid].format = AF_MONO16;
840 			break;
841 		  default:
842 			log_printf(ELOG, "sound_load(): Unsupported wave format!\n");
843 			SDL_FreeWAV((Uint8 *)(wavetab[wid].data.si8));
844 			res = -1;
845 			break;
846 		}
847 		if(spec.channels == 2)
848 			++wavetab[wid].format;
849 		wavetab[wid].rate = spec.freq;
850 	}
851 
852 	if(res < 0)
853 	{
854 		log_printf(ELOG, "audio_wave_load(): Failed to load file"
855 				" \"%s\"! (Path = \"%s\")\n", name,
856 				eel_path());
857 		audio_wave_free(wid);
858 		return -3;
859 	}
860 
861 	if(data)
862 		audio_wave_load_mem(wid, data, size, looped);
863 
864 	if(using_loadwav)
865 		SDL_FreeWAV(data);
866 	else
867 		free(data);
868 
869 	return wid;
870 }
871 
872 
audio_wave_save(int wid,const char * name)873 int audio_wave_save(int wid, const char *name)
874 {
875 	char buf[1024];
876 	audio_wave_t *wave = audio_wave_get(wid);
877 	if(!wave)
878 		return -1;
879 
880 	/* Prepend path */
881 	strncpy(buf, eel_path(), sizeof(buf));
882 #ifdef WIN32
883 	strncat(buf, "\\", sizeof(buf));
884 #elif defined MACOS
885 	strncat(buf, ":", sizeof(buf));
886 #else
887 	strncat(buf, "/", sizeof(buf));
888 #endif
889 	strncat(buf, name, sizeof(buf));
890 	log_printf(DLOG, "Saving to \"%s\"\n", buf);
891 	/* Check extension */
892 	if(strstr(name, ".raw") || strstr(name, ".RAW"))
893 		return SaveRAW(buf, wave->data.si8, wave->size,
894 				(int)wave->format, wave->rate, wave->looped);
895 	else
896 		return -2;
897 }
898 
899 
audio_wave_free(int wid)900 void audio_wave_free(int wid)
901 {
902 	int w, first, last;
903 	CHECKINIT
904 	if(wid < 0)
905 	{
906 		first = 0;
907 		last = AUDIO_MAX_WAVES - 1;
908 	}
909 	else
910 		first = last = wid;
911 	for(w = first; w <= last; ++w)
912 	{
913 		if(!wavetab[w].data.si8)
914 			continue;
915 		if(HTF_FREE == wavetab[w].howtofree)
916 			switch(wavetab[w].format)
917 			{
918 			  case AF_MONO8:
919 			  case AF_STEREO8:
920 			  case AF_MONO16:
921 			  case AF_STEREO16:
922 			  case AF_MONO32:
923 			  case AF_STEREO32:
924 				free(wavetab[w].data.si8);
925 				break;
926 			  case AF_MIDI:
927 				mf_close(wavetab[w].data.midi);
928 				break;
929 			}
930 		wavetab[w].data.si8 = NULL;
931 		wavetab[w].size = 0;
932 		wavetab[w].xsize = 0;
933 		wavetab[w].allocated = 0;
934 	}
935 }
936 
937 
audio_wave_info(int wid)938 void audio_wave_info(int wid)
939 {
940 	int w, first, last;
941 	int count = 0;
942 	int total_size = 0;
943 	int total_time = 0;
944 	if(wid < 0)
945 	{
946 		first = 0;
947 		last = AUDIO_MAX_WAVES - 1;
948 	}
949 	else
950 		first = last = wid;
951 	log_printf(VLOG, "Waveform info:\n");
952 	for(w = first; w <= last; ++w)
953 	{
954 		const char *f;
955 		if(!wavetab[w].allocated)
956 			continue;
957 		switch(wavetab[w].format)
958 		{
959 		  case AF_MONO8:	f = "MONO8   ";	break;
960 		  case AF_STEREO8:	f = "STEREO8 ";	break;
961 		  case AF_MONO16:	f = "MONO16  ";	break;
962 		  case AF_STEREO16:	f = "STEREO16";	break;
963 		  case AF_MONO32:	f = "MONO32  ";	break;
964 		  case AF_STEREO32:	f = "STEREO32";	break;
965 		  case AF_MIDI:		f = "MIDI    ";	break;
966 		  default:		f = "Unknown ";	break;
967 		}
968 		if(wavetab[w].format == AF_MIDI)
969 			log_printf(VLOG, "  (%3d: %s %s, %d PPQN,\t%d events)\n",
970 					w, f, wavetab[w].data.midi->title,
971 					wavetab[w].rate, wavetab[w].size);
972 		else
973 		{
974 			float d = (float)wavetab[w].samples / wavetab[w].rate;
975 			log_printf(VLOG, "   %3d: %s %s, %d Hz,\t%d bytes\t"
976 					"(%.2f s)\n",
977 					w, f, wavetab[w].looped ?
978 							"LOOPED" : "ONESHOT",
979 					wavetab[w].rate, wavetab[w].size, d);
980 			total_size += wavetab[w].size;
981 			total_time += d;
982 			++count;
983 		}
984 	}
985 	log_printf(VLOG, "  Total %d waveforms, total size: %d bytes, "
986 			"total time: %d s\n", count, total_size, total_time);
987 }
988