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 }; 687