1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24: #include <fmod.h>
25: #include <fmod_errors.h>
26: #include "qemu-common.h"
27: #include "audio.h"
28:
29: #define AUDIO_CAP "fmod"
30: #include "audio_int.h"
31:
32: typedef struct FMODVoiceOut {
33: HWVoiceOut hw;
34: unsigned int old_pos;
35: FSOUND_SAMPLE *fmod_sample;
36: int channel;
37: } FMODVoiceOut;
38:
39: typedef struct FMODVoiceIn {
40: HWVoiceIn hw;
41: FSOUND_SAMPLE *fmod_sample;
42: } FMODVoiceIn;
43:
44: static struct {
45: const char *drvname;
46: int nb_samples;
47: int freq;
48: int nb_channels;
49: int bufsize;
50: int threshold;
51: int broken_adc;
52: } conf = {
53: NULL,
54: 2048 * 2,
55: 44100,
56: 2,
57: 0,
58: 0,
59: 0
60: };
61:
62: static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
63: {
64: va_list ap;
65:
66: va_start (ap, fmt);
67: AUD_vlog (AUDIO_CAP, fmt, ap);
68: va_end (ap);
69:
70: AUD_log (AUDIO_CAP, "Reason: %s\n",
71: FMOD_ErrorString (FSOUND_GetError ()));
72: }
73:
74: static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
75: const char *typ,
76: const char *fmt,
77: ...
78: )
79: {
80: va_list ap;
81:
82: AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
83:
84: va_start (ap, fmt);
85: AUD_vlog (AUDIO_CAP, fmt, ap);
86: va_end (ap);
87:
88: AUD_log (AUDIO_CAP, "Reason: %s\n",
89: FMOD_ErrorString (FSOUND_GetError ()));
90: }
91:
92: static int fmod_write (SWVoiceOut *sw, void *buf, int len)
93: {
94: return audio_pcm_sw_write (sw, buf, len);
95: }
96:
97: static void fmod_clear_sample (FMODVoiceOut *fmd)
98: {
99: HWVoiceOut *hw = &fmd->hw;
100: int status;
101: void *p1 = 0, *p2 = 0;
102: unsigned int len1 = 0, len2 = 0;
103:
104: status = FSOUND_Sample_Lock (
105: fmd->fmod_sample,
106: 0,
107: hw->samples << hw->info.shift,
108: &p1,
109: &p2,
110: &len1,
111: &len2
112: );
113:
114: if (!status) {
115: fmod_logerr ("Failed to lock sample\n");
116: return;
117: }
118:
119: if ((len1 & hw->info.align) || (len2 & hw->info.align)) {
120: dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
121: len1, len2, hw->info.align + 1);
122: goto fail;
123: }
124:
125: if ((len1 + len2) - (hw->samples << hw->info.shift)) {
126: dolog ("Lock returned incomplete length %d, %d\n",
127: len1 + len2, hw->samples << hw->info.shift);
128: goto fail;
129: }
130:
131: audio_pcm_info_clear_buf (&hw->info, p1, hw->samples);
132:
133: fail:
134: status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
135: if (!status) {
136: fmod_logerr ("Failed to unlock sample\n");
137: }
138: }
139:
140: static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
141: {
142: int src_len1 = dst_len;
143: int src_len2 = 0;
144: int pos = hw->rpos + dst_len;
145: st_sample_t *src1 = hw->mix_buf + hw->rpos;
146: st_sample_t *src2 = NULL;
147:
148: if (pos > hw->samples) {
149: src_len1 = hw->samples - hw->rpos;
150: src2 = hw->mix_buf;
151: src_len2 = dst_len - src_len1;
152: pos = src_len2;
153: }
154:
155: if (src_len1) {
156: hw->clip (dst, src1, src_len1);
157: }
158:
159: if (src_len2) {
160: dst = advance (dst, src_len1 << hw->info.shift);
161: hw->clip (dst, src2, src_len2);
162: }
163:
164: hw->rpos = pos % hw->samples;
165: }
166:
167: static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2,
168: unsigned int blen1, unsigned int blen2)
169: {
170: int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2);
171: if (!status) {
172: fmod_logerr ("Failed to unlock sample\n");
173: return -1;
174: }
175: return 0;
176: }
177:
178: static int fmod_lock_sample (
179: FSOUND_SAMPLE *sample,
180: struct audio_pcm_info *info,
181: int pos,
182: int len,
183: void **p1,
184: void **p2,
185: unsigned int *blen1,
186: unsigned int *blen2
187: )
188: {
189: int status;
190:
191: status = FSOUND_Sample_Lock (
192: sample,
193: pos << info->shift,
194: len << info->shift,
195: p1,
196: p2,
197: blen1,
198: blen2
199: );
200:
201: if (!status) {
202: fmod_logerr ("Failed to lock sample\n");
203: return -1;
204: }
205:
206: if ((*blen1 & info->align) || (*blen2 & info->align)) {
207: dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
208: *blen1, *blen2, info->align + 1);
209:
210: fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2);
211:
212: *p1 = NULL - 1;
213: *p2 = NULL - 1;
214: *blen1 = ~0U;
215: *blen2 = ~0U;
216: return -1;
217: }
218:
219: if (!*p1 && *blen1) {
220: dolog ("warning: !p1 && blen1=%d\n", *blen1);
221: *blen1 = 0;
222: }
223:
224: if (!p2 && *blen2) {
225: dolog ("warning: !p2 && blen2=%d\n", *blen2);
226: *blen2 = 0;
227: }
228:
229: return 0;
230: }
231:
232: static int fmod_run_out (HWVoiceOut *hw)
233: {
234: FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
235: int live, decr;
236: void *p1 = 0, *p2 = 0;
237: unsigned int blen1 = 0, blen2 = 0;
238: unsigned int len1 = 0, len2 = 0;
239: int nb_live;
240:
241: live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
242: if (!live) {
243: return 0;
244: }
245:
246: if (!hw->pending_disable
247: && nb_live
248: && (conf.threshold && live <= conf.threshold)) {
249: ldebug ("live=%d nb_live=%d\n", live, nb_live);
250: return 0;
251: }
252:
253: decr = live;
254:
255: if (fmd->channel >= 0) {
256: int len = decr;
257: int old_pos = fmd->old_pos;
258: int ppos = FSOUND_GetCurrentPosition (fmd->channel);
259:
260: if (ppos == old_pos || !ppos) {
261: return 0;
262: }
263:
264: if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
265: len = ppos - old_pos;
266: }
267: else {
268: if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
269: len = hw->samples - old_pos + ppos;
270: }
271: }
272: decr = len;
273:
274: if (audio_bug (AUDIO_FUNC, decr < 0)) {
275: dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
276: decr, live, ppos, old_pos, len);
277: return 0;
278: }
279: }
280:
281:
282: if (!decr) {
283: return 0;
284: }
285:
286: if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
287: fmd->old_pos, decr,
288: &p1, &p2,
289: &blen1, &blen2)) {
290: return 0;
291: }
292:
293: len1 = blen1 >> hw->info.shift;
294: len2 = blen2 >> hw->info.shift;
295: ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
296: decr = len1 + len2;
297:
298: if (p1 && len1) {
299: fmod_write_sample (hw, p1, len1);
300: }
301:
302: if (p2 && len2) {
303: fmod_write_sample (hw, p2, len2);
304: }
305:
306: fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
307:
308: fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
309: return decr;
310: }
311:
312: static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
313: {
314: int mode = FSOUND_LOOP_NORMAL;
315:
316: switch (fmt) {
317: case AUD_FMT_S8:
318: mode |= FSOUND_SIGNED | FSOUND_8BITS;
319: break;
320:
321: case AUD_FMT_U8:
322: mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
323: break;
324:
325: case AUD_FMT_S16:
326: mode |= FSOUND_SIGNED | FSOUND_16BITS;
327: break;
328:
329: case AUD_FMT_U16:
330: mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
331: break;
332:
333: default:
334: dolog ("Internal logic error: Bad audio format %d\n", fmt);
335: #ifdef DEBUG_FMOD
336: abort ();
337: #endif
338: mode |= FSOUND_8BITS;
339: }
340: mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
341: return mode;
342: }
343:
344: static void fmod_fini_out (HWVoiceOut *hw)
345: {
346: FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
347:
348: if (fmd->fmod_sample) {
349: FSOUND_Sample_Free (fmd->fmod_sample);
350: fmd->fmod_sample = 0;
351:
352: if (fmd->channel >= 0) {
353: FSOUND_StopSound (fmd->channel);
354: }
355: }
356: }
357:
358: static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as)
359: {
360: int bits16, mode, channel;
361: FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
362: audsettings_t obt_as = *as;
363:
364: mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
365: fmd->fmod_sample = FSOUND_Sample_Alloc (
366: FSOUND_FREE,
367: conf.nb_samples,
368: mode,
369: as->freq,
370: 255,
371: 128,
372: 255
373: );
374:
375: if (!fmd->fmod_sample) {
376: fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
377: return -1;
378: }
379:
380: channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
381: if (channel < 0) {
382: fmod_logerr2 ("DAC", "Failed to start playing sound\n");
383: FSOUND_Sample_Free (fmd->fmod_sample);
384: return -1;
385: }
386: fmd->channel = channel;
387:
388:
389: obt_as.endianness = 0;
390: audio_pcm_init_info (&hw->info, &obt_as);
391: bits16 = (mode & FSOUND_16BITS) != 0;
392: hw->samples = conf.nb_samples;
393: return 0;
394: }
395:
396: static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
397: {
398: int status;
399: FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
400:
401: switch (cmd) {
402: case VOICE_ENABLE:
403: fmod_clear_sample (fmd);
404: status = FSOUND_SetPaused (fmd->channel, 0);
405: if (!status) {
406: fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
407: }
408: break;
409:
410: case VOICE_DISABLE:
411: status = FSOUND_SetPaused (fmd->channel, 1);
412: if (!status) {
413: fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
414: }
415: break;
416: }
417: return 0;
418: }
419:
420: static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as)
421: {
422: int bits16, mode;
423: FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
424: audsettings_t obt_as = *as;
425:
426: if (conf.broken_adc) {
427: return -1;
428: }
429:
430: mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
431: fmd->fmod_sample = FSOUND_Sample_Alloc (
432: FSOUND_FREE,
433: conf.nb_samples,
434: mode,
435: as->freq,
436: 255,
437: 128,
438: 255
439: );
440:
441: if (!fmd->fmod_sample) {
442: fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
443: return -1;
444: }
445:
446:
447: obt_as.endianness = 0;
448: audio_pcm_init_info (&hw->info, &obt_as);
449: bits16 = (mode & FSOUND_16BITS) != 0;
450: hw->samples = conf.nb_samples;
451: return 0;
452: }
453:
454: static void fmod_fini_in (HWVoiceIn *hw)
455: {
456: FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
457:
458: if (fmd->fmod_sample) {
459: FSOUND_Record_Stop ();
460: FSOUND_Sample_Free (fmd->fmod_sample);
461: fmd->fmod_sample = 0;
462: }
463: }
464:
465: static int fmod_run_in (HWVoiceIn *hw)
466: {
467: FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
468: int hwshift = hw->info.shift;
469: int live, dead, new_pos, len;
470: unsigned int blen1 = 0, blen2 = 0;
471: unsigned int len1, len2;
472: unsigned int decr;
473: void *p1, *p2;
474:
475: live = audio_pcm_hw_get_live_in (hw);
476: dead = hw->samples - live;
477: if (!dead) {
478: return 0;
479: }
480:
481: new_pos = FSOUND_Record_GetPosition ();
482: if (new_pos < 0) {
483: fmod_logerr ("Could not get recording position\n");
484: return 0;
485: }
486:
487: len = audio_ring_dist (new_pos, hw->wpos, hw->samples);
488: if (!len) {
489: return 0;
490: }
491: len = audio_MIN (len, dead);
492:
493: if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
494: hw->wpos, len,
495: &p1, &p2,
496: &blen1, &blen2)) {
497: return 0;
498: }
499:
500: len1 = blen1 >> hwshift;
501: len2 = blen2 >> hwshift;
502: decr = len1 + len2;
503:
504: if (p1 && blen1) {
505: hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
506: }
507: if (p2 && len2) {
508: hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
509: }
510:
511: fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
512: hw->wpos = (hw->wpos + decr) % hw->samples;
513: return decr;
514: }
515:
516: static struct {
517: const char *name;
518: int type;
519: } drvtab[] = {
520: {"none", FSOUND_OUTPUT_NOSOUND},
521: #ifdef _WIN32
522: {"winmm", FSOUND_OUTPUT_WINMM},
523: {"dsound", FSOUND_OUTPUT_DSOUND},
524: {"a3d", FSOUND_OUTPUT_A3D},
525: {"asio", FSOUND_OUTPUT_ASIO},
526: #endif
527: #ifdef __linux__
528: {"oss", FSOUND_OUTPUT_OSS},
529: {"alsa", FSOUND_OUTPUT_ALSA},
530: {"esd", FSOUND_OUTPUT_ESD},
531: #endif
532: #ifdef __APPLE__
533: {"mac", FSOUND_OUTPUT_MAC},
534: #endif
535: #if 0
536: {"xbox", FSOUND_OUTPUT_XBOX},
537: {"ps2", FSOUND_OUTPUT_PS2},
538: {"gcube", FSOUND_OUTPUT_GC},
539: #endif
540: {"none-realtime", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
541: };
542:
543: static void *fmod_audio_init (void)
544: {
545: size_t i;
546: double ver;
547: int status;
548: int output_type = -1;
549: const char *drv = conf.drvname;
550:
551: ver = FSOUND_GetVersion ();
552: if (ver < FMOD_VERSION) {
553: dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
554: return NULL;
555: }
556:
557: #ifdef __linux__
558: if (ver < 3.75) {
559: dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
560: "ADC will be disabled.\n");
561: conf.broken_adc = 1;
562: }
563: #endif
564:
565: if (drv) {
566: int found = 0;
567: for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
568: if (!strcmp (drv, drvtab[i].name)) {
569: output_type = drvtab[i].type;
570: found = 1;
571: break;
572: }
573: }
574: if (!found) {
575: dolog ("Unknown FMOD driver `%s'\n", drv);
576: dolog ("Valid drivers:\n");
577: for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
578: dolog (" %s\n", drvtab[i].name);
579: }
580: }
581: }
582:
583: if (output_type != -1) {
584: status = FSOUND_SetOutput (output_type);
585: if (!status) {
586: fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
587: return NULL;
588: }
589: }
590:
591: if (conf.bufsize) {
592: