|
|
1.1 ! root 1: /* ! 2: * QEMU Audio subsystem ! 3: * ! 4: * Copyright (c) 2003-2004 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 <assert.h> ! 25: #include "vl.h" ! 26: ! 27: #define USE_WAV_AUDIO ! 28: ! 29: #include "audio/audio_int.h" ! 30: ! 31: #define dolog(...) AUD_log ("audio", __VA_ARGS__) ! 32: #ifdef DEBUG ! 33: #define ldebug(...) dolog (__VA_ARGS__) ! 34: #else ! 35: #define ldebug(...) ! 36: #endif ! 37: ! 38: #define QC_AUDIO_DRV "QEMU_AUDIO_DRV" ! 39: #define QC_VOICES "QEMU_VOICES" ! 40: #define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT" ! 41: #define QC_FIXED_FREQ "QEMU_FIXED_FREQ" ! 42: ! 43: static HWVoice *hw_voices; ! 44: ! 45: AudioState audio_state = { ! 46: 1, /* use fixed settings */ ! 47: 44100, /* fixed frequency */ ! 48: 2, /* fixed channels */ ! 49: AUD_FMT_S16, /* fixed format */ ! 50: 1, /* number of hw voices */ ! 51: -1 /* voice size */ ! 52: }; ! 53: ! 54: /* http://www.df.lth.se/~john_e/gems/gem002d.html */ ! 55: /* http://www.multi-platforms.com/Tips/PopCount.htm */ ! 56: uint32_t popcount (uint32_t u) ! 57: { ! 58: u = ((u&0x55555555) + ((u>>1)&0x55555555)); ! 59: u = ((u&0x33333333) + ((u>>2)&0x33333333)); ! 60: u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); ! 61: u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); ! 62: u = ( u&0x0000ffff) + (u>>16); ! 63: return u; ! 64: } ! 65: ! 66: inline uint32_t lsbindex (uint32_t u) ! 67: { ! 68: return popcount ((u&-u)-1); ! 69: } ! 70: ! 71: int audio_get_conf_int (const char *key, int defval) ! 72: { ! 73: int val = defval; ! 74: char *strval; ! 75: ! 76: strval = getenv (key); ! 77: if (strval) { ! 78: val = atoi (strval); ! 79: } ! 80: ! 81: return val; ! 82: } ! 83: ! 84: const char *audio_get_conf_str (const char *key, const char *defval) ! 85: { ! 86: const char *val = getenv (key); ! 87: if (!val) ! 88: return defval; ! 89: else ! 90: return val; ! 91: } ! 92: ! 93: void AUD_log (const char *cap, const char *fmt, ...) ! 94: { ! 95: va_list ap; ! 96: fprintf (stderr, "%s: ", cap); ! 97: va_start (ap, fmt); ! 98: vfprintf (stderr, fmt, ap); ! 99: va_end (ap); ! 100: } ! 101: ! 102: /* ! 103: * Soft Voice ! 104: */ ! 105: void pcm_sw_free_resources (SWVoice *sw) ! 106: { ! 107: if (sw->buf) qemu_free (sw->buf); ! 108: if (sw->rate) st_rate_stop (sw->rate); ! 109: sw->buf = NULL; ! 110: sw->rate = NULL; ! 111: } ! 112: ! 113: int pcm_sw_alloc_resources (SWVoice *sw) ! 114: { ! 115: sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t)); ! 116: if (!sw->buf) ! 117: return -1; ! 118: ! 119: sw->rate = st_rate_start (sw->freq, sw->hw->freq); ! 120: if (!sw->rate) { ! 121: qemu_free (sw->buf); ! 122: sw->buf = NULL; ! 123: return -1; ! 124: } ! 125: return 0; ! 126: } ! 127: ! 128: void pcm_sw_fini (SWVoice *sw) ! 129: { ! 130: pcm_sw_free_resources (sw); ! 131: } ! 132: ! 133: int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq, ! 134: int nchannels, audfmt_e fmt) ! 135: { ! 136: int bits = 8, sign = 0; ! 137: ! 138: switch (fmt) { ! 139: case AUD_FMT_S8: ! 140: sign = 1; ! 141: case AUD_FMT_U8: ! 142: break; ! 143: ! 144: case AUD_FMT_S16: ! 145: sign = 1; ! 146: case AUD_FMT_U16: ! 147: bits = 16; ! 148: break; ! 149: } ! 150: ! 151: sw->hw = hw; ! 152: sw->freq = freq; ! 153: sw->fmt = fmt; ! 154: sw->nchannels = nchannels; ! 155: sw->shift = (nchannels == 2) + (bits == 16); ! 156: sw->align = (1 << sw->shift) - 1; ! 157: sw->left = 0; ! 158: sw->pos = 0; ! 159: sw->wpos = 0; ! 160: sw->live = 0; ! 161: sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq; ! 162: sw->bytes_per_second = sw->freq << sw->shift; ! 163: sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16]; ! 164: ! 165: pcm_sw_free_resources (sw); ! 166: return pcm_sw_alloc_resources (sw); ! 167: } ! 168: ! 169: /* Hard voice */ ! 170: void pcm_hw_free_resources (HWVoice *hw) ! 171: { ! 172: if (hw->mix_buf) ! 173: qemu_free (hw->mix_buf); ! 174: hw->mix_buf = NULL; ! 175: } ! 176: ! 177: int pcm_hw_alloc_resources (HWVoice *hw) ! 178: { ! 179: hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t)); ! 180: if (!hw->mix_buf) ! 181: return -1; ! 182: return 0; ! 183: } ! 184: ! 185: void pcm_hw_fini (HWVoice *hw) ! 186: { ! 187: if (hw->active) { ! 188: ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt); ! 189: pcm_hw_free_resources (hw); ! 190: hw->pcm_ops->fini (hw); ! 191: memset (hw, 0, audio_state.drv->voice_size); ! 192: } ! 193: } ! 194: ! 195: void pcm_hw_gc (HWVoice *hw) ! 196: { ! 197: if (hw->nb_voices) ! 198: return; ! 199: ! 200: pcm_hw_fini (hw); ! 201: } ! 202: ! 203: int pcm_hw_get_live (HWVoice *hw) ! 204: { ! 205: int i, alive = 0, live = hw->samples; ! 206: ! 207: for (i = 0; i < hw->nb_voices; i++) { ! 208: if (hw->pvoice[i]->live) { ! 209: live = audio_MIN (hw->pvoice[i]->live, live); ! 210: alive += 1; ! 211: } ! 212: } ! 213: ! 214: if (alive) ! 215: return live; ! 216: else ! 217: return -1; ! 218: } ! 219: ! 220: int pcm_hw_get_live2 (HWVoice *hw, int *nb_active) ! 221: { ! 222: int i, alive = 0, live = hw->samples; ! 223: ! 224: *nb_active = 0; ! 225: for (i = 0; i < hw->nb_voices; i++) { ! 226: if (hw->pvoice[i]->live) { ! 227: if (hw->pvoice[i]->live < live) { ! 228: *nb_active = hw->pvoice[i]->active != 0; ! 229: live = hw->pvoice[i]->live; ! 230: } ! 231: alive += 1; ! 232: } ! 233: } ! 234: ! 235: if (alive) ! 236: return live; ! 237: else ! 238: return -1; ! 239: } ! 240: ! 241: void pcm_hw_dec_live (HWVoice *hw, int decr) ! 242: { ! 243: int i; ! 244: ! 245: for (i = 0; i < hw->nb_voices; i++) { ! 246: if (hw->pvoice[i]->live) { ! 247: hw->pvoice[i]->live -= decr; ! 248: } ! 249: } ! 250: } ! 251: ! 252: void pcm_hw_clear (HWVoice *hw, void *buf, int len) ! 253: { ! 254: if (!len) ! 255: return; ! 256: ! 257: switch (hw->fmt) { ! 258: case AUD_FMT_S16: ! 259: case AUD_FMT_S8: ! 260: memset (buf, len << hw->shift, 0x00); ! 261: break; ! 262: ! 263: case AUD_FMT_U8: ! 264: memset (buf, len << hw->shift, 0x80); ! 265: break; ! 266: ! 267: case AUD_FMT_U16: ! 268: { ! 269: unsigned int i; ! 270: uint16_t *p = buf; ! 271: int shift = hw->nchannels - 1; ! 272: ! 273: for (i = 0; i < len << shift; i++) { ! 274: p[i] = INT16_MAX; ! 275: } ! 276: } ! 277: break; ! 278: } ! 279: } ! 280: ! 281: int pcm_hw_write (SWVoice *sw, void *buf, int size) ! 282: { ! 283: int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck; ! 284: int ret = 0, pos = 0; ! 285: if (!sw) ! 286: return size; ! 287: ! 288: hwsamples = sw->hw->samples; ! 289: samples = size >> sw->shift; ! 290: ! 291: if (!sw->live) { ! 292: sw->wpos = sw->hw->rpos; ! 293: } ! 294: wpos = sw->wpos; ! 295: live = sw->live; ! 296: dead = hwsamples - live; ! 297: swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio; ! 298: swlim = audio_MIN (swlim, samples); ! 299: ! 300: ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n", ! 301: size, live, dead, swlim, wpos); ! 302: if (swlim) ! 303: sw->conv (sw->buf, buf, swlim); ! 304: ! 305: while (swlim) { ! 306: dead = hwsamples - live; ! 307: left = hwsamples - wpos; ! 308: blck = audio_MIN (dead, left); ! 309: if (!blck) { ! 310: /* dolog ("swlim=%d\n", swlim); */ ! 311: break; ! 312: } ! 313: isamp = swlim; ! 314: osamp = blck; ! 315: st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp); ! 316: ret += isamp; ! 317: swlim -= isamp; ! 318: pos += isamp; ! 319: live += osamp; ! 320: wpos = (wpos + osamp) % hwsamples; ! 321: } ! 322: ! 323: sw->wpos = wpos; ! 324: sw->live = live; ! 325: return ret << sw->shift; ! 326: } ! 327: ! 328: int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt) ! 329: { ! 330: int sign = 0, bits = 8; ! 331: ! 332: pcm_hw_fini (hw); ! 333: ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt); ! 334: if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) { ! 335: memset (hw, 0, audio_state.drv->voice_size); ! 336: return -1; ! 337: } ! 338: ! 339: switch (hw->fmt) { ! 340: case AUD_FMT_S8: ! 341: sign = 1; ! 342: case AUD_FMT_U8: ! 343: break; ! 344: ! 345: case AUD_FMT_S16: ! 346: sign = 1; ! 347: case AUD_FMT_U16: ! 348: bits = 16; ! 349: break; ! 350: } ! 351: ! 352: hw->nb_voices = 0; ! 353: hw->active = 1; ! 354: hw->shift = (hw->nchannels == 2) + (bits == 16); ! 355: hw->bytes_per_second = hw->freq << hw->shift; ! 356: hw->align = (1 << hw->shift) - 1; ! 357: hw->samples = hw->bufsize >> hw->shift; ! 358: hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16]; ! 359: if (pcm_hw_alloc_resources (hw)) { ! 360: pcm_hw_fini (hw); ! 361: return -1; ! 362: } ! 363: return 0; ! 364: } ! 365: ! 366: static int dist (void *hw) ! 367: { ! 368: if (hw) { ! 369: return (((uint8_t *) hw - (uint8_t *) hw_voices) ! 370: / audio_state.drv->voice_size) + 1; ! 371: } ! 372: else { ! 373: return 0; ! 374: } ! 375: } ! 376: ! 377: #define ADVANCE(hw) \ ! 378: ((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices) ! 379: ! 380: HWVoice *pcm_hw_find_any (HWVoice *hw) ! 381: { ! 382: int i = dist (hw); ! 383: for (; i < audio_state.nb_hw_voices; i++) { ! 384: hw = ADVANCE (hw); ! 385: return hw; ! 386: } ! 387: return NULL; ! 388: } ! 389: ! 390: HWVoice *pcm_hw_find_any_active (HWVoice *hw) ! 391: { ! 392: int i = dist (hw); ! 393: for (; i < audio_state.nb_hw_voices; i++) { ! 394: hw = ADVANCE (hw); ! 395: if (hw->active) ! 396: return hw; ! 397: } ! 398: return NULL; ! 399: } ! 400: ! 401: HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw) ! 402: { ! 403: int i = dist (hw); ! 404: for (; i < audio_state.nb_hw_voices; i++) { ! 405: hw = ADVANCE (hw); ! 406: if (hw->active && hw->enabled) ! 407: return hw; ! 408: } ! 409: return NULL; ! 410: } ! 411: ! 412: HWVoice *pcm_hw_find_any_passive (HWVoice *hw) ! 413: { ! 414: int i = dist (hw); ! 415: for (; i < audio_state.nb_hw_voices; i++) { ! 416: hw = ADVANCE (hw); ! 417: if (!hw->active) ! 418: return hw; ! 419: } ! 420: return NULL; ! 421: } ! 422: ! 423: HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq, ! 424: int nchannels, audfmt_e fmt) ! 425: { ! 426: while ((hw = pcm_hw_find_any_active (hw))) { ! 427: if (hw->freq == freq && ! 428: hw->nchannels == nchannels && ! 429: hw->fmt == fmt) ! 430: return hw; ! 431: } ! 432: return NULL; ! 433: } ! 434: ! 435: HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt) ! 436: { ! 437: HWVoice *hw; ! 438: ! 439: if (audio_state.fixed_format) { ! 440: freq = audio_state.fixed_freq; ! 441: nchannels = audio_state.fixed_channels; ! 442: fmt = audio_state.fixed_fmt; ! 443: } ! 444: ! 445: hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt); ! 446: ! 447: if (hw) ! 448: return hw; ! 449: ! 450: hw = pcm_hw_find_any_passive (NULL); ! 451: if (hw) { ! 452: hw->pcm_ops = audio_state.drv->pcm_ops; ! 453: if (!hw->pcm_ops) ! 454: return NULL; ! 455: ! 456: if (pcm_hw_init (hw, freq, nchannels, fmt)) { ! 457: pcm_hw_gc (hw); ! 458: return NULL; ! 459: } ! 460: else ! 461: return hw; ! 462: } ! 463: ! 464: return pcm_hw_find_any (NULL); ! 465: } ! 466: ! 467: int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw) ! 468: { ! 469: SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw)); ! 470: if (!pvoice) ! 471: return -1; ! 472: ! 473: memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw)); ! 474: qemu_free (hw->pvoice); ! 475: hw->pvoice = pvoice; ! 476: hw->pvoice[hw->nb_voices++] = sw; ! 477: return 0; ! 478: } ! 479: ! 480: int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw) ! 481: { ! 482: int i, j; ! 483: if (hw->nb_voices > 1) { ! 484: SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw)); ! 485: ! 486: if (!pvoice) { ! 487: dolog ("Can not maintain consistent state (not enough memory)\n"); ! 488: return -1; ! 489: } ! 490: ! 491: for (i = 0, j = 0; i < hw->nb_voices; i++) { ! 492: if (j >= hw->nb_voices - 1) { ! 493: dolog ("Can not maintain consistent state " ! 494: "(invariant violated)\n"); ! 495: return -1; ! 496: } ! 497: if (hw->pvoice[i] != sw) ! 498: pvoice[j++] = hw->pvoice[i]; ! 499: } ! 500: qemu_free (hw->pvoice); ! 501: hw->pvoice = pvoice; ! 502: hw->nb_voices -= 1; ! 503: } ! 504: else { ! 505: qemu_free (hw->pvoice); ! 506: hw->pvoice = NULL; ! 507: hw->nb_voices = 0; ! 508: } ! 509: return 0; ! 510: } ! 511: ! 512: SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt) ! 513: { ! 514: SWVoice *sw; ! 515: HWVoice *hw; ! 516: ! 517: sw = qemu_mallocz (sizeof (*sw)); ! 518: if (!sw) ! 519: goto err1; ! 520: ! 521: hw = pcm_hw_add (freq, nchannels, fmt); ! 522: if (!hw) ! 523: goto err2; ! 524: ! 525: if (pcm_hw_add_sw (hw, sw)) ! 526: goto err3; ! 527: ! 528: if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) ! 529: goto err4; ! 530: ! 531: return sw; ! 532: ! 533: err4: ! 534: pcm_hw_del_sw (hw, sw); ! 535: err3: ! 536: pcm_hw_gc (hw); ! 537: err2: ! 538: qemu_free (sw); ! 539: err1: ! 540: return NULL; ! 541: } ! 542: ! 543: SWVoice *AUD_open (SWVoice *sw, const char *name, ! 544: int freq, int nchannels, audfmt_e fmt) ! 545: { ! 546: if (!audio_state.drv) { ! 547: return NULL; ! 548: } ! 549: ! 550: if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) { ! 551: return sw; ! 552: } ! 553: ! 554: if (sw) { ! 555: ldebug ("Different format %s %d %d %d\n", ! 556: name, ! 557: sw->freq == freq, ! 558: sw->nchannels == nchannels, ! 559: sw->fmt == fmt); ! 560: } ! 561: ! 562: if (nchannels != 1 && nchannels != 2) { ! 563: dolog ("Bogus channel count %d for voice %s\n", nchannels, name); ! 564: return NULL; ! 565: } ! 566: ! 567: if (!audio_state.fixed_format && sw) { ! 568: pcm_sw_fini (sw); ! 569: pcm_hw_del_sw (sw->hw, sw); ! 570: pcm_hw_gc (sw->hw); ! 571: if (sw->name) { ! 572: qemu_free (sw->name); ! 573: sw->name = NULL; ! 574: } ! 575: qemu_free (sw); ! 576: sw = NULL; ! 577: } ! 578: ! 579: if (sw) { ! 580: HWVoice *hw = sw->hw; ! 581: if (!hw) { ! 582: dolog ("Internal logic error voice %s has no hardware store\n", ! 583: name); ! 584: return sw; ! 585: } ! 586: ! 587: if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) { ! 588: pcm_sw_fini (sw); ! 589: pcm_hw_del_sw (hw, sw); ! 590: pcm_hw_gc (hw); ! 591: if (sw->name) { ! 592: qemu_free (sw->name); ! 593: sw->name = NULL; ! 594: } ! 595: qemu_free (sw); ! 596: return NULL; ! 597: } ! 598: } ! 599: else { ! 600: sw = pcm_create_voice_pair (freq, nchannels, fmt); ! 601: if (!sw) { ! 602: dolog ("Failed to create voice %s\n", name); ! 603: return NULL; ! 604: } ! 605: } ! 606: ! 607: if (sw->name) { ! 608: qemu_free (sw->name); ! 609: sw->name = NULL; ! 610: } ! 611: sw->name = qemu_strdup (name); ! 612: return sw; ! 613: } ! 614: ! 615: void AUD_close (SWVoice *sw) ! 616: { ! 617: if (!sw) ! 618: return; ! 619: ! 620: pcm_sw_fini (sw); ! 621: pcm_hw_del_sw (sw->hw, sw); ! 622: pcm_hw_gc (sw->hw); ! 623: if (sw->name) { ! 624: qemu_free (sw->name); ! 625: sw->name = NULL; ! 626: } ! 627: qemu_free (sw); ! 628: } ! 629: ! 630: int AUD_write (SWVoice *sw, void *buf, int size) ! 631: { ! 632: int bytes; ! 633: ! 634: if (!sw->hw->enabled) ! 635: dolog ("Writing to disabled voice %s\n", sw->name); ! 636: bytes = sw->hw->pcm_ops->write (sw, buf, size); ! 637: return bytes; ! 638: } ! 639: ! 640: void AUD_run (void) ! 641: { ! 642: HWVoice *hw = NULL; ! 643: ! 644: while ((hw = pcm_hw_find_any_active_enabled (hw))) { ! 645: int i; ! 646: if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) { ! 647: hw->enabled = 0; ! 648: hw->pcm_ops->ctl (hw, VOICE_DISABLE); ! 649: for (i = 0; i < hw->nb_voices; i++) { ! 650: hw->pvoice[i]->live = 0; ! 651: /* hw->pvoice[i]->old_ticks = 0; */ ! 652: } ! 653: continue; ! 654: } ! 655: ! 656: hw->pcm_ops->run (hw); ! 657: assert (hw->rpos < hw->samples); ! 658: for (i = 0; i < hw->nb_voices; i++) { ! 659: SWVoice *sw = hw->pvoice[i]; ! 660: if (!sw->active && !sw->live && sw->old_ticks) { ! 661: int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks; ! 662: if (delta > audio_state.ticks_threshold) { ! 663: ldebug ("resetting old_ticks for %s\n", sw->name); ! 664: sw->old_ticks = 0; ! 665: } ! 666: } ! 667: } ! 668: } ! 669: } ! 670: ! 671: int AUD_get_free (SWVoice *sw) ! 672: { ! 673: int free; ! 674: ! 675: if (!sw) ! 676: return 4096; ! 677: ! 678: free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio ! 679: / INT_MAX; ! 680: ! 681: free &= ~sw->hw->align; ! 682: if (!free) return 0; ! 683: ! 684: return free; ! 685: } ! 686: ! 687: int AUD_get_buffer_size (SWVoice *sw) ! 688: { ! 689: return sw->hw->bufsize; ! 690: } ! 691: ! 692: void AUD_adjust (SWVoice *sw, int bytes) ! 693: { ! 694: if (!sw) ! 695: return; ! 696: sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second; ! 697: } ! 698: ! 699: void AUD_reset (SWVoice *sw) ! 700: { ! 701: sw->active = 0; ! 702: sw->old_ticks = 0; ! 703: } ! 704: ! 705: int AUD_calc_elapsed (SWVoice *sw) ! 706: { ! 707: int64_t now, delta, bytes; ! 708: int dead, swlim; ! 709: ! 710: if (!sw) ! 711: return 0; ! 712: ! 713: now = qemu_get_clock (vm_clock); ! 714: delta = now - sw->old_ticks; ! 715: bytes = (delta * sw->bytes_per_second) / ticks_per_sec; ! 716: if (delta < 0) { ! 717: dolog ("whoops delta(<0)=%lld\n", delta); ! 718: return 0; ! 719: } ! 720: ! 721: dead = sw->hw->samples - sw->live; ! 722: swlim = ((dead * (int64_t) INT_MAX) / sw->ratio); ! 723: ! 724: if (bytes > swlim) { ! 725: return swlim; ! 726: } ! 727: else { ! 728: return bytes; ! 729: } ! 730: } ! 731: ! 732: void AUD_enable (SWVoice *sw, int on) ! 733: { ! 734: int i; ! 735: HWVoice *hw; ! 736: ! 737: if (!sw) ! 738: return; ! 739: ! 740: hw = sw->hw; ! 741: if (on) { ! 742: if (!sw->live) ! 743: sw->wpos = sw->hw->rpos; ! 744: if (!sw->old_ticks) { ! 745: sw->old_ticks = qemu_get_clock (vm_clock); ! 746: } ! 747: } ! 748: ! 749: if (sw->active != on) { ! 750: if (on) { ! 751: hw->pending_disable = 0; ! 752: if (!hw->enabled) { ! 753: hw->enabled = 1; ! 754: for (i = 0; i < hw->nb_voices; i++) { ! 755: ldebug ("resetting voice\n"); ! 756: sw = hw->pvoice[i]; ! 757: sw->old_ticks = qemu_get_clock (vm_clock); ! 758: } ! 759: hw->pcm_ops->ctl (hw, VOICE_ENABLE); ! 760: } ! 761: } ! 762: else { ! 763: if (hw->enabled && !hw->pending_disable) { ! 764: int nb_active = 0; ! 765: for (i = 0; i < hw->nb_voices; i++) { ! 766: nb_active += hw->pvoice[i]->active != 0; ! 767: } ! 768: ! 769: if (nb_active == 1) { ! 770: hw->pending_disable = 1; ! 771: } ! 772: } ! 773: } ! 774: sw->active = on; ! 775: } ! 776: } ! 777: ! 778: static struct audio_output_driver *drvtab[] = { ! 779: #ifdef CONFIG_OSS ! 780: &oss_output_driver, ! 781: #endif ! 782: #ifdef CONFIG_FMOD ! 783: &fmod_output_driver, ! 784: #endif ! 785: #ifdef CONFIG_SDL ! 786: &sdl_output_driver, ! 787: #endif ! 788: &no_output_driver, ! 789: #ifdef USE_WAV_AUDIO ! 790: &wav_output_driver, ! 791: #endif ! 792: }; ! 793: ! 794: static int voice_init (struct audio_output_driver *drv) ! 795: { ! 796: audio_state.opaque = drv->init (); ! 797: if (audio_state.opaque) { ! 798: if (audio_state.nb_hw_voices > drv->max_voices) { ! 799: dolog ("`%s' does not support %d multiple hardware channels\n" ! 800: "Resetting to %d\n", ! 801: drv->name, audio_state.nb_hw_voices, drv->max_voices); ! 802: audio_state.nb_hw_voices = drv->max_voices; ! 803: } ! 804: hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size); ! 805: if (hw_voices) { ! 806: audio_state.drv = drv; ! 807: return 1; ! 808: } ! 809: else { ! 810: dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n", ! 811: audio_state.nb_hw_voices, drv->name, drv->voice_size); ! 812: drv->fini (audio_state.opaque); ! 813: return 0; ! 814: } ! 815: } ! 816: else { ! 817: dolog ("Could not init `%s' audio\n", drv->name); ! 818: return 0; ! 819: } ! 820: } ! 821: ! 822: static void audio_vm_stop_handler (void *opaque, int reason) ! 823: { ! 824: HWVoice *hw = NULL; ! 825: ! 826: while ((hw = pcm_hw_find_any (hw))) { ! 827: if (!hw->pcm_ops) ! 828: continue; ! 829: ! 830: hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE); ! 831: } ! 832: } ! 833: ! 834: static void audio_atexit (void) ! 835: { ! 836: HWVoice *hw = NULL; ! 837: ! 838: while ((hw = pcm_hw_find_any (hw))) { ! 839: if (!hw->pcm_ops) ! 840: continue; ! 841: ! 842: hw->pcm_ops->ctl (hw, VOICE_DISABLE); ! 843: hw->pcm_ops->fini (hw); ! 844: } ! 845: audio_state.drv->fini (audio_state.opaque); ! 846: } ! 847: ! 848: static void audio_save (QEMUFile *f, void *opaque) ! 849: { ! 850: } ! 851: ! 852: static int audio_load (QEMUFile *f, void *opaque, int version_id) ! 853: { ! 854: if (version_id != 1) ! 855: return -EINVAL; ! 856: ! 857: return 0; ! 858: } ! 859: ! 860: void AUD_init (void) ! 861: { ! 862: int i; ! 863: int done = 0; ! 864: const char *drvname; ! 865: ! 866: audio_state.fixed_format = ! 867: !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format); ! 868: audio_state.fixed_freq = ! 869: audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq); ! 870: audio_state.nb_hw_voices = ! 871: audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices); ! 872: ! 873: if (audio_state.nb_hw_voices <= 0) { ! 874: dolog ("Bogus number of voices %d, resetting to 1\n", ! 875: audio_state.nb_hw_voices); ! 876: } ! 877: ! 878: drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL); ! 879: if (drvname) { ! 880: int found = 0; ! 881: for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { ! 882: if (!strcmp (drvname, drvtab[i]->name)) { ! 883: done = voice_init (drvtab[i]); ! 884: found = 1; ! 885: break; ! 886: } ! 887: } ! 888: if (!found) { ! 889: dolog ("Unknown audio driver `%s'\n", drvname); ! 890: } ! 891: } ! 892: ! 893: qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL); ! 894: atexit (audio_atexit); ! 895: ! 896: if (!done) { ! 897: for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { ! 898: if (drvtab[i]->can_be_default) ! 899: done = voice_init (drvtab[i]); ! 900: } ! 901: } ! 902: ! 903: audio_state.ticks_threshold = ticks_per_sec / 50; ! 904: audio_state.freq_threshold = 100; ! 905: ! 906: register_savevm ("audio", 0, 1, audio_save, audio_load, NULL); ! 907: if (!done) { ! 908: dolog ("Can not initialize audio subsystem\n"); ! 909: voice_init (&no_output_driver); ! 910: } ! 911: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.