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
)
346 int bits16
, mode
, channel
;
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 bits16
= (mode
& FSOUND_16BITS
) != 0;
378 hw
->samples
= conf
.nb_samples
;
382 static int fmod_ctl_out (HWVoiceOut
*hw
, int cmd
, ...)
385 FMODVoiceOut
*fmd
= (FMODVoiceOut
*) hw
;
389 fmod_clear_sample (fmd
);
390 status
= FSOUND_SetPaused (fmd
->channel
, 0);
392 fmod_logerr ("Failed to resume channel %d\n", fmd
->channel
);
397 status
= FSOUND_SetPaused (fmd
->channel
, 1);
399 fmod_logerr ("Failed to pause channel %d\n", fmd
->channel
);
406 static int fmod_init_in (HWVoiceIn
*hw
, struct audsettings
*as
)
409 FMODVoiceIn
*fmd
= (FMODVoiceIn
*) hw
;
410 struct audsettings obt_as
= *as
;
412 if (conf
.broken_adc
) {
416 mode
= aud_to_fmodfmt (as
->fmt
, as
->nchannels
== 2 ? 1 : 0);
417 fmd
->fmod_sample
= FSOUND_Sample_Alloc (
418 FSOUND_FREE
, /* index */
419 conf
.nb_samples
, /* length */
427 if (!fmd
->fmod_sample
) {
428 fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n");
432 /* FMOD always operates on little endian frames? */
433 obt_as
.endianness
= 0;
434 audio_pcm_init_info (&hw
->info
, &obt_as
);
435 bits16
= (mode
& FSOUND_16BITS
) != 0;
436 hw
->samples
= conf
.nb_samples
;
440 static void fmod_fini_in (HWVoiceIn
*hw
)
442 FMODVoiceIn
*fmd
= (FMODVoiceIn
*) hw
;
444 if (fmd
->fmod_sample
) {
445 FSOUND_Record_Stop ();
446 FSOUND_Sample_Free (fmd
->fmod_sample
);
447 fmd
->fmod_sample
= 0;
451 static int fmod_run_in (HWVoiceIn
*hw
)
453 FMODVoiceIn
*fmd
= (FMODVoiceIn
*) hw
;
454 int hwshift
= hw
->info
.shift
;
455 int live
, dead
, new_pos
, len
;
456 unsigned int blen1
= 0, blen2
= 0;
457 unsigned int len1
, len2
;
461 live
= audio_pcm_hw_get_live_in (hw
);
462 dead
= hw
->samples
- live
;
467 new_pos
= FSOUND_Record_GetPosition ();
469 fmod_logerr ("Could not get recording position\n");
473 len
= audio_ring_dist (new_pos
, hw
->wpos
, hw
->samples
);
477 len
= audio_MIN (len
, dead
);
479 if (fmod_lock_sample (fmd
->fmod_sample
, &fmd
->hw
.info
,
486 len1
= blen1
>> hwshift
;
487 len2
= blen2
>> hwshift
;
491 hw
->conv (hw
->conv_buf
+ hw
->wpos
, p1
, len1
);
494 hw
->conv (hw
->conv_buf
, p2
, len2
);
497 fmod_unlock_sample (fmd
->fmod_sample
, p1
, p2
, blen1
, blen2
);
498 hw
->wpos
= (hw
->wpos
+ decr
) % hw
->samples
;
506 { .name
= "none", .type
= FSOUND_OUTPUT_NOSOUND
},
508 { .name
= "winmm", .type
= FSOUND_OUTPUT_WINMM
},
509 { .name
= "dsound", .type
= FSOUND_OUTPUT_DSOUND
},
510 { .name
= "a3d", .type
= FSOUND_OUTPUT_A3D
},
511 { .name
= "asio", .type
= FSOUND_OUTPUT_ASIO
},
514 { .name
= "oss", .type
= FSOUND_OUTPUT_OSS
},
515 { .name
= "alsa", .type
= FSOUND_OUTPUT_ALSA
},
516 { .name
= "esd", .type
= FSOUND_OUTPUT_ESD
},
519 { .name
= "mac", .type
= FSOUND_OUTPUT_MAC
},
522 { .name
= "xbox", .type
= FSOUND_OUTPUT_XBOX
},
523 { .name
= "ps2", .type
= FSOUND_OUTPUT_PS2
},
524 { .name
= "gcube", .type
= FSOUND_OUTPUT_GC
},
526 { .name
= "none-realtime", .type
= FSOUND_OUTPUT_NOSOUND_NONREALTIME
}
529 static void *fmod_audio_init (void)
534 int output_type
= -1;
535 const char *drv
= conf
.drvname
;
537 ver
= FSOUND_GetVersion ();
538 if (ver
< FMOD_VERSION
) {
539 dolog ("Wrong FMOD version %f, need at least %f\n", ver
, FMOD_VERSION
);
545 dolog ("FMOD before 3.75 has bug preventing ADC from working\n"
546 "ADC will be disabled.\n");
553 for (i
= 0; i
< ARRAY_SIZE (drvtab
); i
++) {
554 if (!strcmp (drv
, drvtab
[i
].name
)) {
555 output_type
= drvtab
[i
].type
;
561 dolog ("Unknown FMOD driver `%s'\n", drv
);
562 dolog ("Valid drivers:\n");
563 for (i
= 0; i
< ARRAY_SIZE (drvtab
); i
++) {
564 dolog (" %s\n", drvtab
[i
].name
);
569 if (output_type
!= -1) {
570 status
= FSOUND_SetOutput (output_type
);
572 fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type
);
578 status
= FSOUND_SetBufferSize (conf
.bufsize
);
580 fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf
.bufsize
);
584 status
= FSOUND_Init (conf
.freq
, conf
.nb_channels
, 0);
586 fmod_logerr ("FSOUND_Init failed\n");
593 static int fmod_read (SWVoiceIn
*sw
, void *buf
, int size
)
595 return audio_pcm_sw_read (sw
, buf
, size
);
598 static int fmod_ctl_in (HWVoiceIn
*hw
, int cmd
, ...)
601 FMODVoiceIn
*fmd
= (FMODVoiceIn
*) hw
;
605 status
= FSOUND_Record_StartSample (fmd
->fmod_sample
, 1);
607 fmod_logerr ("Failed to start recording\n");
612 status
= FSOUND_Record_Stop ();
614 fmod_logerr ("Failed to stop recording\n");
621 static void fmod_audio_fini (void *opaque
)
627 static struct audio_option fmod_options
[] = {
631 .valp
= &conf
.drvname
,
632 .descr
= "FMOD driver"
638 .descr
= "Default frequency"
643 .valp
= &conf
.nb_samples
,
644 .descr
= "Buffer size in samples"
649 .valp
= &conf
.nb_channels
,
650 .descr
= "Number of default channels (1 - mono, 2 - stereo)"
655 .valp
= &conf
.bufsize
,
656 .descr
= "(undocumented)"
658 { /* End of list */ }
661 static struct audio_pcm_ops fmod_pcm_ops
= {
662 .init_out
= fmod_init_out
,
663 .fini_out
= fmod_fini_out
,
664 .run_out
= fmod_run_out
,
666 .ctl_out
= fmod_ctl_out
,
668 .init_in
= fmod_init_in
,
669 .fini_in
= fmod_fini_in
,
670 .run_in
= fmod_run_in
,
672 .ctl_in
= fmod_ctl_in
675 struct audio_driver fmod_audio_driver
= {
677 .descr
= "FMOD 3.xx http://www.fmod.org",
678 .options
= fmod_options
,
679 .init
= fmod_audio_init
,
680 .fini
= fmod_audio_fini
,
681 .pcm_ops
= &fmod_pcm_ops
,
683 .max_voices_out
= INT_MAX
,
684 .max_voices_in
= INT_MAX
,
685 .voice_size_out
= sizeof (FMODVoiceOut
),
686 .voice_size_in
= sizeof (FMODVoiceIn
)