Merge branch 'master' of /home/nchip/public_html/qemu into garage-push
[qemu] / audio / fmodaudio.c
1 /*
2  * QEMU FMOD audio driver
3  *
4  * Copyright (c) 2004-2005 Vassili Karpov (malc)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
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     struct st_sample *src1 = hw->mix_buf + hw->rpos;
146     struct st_sample *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, struct audsettings *as)
359 {
360     int bits16, mode, channel;
361     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
362     struct audsettings 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,            /* index */
367         conf.nb_samples,        /* length */
368         mode,                   /* mode */
369         as->freq,               /* freq */
370         255,                    /* volume */
371         128,                    /* pan */
372         255                     /* priority */
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     /* FMOD always operates on little endian frames? */
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, struct audsettings *as)
421 {
422     int bits16, mode;
423     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
424     struct audsettings 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,            /* index */
433         conf.nb_samples,        /* length */
434         mode,                   /* mode */
435         as->freq,               /* freq */
436         255,                    /* volume */
437         128,                    /* pan */
438         255                     /* priority */
439         );
440
441     if (!fmd->fmod_sample) {
442         fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
443         return -1;
444     }
445
446     /* FMOD always operates on little endian frames? */
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 < ARRAY_SIZE (drvtab); 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 < ARRAY_SIZE (drvtab); 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         status = FSOUND_SetBufferSize (conf.bufsize);
593         if (!status) {
594             fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
595         }
596     }
597
598     status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
599     if (!status) {
600         fmod_logerr ("FSOUND_Init failed\n");
601         return NULL;
602     }
603
604     return &conf;
605 }
606
607 static int fmod_read (SWVoiceIn *sw, void *buf, int size)
608 {
609     return audio_pcm_sw_read (sw, buf, size);
610 }
611
612 static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
613 {
614     int status;
615     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
616
617     switch (cmd) {
618     case VOICE_ENABLE:
619         status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
620         if (!status) {
621             fmod_logerr ("Failed to start recording\n");
622         }
623         break;
624
625     case VOICE_DISABLE:
626         status = FSOUND_Record_Stop ();
627         if (!status) {
628             fmod_logerr ("Failed to stop recording\n");
629         }
630         break;
631     }
632     return 0;
633 }
634
635 static void fmod_audio_fini (void *opaque)
636 {
637     (void) opaque;
638     FSOUND_Close ();
639 }
640
641 static struct audio_option fmod_options[] = {
642     {"DRV", AUD_OPT_STR, &conf.drvname,
643      "FMOD driver", NULL, 0},
644     {"FREQ", AUD_OPT_INT, &conf.freq,
645      "Default frequency", NULL, 0},
646     {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
647      "Buffer size in samples", NULL, 0},
648     {"CHANNELS", AUD_OPT_INT, &conf.nb_channels,
649      "Number of default channels (1 - mono, 2 - stereo)", NULL, 0},
650     {"BUFSIZE", AUD_OPT_INT, &conf.bufsize,
651      "(undocumented)", NULL, 0},
652 #if 0
653     {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
654      "(undocumented)"},
655 #endif
656
657     {NULL, 0, NULL, NULL, NULL, 0}
658 };
659
660 static struct audio_pcm_ops fmod_pcm_ops = {
661     fmod_init_out,
662     fmod_fini_out,
663     fmod_run_out,
664     fmod_write,
665     fmod_ctl_out,
666
667     fmod_init_in,
668     fmod_fini_in,
669     fmod_run_in,
670     fmod_read,
671     fmod_ctl_in
672 };
673
674 struct audio_driver fmod_audio_driver = {
675     INIT_FIELD (name           = ) "fmod",
676     INIT_FIELD (descr          = ) "FMOD 3.xx http://www.fmod.org",
677     INIT_FIELD (options        = ) fmod_options,
678     INIT_FIELD (init           = ) fmod_audio_init,
679     INIT_FIELD (fini           = ) fmod_audio_fini,
680     INIT_FIELD (pcm_ops        = ) &fmod_pcm_ops,
681     INIT_FIELD (can_be_default = ) 1,
682     INIT_FIELD (max_voices_out = ) INT_MAX,
683     INIT_FIELD (max_voices_in  = ) INT_MAX,
684     INIT_FIELD (voice_size_out = ) sizeof (FMODVoiceOut),
685     INIT_FIELD (voice_size_in  = ) sizeof (FMODVoiceIn)
686 };