Revert "Fix Sparc/Linux host breakage by df70204db53e3611af986f434e74a882bce190ca"
[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 broken_adc;
51 } conf = {
52     .nb_samples  = 2048 * 2,
53     .freq        = 44100,
54     .nb_channels = 2,
55 };
56
57 static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt, ...)
58 {
59     va_list ap;
60
61     va_start (ap, fmt);
62     AUD_vlog (AUDIO_CAP, fmt, ap);
63     va_end (ap);
64
65     AUD_log (AUDIO_CAP, "Reason: %s\n",
66              FMOD_ErrorString (FSOUND_GetError ()));
67 }
68
69 static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
70     const char *typ,
71     const char *fmt,
72     ...
73     )
74 {
75     va_list ap;
76
77     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
78
79     va_start (ap, fmt);
80     AUD_vlog (AUDIO_CAP, fmt, ap);
81     va_end (ap);
82
83     AUD_log (AUDIO_CAP, "Reason: %s\n",
84              FMOD_ErrorString (FSOUND_GetError ()));
85 }
86
87 static int fmod_write (SWVoiceOut *sw, void *buf, int len)
88 {
89     return audio_pcm_sw_write (sw, buf, len);
90 }
91
92 static void fmod_clear_sample (FMODVoiceOut *fmd)
93 {
94     HWVoiceOut *hw = &fmd->hw;
95     int status;
96     void *p1 = 0, *p2 = 0;
97     unsigned int len1 = 0, len2 = 0;
98
99     status = FSOUND_Sample_Lock (
100         fmd->fmod_sample,
101         0,
102         hw->samples << hw->info.shift,
103         &p1,
104         &p2,
105         &len1,
106         &len2
107         );
108
109     if (!status) {
110         fmod_logerr ("Failed to lock sample\n");
111         return;
112     }
113
114     if ((len1 & hw->info.align) || (len2 & hw->info.align)) {
115         dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
116                len1, len2, hw->info.align + 1);
117         goto fail;
118     }
119
120     if ((len1 + len2) - (hw->samples << hw->info.shift)) {
121         dolog ("Lock returned incomplete length %d, %d\n",
122                len1 + len2, hw->samples << hw->info.shift);
123         goto fail;
124     }
125
126     audio_pcm_info_clear_buf (&hw->info, p1, hw->samples);
127
128  fail:
129     status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
130     if (!status) {
131         fmod_logerr ("Failed to unlock sample\n");
132     }
133 }
134
135 static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
136 {
137     int src_len1 = dst_len;
138     int src_len2 = 0;
139     int pos = hw->rpos + dst_len;
140     struct st_sample *src1 = hw->mix_buf + hw->rpos;
141     struct st_sample *src2 = NULL;
142
143     if (pos > hw->samples) {
144         src_len1 = hw->samples - hw->rpos;
145         src2 = hw->mix_buf;
146         src_len2 = dst_len - src_len1;
147         pos = src_len2;
148     }
149
150     if (src_len1) {
151         hw->clip (dst, src1, src_len1);
152     }
153
154     if (src_len2) {
155         dst = advance (dst, src_len1 << hw->info.shift);
156         hw->clip (dst, src2, src_len2);
157     }
158
159     hw->rpos = pos % hw->samples;
160 }
161
162 static int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2,
163                                unsigned int blen1, unsigned int blen2)
164 {
165     int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2);
166     if (!status) {
167         fmod_logerr ("Failed to unlock sample\n");
168         return -1;
169     }
170     return 0;
171 }
172
173 static int fmod_lock_sample (
174     FSOUND_SAMPLE *sample,
175     struct audio_pcm_info *info,
176     int pos,
177     int len,
178     void **p1,
179     void **p2,
180     unsigned int *blen1,
181     unsigned int *blen2
182     )
183 {
184     int status;
185
186     status = FSOUND_Sample_Lock (
187         sample,
188         pos << info->shift,
189         len << info->shift,
190         p1,
191         p2,
192         blen1,
193         blen2
194         );
195
196     if (!status) {
197         fmod_logerr ("Failed to lock sample\n");
198         return -1;
199     }
200
201     if ((*blen1 & info->align) || (*blen2 & info->align)) {
202         dolog ("Lock returned misaligned length %d, %d, alignment %d\n",
203                *blen1, *blen2, info->align + 1);
204
205         fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2);
206
207         *p1 = NULL - 1;
208         *p2 = NULL - 1;
209         *blen1 = ~0U;
210         *blen2 = ~0U;
211         return -1;
212     }
213
214     if (!*p1 && *blen1) {
215         dolog ("warning: !p1 && blen1=%d\n", *blen1);
216         *blen1 = 0;
217     }
218
219     if (!p2 && *blen2) {
220         dolog ("warning: !p2 && blen2=%d\n", *blen2);
221         *blen2 = 0;
222     }
223
224     return 0;
225 }
226
227 static int fmod_run_out (HWVoiceOut *hw)
228 {
229     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
230     int live, decr;
231     void *p1 = 0, *p2 = 0;
232     unsigned int blen1 = 0, blen2 = 0;
233     unsigned int len1 = 0, len2 = 0;
234     int nb_live;
235
236     live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
237     if (!live) {
238         return 0;
239     }
240
241     if (!hw->pending_disable && nb_live) {
242         ldebug ("live=%d nb_live=%d\n", live, nb_live);
243         return 0;
244     }
245
246     decr = live;
247
248     if (fmd->channel >= 0) {
249         int len = decr;
250         int old_pos = fmd->old_pos;
251         int ppos = FSOUND_GetCurrentPosition (fmd->channel);
252
253         if (ppos == old_pos || !ppos) {
254             return 0;
255         }
256
257         if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
258             len = ppos - old_pos;
259         }
260         else {
261             if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
262                 len = hw->samples - old_pos + ppos;
263             }
264         }
265         decr = len;
266
267         if (audio_bug (AUDIO_FUNC, decr < 0)) {
268             dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
269                    decr, live, ppos, old_pos, len);
270             return 0;
271         }
272     }
273
274
275     if (!decr) {
276         return 0;
277     }
278
279     if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
280                           fmd->old_pos, decr,
281                           &p1, &p2,
282                           &blen1, &blen2)) {
283         return 0;
284     }
285
286     len1 = blen1 >> hw->info.shift;
287     len2 = blen2 >> hw->info.shift;
288     ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
289     decr = len1 + len2;
290
291     if (p1 && len1) {
292         fmod_write_sample (hw, p1, len1);
293     }
294
295     if (p2 && len2) {
296         fmod_write_sample (hw, p2, len2);
297     }
298
299     fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
300
301     fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
302     return decr;
303 }
304
305 static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
306 {
307     int mode = FSOUND_LOOP_NORMAL;
308
309     switch (fmt) {
310     case AUD_FMT_S8:
311         mode |= FSOUND_SIGNED | FSOUND_8BITS;
312         break;
313
314     case AUD_FMT_U8:
315         mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
316         break;
317
318     case AUD_FMT_S16:
319         mode |= FSOUND_SIGNED | FSOUND_16BITS;
320         break;
321
322     case AUD_FMT_U16:
323         mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
324         break;
325
326     default:
327         dolog ("Internal logic error: Bad audio format %d\n", fmt);
328 #ifdef DEBUG_FMOD
329         abort ();
330 #endif
331         mode |= FSOUND_8BITS;
332     }
333     mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
334     return mode;
335 }
336
337 static void fmod_fini_out (HWVoiceOut *hw)
338 {
339     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
340
341     if (fmd->fmod_sample) {
342         FSOUND_Sample_Free (fmd->fmod_sample);
343         fmd->fmod_sample = 0;
344
345         if (fmd->channel >= 0) {
346             FSOUND_StopSound (fmd->channel);
347         }
348     }
349 }
350
351 static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
352 {
353     int bits16, mode, channel;
354     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
355     struct audsettings obt_as = *as;
356
357     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
358     fmd->fmod_sample = FSOUND_Sample_Alloc (
359         FSOUND_FREE,            /* index */
360         conf.nb_samples,        /* length */
361         mode,                   /* mode */
362         as->freq,               /* freq */
363         255,                    /* volume */
364         128,                    /* pan */
365         255                     /* priority */
366         );
367
368     if (!fmd->fmod_sample) {
369         fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
370         return -1;
371     }
372
373     channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
374     if (channel < 0) {
375         fmod_logerr2 ("DAC", "Failed to start playing sound\n");
376         FSOUND_Sample_Free (fmd->fmod_sample);
377         return -1;
378     }
379     fmd->channel = channel;
380
381     /* FMOD always operates on little endian frames? */
382     obt_as.endianness = 0;
383     audio_pcm_init_info (&hw->info, &obt_as);
384     bits16 = (mode & FSOUND_16BITS) != 0;
385     hw->samples = conf.nb_samples;
386     return 0;
387 }
388
389 static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
390 {
391     int status;
392     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
393
394     switch (cmd) {
395     case VOICE_ENABLE:
396         fmod_clear_sample (fmd);
397         status = FSOUND_SetPaused (fmd->channel, 0);
398         if (!status) {
399             fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
400         }
401         break;
402
403     case VOICE_DISABLE:
404         status = FSOUND_SetPaused (fmd->channel, 1);
405         if (!status) {
406             fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
407         }
408         break;
409     }
410     return 0;
411 }
412
413 static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
414 {
415     int bits16, mode;
416     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
417     struct audsettings obt_as = *as;
418
419     if (conf.broken_adc) {
420         return -1;
421     }
422
423     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
424     fmd->fmod_sample = FSOUND_Sample_Alloc (
425         FSOUND_FREE,            /* index */
426         conf.nb_samples,        /* length */
427         mode,                   /* mode */
428         as->freq,               /* freq */
429         255,                    /* volume */
430         128,                    /* pan */
431         255                     /* priority */
432         );
433
434     if (!fmd->fmod_sample) {
435         fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
436         return -1;
437     }
438
439     /* FMOD always operates on little endian frames? */
440     obt_as.endianness = 0;
441     audio_pcm_init_info (&hw->info, &obt_as);
442     bits16 = (mode & FSOUND_16BITS) != 0;
443     hw->samples = conf.nb_samples;
444     return 0;
445 }
446
447 static void fmod_fini_in (HWVoiceIn *hw)
448 {
449     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
450
451     if (fmd->fmod_sample) {
452         FSOUND_Record_Stop ();
453         FSOUND_Sample_Free (fmd->fmod_sample);
454         fmd->fmod_sample = 0;
455     }
456 }
457
458 static int fmod_run_in (HWVoiceIn *hw)
459 {
460     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
461     int hwshift = hw->info.shift;
462     int live, dead, new_pos, len;
463     unsigned int blen1 = 0, blen2 = 0;
464     unsigned int len1, len2;
465     unsigned int decr;
466     void *p1, *p2;
467
468     live = audio_pcm_hw_get_live_in (hw);
469     dead = hw->samples - live;
470     if (!dead) {
471         return 0;
472     }
473
474     new_pos = FSOUND_Record_GetPosition ();
475     if (new_pos < 0) {
476         fmod_logerr ("Could not get recording position\n");
477         return 0;
478     }
479
480     len = audio_ring_dist (new_pos,  hw->wpos, hw->samples);
481     if (!len) {
482         return 0;
483     }
484     len = audio_MIN (len, dead);
485
486     if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
487                           hw->wpos, len,
488                           &p1, &p2,
489                           &blen1, &blen2)) {
490         return 0;
491     }
492
493     len1 = blen1 >> hwshift;
494     len2 = blen2 >> hwshift;
495     decr = len1 + len2;
496
497     if (p1 && blen1) {
498         hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume);
499     }
500     if (p2 && len2) {
501         hw->conv (hw->conv_buf, p2, len2, &nominal_volume);
502     }
503
504     fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
505     hw->wpos = (hw->wpos + decr) % hw->samples;
506     return decr;
507 }
508
509 static struct {
510     const char *name;
511     int type;
512 } drvtab[] = {
513     { .name = "none",   .type = FSOUND_OUTPUT_NOSOUND },
514 #ifdef _WIN32
515     { .name = "winmm",  .type = FSOUND_OUTPUT_WINMM   },
516     { .name = "dsound", .type = FSOUND_OUTPUT_DSOUND  },
517     { .name = "a3d",    .type = FSOUND_OUTPUT_A3D     },
518     { .name = "asio",   .type = FSOUND_OUTPUT_ASIO    },
519 #endif
520 #ifdef __linux__
521     { .name = "oss",    .type = FSOUND_OUTPUT_OSS     },
522     { .name = "alsa",   .type = FSOUND_OUTPUT_ALSA    },
523     { .name = "esd",    .type = FSOUND_OUTPUT_ESD     },
524 #endif
525 #ifdef __APPLE__
526     { .name = "mac",    .type = FSOUND_OUTPUT_MAC     },
527 #endif
528 #if 0
529     { .name = "xbox",   .type = FSOUND_OUTPUT_XBOX    },
530     { .name = "ps2",    .type = FSOUND_OUTPUT_PS2     },
531     { .name = "gcube",  .type = FSOUND_OUTPUT_GC      },
532 #endif
533     { .name = "none-realtime", .type = FSOUND_OUTPUT_NOSOUND_NONREALTIME }
534 };
535
536 static void *fmod_audio_init (void)
537 {
538     size_t i;
539     double ver;
540     int status;
541     int output_type = -1;
542     const char *drv = conf.drvname;
543
544     ver = FSOUND_GetVersion ();
545     if (ver < FMOD_VERSION) {
546         dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
547         return NULL;
548     }
549
550 #ifdef __linux__
551     if (ver < 3.75) {
552         dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
553                "ADC will be disabled.\n");
554         conf.broken_adc = 1;
555     }
556 #endif
557
558     if (drv) {
559         int found = 0;
560         for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
561             if (!strcmp (drv, drvtab[i].name)) {
562                 output_type = drvtab[i].type;
563                 found = 1;
564                 break;
565             }
566         }
567         if (!found) {
568             dolog ("Unknown FMOD driver `%s'\n", drv);
569             dolog ("Valid drivers:\n");
570             for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
571                 dolog ("  %s\n", drvtab[i].name);
572             }
573         }
574     }
575
576     if (output_type != -1) {
577         status = FSOUND_SetOutput (output_type);
578         if (!status) {
579             fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
580             return NULL;
581         }
582     }
583
584     if (conf.bufsize) {
585         status = FSOUND_SetBufferSize (conf.bufsize);
586         if (!status) {
587             fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
588         }
589     }
590
591     status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
592     if (!status) {
593         fmod_logerr ("FSOUND_Init failed\n");
594         return NULL;
595     }
596
597     return &conf;
598 }
599
600 static int fmod_read (SWVoiceIn *sw, void *buf, int size)
601 {
602     return audio_pcm_sw_read (sw, buf, size);
603 }
604
605 static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
606 {
607     int status;
608     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
609
610     switch (cmd) {
611     case VOICE_ENABLE:
612         status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
613         if (!status) {
614             fmod_logerr ("Failed to start recording\n");
615         }
616         break;
617
618     case VOICE_DISABLE:
619         status = FSOUND_Record_Stop ();
620         if (!status) {
621             fmod_logerr ("Failed to stop recording\n");
622         }
623         break;
624     }
625     return 0;
626 }
627
628 static void fmod_audio_fini (void *opaque)
629 {
630     (void) opaque;
631     FSOUND_Close ();
632 }
633
634 static struct audio_option fmod_options[] = {
635     {
636         .name  = "DRV",
637         .tag   = AUD_OPT_STR,
638         .valp  = &conf.drvname,
639         .descr = "FMOD driver"
640     },
641     {
642         .name  = "FREQ",
643         .tag   = AUD_OPT_INT,
644         .valp  = &conf.freq,
645         .descr = "Default frequency"
646     },
647     {
648         .name  = "SAMPLES",
649         .tag   = AUD_OPT_INT,
650         .valp  = &conf.nb_samples,
651         .descr = "Buffer size in samples"
652     },
653     {
654         .name  = "CHANNELS",
655         .tag   = AUD_OPT_INT,
656         .valp  = &conf.nb_channels,
657         .descr = "Number of default channels (1 - mono, 2 - stereo)"
658     },
659     {
660         .name  = "BUFSIZE",
661         .tag   = AUD_OPT_INT,
662         .valp  = &conf.bufsize,
663         .descr = "(undocumented)"
664     },
665     { /* End of list */ }
666 };
667
668 static struct audio_pcm_ops fmod_pcm_ops = {
669     .init_out = fmod_init_out,
670     .fini_out = fmod_fini_out,
671     .run_out  = fmod_run_out,
672     .write    = fmod_write,
673     .ctl_out  = fmod_ctl_out,
674
675     .init_in  = fmod_init_in,
676     .fini_in  = fmod_fini_in,
677     .run_in   = fmod_run_in,
678     .read     = fmod_read,
679     .ctl_in   = fmod_ctl_in
680 };
681
682 struct audio_driver fmod_audio_driver = {
683     .name           = "fmod",
684     .descr          = "FMOD 3.xx http://www.fmod.org",
685     .options        = fmod_options,
686     .init           = fmod_audio_init,
687     .fini           = fmod_audio_fini,
688     .pcm_ops        = &fmod_pcm_ops,
689     .can_be_default = 1,
690     .max_voices_out = INT_MAX,
691     .max_voices_in  = INT_MAX,
692     .voice_size_out = sizeof (FMODVoiceOut),
693     .voice_size_in  = sizeof (FMODVoiceIn)
694 };