2 * QEMU FMOD audio driver
4 * Copyright (c) 2004-2005 Vassili Karpov (malc)
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
25 #include <fmod_errors.h>
26 #include "qemu-common.h"
29 #define AUDIO_CAP "fmod"
30 #include "audio_int.h"
32 typedef struct FMODVoiceOut
{
35 FSOUND_SAMPLE
*fmod_sample
;
39 typedef struct FMODVoiceIn
{
41 FSOUND_SAMPLE
*fmod_sample
;
52 .nb_samples
= 2048 * 2,
57 static void GCC_FMT_ATTR (1, 2) fmod_logerr (const char *fmt
, ...)
62 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
65 AUD_log (AUDIO_CAP
, "Reason: %s\n",
66 FMOD_ErrorString (FSOUND_GetError ()));
69 static void GCC_FMT_ATTR (2, 3) fmod_logerr2 (
77 AUD_log (AUDIO_CAP
, "Could not initialize %s\n", typ
);
80 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
83 AUD_log (AUDIO_CAP
, "Reason: %s\n",
84 FMOD_ErrorString (FSOUND_GetError ()));
87 static int fmod_write (SWVoiceOut
*sw
, void *buf
, int len
)
89 return audio_pcm_sw_write (sw
, buf
, len
);
92 static void fmod_clear_sample (FMODVoiceOut
*fmd
)
94 HWVoiceOut
*hw
= &fmd
->hw
;
96 void *p1
= 0, *p2
= 0;
97 unsigned int len1
= 0, len2
= 0;
99 status
= FSOUND_Sample_Lock (
102 hw
->samples
<< hw
->info
.shift
,
110 fmod_logerr ("Failed to lock sample\n");
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);
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
);
126 audio_pcm_info_clear_buf (&hw
->info
, p1
, hw
->samples
);
129 status
= FSOUND_Sample_Unlock (fmd
->fmod_sample
, p1
, p2
, len1
, len2
);
131 fmod_logerr ("Failed to unlock sample\n");
135 static void fmod_write_sample (HWVoiceOut
*hw
, uint8_t *dst
, int dst_len
)
137 int src_len1
= dst_len
;
139 int pos
= hw
->rpos
+ dst_len
;
140 struct st_sample
*src1
= hw
->mix_buf
+ hw
->rpos
;
141 struct st_sample
*src2
= NULL
;
143 if (pos
> hw
->samples
) {
144 src_len1
= hw
->samples
- hw
->rpos
;
146 src_len2
= dst_len
- src_len1
;
151 hw
->clip (dst
, src1
, src_len1
);
155 dst
= advance (dst
, src_len1
<< hw
->info
.shift
);
156 hw
->clip (dst
, src2
, src_len2
);
159 hw
->rpos
= pos
% hw
->samples
;
162 static int fmod_unlock_sample (FSOUND_SAMPLE
*sample
, void *p1
, void *p2
,
163 unsigned int blen1
, unsigned int blen2
)
165 int status
= FSOUND_Sample_Unlock (sample
, p1
, p2
, blen1
, blen2
);
167 fmod_logerr ("Failed to unlock sample\n");
173 static int fmod_lock_sample (
174 FSOUND_SAMPLE
*sample
,
175 struct audio_pcm_info
*info
,
186 status
= FSOUND_Sample_Lock (
197 fmod_logerr ("Failed to lock sample\n");
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);
205 fmod_unlock_sample (sample
, *p1
, *p2
, *blen1
, *blen2
);
214 if (!*p1
&& *blen1
) {
215 dolog ("warning: !p1 && blen1=%d\n", *blen1
);
220 dolog ("warning: !p2 && blen2=%d\n", *blen2
);
227 static int fmod_run_out (HWVoiceOut
*hw
, int live
)
229 FMODVoiceOut
*fmd
= (FMODVoiceOut
*) hw
;
231 void *p1
= 0, *p2
= 0;
232 unsigned int blen1
= 0, blen2
= 0;
233 unsigned int len1
= 0, len2
= 0;
235 if (!hw
->pending_disable
) {
241 if (fmd
->channel
>= 0) {
243 int old_pos
= fmd
->old_pos
;
244 int ppos
= FSOUND_GetCurrentPosition (fmd
->channel
);
246 if (ppos
== old_pos
|| !ppos
) {
250 if ((old_pos
< ppos
) && ((old_pos
+ len
) > ppos
)) {
251 len
= ppos
- old_pos
;
254 if ((old_pos
> ppos
) && ((old_pos
+ len
) > (ppos
+ hw
->samples
))) {
255 len
= hw
->samples
- old_pos
+ ppos
;
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
);
272 if (fmod_lock_sample (fmd
->fmod_sample
, &fmd
->hw
.info
,
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
);
285 fmod_write_sample (hw
, p1
, len1
);
289 fmod_write_sample (hw
, p2
, len2
);
292 fmod_unlock_sample (fmd
->fmod_sample
, p1
, p2
, blen1
, blen2
);
294 fmd
->old_pos
= (fmd
->old_pos
+ decr
) % hw
->samples
;
298 static int aud_to_fmodfmt (audfmt_e fmt
, int stereo
)
300 int mode
= FSOUND_LOOP_NORMAL
;
304 mode
|= FSOUND_SIGNED
| FSOUND_8BITS
;
308 mode
|= FSOUND_UNSIGNED
| FSOUND_8BITS
;
312 mode
|= FSOUND_SIGNED
| FSOUND_16BITS
;
316 mode
|= FSOUND_UNSIGNED
| FSOUND_16BITS
;
320 dolog ("Internal logic error: Bad audio format %d\n", fmt
);
324 mode
|= FSOUND_8BITS
;
326 mode
|= stereo
? FSOUND_STEREO
: FSOUND_MONO
;
330 static void fmod_fini_out (HWVoiceOut
*hw
)
332 FMODVoiceOut
*fmd
= (FMODVoiceOut
*) hw
;
334 if (fmd
->fmod_sample
) {
335 FSOUND_Sample_Free (fmd
->fmod_sample
);
336 fmd
->fmod_sample
= 0;
338 if (fmd
->channel
>= 0) {
339 FSOUND_StopSound (fmd
->channel
);
344 static int fmod_init_out (HWVoiceOut
*hw
, struct audsettings
*as
)
347 FMODVoiceOut
*fmd
= (FMODVoiceOut
*) hw
;
348 struct audsettings obt_as
= *as
;
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 */
361 if (!fmd
->fmod_sample
) {
362 fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n");
366 channel
= FSOUND_PlaySoundEx (FSOUND_FREE
, fmd
->fmod_sample
, 0, 1);
368 fmod_logerr2 ("DAC", "Failed to start playing sound\n");
369 FSOUND_Sample_Free (fmd
->fmod_sample
);
372 fmd
->channel
= channel
;
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
;
381 static int fmod_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
384 FMODVoiceOut
*fmd
= (FMODVoiceOut
*) hw
;
388 fmod_clear_sample (fmd
);
389 status
= FSOUND_SetPaused (fmd
->channel
, 0);
391 fmod_logerr ("Failed to resume channel %d\n", fmd
->channel
);
396 status
= FSOUND_SetPaused (fmd
->channel
, 1);
398 fmod_logerr ("Failed to pause channel %d\n", fmd
->channel
);
405 static int fmod_init_in (HWVoiceIn
*hw
, struct audsettings
*as
)
408 FMODVoiceIn
*fmd
= (FMODVoiceIn
*) hw
;
409 struct audsettings obt_as
= *as
;
411 if (conf
.broken_adc
) {
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 */
426 if (!fmd
->fmod_sample
) {
427 fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
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
;
438 static void fmod_fini_in (HWVoiceIn
*hw
)
440 FMODVoiceIn
*fmd
= (FMODVoiceIn
*) hw
;
442 if (fmd
->fmod_sample
) {
443 FSOUND_Record_Stop ();
444 FSOUND_Sample_Free (fmd
->fmod_sample
);
445 fmd
->fmod_sample
= 0;
449 static int fmod_run_in (HWVoiceIn
*hw
)
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
;
459 live
= audio_pcm_hw_get_live_in (hw
);
460 dead
= hw
->samples
- live
;
465 new_pos
= FSOUND_Record_GetPosition ();
467 fmod_logerr ("Could not get recording position\n");
471 len
= audio_ring_dist (new_pos
, hw
->wpos
, hw
->samples
);
475 len
= audio_MIN (len
, dead
);
477 if (fmod_lock_sample (fmd
->fmod_sample
, &fmd
->hw
.info
,
484 len1
= blen1
>> hwshift
;
485 len2
= blen2
>> hwshift
;
489 hw
->conv (hw
->conv_buf
+ hw
->wpos
, p1
, len1
);
492 hw
->conv (hw
->conv_buf
, p2
, len2
);
495 fmod_unlock_sample (fmd
->fmod_sample
, p1
, p2
, blen1
, blen2
);
496 hw
->wpos
= (hw
->wpos
+ decr
) % hw
->samples
;
504 { .name
= "none", .type
= FSOUND_OUTPUT_NOSOUND
},
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
},
512 { .name
= "oss", .type
= FSOUND_OUTPUT_OSS
},
513 { .name
= "alsa", .type
= FSOUND_OUTPUT_ALSA
},
514 { .name
= "esd", .type
= FSOUND_OUTPUT_ESD
},
517 { .name
= "mac", .type
= FSOUND_OUTPUT_MAC
},
520 { .name
= "xbox", .type
= FSOUND_OUTPUT_XBOX
},
521 { .name
= "ps2", .type
= FSOUND_OUTPUT_PS2
},
522 { .name
= "gcube", .type
= FSOUND_OUTPUT_GC
},
524 { .name
= "none-realtime", .type
= FSOUND_OUTPUT_NOSOUND_NONREALTIME
}
527 static void *fmod_audio_init (void)
532 int output_type
= -1;
533 const char *drv
= conf
.drvname
;
535 ver
= FSOUND_GetVersion ();
536 if (ver
< FMOD_VERSION
) {
537 dolog ("Wrong FMOD version %f, need at least %f\n", ver
, FMOD_VERSION
);
543 dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
544 "ADC will be disabled.\n");
551 for (i
= 0; i
< ARRAY_SIZE (drvtab
); i
++) {
552 if (!strcmp (drv
, drvtab
[i
].name
)) {
553 output_type
= drvtab
[i
].type
;
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
);
567 if (output_type
!= -1) {
568 status
= FSOUND_SetOutput (output_type
);
570 fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type
);
576 status
= FSOUND_SetBufferSize (conf
.bufsize
);
578 fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf
.bufsize
);
582 status
= FSOUND_Init (conf
.freq
, conf
.nb_channels
, 0);
584 fmod_logerr ("FSOUND_Init failed\n");
591 static int fmod_read (SWVoiceIn
*sw
, void *buf
, int size
)
593 return audio_pcm_sw_read (sw
, buf
, size
);
596 static int fmod_ctl_in (HWVoiceIn
*hw
, int cmd
, ...)
599 FMODVoiceIn
*fmd
= (FMODVoiceIn
*) hw
;
603 status
= FSOUND_Record_StartSample (fmd
->fmod_sample
, 1);
605 fmod_logerr ("Failed to start recording\n");
610 status
= FSOUND_Record_Stop ();
612 fmod_logerr ("Failed to stop recording\n");
619 static void fmod_audio_fini (void *opaque
)
625 static struct audio_option fmod_options
[] = {
629 .valp
= &conf
.drvname
,
630 .descr
= "FMOD driver"
636 .descr
= "Default frequency"
641 .valp
= &conf
.nb_samples
,
642 .descr
= "Buffer size in samples"
647 .valp
= &conf
.nb_channels
,
648 .descr
= "Number of default channels (1 - mono, 2 - stereo)"
653 .valp
= &conf
.bufsize
,
654 .descr
= "(undocumented)"
656 { /* End of list */ }
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
,
664 .ctl_out
= fmod_ctl_out
,
666 .init_in
= fmod_init_in
,
667 .fini_in
= fmod_fini_in
,
668 .run_in
= fmod_run_in
,
670 .ctl_in
= fmod_ctl_in
673 struct audio_driver fmod_audio_driver
= {
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
,
681 .max_voices_out
= INT_MAX
,
682 .max_voices_in
= INT_MAX
,
683 .voice_size_out
= sizeof (FMODVoiceOut
),
684 .voice_size_in
= sizeof (FMODVoiceIn
)