tizen 2.3.1 release
[external/qemu.git] / 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, int live)
228 {
229     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
230     int decr;
231     void *p1 = 0, *p2 = 0;
232     unsigned int blen1 = 0, blen2 = 0;
233     unsigned int len1 = 0, len2 = 0;
234
235     if (!hw->pending_disable) {
236         return 0;
237     }
238
239     decr = live;
240
241     if (fmd->channel >= 0) {
242         int len = decr;
243         int old_pos = fmd->old_pos;
244         int ppos = FSOUND_GetCurrentPosition (fmd->channel);
245
246         if (ppos == old_pos || !ppos) {
247             return 0;
248         }
249
250         if ((old_pos < ppos) && ((old_pos + len) > ppos)) {
251             len = ppos - old_pos;
252         }
253         else {
254             if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) {
255                 len = hw->samples - old_pos + ppos;
256             }
257         }
258         decr = len;
259
260         if (audio_bug (AUDIO_FUNC, decr < 0)) {
261             dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n",
262                    decr, live, ppos, old_pos, len);
263             return 0;
264         }
265     }
266
267
268     if (!decr) {
269         return 0;
270     }
271
272     if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
273                           fmd->old_pos, decr,
274                           &p1, &p2,
275                           &blen1, &blen2)) {
276         return 0;
277     }
278
279     len1 = blen1 >> hw->info.shift;
280     len2 = blen2 >> hw->info.shift;
281     ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
282     decr = len1 + len2;
283
284     if (p1 && len1) {
285         fmod_write_sample (hw, p1, len1);
286     }
287
288     if (p2 && len2) {
289         fmod_write_sample (hw, p2, len2);
290     }
291
292     fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
293
294     fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
295     return decr;
296 }
297
298 static int aud_to_fmodfmt (audfmt_e fmt, int stereo)
299 {
300     int mode = FSOUND_LOOP_NORMAL;
301
302     switch (fmt) {
303     case AUD_FMT_S8:
304         mode |= FSOUND_SIGNED | FSOUND_8BITS;
305         break;
306
307     case AUD_FMT_U8:
308         mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
309         break;
310
311     case AUD_FMT_S16:
312         mode |= FSOUND_SIGNED | FSOUND_16BITS;
313         break;
314
315     case AUD_FMT_U16:
316         mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
317         break;
318
319     default:
320         dolog ("Internal logic error: Bad audio format %d\n", fmt);
321 #ifdef DEBUG_FMOD
322         abort ();
323 #endif
324         mode |= FSOUND_8BITS;
325     }
326     mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
327     return mode;
328 }
329
330 static void fmod_fini_out (HWVoiceOut *hw)
331 {
332     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
333
334     if (fmd->fmod_sample) {
335         FSOUND_Sample_Free (fmd->fmod_sample);
336         fmd->fmod_sample = 0;
337
338         if (fmd->channel >= 0) {
339             FSOUND_StopSound (fmd->channel);
340         }
341     }
342 }
343
344 static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
345 {
346     int mode, channel;
347     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
348     struct audsettings obt_as = *as;
349
350     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
351     fmd->fmod_sample = FSOUND_Sample_Alloc (
352         FSOUND_FREE,            /* index */
353         conf.nb_samples,        /* length */
354         mode,                   /* mode */
355         as->freq,               /* freq */
356         255,                    /* volume */
357         128,                    /* pan */
358         255                     /* priority */
359         );
360
361     if (!fmd->fmod_sample) {
362         fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
363         return -1;
364     }
365
366     channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
367     if (channel < 0) {
368         fmod_logerr2 ("DAC", "Failed to start playing sound\n");
369         FSOUND_Sample_Free (fmd->fmod_sample);
370         return -1;
371     }
372     fmd->channel = channel;
373
374     /* FMOD always operates on little endian frames? */
375     obt_as.endianness = 0;
376     audio_pcm_init_info (&hw->info, &obt_as);
377     hw->samples = conf.nb_samples;
378     return 0;
379 }
380
381 static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
382 {
383     int status;
384     FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
385
386     switch (cmd) {
387     case VOICE_ENABLE:
388         fmod_clear_sample (fmd);
389         status = FSOUND_SetPaused (fmd->channel, 0);
390         if (!status) {
391             fmod_logerr ("Failed to resume channel %d\n", fmd->channel);
392         }
393         break;
394
395     case VOICE_DISABLE:
396         status = FSOUND_SetPaused (fmd->channel, 1);
397         if (!status) {
398             fmod_logerr ("Failed to pause channel %d\n", fmd->channel);
399         }
400         break;
401     }
402     return 0;
403 }
404
405 static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
406 {
407     int mode;
408     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
409     struct audsettings obt_as = *as;
410
411     if (conf.broken_adc) {
412         return -1;
413     }
414
415     mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0);
416     fmd->fmod_sample = FSOUND_Sample_Alloc (
417         FSOUND_FREE,            /* index */
418         conf.nb_samples,        /* length */
419         mode,                   /* mode */
420         as->freq,               /* freq */
421         255,                    /* volume */
422         128,                    /* pan */
423         255                     /* priority */
424         );
425
426     if (!fmd->fmod_sample) {
427         fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
428         return -1;
429     }
430
431     /* FMOD always operates on little endian frames? */
432     obt_as.endianness = 0;
433     audio_pcm_init_info (&hw->info, &obt_as);
434     hw->samples = conf.nb_samples;
435     return 0;
436 }
437
438 static void fmod_fini_in (HWVoiceIn *hw)
439 {
440     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
441
442     if (fmd->fmod_sample) {
443         FSOUND_Record_Stop ();
444         FSOUND_Sample_Free (fmd->fmod_sample);
445         fmd->fmod_sample = 0;
446     }
447 }
448
449 static int fmod_run_in (HWVoiceIn *hw)
450 {
451     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
452     int hwshift = hw->info.shift;
453     int live, dead, new_pos, len;
454     unsigned int blen1 = 0, blen2 = 0;
455     unsigned int len1, len2;
456     unsigned int decr;
457     void *p1, *p2;
458
459     live = audio_pcm_hw_get_live_in (hw);
460     dead = hw->samples - live;
461     if (!dead) {
462         return 0;
463     }
464
465     new_pos = FSOUND_Record_GetPosition ();
466     if (new_pos < 0) {
467         fmod_logerr ("Could not get recording position\n");
468         return 0;
469     }
470
471     len = audio_ring_dist (new_pos,  hw->wpos, hw->samples);
472     if (!len) {
473         return 0;
474     }
475     len = audio_MIN (len, dead);
476
477     if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info,
478                           hw->wpos, len,
479                           &p1, &p2,
480                           &blen1, &blen2)) {
481         return 0;
482     }
483
484     len1 = blen1 >> hwshift;
485     len2 = blen2 >> hwshift;
486     decr = len1 + len2;
487
488     if (p1 && blen1) {
489         hw->conv (hw->conv_buf + hw->wpos, p1, len1);
490     }
491     if (p2 && len2) {
492         hw->conv (hw->conv_buf, p2, len2);
493     }
494
495     fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2);
496     hw->wpos = (hw->wpos + decr) % hw->samples;
497     return decr;
498 }
499
500 static struct {
501     const char *name;
502     int type;
503 } drvtab[] = {
504     { .name = "none",   .type = FSOUND_OUTPUT_NOSOUND },
505 #ifdef _WIN32
506     { .name = "winmm",  .type = FSOUND_OUTPUT_WINMM   },
507     { .name = "dsound", .type = FSOUND_OUTPUT_DSOUND  },
508     { .name = "a3d",    .type = FSOUND_OUTPUT_A3D     },
509     { .name = "asio",   .type = FSOUND_OUTPUT_ASIO    },
510 #endif
511 #ifdef __linux__
512     { .name = "oss",    .type = FSOUND_OUTPUT_OSS     },
513     { .name = "alsa",   .type = FSOUND_OUTPUT_ALSA    },
514     { .name = "esd",    .type = FSOUND_OUTPUT_ESD     },
515 #endif
516 #ifdef __APPLE__
517     { .name = "mac",    .type = FSOUND_OUTPUT_MAC     },
518 #endif
519 #if 0
520     { .name = "xbox",   .type = FSOUND_OUTPUT_XBOX    },
521     { .name = "ps2",    .type = FSOUND_OUTPUT_PS2     },
522     { .name = "gcube",  .type = FSOUND_OUTPUT_GC      },
523 #endif
524     { .name = "none-realtime", .type = FSOUND_OUTPUT_NOSOUND_NONREALTIME }
525 };
526
527 static void *fmod_audio_init (void)
528 {
529     size_t i;
530     double ver;
531     int status;
532     int output_type = -1;
533     const char *drv = conf.drvname;
534
535     ver = FSOUND_GetVersion ();
536     if (ver < FMOD_VERSION) {
537         dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
538         return NULL;
539     }
540
541 #ifdef __linux__
542     if (ver < 3.75) {
543         dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
544                "ADC will be disabled.\n");
545         conf.broken_adc = 1;
546     }
547 #endif
548
549     if (drv) {
550         int found = 0;
551         for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
552             if (!strcmp (drv, drvtab[i].name)) {
553                 output_type = drvtab[i].type;
554                 found = 1;
555                 break;
556             }
557         }
558         if (!found) {
559             dolog ("Unknown FMOD driver `%s'\n", drv);
560             dolog ("Valid drivers:\n");
561             for (i = 0; i < ARRAY_SIZE (drvtab); i++) {
562                 dolog ("  %s\n", drvtab[i].name);
563             }
564         }
565     }
566
567     if (output_type != -1) {
568         status = FSOUND_SetOutput (output_type);
569         if (!status) {
570             fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type);
571             return NULL;
572         }
573     }
574
575     if (conf.bufsize) {
576         status = FSOUND_SetBufferSize (conf.bufsize);
577         if (!status) {
578             fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize);
579         }
580     }
581
582     status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
583     if (!status) {
584         fmod_logerr ("FSOUND_Init failed\n");
585         return NULL;
586     }
587
588     return &conf;
589 }
590
591 static int fmod_read (SWVoiceIn *sw, void *buf, int size)
592 {
593     return audio_pcm_sw_read (sw, buf, size);
594 }
595
596 static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...)
597 {
598     int status;
599     FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
600
601     switch (cmd) {
602     case VOICE_ENABLE:
603         status = FSOUND_Record_StartSample (fmd->fmod_sample, 1);
604         if (!status) {
605             fmod_logerr ("Failed to start recording\n");
606         }
607         break;
608
609     case VOICE_DISABLE:
610         status = FSOUND_Record_Stop ();
611         if (!status) {
612             fmod_logerr ("Failed to stop recording\n");
613         }
614         break;
615     }
616     return 0;
617 }
618
619 static void fmod_audio_fini (void *opaque)
620 {
621     (void) opaque;
622     FSOUND_Close ();
623 }
624
625 static struct audio_option fmod_options[] = {
626     {
627         .name  = "DRV",
628         .tag   = AUD_OPT_STR,
629         .valp  = &conf.drvname,
630         .descr = "FMOD driver"
631     },
632     {
633         .name  = "FREQ",
634         .tag   = AUD_OPT_INT,
635         .valp  = &conf.freq,
636         .descr = "Default frequency"
637     },
638     {
639         .name  = "SAMPLES",
640         .tag   = AUD_OPT_INT,
641         .valp  = &conf.nb_samples,
642         .descr = "Buffer size in samples"
643     },
644     {
645         .name  = "CHANNELS",
646         .tag   = AUD_OPT_INT,
647         .valp  = &conf.nb_channels,
648         .descr = "Number of default channels (1 - mono, 2 - stereo)"
649     },
650     {
651         .name  = "BUFSIZE",
652         .tag   = AUD_OPT_INT,
653         .valp  = &conf.bufsize,
654         .descr = "(undocumented)"
655     },
656     { /* End of list */ }
657 };
658
659 static struct audio_pcm_ops fmod_pcm_ops = {
660     .init_out = fmod_init_out,
661     .fini_out = fmod_fini_out,
662     .run_out  = fmod_run_out,
663     .write    = fmod_write,
664     .ctl_out  = fmod_ctl_out,
665
666     .init_in  = fmod_init_in,
667     .fini_in  = fmod_fini_in,
668     .run_in   = fmod_run_in,
669     .read     = fmod_read,
670     .ctl_in   = fmod_ctl_in
671 };
672
673 struct audio_driver fmod_audio_driver = {
674     .name           = "fmod",
675     .descr          = "FMOD 3.xx http://www.fmod.org",
676     .options        = fmod_options,
677     .init           = fmod_audio_init,
678     .fini           = fmod_audio_fini,
679     .pcm_ops        = &fmod_pcm_ops,
680     .can_be_default = 1,
681     .max_voices_out = INT_MAX,
682     .max_voices_in  = INT_MAX,
683     .voice_size_out = sizeof (FMODVoiceOut),
684     .voice_size_in  = sizeof (FMODVoiceIn)
685 };