ia64/xen-unstable

changeset 8417:b34f4169b12e

Add sound blaster support to VMX device model.

Signed-off-by: Zhai Edwin <edwin.zhai@intel.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue Dec 20 12:55:19 2005 +0100 (2005-12-20)
parents 870c7e7da81e
children 931acb64fbaf
files tools/examples/xmexample.vmx tools/ioemu/audio/audio.c tools/ioemu/audio/audio.h tools/ioemu/audio/audio_int.h tools/ioemu/audio/mixeng.c tools/ioemu/audio/mixeng.h tools/ioemu/audio/mixeng_template.h tools/ioemu/audio/noaudio.c tools/ioemu/audio/ossaudio.c tools/ioemu/audio/sdlaudio.c tools/ioemu/audio/wavaudio.c tools/ioemu/hw/pc.c tools/ioemu/target-i386-dm/Makefile tools/ioemu/vl.h tools/python/xen/xend/image.py tools/python/xen/xm/create.py
line diff
     1.1 --- a/tools/examples/xmexample.vmx	Tue Dec 20 12:52:38 2005 +0100
     1.2 +++ b/tools/examples/xmexample.vmx	Tue Dec 20 12:55:19 2005 +0100
     1.3 @@ -135,7 +135,7 @@ ne2000=0
     1.4  
     1.5  #-----------------------------------------------------------------------------
     1.6  #   enable audio support
     1.7 -#enable-audio=1
     1.8 +#audio=1
     1.9  
    1.10  
    1.11  #-----------------------------------------------------------------------------
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/ioemu/audio/audio.c	Tue Dec 20 12:55:19 2005 +0100
     2.3 @@ -0,0 +1,910 @@
     2.4 +/*
     2.5 + * QEMU Audio subsystem
     2.6 + * 
     2.7 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
     2.8 + * 
     2.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    2.10 + * of this software and associated documentation files (the "Software"), to deal
    2.11 + * in the Software without restriction, including without limitation the rights
    2.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    2.13 + * copies of the Software, and to permit persons to whom the Software is
    2.14 + * furnished to do so, subject to the following conditions:
    2.15 + *
    2.16 + * The above copyright notice and this permission notice shall be included in
    2.17 + * all copies or substantial portions of the Software.
    2.18 + *
    2.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    2.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    2.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    2.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    2.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    2.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    2.25 + * THE SOFTWARE.
    2.26 + */
    2.27 +#include <assert.h>
    2.28 +#include "vl.h"
    2.29 +
    2.30 +#define USE_WAV_AUDIO
    2.31 +
    2.32 +#include "audio/audio_int.h"
    2.33 +
    2.34 +#define dolog(...) AUD_log ("audio", __VA_ARGS__)
    2.35 +#ifdef DEBUG
    2.36 +#define ldebug(...) dolog (__VA_ARGS__)
    2.37 +#else
    2.38 +#define ldebug(...)
    2.39 +#endif
    2.40 +
    2.41 +#define QC_AUDIO_DRV    "QEMU_AUDIO_DRV"
    2.42 +#define QC_VOICES       "QEMU_VOICES"
    2.43 +#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT"
    2.44 +#define QC_FIXED_FREQ   "QEMU_FIXED_FREQ"
    2.45 +
    2.46 +static HWVoice *hw_voices;
    2.47 +
    2.48 +AudioState audio_state = {
    2.49 +    1,                          /* use fixed settings */
    2.50 +    44100,                      /* fixed frequency */
    2.51 +    2,                          /* fixed channels */
    2.52 +    AUD_FMT_S16,                /* fixed format */
    2.53 +    1,                          /* number of hw voices */
    2.54 +    -1                          /* voice size */
    2.55 +};
    2.56 +
    2.57 +/* http://www.df.lth.se/~john_e/gems/gem002d.html */
    2.58 +/* http://www.multi-platforms.com/Tips/PopCount.htm */
    2.59 +uint32_t popcount (uint32_t u)
    2.60 +{
    2.61 +    u = ((u&0x55555555) + ((u>>1)&0x55555555));
    2.62 +    u = ((u&0x33333333) + ((u>>2)&0x33333333));
    2.63 +    u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
    2.64 +    u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
    2.65 +    u = ( u&0x0000ffff) + (u>>16);
    2.66 +    return u;
    2.67 +}
    2.68 +
    2.69 +inline uint32_t lsbindex (uint32_t u)
    2.70 +{
    2.71 +    return popcount ((u&-u)-1);
    2.72 +}
    2.73 +
    2.74 +int audio_get_conf_int (const char *key, int defval)
    2.75 +{
    2.76 +    int val = defval;
    2.77 +    char *strval;
    2.78 +
    2.79 +    strval = getenv (key);
    2.80 +    if (strval) {
    2.81 +        val = atoi (strval);
    2.82 +    }
    2.83 +
    2.84 +    return val;
    2.85 +}
    2.86 +
    2.87 +const char *audio_get_conf_str (const char *key, const char *defval)
    2.88 +{
    2.89 +    const char *val = getenv (key);
    2.90 +    if (!val)
    2.91 +        return defval;
    2.92 +    else
    2.93 +        return val;
    2.94 +}
    2.95 +
    2.96 +void AUD_log (const char *cap, const char *fmt, ...)
    2.97 +{
    2.98 +    va_list ap;
    2.99 +    fprintf (stderr, "%s: ", cap);
   2.100 +    va_start (ap, fmt);
   2.101 +    vfprintf (stderr, fmt, ap);
   2.102 +    va_end (ap);
   2.103 +}
   2.104 +
   2.105 +/*
   2.106 + * Soft Voice
   2.107 + */
   2.108 +void pcm_sw_free_resources (SWVoice *sw)
   2.109 +{
   2.110 +    if (sw->buf) qemu_free (sw->buf);
   2.111 +    if (sw->rate) st_rate_stop (sw->rate);
   2.112 +    sw->buf = NULL;
   2.113 +    sw->rate = NULL;
   2.114 +}
   2.115 +
   2.116 +int pcm_sw_alloc_resources (SWVoice *sw)
   2.117 +{
   2.118 +    sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
   2.119 +    if (!sw->buf)
   2.120 +        return -1;
   2.121 +
   2.122 +    sw->rate = st_rate_start (sw->freq, sw->hw->freq);
   2.123 +    if (!sw->rate) {
   2.124 +        qemu_free (sw->buf);
   2.125 +        sw->buf = NULL;
   2.126 +        return -1;
   2.127 +    }
   2.128 +    return 0;
   2.129 +}
   2.130 +
   2.131 +void pcm_sw_fini (SWVoice *sw)
   2.132 +{
   2.133 +    pcm_sw_free_resources (sw);
   2.134 +}
   2.135 +
   2.136 +int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
   2.137 +                 int nchannels, audfmt_e fmt)
   2.138 +{
   2.139 +    int bits = 8, sign = 0;
   2.140 +
   2.141 +    switch (fmt) {
   2.142 +    case AUD_FMT_S8:
   2.143 +        sign = 1;
   2.144 +    case AUD_FMT_U8:
   2.145 +        break;
   2.146 +
   2.147 +    case AUD_FMT_S16:
   2.148 +        sign = 1;
   2.149 +    case AUD_FMT_U16:
   2.150 +        bits = 16;
   2.151 +        break;
   2.152 +    }
   2.153 +
   2.154 +    sw->hw = hw;
   2.155 +    sw->freq = freq;
   2.156 +    sw->fmt = fmt;
   2.157 +    sw->nchannels = nchannels;
   2.158 +    sw->shift = (nchannels == 2) + (bits == 16);
   2.159 +    sw->align = (1 << sw->shift) - 1;
   2.160 +    sw->left = 0;
   2.161 +    sw->pos = 0;
   2.162 +    sw->wpos = 0;
   2.163 +    sw->live = 0;
   2.164 +    sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq;
   2.165 +    sw->bytes_per_second = sw->freq << sw->shift;
   2.166 +    sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16];
   2.167 +
   2.168 +    pcm_sw_free_resources (sw);
   2.169 +    return pcm_sw_alloc_resources (sw);
   2.170 +}
   2.171 +
   2.172 +/* Hard voice */
   2.173 +void pcm_hw_free_resources (HWVoice *hw)
   2.174 +{
   2.175 +    if (hw->mix_buf)
   2.176 +        qemu_free (hw->mix_buf);
   2.177 +    hw->mix_buf = NULL;
   2.178 +}
   2.179 +
   2.180 +int pcm_hw_alloc_resources (HWVoice *hw)
   2.181 +{
   2.182 +    hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
   2.183 +    if (!hw->mix_buf)
   2.184 +        return -1;
   2.185 +    return 0;
   2.186 +}
   2.187 +
   2.188 +void pcm_hw_fini (HWVoice *hw)
   2.189 +{
   2.190 +    if (hw->active) {
   2.191 +        ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);
   2.192 +        pcm_hw_free_resources (hw);
   2.193 +        hw->pcm_ops->fini (hw);
   2.194 +        memset (hw, 0, audio_state.drv->voice_size);
   2.195 +    }
   2.196 +}
   2.197 +
   2.198 +void pcm_hw_gc (HWVoice *hw)
   2.199 +{
   2.200 +    if (hw->nb_voices)
   2.201 +        return;
   2.202 +
   2.203 +    pcm_hw_fini (hw);
   2.204 +}
   2.205 +
   2.206 +int pcm_hw_get_live (HWVoice *hw)
   2.207 +{
   2.208 +    int i, alive = 0, live = hw->samples;
   2.209 +
   2.210 +    for (i = 0; i < hw->nb_voices; i++) {
   2.211 +        if (hw->pvoice[i]->live) {
   2.212 +            live = audio_MIN (hw->pvoice[i]->live, live);
   2.213 +            alive += 1;
   2.214 +        }
   2.215 +    }
   2.216 +
   2.217 +    if (alive)
   2.218 +        return live;
   2.219 +    else
   2.220 +        return -1;
   2.221 +}
   2.222 +
   2.223 +int pcm_hw_get_live2 (HWVoice *hw, int *nb_active)
   2.224 +{
   2.225 +    int i, alive = 0, live = hw->samples;
   2.226 +
   2.227 +    *nb_active = 0;
   2.228 +    for (i = 0; i < hw->nb_voices; i++) {
   2.229 +        if (hw->pvoice[i]->live) {
   2.230 +            if (hw->pvoice[i]->live < live) {
   2.231 +                *nb_active = hw->pvoice[i]->active != 0;
   2.232 +                live = hw->pvoice[i]->live;
   2.233 +            }
   2.234 +            alive += 1;
   2.235 +        }
   2.236 +    }
   2.237 +
   2.238 +    if (alive)
   2.239 +        return live;
   2.240 +    else
   2.241 +        return -1;
   2.242 +}
   2.243 +
   2.244 +void pcm_hw_dec_live (HWVoice *hw, int decr)
   2.245 +{
   2.246 +    int i;
   2.247 +
   2.248 +    for (i = 0; i < hw->nb_voices; i++) {
   2.249 +        if (hw->pvoice[i]->live) {
   2.250 +            hw->pvoice[i]->live -= decr;
   2.251 +        }
   2.252 +    }
   2.253 +}
   2.254 +
   2.255 +void pcm_hw_clear (HWVoice *hw, void *buf, int len)
   2.256 +{
   2.257 +    if (!len)
   2.258 +        return;
   2.259 +
   2.260 +    switch (hw->fmt) {
   2.261 +    case AUD_FMT_S16:
   2.262 +    case AUD_FMT_S8:
   2.263 +        memset (buf, len << hw->shift, 0x00);
   2.264 +        break;
   2.265 +
   2.266 +    case AUD_FMT_U8:
   2.267 +        memset (buf, len << hw->shift, 0x80);
   2.268 +        break;
   2.269 +
   2.270 +    case AUD_FMT_U16:
   2.271 +        {
   2.272 +            unsigned int i;
   2.273 +            uint16_t *p = buf;
   2.274 +            int shift = hw->nchannels - 1;
   2.275 +
   2.276 +            for (i = 0; i < len << shift; i++) {
   2.277 +                p[i] = INT16_MAX;
   2.278 +            }
   2.279 +        }
   2.280 +        break;
   2.281 +    }
   2.282 +}
   2.283 +
   2.284 +int pcm_hw_write (SWVoice *sw, void *buf, int size)
   2.285 +{
   2.286 +    int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
   2.287 +    int ret = 0, pos = 0;
   2.288 +    if (!sw)
   2.289 +        return size;
   2.290 +
   2.291 +    hwsamples = sw->hw->samples;
   2.292 +    samples = size >> sw->shift;
   2.293 +
   2.294 +    if (!sw->live) {
   2.295 +        sw->wpos = sw->hw->rpos;
   2.296 +    }
   2.297 +    wpos = sw->wpos;
   2.298 +    live = sw->live;
   2.299 +    dead = hwsamples - live;
   2.300 +    swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio;
   2.301 +    swlim = audio_MIN (swlim, samples);
   2.302 +
   2.303 +    ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",
   2.304 +           size, live, dead, swlim, wpos);
   2.305 +    if (swlim)
   2.306 +        sw->conv (sw->buf, buf, swlim);
   2.307 +
   2.308 +    while (swlim) {
   2.309 +        dead = hwsamples - live;
   2.310 +        left = hwsamples - wpos;
   2.311 +        blck = audio_MIN (dead, left);
   2.312 +        if (!blck) {
   2.313 +            /* dolog ("swlim=%d\n", swlim); */
   2.314 +            break;
   2.315 +        }
   2.316 +        isamp = swlim;
   2.317 +        osamp = blck;
   2.318 +        st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp);
   2.319 +        ret += isamp;
   2.320 +        swlim -= isamp;
   2.321 +        pos += isamp;
   2.322 +        live += osamp;
   2.323 +        wpos = (wpos + osamp) % hwsamples;
   2.324 +    }
   2.325 +
   2.326 +    sw->wpos = wpos;
   2.327 +    sw->live = live;
   2.328 +    return ret << sw->shift;
   2.329 +}
   2.330 +
   2.331 +int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
   2.332 +{
   2.333 +    int sign = 0, bits = 8;
   2.334 +
   2.335 +    pcm_hw_fini (hw);
   2.336 +    ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);
   2.337 +    if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {
   2.338 +        memset (hw, 0, audio_state.drv->voice_size);
   2.339 +        return -1;
   2.340 +    }
   2.341 +
   2.342 +    switch (hw->fmt) {
   2.343 +    case AUD_FMT_S8:
   2.344 +        sign = 1;
   2.345 +    case AUD_FMT_U8:
   2.346 +        break;
   2.347 +
   2.348 +    case AUD_FMT_S16:
   2.349 +        sign = 1;
   2.350 +    case AUD_FMT_U16:
   2.351 +        bits = 16;
   2.352 +        break;
   2.353 +    }
   2.354 +
   2.355 +    hw->nb_voices = 0;
   2.356 +    hw->active = 1;
   2.357 +    hw->shift = (hw->nchannels == 2) + (bits == 16);
   2.358 +    hw->bytes_per_second = hw->freq << hw->shift;
   2.359 +    hw->align = (1 << hw->shift) - 1;
   2.360 +    hw->samples = hw->bufsize >> hw->shift;
   2.361 +    hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16];
   2.362 +    if (pcm_hw_alloc_resources (hw)) {
   2.363 +        pcm_hw_fini (hw);
   2.364 +        return -1;
   2.365 +    }
   2.366 +    return 0;
   2.367 +}
   2.368 +
   2.369 +static int dist (void *hw)
   2.370 +{
   2.371 +    if (hw) {
   2.372 +        return (((uint8_t *) hw - (uint8_t *) hw_voices)
   2.373 +                / audio_state.voice_size) + 1;
   2.374 +    }
   2.375 +    else {
   2.376 +        return 0;
   2.377 +    }
   2.378 +}
   2.379 +
   2.380 +#define ADVANCE(hw) hw ? advance (hw, audio_state.voice_size) : hw_voices
   2.381 +
   2.382 +HWVoice *pcm_hw_find_any (HWVoice *hw)
   2.383 +{
   2.384 +    int i = dist (hw);
   2.385 +    for (; i < audio_state.nb_hw_voices; i++) {
   2.386 +        hw = ADVANCE (hw);
   2.387 +        return hw;
   2.388 +    }
   2.389 +    return NULL;
   2.390 +}
   2.391 +
   2.392 +HWVoice *pcm_hw_find_any_active (HWVoice *hw)
   2.393 +{
   2.394 +    int i = dist (hw);
   2.395 +    for (; i < audio_state.nb_hw_voices; i++) {
   2.396 +        hw = ADVANCE (hw);
   2.397 +        if (hw->active)
   2.398 +            return hw;
   2.399 +    }
   2.400 +    return NULL;
   2.401 +}
   2.402 +
   2.403 +HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw)
   2.404 +{
   2.405 +    int i = dist (hw);
   2.406 +    for (; i < audio_state.nb_hw_voices; i++) {
   2.407 +        hw = ADVANCE (hw);
   2.408 +        if (hw->active && hw->enabled)
   2.409 +            return hw;
   2.410 +    }
   2.411 +    return NULL;
   2.412 +}
   2.413 +
   2.414 +HWVoice *pcm_hw_find_any_passive (HWVoice *hw)
   2.415 +{
   2.416 +    int i = dist (hw);
   2.417 +    for (; i < audio_state.nb_hw_voices; i++) {
   2.418 +        hw = ADVANCE (hw);
   2.419 +        if (!hw->active)
   2.420 +            return hw;
   2.421 +    }
   2.422 +    return NULL;
   2.423 +}
   2.424 +
   2.425 +HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,
   2.426 +                               int nchannels, audfmt_e fmt)
   2.427 +{
   2.428 +    while ((hw = pcm_hw_find_any_active (hw))) {
   2.429 +        if (hw->freq == freq &&
   2.430 +            hw->nchannels == nchannels &&
   2.431 +            hw->fmt == fmt)
   2.432 +            return hw;
   2.433 +    }
   2.434 +    return NULL;
   2.435 +}
   2.436 +
   2.437 +HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt)
   2.438 +{
   2.439 +    HWVoice *hw;
   2.440 +
   2.441 +    if (audio_state.fixed_format) {
   2.442 +        freq = audio_state.fixed_freq;
   2.443 +        nchannels = audio_state.fixed_channels;
   2.444 +        fmt = audio_state.fixed_fmt;
   2.445 +    }
   2.446 +
   2.447 +    hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);
   2.448 +
   2.449 +    if (hw)
   2.450 +        return hw;
   2.451 +
   2.452 +    hw = pcm_hw_find_any_passive (NULL);
   2.453 +    if (hw) {
   2.454 +        hw->pcm_ops = audio_state.drv->pcm_ops;
   2.455 +        if (!hw->pcm_ops)
   2.456 +            return NULL;
   2.457 +
   2.458 +        if (pcm_hw_init (hw, freq, nchannels, fmt)) {
   2.459 +            pcm_hw_gc (hw);
   2.460 +            return NULL;
   2.461 +        }
   2.462 +        else
   2.463 +            return hw;
   2.464 +    }
   2.465 +
   2.466 +    return pcm_hw_find_any (NULL);
   2.467 +}
   2.468 +
   2.469 +int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)
   2.470 +{
   2.471 +    SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw));
   2.472 +    if (!pvoice)
   2.473 +        return -1;
   2.474 +
   2.475 +    memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));
   2.476 +    qemu_free (hw->pvoice);
   2.477 +    hw->pvoice = pvoice;
   2.478 +    hw->pvoice[hw->nb_voices++] = sw;
   2.479 +    return 0;
   2.480 +}
   2.481 +
   2.482 +int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)
   2.483 +{
   2.484 +    int i, j;
   2.485 +    if (hw->nb_voices > 1) {
   2.486 +        SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw));
   2.487 +
   2.488 +        if (!pvoice) {
   2.489 +            dolog ("Can not maintain consistent state (not enough memory)\n");
   2.490 +            return -1;
   2.491 +        }
   2.492 +
   2.493 +        for (i = 0, j = 0; i < hw->nb_voices; i++) {
   2.494 +            if (j >= hw->nb_voices - 1) {
   2.495 +                dolog ("Can not maintain consistent state "
   2.496 +                       "(invariant violated)\n");
   2.497 +                return -1;
   2.498 +            }
   2.499 +            if (hw->pvoice[i] != sw)
   2.500 +                pvoice[j++] = hw->pvoice[i];
   2.501 +        }
   2.502 +        qemu_free (hw->pvoice);
   2.503 +        hw->pvoice = pvoice;
   2.504 +        hw->nb_voices -= 1;
   2.505 +    }
   2.506 +    else {
   2.507 +        qemu_free (hw->pvoice);
   2.508 +        hw->pvoice = NULL;
   2.509 +        hw->nb_voices = 0;
   2.510 +    }
   2.511 +    return 0;
   2.512 +}
   2.513 +
   2.514 +SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt)
   2.515 +{
   2.516 +    SWVoice *sw;
   2.517 +    HWVoice *hw;
   2.518 +
   2.519 +    sw = qemu_mallocz (sizeof (*sw));
   2.520 +    if (!sw)
   2.521 +        goto err1;
   2.522 +
   2.523 +    hw = pcm_hw_add (freq, nchannels, fmt);
   2.524 +    if (!hw)
   2.525 +        goto err2;
   2.526 +
   2.527 +    if (pcm_hw_add_sw (hw, sw))
   2.528 +        goto err3;
   2.529 +
   2.530 +    if (pcm_sw_init (sw, hw, freq, nchannels, fmt))
   2.531 +        goto err4;
   2.532 +
   2.533 +    return sw;
   2.534 +
   2.535 +err4:
   2.536 +    pcm_hw_del_sw (hw, sw);
   2.537 +err3:
   2.538 +    pcm_hw_gc (hw);
   2.539 +err2:
   2.540 +    qemu_free (sw);
   2.541 +err1:
   2.542 +    return NULL;
   2.543 +}
   2.544 +
   2.545 +SWVoice *AUD_open (SWVoice *sw, const char *name,
   2.546 +                   int freq, int nchannels, audfmt_e fmt)
   2.547 +{
   2.548 +    if (!audio_state.drv) {
   2.549 +        return NULL;
   2.550 +    }
   2.551 +
   2.552 +    if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {
   2.553 +        return sw;
   2.554 +    }
   2.555 +
   2.556 +    if (sw) {
   2.557 +        ldebug ("Different format %s %d %d %d\n",
   2.558 +                name,
   2.559 +                sw->freq == freq,
   2.560 +                sw->nchannels == nchannels,
   2.561 +                sw->fmt == fmt);
   2.562 +    }
   2.563 +
   2.564 +    if (nchannels != 1 && nchannels != 2) {
   2.565 +        dolog ("Bogus channel count %d for voice %s\n", nchannels, name);
   2.566 +        return NULL;
   2.567 +    }
   2.568 +
   2.569 +    if (!audio_state.fixed_format && sw) {
   2.570 +        pcm_sw_fini (sw);
   2.571 +        pcm_hw_del_sw (sw->hw, sw);
   2.572 +        pcm_hw_gc (sw->hw);
   2.573 +        if (sw->name) {
   2.574 +            qemu_free (sw->name);
   2.575 +            sw->name = NULL;
   2.576 +        }
   2.577 +        qemu_free (sw);
   2.578 +        sw = NULL;
   2.579 +    }
   2.580 +
   2.581 +    if (sw) {
   2.582 +        HWVoice *hw = sw->hw;
   2.583 +        if (!hw) {
   2.584 +            dolog ("Internal logic error voice %s has no hardware store\n",
   2.585 +                   name);
   2.586 +            return sw;
   2.587 +        }
   2.588 +
   2.589 +        if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {
   2.590 +            pcm_sw_fini (sw);
   2.591 +            pcm_hw_del_sw (hw, sw);
   2.592 +            pcm_hw_gc (hw);
   2.593 +            if (sw->name) {
   2.594 +                qemu_free (sw->name);
   2.595 +                sw->name = NULL;
   2.596 +            }
   2.597 +            qemu_free (sw);
   2.598 +            return NULL;
   2.599 +        }
   2.600 +    }
   2.601 +    else {
   2.602 +        sw = pcm_create_voice_pair (freq, nchannels, fmt);
   2.603 +        if (!sw) {
   2.604 +            dolog ("Failed to create voice %s\n", name);
   2.605 +            return NULL;
   2.606 +        }
   2.607 +    }
   2.608 +
   2.609 +    if (sw->name) {
   2.610 +        qemu_free (sw->name);
   2.611 +        sw->name = NULL;
   2.612 +    }
   2.613 +    sw->name = qemu_strdup (name);
   2.614 +    return sw;
   2.615 +}
   2.616 +
   2.617 +void AUD_close (SWVoice *sw)
   2.618 +{
   2.619 +    if (!sw)
   2.620 +        return;
   2.621 +
   2.622 +    pcm_sw_fini (sw);
   2.623 +    pcm_hw_del_sw (sw->hw, sw);
   2.624 +    pcm_hw_gc (sw->hw);
   2.625 +    if (sw->name) {
   2.626 +        qemu_free (sw->name);
   2.627 +        sw->name = NULL;
   2.628 +    }
   2.629 +    qemu_free (sw);
   2.630 +}
   2.631 +
   2.632 +int AUD_write (SWVoice *sw, void *buf, int size)
   2.633 +{
   2.634 +    int bytes;
   2.635 +
   2.636 +    if (!sw->hw->enabled)
   2.637 +        dolog ("Writing to disabled voice %s\n", sw->name);
   2.638 +    bytes = sw->hw->pcm_ops->write (sw, buf, size);
   2.639 +    return bytes;
   2.640 +}
   2.641 +
   2.642 +void AUD_run (void)
   2.643 +{
   2.644 +    HWVoice *hw = NULL;
   2.645 +
   2.646 +    while ((hw = pcm_hw_find_any_active_enabled (hw))) {
   2.647 +        int i;
   2.648 +        if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) {
   2.649 +            hw->enabled = 0;
   2.650 +            hw->pcm_ops->ctl (hw, VOICE_DISABLE);
   2.651 +            for (i = 0; i < hw->nb_voices; i++) {
   2.652 +                hw->pvoice[i]->live = 0;
   2.653 +                /* hw->pvoice[i]->old_ticks = 0; */
   2.654 +            }
   2.655 +            continue;
   2.656 +        }
   2.657 +
   2.658 +        hw->pcm_ops->run (hw);
   2.659 +        assert (hw->rpos < hw->samples);
   2.660 +        for (i = 0; i < hw->nb_voices; i++) {
   2.661 +            SWVoice *sw = hw->pvoice[i];
   2.662 +            if (!sw->active && !sw->live && sw->old_ticks) {
   2.663 +                int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks;
   2.664 +                if (delta > audio_state.ticks_threshold) {
   2.665 +                    ldebug ("resetting old_ticks for %s\n", sw->name);
   2.666 +                    sw->old_ticks = 0;
   2.667 +                }
   2.668 +            }
   2.669 +        }
   2.670 +    }
   2.671 +}
   2.672 +
   2.673 +int AUD_get_free (SWVoice *sw)
   2.674 +{
   2.675 +    int free;
   2.676 +
   2.677 +    if (!sw)
   2.678 +        return 4096;
   2.679 +
   2.680 +    free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio
   2.681 +        / INT_MAX;
   2.682 +
   2.683 +    free &= ~sw->hw->align;
   2.684 +    if (!free) return 0;
   2.685 +
   2.686 +    return free;
   2.687 +}
   2.688 +
   2.689 +int AUD_get_buffer_size (SWVoice *sw)
   2.690 +{
   2.691 +    return sw->hw->bufsize;
   2.692 +}
   2.693 +
   2.694 +void AUD_adjust (SWVoice *sw, int bytes)
   2.695 +{
   2.696 +    if (!sw)
   2.697 +        return;
   2.698 +    sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second;
   2.699 +}
   2.700 +
   2.701 +void AUD_reset (SWVoice *sw)
   2.702 +{
   2.703 +    sw->active = 0;
   2.704 +    sw->old_ticks = 0;
   2.705 +}
   2.706 +
   2.707 +int AUD_calc_elapsed (SWVoice *sw)
   2.708 +{
   2.709 +    int64_t now, delta, bytes;
   2.710 +    int dead, swlim;
   2.711 +
   2.712 +    if (!sw)
   2.713 +        return 0;
   2.714 +
   2.715 +    now = qemu_get_clock (vm_clock);
   2.716 +    delta = now - sw->old_ticks;
   2.717 +    bytes = (delta * sw->bytes_per_second) / ticks_per_sec;
   2.718 +    if (delta < 0) {
   2.719 +        dolog ("whoops delta(<0)=%lld\n", delta);
   2.720 +        return 0;
   2.721 +    }
   2.722 +
   2.723 +    dead = sw->hw->samples - sw->live;
   2.724 +    swlim = ((dead * (int64_t) INT_MAX) / sw->ratio);
   2.725 +
   2.726 +    if (bytes > swlim) {
   2.727 +        return swlim;
   2.728 +    }
   2.729 +    else {
   2.730 +        return bytes;
   2.731 +    }
   2.732 +}
   2.733 +
   2.734 +void AUD_enable (SWVoice *sw, int on)
   2.735 +{
   2.736 +    int i;
   2.737 +    HWVoice *hw;
   2.738 +
   2.739 +    if (!sw)
   2.740 +        return;
   2.741 +
   2.742 +    hw = sw->hw;
   2.743 +    if (on) {
   2.744 +        if (!sw->live)
   2.745 +            sw->wpos = sw->hw->rpos;
   2.746 +        if (!sw->old_ticks) {
   2.747 +            sw->old_ticks = qemu_get_clock (vm_clock);
   2.748 +        }
   2.749 +    }
   2.750 +
   2.751 +    if (sw->active != on) {
   2.752 +        if (on) {
   2.753 +            hw->pending_disable = 0;
   2.754 +            if (!hw->enabled) {
   2.755 +                hw->enabled = 1;
   2.756 +                for (i = 0; i < hw->nb_voices; i++) {
   2.757 +                    ldebug ("resetting voice\n");
   2.758 +                    sw = hw->pvoice[i];
   2.759 +                    sw->old_ticks = qemu_get_clock (vm_clock);
   2.760 +                }
   2.761 +                hw->pcm_ops->ctl (hw, VOICE_ENABLE);
   2.762 +            }
   2.763 +        }
   2.764 +        else {
   2.765 +            if (hw->enabled && !hw->pending_disable) {
   2.766 +                int nb_active = 0;
   2.767 +                for (i = 0; i < hw->nb_voices; i++) {
   2.768 +                    nb_active += hw->pvoice[i]->active != 0;
   2.769 +                }
   2.770 +
   2.771 +                if (nb_active == 1) {
   2.772 +                    hw->pending_disable = 1;
   2.773 +                }
   2.774 +            }
   2.775 +        }
   2.776 +        sw->active = on;
   2.777 +    }
   2.778 +}
   2.779 +
   2.780 +static struct audio_output_driver *drvtab[] = {
   2.781 +#ifdef CONFIG_OSS
   2.782 +    &oss_output_driver,
   2.783 +#endif
   2.784 +#ifdef CONFIG_FMOD
   2.785 +    &fmod_output_driver,
   2.786 +#endif
   2.787 +#ifdef CONFIG_SDL
   2.788 +    &sdl_output_driver,
   2.789 +#endif
   2.790 +    &no_output_driver,
   2.791 +#ifdef USE_WAV_AUDIO
   2.792 +    &wav_output_driver,
   2.793 +#endif
   2.794 +};
   2.795 +
   2.796 +static int voice_init (struct audio_output_driver *drv)
   2.797 +{
   2.798 +    audio_state.opaque = drv->init ();
   2.799 +    if (audio_state.opaque) {
   2.800 +        if (audio_state.nb_hw_voices > drv->max_voices) {
   2.801 +            dolog ("`%s' does not support %d multiple hardware channels\n"
   2.802 +                   "Resetting to %d\n",
   2.803 +                   drv->name, audio_state.nb_hw_voices, drv->max_voices);
   2.804 +            audio_state.nb_hw_voices = drv->max_voices;
   2.805 +        }
   2.806 +        hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size);
   2.807 +        if (hw_voices) {
   2.808 +            audio_state.drv = drv;
   2.809 +            return 1;
   2.810 +        }
   2.811 +        else {
   2.812 +            dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",
   2.813 +                   audio_state.nb_hw_voices, drv->name, drv->voice_size);
   2.814 +            drv->fini (audio_state.opaque);
   2.815 +            return 0;
   2.816 +        }
   2.817 +    }
   2.818 +    else {
   2.819 +        dolog ("Could not init `%s' audio\n", drv->name);
   2.820 +        return 0;
   2.821 +    }
   2.822 +}
   2.823 +
   2.824 +static void audio_vm_stop_handler (void *opaque, int reason)
   2.825 +{
   2.826 +    HWVoice *hw = NULL;
   2.827 +
   2.828 +    while ((hw = pcm_hw_find_any (hw))) {
   2.829 +        if (!hw->pcm_ops)
   2.830 +            continue;
   2.831 +
   2.832 +        hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE);
   2.833 +    }
   2.834 +}
   2.835 +
   2.836 +static void audio_atexit (void)
   2.837 +{
   2.838 +    HWVoice *hw = NULL;
   2.839 +
   2.840 +    while ((hw = pcm_hw_find_any (hw))) {
   2.841 +        if (!hw->pcm_ops)
   2.842 +            continue;
   2.843 +
   2.844 +        hw->pcm_ops->ctl (hw, VOICE_DISABLE);
   2.845 +        hw->pcm_ops->fini (hw);
   2.846 +    }
   2.847 +    audio_state.drv->fini (audio_state.opaque);
   2.848 +}
   2.849 +
   2.850 +static void audio_save (QEMUFile *f, void *opaque)
   2.851 +{
   2.852 +}
   2.853 +
   2.854 +static int audio_load (QEMUFile *f, void *opaque, int version_id)
   2.855 +{
   2.856 +    if (version_id != 1)
   2.857 +        return -EINVAL;
   2.858 +
   2.859 +    return 0;
   2.860 +}
   2.861 +
   2.862 +void AUD_init (void)
   2.863 +{
   2.864 +    int i;
   2.865 +    int done = 0;
   2.866 +    const char *drvname;
   2.867 +
   2.868 +    audio_state.fixed_format =
   2.869 +        !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format);
   2.870 +    audio_state.fixed_freq =
   2.871 +        audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq);
   2.872 +    audio_state.nb_hw_voices =
   2.873 +        audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices);
   2.874 +
   2.875 +    if (audio_state.nb_hw_voices <= 0) {
   2.876 +        dolog ("Bogus number of voices %d, resetting to 1\n",
   2.877 +               audio_state.nb_hw_voices);
   2.878 +    }
   2.879 +
   2.880 +    drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);
   2.881 +    if (drvname) {
   2.882 +        int found = 0;
   2.883 +        for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
   2.884 +            if (!strcmp (drvname, drvtab[i]->name)) {
   2.885 +                done = voice_init (drvtab[i]);
   2.886 +                found = 1;
   2.887 +                break;
   2.888 +            }
   2.889 +        }
   2.890 +        if (!found) {
   2.891 +            dolog ("Unknown audio driver `%s'\n", drvname);
   2.892 +        }
   2.893 +    }
   2.894 +
   2.895 +    qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL);
   2.896 +    atexit (audio_atexit);
   2.897 +
   2.898 +    if (!done) {
   2.899 +        for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
   2.900 +            if (drvtab[i]->can_be_default)
   2.901 +                done = voice_init (drvtab[i]);
   2.902 +        }
   2.903 +    }
   2.904 +
   2.905 +    audio_state.ticks_threshold = ticks_per_sec / 50;
   2.906 +    audio_state.freq_threshold = 100;
   2.907 +
   2.908 +    register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);
   2.909 +    if (!done) {
   2.910 +        dolog ("Can not initialize audio subsystem\n");
   2.911 +        voice_init (&no_output_driver);
   2.912 +    }
   2.913 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/ioemu/audio/audio.h	Tue Dec 20 12:55:19 2005 +0100
     3.3 @@ -0,0 +1,65 @@
     3.4 +/*
     3.5 + * QEMU Audio subsystem header
     3.6 + * 
     3.7 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
     3.8 + * 
     3.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    3.10 + * of this software and associated documentation files (the "Software"), to deal
    3.11 + * in the Software without restriction, including without limitation the rights
    3.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    3.13 + * copies of the Software, and to permit persons to whom the Software is
    3.14 + * furnished to do so, subject to the following conditions:
    3.15 + *
    3.16 + * The above copyright notice and this permission notice shall be included in
    3.17 + * all copies or substantial portions of the Software.
    3.18 + *
    3.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    3.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    3.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    3.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    3.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    3.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    3.25 + * THE SOFTWARE.
    3.26 + */
    3.27 +#ifndef QEMU_AUDIO_H
    3.28 +#define QEMU_AUDIO_H
    3.29 +
    3.30 +#include "mixeng.h"
    3.31 +
    3.32 +typedef enum {
    3.33 +  AUD_FMT_U8,
    3.34 +  AUD_FMT_S8,
    3.35 +  AUD_FMT_U16,
    3.36 +  AUD_FMT_S16
    3.37 +} audfmt_e;
    3.38 +
    3.39 +typedef struct SWVoice SWVoice;
    3.40 +
    3.41 +SWVoice * AUD_open (SWVoice *sw, const char *name, int freq,
    3.42 +                    int nchannels, audfmt_e fmt);
    3.43 +void   AUD_init (void);
    3.44 +void   AUD_log (const char *cap, const char *fmt, ...)
    3.45 +    __attribute__ ((__format__ (__printf__, 2, 3)));;
    3.46 +void   AUD_close (SWVoice *sw);
    3.47 +int    AUD_write (SWVoice *sw, void *pcm_buf, int size);
    3.48 +void   AUD_adjust (SWVoice *sw, int leftover);
    3.49 +void   AUD_reset (SWVoice *sw);
    3.50 +int    AUD_get_free (SWVoice *sw);
    3.51 +int    AUD_get_buffer_size (SWVoice *sw);
    3.52 +void   AUD_run (void);
    3.53 +void   AUD_enable (SWVoice *sw, int on);
    3.54 +int    AUD_calc_elapsed (SWVoice *sw);
    3.55 +
    3.56 +static inline void *advance (void *p, int incr)
    3.57 +{
    3.58 +    uint8_t *d = p;
    3.59 +    return (d + incr);
    3.60 +}
    3.61 +
    3.62 +uint32_t popcount (uint32_t u);
    3.63 +inline uint32_t lsbindex (uint32_t u);
    3.64 +
    3.65 +#define audio_MIN(a, b) ((a)>(b)?(b):(a))
    3.66 +#define audio_MAX(a, b) ((a)<(b)?(b):(a))
    3.67 +
    3.68 +#endif  /* audio.h */
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/ioemu/audio/audio_int.h	Tue Dec 20 12:55:19 2005 +0100
     4.3 @@ -0,0 +1,164 @@
     4.4 +/*
     4.5 + * QEMU Audio subsystem header
     4.6 + * 
     4.7 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
     4.8 + * 
     4.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    4.10 + * of this software and associated documentation files (the "Software"), to deal
    4.11 + * in the Software without restriction, including without limitation the rights
    4.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    4.13 + * copies of the Software, and to permit persons to whom the Software is
    4.14 + * furnished to do so, subject to the following conditions:
    4.15 + *
    4.16 + * The above copyright notice and this permission notice shall be included in
    4.17 + * all copies or substantial portions of the Software.
    4.18 + *
    4.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    4.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    4.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    4.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    4.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    4.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    4.25 + * THE SOFTWARE.
    4.26 + */
    4.27 +#ifndef QEMU_AUDIO_INT_H
    4.28 +#define QEMU_AUDIO_INT_H
    4.29 +
    4.30 +#include "vl.h"
    4.31 +
    4.32 +struct pcm_ops;
    4.33 +
    4.34 +typedef struct HWVoice {
    4.35 +    int active;
    4.36 +    int enabled;
    4.37 +    int pending_disable;
    4.38 +    int valid;
    4.39 +    int freq;
    4.40 +
    4.41 +    f_sample *clip;
    4.42 +    audfmt_e fmt;
    4.43 +    int nchannels;
    4.44 +
    4.45 +    int align;
    4.46 +    int shift;
    4.47 +
    4.48 +    int rpos;
    4.49 +    int bufsize;
    4.50 +
    4.51 +    int bytes_per_second;
    4.52 +    st_sample_t *mix_buf;
    4.53 +
    4.54 +    int samples;
    4.55 +    int64_t old_ticks;
    4.56 +    int nb_voices;
    4.57 +    struct SWVoice **pvoice;
    4.58 +    struct pcm_ops *pcm_ops;
    4.59 +} HWVoice;
    4.60 +
    4.61 +extern struct pcm_ops no_pcm_ops;
    4.62 +extern struct audio_output_driver no_output_driver;
    4.63 +
    4.64 +extern struct pcm_ops oss_pcm_ops;
    4.65 +extern struct audio_output_driver oss_output_driver;
    4.66 +
    4.67 +extern struct pcm_ops sdl_pcm_ops;
    4.68 +extern struct audio_output_driver sdl_output_driver;
    4.69 +
    4.70 +extern struct pcm_ops wav_pcm_ops;
    4.71 +extern struct audio_output_driver wav_output_driver;
    4.72 +
    4.73 +extern struct pcm_ops fmod_pcm_ops;
    4.74 +extern struct audio_output_driver fmod_output_driver;
    4.75 +
    4.76 +struct audio_output_driver {
    4.77 +    const char *name;
    4.78 +    void *(*init) (void);
    4.79 +    void (*fini) (void *);
    4.80 +    struct pcm_ops *pcm_ops;
    4.81 +    int can_be_default;
    4.82 +    int max_voices;
    4.83 +    int voice_size;
    4.84 +};
    4.85 +
    4.86 +typedef struct AudioState {
    4.87 +    int fixed_format;
    4.88 +    int fixed_freq;
    4.89 +    int fixed_channels;
    4.90 +    int fixed_fmt;
    4.91 +    int nb_hw_voices;
    4.92 +    int voice_size;
    4.93 +    int64_t ticks_threshold;
    4.94 +    int freq_threshold;
    4.95 +    void *opaque;
    4.96 +    struct audio_output_driver *drv;
    4.97 +} AudioState;
    4.98 +extern AudioState audio_state;
    4.99 +
   4.100 +struct SWVoice {
   4.101 +    int freq;
   4.102 +    audfmt_e fmt;
   4.103 +    int nchannels;
   4.104 +
   4.105 +    int shift;
   4.106 +    int align;
   4.107 +
   4.108 +    t_sample *conv;
   4.109 +
   4.110 +    int left;
   4.111 +    int pos;
   4.112 +    int bytes_per_second;
   4.113 +    int64_t ratio;
   4.114 +    st_sample_t *buf;
   4.115 +    void *rate;
   4.116 +
   4.117 +    int wpos;
   4.118 +    int live;
   4.119 +    int active;
   4.120 +    int64_t old_ticks;
   4.121 +    HWVoice *hw;
   4.122 +    char *name;
   4.123 +};
   4.124 +
   4.125 +struct pcm_ops {
   4.126 +    int  (*init)  (HWVoice *hw, int freq, int nchannels, audfmt_e fmt);
   4.127 +    void (*fini)  (HWVoice *hw);
   4.128 +    void (*run)   (HWVoice *hw);
   4.129 +    int  (*write) (SWVoice *sw, void *buf, int size);
   4.130 +    int  (*ctl)   (HWVoice *hw, int cmd, ...);
   4.131 +};
   4.132 +
   4.133 +void      pcm_sw_free_resources (SWVoice *sw);
   4.134 +int       pcm_sw_alloc_resources (SWVoice *sw);
   4.135 +void      pcm_sw_fini (SWVoice *sw);
   4.136 +int       pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
   4.137 +                       int nchannels, audfmt_e fmt);
   4.138 +
   4.139 +void      pcm_hw_clear (HWVoice *hw, void *buf, int len);
   4.140 +HWVoice * pcm_hw_find_any (HWVoice *hw);
   4.141 +HWVoice * pcm_hw_find_any_active (HWVoice *hw);
   4.142 +HWVoice * pcm_hw_find_any_passive (HWVoice *hw);
   4.143 +HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq,
   4.144 +                                int nchannels, audfmt_e fmt);
   4.145 +HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt);
   4.146 +int       pcm_hw_add_sw (HWVoice *hw, SWVoice *sw);
   4.147 +int       pcm_hw_del_sw (HWVoice *hw, SWVoice *sw);
   4.148 +SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt);
   4.149 +
   4.150 +void      pcm_hw_free_resources (HWVoice *hw);
   4.151 +int       pcm_hw_alloc_resources (HWVoice *hw);
   4.152 +void      pcm_hw_fini (HWVoice *hw);
   4.153 +void      pcm_hw_gc (HWVoice *hw);
   4.154 +int       pcm_hw_get_live (HWVoice *hw);
   4.155 +int       pcm_hw_get_live2 (HWVoice *hw, int *nb_active);
   4.156 +void      pcm_hw_dec_live (HWVoice *hw, int decr);
   4.157 +int       pcm_hw_write (SWVoice *sw, void *buf, int len);
   4.158 +
   4.159 +int         audio_get_conf_int (const char *key, int defval);
   4.160 +const char *audio_get_conf_str (const char *key, const char *defval);
   4.161 +
   4.162 +struct audio_output_driver;
   4.163 +
   4.164 +#define VOICE_ENABLE 1
   4.165 +#define VOICE_DISABLE 2
   4.166 +
   4.167 +#endif /* audio_int.h */
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/ioemu/audio/mixeng.c	Tue Dec 20 12:55:19 2005 +0100
     5.3 @@ -0,0 +1,255 @@
     5.4 +/*
     5.5 + * QEMU Mixing engine
     5.6 + *
     5.7 + * Copyright (c) 2004 Vassili Karpov (malc)
     5.8 + * Copyright (c) 1998 Fabrice Bellard
     5.9 + *
    5.10 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    5.11 + * of this software and associated documentation files (the "Software"), to deal
    5.12 + * in the Software without restriction, including without limitation the rights
    5.13 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    5.14 + * copies of the Software, and to permit persons to whom the Software is
    5.15 + * furnished to do so, subject to the following conditions:
    5.16 + *
    5.17 + * The above copyright notice and this permission notice shall be included in
    5.18 + * all copies or substantial portions of the Software.
    5.19 + *
    5.20 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    5.21 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    5.22 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    5.23 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    5.24 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    5.25 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    5.26 + * THE SOFTWARE.
    5.27 + */
    5.28 +#include "vl.h"
    5.29 +//#define DEBUG_FP
    5.30 +#include "audio/mixeng.h"
    5.31 +
    5.32 +#define IN_T int8_t
    5.33 +#define IN_MIN CHAR_MIN
    5.34 +#define IN_MAX CHAR_MAX
    5.35 +#define SIGNED
    5.36 +#include "mixeng_template.h"
    5.37 +#undef SIGNED
    5.38 +#undef IN_MAX
    5.39 +#undef IN_MIN
    5.40 +#undef IN_T
    5.41 +
    5.42 +#define IN_T uint8_t
    5.43 +#define IN_MIN 0
    5.44 +#define IN_MAX UCHAR_MAX
    5.45 +#include "mixeng_template.h"
    5.46 +#undef IN_MAX
    5.47 +#undef IN_MIN
    5.48 +#undef IN_T
    5.49 +
    5.50 +#define IN_T int16_t
    5.51 +#define IN_MIN SHRT_MIN
    5.52 +#define IN_MAX SHRT_MAX
    5.53 +#define SIGNED
    5.54 +#include "mixeng_template.h"
    5.55 +#undef SIGNED
    5.56 +#undef IN_MAX
    5.57 +#undef IN_MIN
    5.58 +#undef IN_T
    5.59 +
    5.60 +#define IN_T uint16_t
    5.61 +#define IN_MIN 0
    5.62 +#define IN_MAX USHRT_MAX
    5.63 +#include "mixeng_template.h"
    5.64 +#undef IN_MAX
    5.65 +#undef IN_MIN
    5.66 +#undef IN_T
    5.67 +
    5.68 +t_sample *mixeng_conv[2][2][2] = {
    5.69 +    {
    5.70 +        {
    5.71 +            conv_uint8_t_to_mono,
    5.72 +            conv_uint16_t_to_mono
    5.73 +        },
    5.74 +        {
    5.75 +            conv_int8_t_to_mono,
    5.76 +            conv_int16_t_to_mono
    5.77 +        }
    5.78 +    },
    5.79 +    {
    5.80 +        {
    5.81 +            conv_uint8_t_to_stereo,
    5.82 +            conv_uint16_t_to_stereo
    5.83 +        },
    5.84 +        {
    5.85 +            conv_int8_t_to_stereo,
    5.86 +            conv_int16_t_to_stereo
    5.87 +        }
    5.88 +    }
    5.89 +};
    5.90 +
    5.91 +f_sample *mixeng_clip[2][2][2] = {
    5.92 +    {
    5.93 +        {
    5.94 +            clip_uint8_t_from_mono,
    5.95 +            clip_uint16_t_from_mono
    5.96 +        },
    5.97 +        {
    5.98 +            clip_int8_t_from_mono,
    5.99 +            clip_int16_t_from_mono
   5.100 +        }
   5.101 +    },
   5.102 +    {
   5.103 +        {
   5.104 +            clip_uint8_t_from_stereo,
   5.105 +            clip_uint16_t_from_stereo
   5.106 +        },
   5.107 +        {
   5.108 +            clip_int8_t_from_stereo,
   5.109 +            clip_int16_t_from_stereo
   5.110 +        }
   5.111 +    }
   5.112 +};
   5.113 +
   5.114 +/*
   5.115 + * August 21, 1998
   5.116 + * Copyright 1998 Fabrice Bellard.
   5.117 + *
   5.118 + * [Rewrote completly the code of Lance Norskog And Sundry
   5.119 + * Contributors with a more efficient algorithm.]
   5.120 + *
   5.121 + * This source code is freely redistributable and may be used for
   5.122 + * any purpose.  This copyright notice must be maintained. 
   5.123 + * Lance Norskog And Sundry Contributors are not responsible for 
   5.124 + * the consequences of using this software.  
   5.125 + */
   5.126 +
   5.127 +/*
   5.128 + * Sound Tools rate change effect file.
   5.129 + */
   5.130 +/*
   5.131 + * Linear Interpolation.
   5.132 + *
   5.133 + * The use of fractional increment allows us to use no buffer. It
   5.134 + * avoid the problems at the end of the buffer we had with the old
   5.135 + * method which stored a possibly big buffer of size
   5.136 + * lcm(in_rate,out_rate).
   5.137 + *
   5.138 + * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If
   5.139 + * the input & output frequencies are equal, a delay of one sample is
   5.140 + * introduced.  Limited to processing 32-bit count worth of samples.
   5.141 + *
   5.142 + * 1 << FRAC_BITS evaluating to zero in several places.  Changed with
   5.143 + * an (unsigned long) cast to make it safe.  MarkMLl 2/1/99
   5.144 + */
   5.145 +
   5.146 +/* Private data */
   5.147 +typedef struct ratestuff {
   5.148 +    uint64_t opos;
   5.149 +    uint64_t opos_inc;
   5.150 +    uint32_t ipos;              /* position in the input stream (integer) */
   5.151 +    st_sample_t ilast;          /* last sample in the input stream */
   5.152 +} *rate_t;
   5.153 +
   5.154 +/*
   5.155 + * Prepare processing.
   5.156 + */
   5.157 +void *st_rate_start (int inrate, int outrate)
   5.158 +{
   5.159 +    rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff));
   5.160 +
   5.161 +    if (!rate) {
   5.162 +        exit (EXIT_FAILURE);
   5.163 +    }
   5.164 +
   5.165 +    if (inrate == outrate) {
   5.166 +        // exit (EXIT_FAILURE);
   5.167 +    }
   5.168 +
   5.169 +    if (inrate >= 65535 || outrate >= 65535) {
   5.170 +        // exit (EXIT_FAILURE);
   5.171 +    }
   5.172 +
   5.173 +    rate->opos = 0;
   5.174 +
   5.175 +    /* increment */
   5.176 +    rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate;
   5.177 +
   5.178 +    rate->ipos = 0;
   5.179 +    rate->ilast.l = 0;
   5.180 +    rate->ilast.r = 0;
   5.181 +    return rate;
   5.182 +}
   5.183 +
   5.184 +/*
   5.185 + * Processed signed long samples from ibuf to obuf.
   5.186 + * Return number of samples processed.
   5.187 + */
   5.188 +void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
   5.189 +                   int *isamp, int *osamp)
   5.190 +{
   5.191 +    rate_t rate = (rate_t) opaque;
   5.192 +    st_sample_t *istart, *iend;
   5.193 +    st_sample_t *ostart, *oend;
   5.194 +    st_sample_t ilast, icur, out;
   5.195 +    int64_t t;
   5.196 +
   5.197 +    ilast = rate->ilast;
   5.198 +
   5.199 +    istart = ibuf;
   5.200 +    iend = ibuf + *isamp;
   5.201 +
   5.202 +    ostart = obuf;
   5.203 +    oend = obuf + *osamp;
   5.204 +
   5.205 +    if (rate->opos_inc == 1ULL << 32) {
   5.206 +        int i, n = *isamp > *osamp ? *osamp : *isamp;
   5.207 +        for (i = 0; i < n; i++) {
   5.208 +            obuf[i].l += ibuf[i].r;
   5.209 +            obuf[i].r += ibuf[i].r;
   5.210 +        }
   5.211 +        *isamp = n;
   5.212 +        *osamp = n;
   5.213 +        return;
   5.214 +    }
   5.215 +
   5.216 +    while (obuf < oend) {
   5.217 +
   5.218 +        /* Safety catch to make sure we have input samples.  */
   5.219 +        if (ibuf >= iend)
   5.220 +            break;
   5.221 +
   5.222 +        /* read as many input samples so that ipos > opos */
   5.223 +
   5.224 +        while (rate->ipos <= (rate->opos >> 32)) {
   5.225 +            ilast = *ibuf++;
   5.226 +            rate->ipos++;
   5.227 +            /* See if we finished the input buffer yet */
   5.228 +            if (ibuf >= iend) goto the_end;
   5.229 +        }
   5.230 +
   5.231 +        icur = *ibuf;
   5.232 +
   5.233 +        /* interpolate */
   5.234 +        t = rate->opos & 0xffffffff;
   5.235 +        out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX;
   5.236 +        out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX;
   5.237 +
   5.238 +        /* output sample & increment position */
   5.239 +#if 0
   5.240 +        *obuf++ = out;
   5.241 +#else
   5.242 +        obuf->l += out.l;
   5.243 +        obuf->r += out.r;
   5.244 +        obuf += 1;
   5.245 +#endif
   5.246 +        rate->opos += rate->opos_inc;
   5.247 +    }
   5.248 +
   5.249 +the_end:
   5.250 +    *isamp = ibuf - istart;
   5.251 +    *osamp = obuf - ostart;
   5.252 +    rate->ilast = ilast;
   5.253 +}
   5.254 +
   5.255 +void st_rate_stop (void *opaque)
   5.256 +{
   5.257 +    qemu_free (opaque);
   5.258 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/ioemu/audio/mixeng.h	Tue Dec 20 12:55:19 2005 +0100
     6.3 @@ -0,0 +1,39 @@
     6.4 +/*
     6.5 + * QEMU Mixing engine header
     6.6 + * 
     6.7 + * Copyright (c) 2004 Vassili Karpov (malc)
     6.8 + * 
     6.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    6.10 + * of this software and associated documentation files (the "Software"), to deal
    6.11 + * in the Software without restriction, including without limitation the rights
    6.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    6.13 + * copies of the Software, and to permit persons to whom the Software is
    6.14 + * furnished to do so, subject to the following conditions:
    6.15 + *
    6.16 + * The above copyright notice and this permission notice shall be included in
    6.17 + * all copies or substantial portions of the Software.
    6.18 + *
    6.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    6.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    6.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    6.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    6.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    6.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    6.25 + * THE SOFTWARE.
    6.26 + */
    6.27 +#ifndef QEMU_MIXENG_H
    6.28 +#define QEMU_MIXENG_H
    6.29 +
    6.30 +typedef void (t_sample) (void *dst, const void *src, int samples);
    6.31 +typedef void (f_sample) (void *dst, const void *src, int samples);
    6.32 +typedef struct { int64_t l; int64_t r; } st_sample_t;
    6.33 +
    6.34 +extern t_sample *mixeng_conv[2][2][2];
    6.35 +extern f_sample *mixeng_clip[2][2][2];
    6.36 +
    6.37 +void *st_rate_start (int inrate, int outrate);
    6.38 +void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
    6.39 +                   int *isamp, int *osamp);
    6.40 +void st_rate_stop (void *opaque);
    6.41 +
    6.42 +#endif  /* mixeng.h */
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/ioemu/audio/mixeng_template.h	Tue Dec 20 12:55:19 2005 +0100
     7.3 @@ -0,0 +1,111 @@
     7.4 +/*
     7.5 + * QEMU Mixing engine
     7.6 + * 
     7.7 + * Copyright (c) 2004 Vassili Karpov (malc)
     7.8 + * 
     7.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    7.10 + * of this software and associated documentation files (the "Software"), to deal
    7.11 + * in the Software without restriction, including without limitation the rights
    7.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    7.13 + * copies of the Software, and to permit persons to whom the Software is
    7.14 + * furnished to do so, subject to the following conditions:
    7.15 + *
    7.16 + * The above copyright notice and this permission notice shall be included in
    7.17 + * all copies or substantial portions of the Software.
    7.18 + *
    7.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    7.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    7.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    7.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    7.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    7.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    7.25 + * THE SOFTWARE.
    7.26 + */
    7.27 +
    7.28 +/*
    7.29 + * Tusen tack till Mike Nordell
    7.30 + * dec++'ified by Dscho
    7.31 + */
    7.32 +
    7.33 +#ifdef SIGNED
    7.34 +#define HALFT IN_MAX
    7.35 +#define HALF IN_MAX
    7.36 +#else
    7.37 +#define HALFT ((IN_MAX)>>1)
    7.38 +#define HALF HALFT
    7.39 +#endif
    7.40 +
    7.41 +static int64_t inline glue(conv_,IN_T) (IN_T v)
    7.42 +{
    7.43 +#ifdef SIGNED
    7.44 +    return (INT_MAX*(int64_t)v)/HALF;
    7.45 +#else
    7.46 +    return (INT_MAX*((int64_t)v-HALFT))/HALF;
    7.47 +#endif
    7.48 +}
    7.49 +
    7.50 +static IN_T inline glue(clip_,IN_T) (int64_t v)
    7.51 +{
    7.52 +    if (v >= INT_MAX)
    7.53 +        return IN_MAX;
    7.54 +    else if (v < -INT_MAX)
    7.55 +        return IN_MIN;
    7.56 +
    7.57 +#ifdef SIGNED
    7.58 +    return (IN_T) (v*HALF/INT_MAX);
    7.59 +#else
    7.60 +    return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX;
    7.61 +#endif
    7.62 +}
    7.63 +
    7.64 +static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src,
    7.65 +                                               int samples)
    7.66 +{
    7.67 +    st_sample_t *out = (st_sample_t *) dst;
    7.68 +    IN_T *in = (IN_T *) src;
    7.69 +    while (samples--) {
    7.70 +        out->l = glue(conv_,IN_T) (*in++);
    7.71 +        out->r = glue(conv_,IN_T) (*in++);
    7.72 +        out += 1;
    7.73 +    }
    7.74 +}
    7.75 +
    7.76 +static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src,
    7.77 +                                             int samples)
    7.78 +{
    7.79 +    st_sample_t *out = (st_sample_t *) dst;
    7.80 +    IN_T *in = (IN_T *) src;
    7.81 +    while (samples--) {
    7.82 +        out->l = glue(conv_,IN_T) (in[0]);
    7.83 +        out->r = out->l;
    7.84 +        out += 1;
    7.85 +        in += 1;
    7.86 +    }
    7.87 +}
    7.88 +
    7.89 +static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src,
    7.90 +                                                 int samples)
    7.91 +{
    7.92 +    st_sample_t *in = (st_sample_t *) src;
    7.93 +    IN_T *out = (IN_T *) dst;
    7.94 +    while (samples--) {
    7.95 +        *out++ = glue(clip_,IN_T) (in->l);
    7.96 +        *out++ = glue(clip_,IN_T) (in->r);
    7.97 +        in += 1;
    7.98 +    }
    7.99 +}
   7.100 +
   7.101 +static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src,
   7.102 +                                               int samples)
   7.103 +{
   7.104 +    st_sample_t *in = (st_sample_t *) src;
   7.105 +    IN_T *out = (IN_T *) dst;
   7.106 +    while (samples--) {
   7.107 +        *out++ = glue(clip_,IN_T) (in->l + in->r);
   7.108 +        in += 1;
   7.109 +    }
   7.110 +}
   7.111 +
   7.112 +#undef HALF
   7.113 +#undef HALFT
   7.114 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/ioemu/audio/noaudio.c	Tue Dec 20 12:55:19 2005 +0100
     8.3 @@ -0,0 +1,130 @@
     8.4 +/*
     8.5 + * QEMU NULL audio output driver
     8.6 + * 
     8.7 + * Copyright (c) 2004 Vassili Karpov (malc)
     8.8 + * 
     8.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    8.10 + * of this software and associated documentation files (the "Software"), to deal
    8.11 + * in the Software without restriction, including without limitation the rights
    8.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    8.13 + * copies of the Software, and to permit persons to whom the Software is
    8.14 + * furnished to do so, subject to the following conditions:
    8.15 + *
    8.16 + * The above copyright notice and this permission notice shall be included in
    8.17 + * all copies or substantial portions of the Software.
    8.18 + *
    8.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    8.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    8.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    8.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    8.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    8.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    8.25 + * THE SOFTWARE.
    8.26 + */
    8.27 +#include "vl.h"
    8.28 +
    8.29 +#include "audio/audio_int.h"
    8.30 +
    8.31 +typedef struct NoVoice {
    8.32 +    HWVoice hw;
    8.33 +    int64_t old_ticks;
    8.34 +} NoVoice;
    8.35 +
    8.36 +#define dolog(...) AUD_log ("noaudio", __VA_ARGS__)
    8.37 +#ifdef DEBUG
    8.38 +#define ldebug(...) dolog (__VA_ARGS__)
    8.39 +#else
    8.40 +#define ldebug(...)
    8.41 +#endif
    8.42 +
    8.43 +static void no_hw_run (HWVoice *hw)
    8.44 +{
    8.45 +    NoVoice *no = (NoVoice *) hw;
    8.46 +    int rpos, live, decr, samples;
    8.47 +    uint8_t *dst;
    8.48 +    st_sample_t *src;
    8.49 +    int64_t now = qemu_get_clock (vm_clock);
    8.50 +    int64_t ticks = now - no->old_ticks;
    8.51 +    int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
    8.52 +
    8.53 +    if (bytes > INT_MAX)
    8.54 +        samples = INT_MAX >> hw->shift;
    8.55 +    else
    8.56 +        samples = bytes >> hw->shift;
    8.57 +
    8.58 +    live = pcm_hw_get_live (hw);
    8.59 +    if (live <= 0)
    8.60 +        return;
    8.61 +
    8.62 +    no->old_ticks = now;
    8.63 +    decr = audio_MIN (live, samples);
    8.64 +    samples = decr;
    8.65 +    rpos = hw->rpos;
    8.66 +    while (samples) {
    8.67 +        int left_till_end_samples = hw->samples - rpos;
    8.68 +        int convert_samples = audio_MIN (samples, left_till_end_samples);
    8.69 +
    8.70 +        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
    8.71 +        memset (src, 0, convert_samples * sizeof (st_sample_t));
    8.72 +
    8.73 +        rpos = (rpos + convert_samples) % hw->samples;
    8.74 +        samples -= convert_samples;
    8.75 +    }
    8.76 +
    8.77 +    pcm_hw_dec_live (hw, decr);
    8.78 +    hw->rpos = rpos;
    8.79 +}
    8.80 +
    8.81 +static int no_hw_write (SWVoice *sw, void *buf, int len)
    8.82 +{
    8.83 +    return pcm_hw_write (sw, buf, len);
    8.84 +}
    8.85 +
    8.86 +static int no_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
    8.87 +{
    8.88 +    NoVoice *no = (NoVoice *) hw;
    8.89 +    hw->freq = freq;
    8.90 +    hw->nchannels = nchannels;
    8.91 +    hw->fmt = fmt;
    8.92 +    hw->bufsize = 4096;
    8.93 +    return 0;
    8.94 +}
    8.95 +
    8.96 +static void no_hw_fini (HWVoice *hw)
    8.97 +{
    8.98 +    (void) hw;
    8.99 +}
   8.100 +
   8.101 +static int no_hw_ctl (HWVoice *hw, int cmd, ...)
   8.102 +{
   8.103 +    (void) hw;
   8.104 +    (void) cmd;
   8.105 +    return 0;
   8.106 +}
   8.107 +
   8.108 +static void *no_audio_init (void)
   8.109 +{
   8.110 +    return &no_audio_init;
   8.111 +}
   8.112 +
   8.113 +static void no_audio_fini (void *opaque)
   8.114 +{
   8.115 +}
   8.116 +
   8.117 +struct pcm_ops no_pcm_ops = {
   8.118 +    no_hw_init,
   8.119 +    no_hw_fini,
   8.120 +    no_hw_run,
   8.121 +    no_hw_write,
   8.122 +    no_hw_ctl
   8.123 +};
   8.124 +
   8.125 +struct audio_output_driver no_output_driver = {
   8.126 +    "none",
   8.127 +    no_audio_init,
   8.128 +    no_audio_fini,
   8.129 +    &no_pcm_ops,
   8.130 +    1,
   8.131 +    1,
   8.132 +    sizeof (NoVoice)
   8.133 +};
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/tools/ioemu/audio/ossaudio.c	Tue Dec 20 12:55:19 2005 +0100
     9.3 @@ -0,0 +1,475 @@
     9.4 +/*
     9.5 + * QEMU OSS audio output driver
     9.6 + * 
     9.7 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
     9.8 + * 
     9.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    9.10 + * of this software and associated documentation files (the "Software"), to deal
    9.11 + * in the Software without restriction, including without limitation the rights
    9.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    9.13 + * copies of the Software, and to permit persons to whom the Software is
    9.14 + * furnished to do so, subject to the following conditions:
    9.15 + *
    9.16 + * The above copyright notice and this permission notice shall be included in
    9.17 + * all copies or substantial portions of the Software.
    9.18 + *
    9.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    9.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    9.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    9.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    9.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    9.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    9.25 + * THE SOFTWARE.
    9.26 + */
    9.27 +#include <sys/mman.h>
    9.28 +#include <sys/types.h>
    9.29 +#include <sys/ioctl.h>
    9.30 +#include <sys/soundcard.h>
    9.31 +#include <assert.h>
    9.32 +#include "vl.h"
    9.33 +
    9.34 +#include "audio/audio_int.h"
    9.35 +
    9.36 +typedef struct OSSVoice {
    9.37 +    HWVoice hw;
    9.38 +    void *pcm_buf;
    9.39 +    int fd;
    9.40 +    int nfrags;
    9.41 +    int fragsize;
    9.42 +    int mmapped;
    9.43 +    int old_optr;
    9.44 +} OSSVoice;
    9.45 +
    9.46 +#define dolog(...) AUD_log ("oss", __VA_ARGS__)
    9.47 +#ifdef DEBUG
    9.48 +#define ldebug(...) dolog (__VA_ARGS__)
    9.49 +#else
    9.50 +#define ldebug(...)
    9.51 +#endif
    9.52 +
    9.53 +#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
    9.54 +#define QC_OSS_NFRAGS   "QEMU_OSS_NFRAGS"
    9.55 +#define QC_OSS_MMAP     "QEMU_OSS_MMAP"
    9.56 +#define QC_OSS_DEV      "QEMU_OSS_DEV"
    9.57 +
    9.58 +#define errstr() strerror (errno)
    9.59 +
    9.60 +static struct {
    9.61 +    int try_mmap;
    9.62 +    int nfrags;
    9.63 +    int fragsize;
    9.64 +    const char *dspname;
    9.65 +} conf = {
    9.66 +    .try_mmap = 0,
    9.67 +    .nfrags = 4,
    9.68 +    .fragsize = 4096,
    9.69 +    .dspname = "/dev/dsp"
    9.70 +};
    9.71 +
    9.72 +struct oss_params {
    9.73 +    int freq;
    9.74 +    audfmt_e fmt;
    9.75 +    int nchannels;
    9.76 +    int nfrags;
    9.77 +    int fragsize;
    9.78 +};
    9.79 +
    9.80 +static int oss_hw_write (SWVoice *sw, void *buf, int len)
    9.81 +{
    9.82 +    return pcm_hw_write (sw, buf, len);
    9.83 +}
    9.84 +
    9.85 +static int AUD_to_ossfmt (audfmt_e fmt)
    9.86 +{
    9.87 +    switch (fmt) {
    9.88 +    case AUD_FMT_S8: return AFMT_S8;
    9.89 +    case AUD_FMT_U8: return AFMT_U8;
    9.90 +    case AUD_FMT_S16: return AFMT_S16_LE;
    9.91 +    case AUD_FMT_U16: return AFMT_U16_LE;
    9.92 +    default:
    9.93 +        dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
    9.94 +        exit (EXIT_FAILURE);
    9.95 +    }
    9.96 +}
    9.97 +
    9.98 +static int oss_to_audfmt (int fmt)
    9.99 +{
   9.100 +    switch (fmt) {
   9.101 +    case AFMT_S8: return AUD_FMT_S8;
   9.102 +    case AFMT_U8: return AUD_FMT_U8;
   9.103 +    case AFMT_S16_LE: return AUD_FMT_S16;
   9.104 +    case AFMT_U16_LE: return AUD_FMT_U16;
   9.105 +    default:
   9.106 +        dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
   9.107 +               "Aborting\n",
   9.108 +               fmt);
   9.109 +        exit (EXIT_FAILURE);
   9.110 +    }
   9.111 +}
   9.112 +
   9.113 +#ifdef DEBUG_PCM
   9.114 +static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt)
   9.115 +{
   9.116 +    dolog ("parameter | requested value | obtained value\n");
   9.117 +    dolog ("format    |      %10d |     %10d\n", req->fmt, obt->fmt);
   9.118 +    dolog ("channels  |      %10d |     %10d\n", req->nchannels, obt->nchannels);
   9.119 +    dolog ("frequency |      %10d |     %10d\n", req->freq, obt->freq);
   9.120 +    dolog ("nfrags    |      %10d |     %10d\n", req->nfrags, obt->nfrags);
   9.121 +    dolog ("fragsize  |      %10d |     %10d\n", req->fragsize, obt->fragsize);
   9.122 +}
   9.123 +#endif
   9.124 +
   9.125 +static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
   9.126 +{
   9.127 +    int fd;
   9.128 +    int mmmmssss;
   9.129 +    audio_buf_info abinfo;
   9.130 +    int fmt, freq, nchannels;
   9.131 +    const char *dspname = conf.dspname;
   9.132 +
   9.133 +    fd = open (dspname, O_RDWR | O_NONBLOCK);
   9.134 +    if (-1 == fd) {
   9.135 +        dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
   9.136 +               "Reason:%s\n",
   9.137 +               dspname,
   9.138 +               errstr ());
   9.139 +        return -1;
   9.140 +    }
   9.141 +
   9.142 +    freq = req->freq;
   9.143 +    nchannels = req->nchannels;
   9.144 +    fmt = req->fmt;
   9.145 +
   9.146 +    if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
   9.147 +        dolog ("Could not initialize audio hardware\n"
   9.148 +               "Failed to set sample size\n"
   9.149 +               "Reason: %s\n",
   9.150 +               errstr ());
   9.151 +        goto err;
   9.152 +    }
   9.153 +
   9.154 +    if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
   9.155 +        dolog ("Could not initialize audio hardware\n"
   9.156 +               "Failed to set number of channels\n"
   9.157 +               "Reason: %s\n",
   9.158 +               errstr ());
   9.159 +        goto err;
   9.160 +    }
   9.161 +
   9.162 +    if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
   9.163 +        dolog ("Could not initialize audio hardware\n"
   9.164 +               "Failed to set frequency\n"
   9.165 +               "Reason: %s\n",
   9.166 +               errstr ());
   9.167 +        goto err;
   9.168 +    }
   9.169 +
   9.170 +    if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
   9.171 +        dolog ("Could not initialize audio hardware\n"
   9.172 +               "Failed to set non-blocking mode\n"
   9.173 +               "Reason: %s\n",
   9.174 +               errstr ());
   9.175 +        goto err;
   9.176 +    }
   9.177 +
   9.178 +    mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
   9.179 +    if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
   9.180 +        dolog ("Could not initialize audio hardware\n"
   9.181 +               "Failed to set buffer length (%d, %d)\n"
   9.182 +               "Reason:%s\n",
   9.183 +               conf.nfrags, conf.fragsize,
   9.184 +               errstr ());
   9.185 +        goto err;
   9.186 +    }
   9.187 +
   9.188 +    if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) {
   9.189 +        dolog ("Could not initialize audio hardware\n"
   9.190 +               "Failed to get buffer length\n"
   9.191 +               "Reason:%s\n",
   9.192 +               errstr ());
   9.193 +        goto err;
   9.194 +    }
   9.195 +
   9.196 +    obt->fmt = fmt;
   9.197 +    obt->nchannels = nchannels;
   9.198 +    obt->freq = freq;
   9.199 +    obt->nfrags = abinfo.fragstotal;
   9.200 +    obt->fragsize = abinfo.fragsize;
   9.201 +    *pfd = fd;
   9.202 +
   9.203 +    if ((req->fmt != obt->fmt) ||
   9.204 +        (req->nchannels != obt->nchannels) ||
   9.205 +        (req->freq != obt->freq) ||
   9.206 +        (req->fragsize != obt->fragsize) ||
   9.207 +        (req->nfrags != obt->nfrags)) {
   9.208 +#ifdef DEBUG_PCM
   9.209 +        dolog ("Audio parameters mismatch\n");
   9.210 +        oss_dump_pcm_info (req, obt);
   9.211 +#endif
   9.212 +    }
   9.213 +
   9.214 +#ifdef DEBUG_PCM
   9.215 +    oss_dump_pcm_info (req, obt);
   9.216 +#endif
   9.217 +    return 0;
   9.218 +
   9.219 +err:
   9.220 +    close (fd);
   9.221 +    return -1;
   9.222 +}
   9.223 +
   9.224 +static void oss_hw_run (HWVoice *hw)
   9.225 +{
   9.226 +    OSSVoice *oss = (OSSVoice *) hw;
   9.227 +    int err, rpos, live, decr;
   9.228 +    int samples;
   9.229 +    uint8_t *dst;
   9.230 +    st_sample_t *src;
   9.231 +    struct audio_buf_info abinfo;
   9.232 +    struct count_info cntinfo;
   9.233 +
   9.234 +    live = pcm_hw_get_live (hw);
   9.235 +    if (live <= 0)
   9.236 +        return;
   9.237 +
   9.238 +    if (oss->mmapped) {
   9.239 +        int bytes;
   9.240 +
   9.241 +        err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
   9.242 +        if (err < 0) {
   9.243 +            dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
   9.244 +            return;
   9.245 +        }
   9.246 +
   9.247 +        if (cntinfo.ptr == oss->old_optr) {
   9.248 +            if (abs (hw->samples - live) < 64)
   9.249 +                dolog ("overrun\n");
   9.250 +            return;
   9.251 +        }
   9.252 +
   9.253 +        if (cntinfo.ptr > oss->old_optr) {
   9.254 +            bytes = cntinfo.ptr - oss->old_optr;
   9.255 +        }
   9.256 +        else {
   9.257 +            bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
   9.258 +        }
   9.259 +
   9.260 +        decr = audio_MIN (bytes >> hw->shift, live);
   9.261 +    }
   9.262 +    else {
   9.263 +        err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
   9.264 +        if (err < 0) {
   9.265 +            dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
   9.266 +            return;
   9.267 +        }
   9.268 +
   9.269 +        decr = audio_MIN (abinfo.bytes >> hw->shift, live);
   9.270 +        if (decr <= 0)
   9.271 +            return;
   9.272 +    }
   9.273 +
   9.274 +    samples = decr;
   9.275 +    rpos = hw->rpos;
   9.276 +    while (samples) {
   9.277 +        int left_till_end_samples = hw->samples - rpos;
   9.278 +        int convert_samples = audio_MIN (samples, left_till_end_samples);
   9.279 +
   9.280 +        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
   9.281 +        dst = advance (oss->pcm_buf, rpos << hw->shift);
   9.282 +
   9.283 +        hw->clip (dst, src, convert_samples);
   9.284 +        if (!oss->mmapped) {
   9.285 +            int written;
   9.286 +
   9.287 +            written = write (oss->fd, dst, convert_samples << hw->shift);
   9.288 +            /* XXX: follow errno recommendations ? */
   9.289 +            if (written == -1) {
   9.290 +                dolog ("Failed to write audio\nReason: %s\n", errstr ());
   9.291 +                continue;
   9.292 +            }
   9.293 +
   9.294 +            if (written != convert_samples << hw->shift) {
   9.295 +                int wsamples = written >> hw->shift;
   9.296 +                int wbytes = wsamples << hw->shift;
   9.297 +                if (wbytes != written) {
   9.298 +                    dolog ("Unaligned write %d, %d\n", wbytes, written);
   9.299 +                }
   9.300 +                memset (src, 0, wbytes);
   9.301 +                decr -= samples;
   9.302 +                rpos = (rpos + wsamples) % hw->samples;
   9.303 +                break;
   9.304 +            }
   9.305 +        }
   9.306 +        memset (src, 0, convert_samples * sizeof (st_sample_t));
   9.307 +
   9.308 +        rpos = (rpos + convert_samples) % hw->samples;
   9.309 +        samples -= convert_samples;
   9.310 +    }
   9.311 +    if (oss->mmapped) {
   9.312 +        oss->old_optr = cntinfo.ptr;
   9.313 +    }
   9.314 +
   9.315 +    pcm_hw_dec_live (hw, decr);
   9.316 +    hw->rpos = rpos;
   9.317 +}
   9.318 +
   9.319 +static void oss_hw_fini (HWVoice *hw)
   9.320 +{
   9.321 +    int err;
   9.322 +    OSSVoice *oss = (OSSVoice *) hw;
   9.323 +
   9.324 +    ldebug ("oss_hw_fini\n");
   9.325 +    err = close (oss->fd);
   9.326 +    if (err) {
   9.327 +        dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
   9.328 +    }
   9.329 +    oss->fd = -1;
   9.330 +
   9.331 +    if (oss->pcm_buf) {
   9.332 +        if (oss->mmapped) {
   9.333 +            err = munmap (oss->pcm_buf, hw->bufsize);
   9.334 +            if (err) {
   9.335 +                dolog ("Failed to unmap OSS buffer\nReason: %s\n",
   9.336 +                       errstr ());
   9.337 +            }
   9.338 +        }
   9.339 +        else {
   9.340 +            qemu_free (oss->pcm_buf);
   9.341 +        }
   9.342 +        oss->pcm_buf = NULL;
   9.343 +    }
   9.344 +}
   9.345 +
   9.346 +static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
   9.347 +{
   9.348 +    OSSVoice *oss = (OSSVoice *) hw;
   9.349 +    struct oss_params req, obt;
   9.350 +
   9.351 +    assert (!oss->fd);
   9.352 +    req.fmt = AUD_to_ossfmt (fmt);
   9.353 +    req.freq = freq;
   9.354 +    req.nchannels = nchannels;
   9.355 +    req.fragsize = conf.fragsize;
   9.356 +    req.nfrags = conf.nfrags;
   9.357 +
   9.358 +    if (oss_open (&req, &obt, &oss->fd))
   9.359 +        return -1;
   9.360 +
   9.361 +    hw->freq = obt.freq;
   9.362 +    hw->fmt = oss_to_audfmt (obt.fmt);
   9.363 +    hw->nchannels = obt.nchannels;
   9.364 +
   9.365 +    oss->nfrags = obt.nfrags;
   9.366 +    oss->fragsize = obt.fragsize;
   9.367 +    hw->bufsize = obt.nfrags * obt.fragsize;
   9.368 +
   9.369 +    oss->mmapped = 0;
   9.370 +    if (conf.try_mmap) {
   9.371 +        oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
   9.372 +                             MAP_SHARED, oss->fd, 0);
   9.373 +        if (oss->pcm_buf == MAP_FAILED) {
   9.374 +            dolog ("Failed to mmap OSS device\nReason: %s\n",
   9.375 +                   errstr ());
   9.376 +        } else {
   9.377 +            int err;
   9.378 +            int trig = 0;
   9.379 +            if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
   9.380 +                dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
   9.381 +                       errstr ());
   9.382 +            }
   9.383 +            else {
   9.384 +                trig = PCM_ENABLE_OUTPUT;
   9.385 +                if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
   9.386 +                    dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
   9.387 +                           "Reason: %s\n", errstr ());
   9.388 +                }
   9.389 +                else {
   9.390 +                    oss->mmapped = 1;
   9.391 +                }
   9.392 +            }
   9.393 +
   9.394 +            if (!oss->mmapped) {
   9.395 +                err = munmap (oss->pcm_buf, hw->bufsize);
   9.396 +                if (err) {
   9.397 +                    dolog ("Failed to unmap OSS device\nReason: %s\n",
   9.398 +                           errstr ());
   9.399 +                }
   9.400 +            }
   9.401 +        }
   9.402 +    }
   9.403 +
   9.404 +    if (!oss->mmapped) {
   9.405 +        oss->pcm_buf = qemu_mallocz (hw->bufsize);
   9.406 +        if (!oss->pcm_buf) {
   9.407 +            close (oss->fd);
   9.408 +            oss->fd = -1;
   9.409 +            return -1;
   9.410 +        }
   9.411 +    }
   9.412 +
   9.413 +    return 0;
   9.414 +}
   9.415 +
   9.416 +static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
   9.417 +{
   9.418 +    int trig;
   9.419 +    OSSVoice *oss = (OSSVoice *) hw;
   9.420 +
   9.421 +    if (!oss->mmapped)
   9.422 +        return 0;
   9.423 +
   9.424 +    switch (cmd) {
   9.425 +    case VOICE_ENABLE:
   9.426 +        ldebug ("enabling voice\n");
   9.427 +        pcm_hw_clear (hw, oss->pcm_buf, hw->samples);
   9.428 +        trig = PCM_ENABLE_OUTPUT;
   9.429 +        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
   9.430 +            dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
   9.431 +                   "Reason: %s\n", errstr ());
   9.432 +            return -1;
   9.433 +        }
   9.434 +        break;
   9.435 +
   9.436 +    case VOICE_DISABLE:
   9.437 +        ldebug ("disabling voice\n");
   9.438 +        trig = 0;
   9.439 +        if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
   9.440 +            dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
   9.441 +                   errstr ());
   9.442 +            return -1;
   9.443 +        }
   9.444 +        break;
   9.445 +    }
   9.446 +    return 0;
   9.447 +}
   9.448 +
   9.449 +static void *oss_audio_init (void)
   9.450 +{
   9.451 +    conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize);
   9.452 +    conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags);
   9.453 +    conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap);
   9.454 +    conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname);
   9.455 +    return &conf;
   9.456 +}
   9.457 +
   9.458 +static void oss_audio_fini (void *opaque)
   9.459 +{
   9.460 +}
   9.461 +
   9.462 +struct pcm_ops oss_pcm_ops = {
   9.463 +    oss_hw_init,
   9.464 +    oss_hw_fini,
   9.465 +    oss_hw_run,
   9.466 +    oss_hw_write,
   9.467 +    oss_hw_ctl
   9.468 +};
   9.469 +
   9.470 +struct audio_output_driver oss_output_driver = {
   9.471 +    "oss",
   9.472 +    oss_audio_init,
   9.473 +    oss_audio_fini,
   9.474 +    &oss_pcm_ops,
   9.475 +    1,
   9.476 +    INT_MAX,
   9.477 +    sizeof (OSSVoice)
   9.478 +};
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tools/ioemu/audio/sdlaudio.c	Tue Dec 20 12:55:19 2005 +0100
    10.3 @@ -0,0 +1,332 @@
    10.4 +/*
    10.5 + * QEMU SDL audio output driver
    10.6 + * 
    10.7 + * Copyright (c) 2004 Vassili Karpov (malc)
    10.8 + * 
    10.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   10.10 + * of this software and associated documentation files (the "Software"), to deal
   10.11 + * in the Software without restriction, including without limitation the rights
   10.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10.13 + * copies of the Software, and to permit persons to whom the Software is
   10.14 + * furnished to do so, subject to the following conditions:
   10.15 + *
   10.16 + * The above copyright notice and this permission notice shall be included in
   10.17 + * all copies or substantial portions of the Software.
   10.18 + *
   10.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   10.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   10.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   10.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   10.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   10.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   10.25 + * THE SOFTWARE.
   10.26 + */
   10.27 +#include <SDL.h>
   10.28 +#include <SDL_thread.h>
   10.29 +#include "vl.h"
   10.30 +
   10.31 +#include "audio/audio_int.h"
   10.32 +
   10.33 +typedef struct SDLVoice {
   10.34 +    HWVoice hw;
   10.35 +} SDLVoice;
   10.36 +
   10.37 +#define dolog(...) AUD_log ("sdl", __VA_ARGS__)
   10.38 +#ifdef DEBUG
   10.39 +#define ldebug(...) dolog (__VA_ARGS__)
   10.40 +#else
   10.41 +#define ldebug(...)
   10.42 +#endif
   10.43 +
   10.44 +#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"
   10.45 +
   10.46 +#define errstr() SDL_GetError ()
   10.47 +
   10.48 +static struct {
   10.49 +    int nb_samples;
   10.50 +} conf = {
   10.51 +    1024
   10.52 +};
   10.53 +
   10.54 +struct SDLAudioState {
   10.55 +    int exit;
   10.56 +    SDL_mutex *mutex;
   10.57 +    SDL_sem *sem;
   10.58 +    int initialized;
   10.59 +} glob_sdl;
   10.60 +typedef struct SDLAudioState SDLAudioState;
   10.61 +
   10.62 +static void sdl_hw_run (HWVoice *hw)
   10.63 +{
   10.64 +    (void) hw;
   10.65 +}
   10.66 +
   10.67 +static int sdl_lock (SDLAudioState *s)
   10.68 +{
   10.69 +    if (SDL_LockMutex (s->mutex)) {
   10.70 +        dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
   10.71 +        return -1;
   10.72 +    }
   10.73 +    return 0;
   10.74 +}
   10.75 +
   10.76 +static int sdl_unlock (SDLAudioState *s)
   10.77 +{
   10.78 +    if (SDL_UnlockMutex (s->mutex)) {
   10.79 +        dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
   10.80 +        return -1;
   10.81 +    }
   10.82 +    return 0;
   10.83 +}
   10.84 +
   10.85 +static int sdl_post (SDLAudioState *s)
   10.86 +{
   10.87 +    if (SDL_SemPost (s->sem)) {
   10.88 +        dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
   10.89 +        return -1;
   10.90 +    }
   10.91 +    return 0;
   10.92 +}
   10.93 +
   10.94 +static int sdl_wait (SDLAudioState *s)
   10.95 +{
   10.96 +    if (SDL_SemWait (s->sem)) {
   10.97 +        dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
   10.98 +        return -1;
   10.99 +    }
  10.100 +    return 0;
  10.101 +}
  10.102 +
  10.103 +static int sdl_unlock_and_post (SDLAudioState *s)
  10.104 +{
  10.105 +    if (sdl_unlock (s))
  10.106 +        return -1;
  10.107 +
  10.108 +    return sdl_post (s);
  10.109 +}
  10.110 +
  10.111 +static int sdl_hw_write (SWVoice *sw, void *buf, int len)
  10.112 +{
  10.113 +    int ret;
  10.114 +    SDLAudioState *s = &glob_sdl;
  10.115 +    sdl_lock (s);
  10.116 +    ret = pcm_hw_write (sw, buf, len);
  10.117 +    sdl_unlock_and_post (s);
  10.118 +    return ret;
  10.119 +}
  10.120 +
  10.121 +static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)
  10.122 +{
  10.123 +    *shift = 0;
  10.124 +    switch (fmt) {
  10.125 +    case AUD_FMT_S8: return AUDIO_S8;
  10.126 +    case AUD_FMT_U8: return AUDIO_U8;
  10.127 +    case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;
  10.128 +    case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;
  10.129 +    default:
  10.130 +        dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
  10.131 +        exit (EXIT_FAILURE);
  10.132 +    }
  10.133 +}
  10.134 +
  10.135 +static int sdl_to_audfmt (int fmt)
  10.136 +{
  10.137 +    switch (fmt) {
  10.138 +    case AUDIO_S8: return AUD_FMT_S8;
  10.139 +    case AUDIO_U8: return AUD_FMT_U8;
  10.140 +    case AUDIO_S16LSB: return AUD_FMT_S16;
  10.141 +    case AUDIO_U16LSB: return AUD_FMT_U16;
  10.142 +    default:
  10.143 +        dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
  10.144 +               "Aborting\n", fmt);
  10.145 +        exit (EXIT_FAILURE);
  10.146 +    }
  10.147 +}
  10.148 +
  10.149 +static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
  10.150 +{
  10.151 +    int status;
  10.152 +
  10.153 +    status = SDL_OpenAudio (req, obt);
  10.154 +    if (status) {
  10.155 +        dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
  10.156 +    }
  10.157 +    return status;
  10.158 +}
  10.159 +
  10.160 +static void sdl_close (SDLAudioState *s)
  10.161 +{
  10.162 +    if (s->initialized) {
  10.163 +        sdl_lock (s);
  10.164 +        s->exit = 1;
  10.165 +        sdl_unlock_and_post (s);
  10.166 +        SDL_PauseAudio (1);
  10.167 +        SDL_CloseAudio ();
  10.168 +        s->initialized = 0;
  10.169 +    }
  10.170 +}
  10.171 +
  10.172 +static void sdl_callback (void *opaque, Uint8 *buf, int len)
  10.173 +{
  10.174 +    SDLVoice *sdl = opaque;
  10.175 +    SDLAudioState *s = &glob_sdl;
  10.176 +    HWVoice *hw = &sdl->hw;
  10.177 +    int samples = len >> hw->shift;
  10.178 +
  10.179 +    if (s->exit) {
  10.180 +        return;
  10.181 +    }
  10.182 +
  10.183 +    while (samples) {
  10.184 +        int to_mix, live, decr;
  10.185 +
  10.186 +        /* dolog ("in callback samples=%d\n", samples); */
  10.187 +        sdl_wait (s);
  10.188 +        if (s->exit) {
  10.189 +            return;
  10.190 +        }
  10.191 +
  10.192 +        sdl_lock (s);
  10.193 +        live = pcm_hw_get_live (hw);
  10.194 +        if (live <= 0)
  10.195 +            goto again;
  10.196 +
  10.197 +        /* dolog ("in callback live=%d\n", live); */
  10.198 +        to_mix = audio_MIN (samples, live);
  10.199 +        decr = to_mix;
  10.200 +        while (to_mix) {
  10.201 +            int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
  10.202 +            st_sample_t *src = hw->mix_buf + hw->rpos;
  10.203 +
  10.204 +            /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
  10.205 +            hw->clip (buf, src, chunk);
  10.206 +            memset (src, 0, chunk * sizeof (st_sample_t));
  10.207 +            hw->rpos = (hw->rpos + chunk) % hw->samples;
  10.208 +            to_mix -= chunk;
  10.209 +            buf += chunk << hw->shift;
  10.210 +        }
  10.211 +        samples -= decr;
  10.212 +        pcm_hw_dec_live (hw, decr);
  10.213 +
  10.214 +    again:
  10.215 +        sdl_unlock (s);
  10.216 +    }
  10.217 +    /* dolog ("done len=%d\n", len); */
  10.218 +}
  10.219 +
  10.220 +static void sdl_hw_fini (HWVoice *hw)
  10.221 +{
  10.222 +    ldebug ("sdl_hw_fini %d fixed=%d\n",
  10.223 +             glob_sdl.initialized, audio_conf.fixed_format);
  10.224 +    sdl_close (&glob_sdl);
  10.225 +}
  10.226 +
  10.227 +static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
  10.228 +{
  10.229 +    SDLVoice *sdl = (SDLVoice *) hw;
  10.230 +    SDLAudioState *s = &glob_sdl;
  10.231 +    SDL_AudioSpec req, obt;
  10.232 +    int shift;
  10.233 +
  10.234 +    ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
  10.235 +            s->initialized, freq, audio_conf.fixed_format);
  10.236 +
  10.237 +    if (nchannels != 2) {
  10.238 +        dolog ("Bogus channel count %d\n", nchannels);
  10.239 +        return -1;
  10.240 +    }
  10.241 +
  10.242 +    req.freq = freq;
  10.243 +    req.format = AUD_to_sdlfmt (fmt, &shift);
  10.244 +    req.channels = nchannels;
  10.245 +    req.samples = conf.nb_samples;
  10.246 +    shift <<= nchannels == 2;
  10.247 +
  10.248 +    req.callback = sdl_callback;
  10.249 +    req.userdata = sdl;
  10.250 +
  10.251 +    if (sdl_open (&req, &obt))
  10.252 +        return -1;
  10.253 +
  10.254 +    hw->freq = obt.freq;
  10.255 +    hw->fmt = sdl_to_audfmt (obt.format);
  10.256 +    hw->nchannels = obt.channels;
  10.257 +    hw->bufsize = obt.samples << shift;
  10.258 +
  10.259 +    s->initialized = 1;
  10.260 +    s->exit = 0;
  10.261 +    SDL_PauseAudio (0);
  10.262 +    return 0;
  10.263 +}
  10.264 +
  10.265 +static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
  10.266 +{
  10.267 +    (void) hw;
  10.268 +
  10.269 +    switch (cmd) {
  10.270 +    case VOICE_ENABLE:
  10.271 +        SDL_PauseAudio (0);
  10.272 +        break;
  10.273 +
  10.274 +    case VOICE_DISABLE:
  10.275 +        SDL_PauseAudio (1);
  10.276 +        break;
  10.277 +    }
  10.278 +    return 0;
  10.279 +}
  10.280 +
  10.281 +static void *sdl_audio_init (void)
  10.282 +{
  10.283 +    SDLAudioState *s = &glob_sdl;
  10.284 +    conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);
  10.285 +
  10.286 +    if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
  10.287 +        dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
  10.288 +               errstr ());
  10.289 +        return NULL;
  10.290 +    }
  10.291 +
  10.292 +    s->mutex = SDL_CreateMutex ();
  10.293 +    if (!s->mutex) {
  10.294 +        dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());
  10.295 +        SDL_QuitSubSystem (SDL_INIT_AUDIO);
  10.296 +        return NULL;
  10.297 +    }
  10.298 +
  10.299 +    s->sem = SDL_CreateSemaphore (0);
  10.300 +    if (!s->sem) {
  10.301 +        dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
  10.302 +        SDL_DestroyMutex (s->mutex);
  10.303 +        SDL_QuitSubSystem (SDL_INIT_AUDIO);
  10.304 +        return NULL;
  10.305 +    }
  10.306 +
  10.307 +    return s;
  10.308 +}
  10.309 +
  10.310 +static void sdl_audio_fini (void *opaque)
  10.311 +{
  10.312 +    SDLAudioState *s = opaque;
  10.313 +    sdl_close (s);
  10.314 +    SDL_DestroySemaphore (s->sem);
  10.315 +    SDL_DestroyMutex (s->mutex);
  10.316 +    SDL_QuitSubSystem (SDL_INIT_AUDIO);
  10.317 +}
  10.318 +
  10.319 +struct pcm_ops sdl_pcm_ops = {
  10.320 +    sdl_hw_init,
  10.321 +    sdl_hw_fini,
  10.322 +    sdl_hw_run,
  10.323 +    sdl_hw_write,
  10.324 +    sdl_hw_ctl
  10.325 +};
  10.326 +
  10.327 +struct audio_output_driver sdl_output_driver = {
  10.328 +    "sdl",
  10.329 +    sdl_audio_init,
  10.330 +    sdl_audio_fini,
  10.331 +    &sdl_pcm_ops,
  10.332 +    1,
  10.333 +    1,
  10.334 +    sizeof (SDLVoice)
  10.335 +};
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tools/ioemu/audio/wavaudio.c	Tue Dec 20 12:55:19 2005 +0100
    11.3 @@ -0,0 +1,217 @@
    11.4 +/*
    11.5 + * QEMU WAV audio output driver
    11.6 + * 
    11.7 + * Copyright (c) 2004 Vassili Karpov (malc)
    11.8 + * 
    11.9 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   11.10 + * of this software and associated documentation files (the "Software"), to deal
   11.11 + * in the Software without restriction, including without limitation the rights
   11.12 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   11.13 + * copies of the Software, and to permit persons to whom the Software is
   11.14 + * furnished to do so, subject to the following conditions:
   11.15 + *
   11.16 + * The above copyright notice and this permission notice shall be included in
   11.17 + * all copies or substantial portions of the Software.
   11.18 + *
   11.19 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   11.20 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   11.21 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   11.22 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   11.23 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   11.24 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   11.25 + * THE SOFTWARE.
   11.26 + */
   11.27 +#include "vl.h"
   11.28 +
   11.29 +#include "audio/audio_int.h"
   11.30 +
   11.31 +typedef struct WAVVoice {
   11.32 +    HWVoice hw;
   11.33 +    QEMUFile *f;
   11.34 +    int64_t old_ticks;
   11.35 +    void *pcm_buf;
   11.36 +    int total_samples;
   11.37 +} WAVVoice;
   11.38 +
   11.39 +#define dolog(...) AUD_log ("wav", __VA_ARGS__)
   11.40 +#ifdef DEBUG
   11.41 +#define ldebug(...) dolog (__VA_ARGS__)
   11.42 +#else
   11.43 +#define ldebug(...)
   11.44 +#endif
   11.45 +
   11.46 +static struct {
   11.47 +    const char *wav_path;
   11.48 +} conf = {
   11.49 +    .wav_path = "qemu.wav"
   11.50 +};
   11.51 +
   11.52 +static void wav_hw_run (HWVoice *hw)
   11.53 +{
   11.54 +    WAVVoice *wav = (WAVVoice *) hw;
   11.55 +    int rpos, live, decr, samples;
   11.56 +    uint8_t *dst;
   11.57 +    st_sample_t *src;
   11.58 +    int64_t now = qemu_get_clock (vm_clock);
   11.59 +    int64_t ticks = now - wav->old_ticks;
   11.60 +    int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
   11.61 +
   11.62 +    if (bytes > INT_MAX)
   11.63 +        samples = INT_MAX >> hw->shift;
   11.64 +    else
   11.65 +        samples = bytes >> hw->shift;
   11.66 +
   11.67 +    live = pcm_hw_get_live (hw);
   11.68 +    if (live <= 0)
   11.69 +        return;
   11.70 +
   11.71 +    wav->old_ticks = now;
   11.72 +    decr = audio_MIN (live, samples);
   11.73 +    samples = decr;
   11.74 +    rpos = hw->rpos;
   11.75 +    while (samples) {
   11.76 +        int left_till_end_samples = hw->samples - rpos;
   11.77 +        int convert_samples = audio_MIN (samples, left_till_end_samples);
   11.78 +
   11.79 +        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
   11.80 +        dst = advance (wav->pcm_buf, rpos << hw->shift);
   11.81 +
   11.82 +        hw->clip (dst, src, convert_samples);
   11.83 +        qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
   11.84 +        memset (src, 0, convert_samples * sizeof (st_sample_t));
   11.85 +
   11.86 +        rpos = (rpos + convert_samples) % hw->samples;
   11.87 +        samples -= convert_samples;
   11.88 +        wav->total_samples += convert_samples;
   11.89 +    }
   11.90 +
   11.91 +    pcm_hw_dec_live (hw, decr);
   11.92 +    hw->rpos = rpos;
   11.93 +}
   11.94 +
   11.95 +static int wav_hw_write (SWVoice *sw, void *buf, int len)
   11.96 +{
   11.97 +    return pcm_hw_write (sw, buf, len);
   11.98 +}
   11.99 +
  11.100 +/* VICE code: Store number as little endian. */
  11.101 +static void le_store (uint8_t *buf, uint32_t val, int len)
  11.102 +{
  11.103 +    int i;
  11.104 +    for (i = 0; i < len; i++) {
  11.105 +        buf[i] = (uint8_t) (val & 0xff);
  11.106 +        val >>= 8;
  11.107 +    }
  11.108 +}
  11.109 +
  11.110 +static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
  11.111 +{
  11.112 +    WAVVoice *wav = (WAVVoice *) hw;
  11.113 +    int bits16 = 0, stereo = audio_state.fixed_channels == 2;
  11.114 +    uint8_t hdr[] = {
  11.115 +        0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
  11.116 +        0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
  11.117 +        0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
  11.118 +        0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
  11.119 +    };
  11.120 +
  11.121 +    switch (audio_state.fixed_fmt) {
  11.122 +    case AUD_FMT_S8:
  11.123 +    case AUD_FMT_U8:
  11.124 +        break;
  11.125 +
  11.126 +    case AUD_FMT_S16:
  11.127 +    case AUD_FMT_U16:
  11.128 +        bits16 = 1;
  11.129 +        break;
  11.130 +    }
  11.131 +
  11.132 +    hdr[34] = bits16 ? 0x10 : 0x08;
  11.133 +    hw->freq = 44100;
  11.134 +    hw->nchannels = stereo ? 2 : 1;
  11.135 +    hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
  11.136 +    hw->bufsize = 4096;
  11.137 +    wav->pcm_buf = qemu_mallocz (hw->bufsize);
  11.138 +    if (!wav->pcm_buf)
  11.139 +        return -1;
  11.140 +
  11.141 +    le_store (hdr + 22, hw->nchannels, 2);
  11.142 +    le_store (hdr + 24, hw->freq, 4);
  11.143 +    le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
  11.144 +    le_store (hdr + 32, 1 << (bits16 + stereo), 2);
  11.145 +
  11.146 +    wav->f = fopen (conf.wav_path, "wb");
  11.147 +    if (!wav->f) {
  11.148 +        dolog ("failed to open wave file `%s'\nReason: %s\n",
  11.149 +               conf.wav_path, strerror (errno));
  11.150 +        qemu_free (wav->pcm_buf);
  11.151 +        wav->pcm_buf = NULL;
  11.152 +        return -1;
  11.153 +    }
  11.154 +
  11.155 +    qemu_put_buffer (wav->f, hdr, sizeof (hdr));
  11.156 +    return 0;
  11.157 +}
  11.158 +
  11.159 +static void wav_hw_fini (HWVoice *hw)
  11.160 +{
  11.161 +    WAVVoice *wav = (WAVVoice *) hw;
  11.162 +    int stereo = hw->nchannels == 2;
  11.163 +    uint8_t rlen[4];
  11.164 +    uint8_t dlen[4];
  11.165 +    uint32_t rifflen = (wav->total_samples << stereo) + 36;
  11.166 +    uint32_t datalen = wav->total_samples << stereo;
  11.167 +
  11.168 +    if (!wav->f || !hw->active)
  11.169 +        return;
  11.170 +
  11.171 +    le_store (rlen, rifflen, 4);
  11.172 +    le_store (dlen, datalen, 4);
  11.173 +
  11.174 +    qemu_fseek (wav->f, 4, SEEK_SET);
  11.175 +    qemu_put_buffer (wav->f, rlen, 4);
  11.176 +
  11.177 +    qemu_fseek (wav->f, 32, SEEK_CUR);
  11.178 +    qemu_put_buffer (wav->f, dlen, 4);
  11.179 +
  11.180 +    fclose (wav->f);
  11.181 +    wav->f = NULL;
  11.182 +
  11.183 +    qemu_free (wav->pcm_buf);
  11.184 +    wav->pcm_buf = NULL;
  11.185 +}
  11.186 +
  11.187 +static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
  11.188 +{
  11.189 +    (void) hw;
  11.190 +    (void) cmd;
  11.191 +    return 0;
  11.192 +}
  11.193 +
  11.194 +static void *wav_audio_init (void)
  11.195 +{
  11.196 +    return &conf;
  11.197 +}
  11.198 +
  11.199 +static void wav_audio_fini (void *opaque)
  11.200 +{
  11.201 +    ldebug ("wav_fini");
  11.202 +}
  11.203 +
  11.204 +struct pcm_ops wav_pcm_ops = {
  11.205 +    wav_hw_init,
  11.206 +    wav_hw_fini,
  11.207 +    wav_hw_run,
  11.208 +    wav_hw_write,
  11.209 +    wav_hw_ctl
  11.210 +};
  11.211 +
  11.212 +struct audio_output_driver wav_output_driver = {
  11.213 +    "wav",
  11.214 +    wav_audio_init,
  11.215 +    wav_audio_fini,
  11.216 +    &wav_pcm_ops,
  11.217 +    1,
  11.218 +    1,
  11.219 +    sizeof (WAVVoice)
  11.220 +};
    12.1 --- a/tools/ioemu/hw/pc.c	Tue Dec 20 12:52:38 2005 +0100
    12.2 +++ b/tools/ioemu/hw/pc.c	Tue Dec 20 12:55:19 2005 +0100
    12.3 @@ -563,6 +563,15 @@ void pc_init(uint64_t ram_size, int vga_
    12.4  
    12.5      kbd_init();
    12.6      DMA_init(0);
    12.7 +   
    12.8 +    if (audio_enabled) {
    12.9 +        AUD_init();
   12.10 +#ifdef USE_SB16
   12.11 +        if (sb16_enabled)
   12.12 +            SB16_init();
   12.13 +#endif
   12.14 +    }
   12.15 +    
   12.16  
   12.17      floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
   12.18  
    13.1 --- a/tools/ioemu/target-i386-dm/Makefile	Tue Dec 20 12:52:38 2005 +0100
    13.2 +++ b/tools/ioemu/target-i386-dm/Makefile	Tue Dec 20 12:55:19 2005 +0100
    13.3 @@ -272,6 +272,7 @@ endif
    13.4  VL_OBJS+= ide.o ne2000.o pckbd.o vga.o dma.o
    13.5  VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259_stub.o i8254.o pc.o port-e9.o
    13.6  VL_OBJS+= cirrus_vga.o pcnet.o
    13.7 +VL_OBJS+= $(SOUND_HW) $(AUDIODRV) mixeng.o
    13.8  
    13.9  ifeq ($(TARGET_ARCH), ppc)
   13.10  VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
    14.1 --- a/tools/ioemu/vl.h	Tue Dec 20 12:52:38 2005 +0100
    14.2 +++ b/tools/ioemu/vl.h	Tue Dec 20 12:55:19 2005 +0100
    14.3 @@ -37,6 +37,7 @@
    14.4  #include <unistd.h>
    14.5  #include <fcntl.h>
    14.6  #include <sys/stat.h>
    14.7 +#include "audio/audio.h"
    14.8  
    14.9  #ifndef O_LARGEFILE
   14.10  #define O_LARGEFILE 0
    15.1 --- a/tools/python/xen/xend/image.py	Tue Dec 20 12:52:38 2005 +0100
    15.2 +++ b/tools/python/xen/xend/image.py	Tue Dec 20 12:55:19 2005 +0100
    15.3 @@ -237,7 +237,7 @@ class VmxImageHandler(ImageHandler):
    15.4      # Return a list of cmd line args to the device models based on the
    15.5      # xm config file
    15.6      def parseDeviceModelArgs(self, imageConfig, deviceConfig):
    15.7 -        dmargs = [ 'cdrom', 'boot', 'fda', 'fdb', 'ne2000', 
    15.8 +        dmargs = [ 'cdrom', 'boot', 'fda', 'fdb', 'ne2000', 'audio',
    15.9                     'localtime', 'serial', 'stdvga', 'isa', 'vcpus']
   15.10          ret = []
   15.11          for a in dmargs:
   15.12 @@ -246,9 +246,10 @@ class VmxImageHandler(ImageHandler):
   15.13              # python doesn't allow '-' in variable names
   15.14              if a == 'stdvga': a = 'std-vga'
   15.15              if a == 'ne2000': a = 'nic-ne2000'
   15.16 +            if a == 'audio': a = 'enable-audio'
   15.17  
   15.18              # Handle booleans gracefully
   15.19 -            if a in ['localtime', 'std-vga', 'isa', 'nic-ne2000']:
   15.20 +            if a in ['localtime', 'std-vga', 'isa', 'nic-ne2000', 'enable-audio']:
   15.21                  if v != None: v = int(v)
   15.22                  if v: ret.append("-%s" % a)
   15.23              else:
    16.1 --- a/tools/python/xen/xm/create.py	Tue Dec 20 12:52:38 2005 +0100
    16.2 +++ b/tools/python/xen/xm/create.py	Tue Dec 20 12:55:19 2005 +0100
    16.3 @@ -372,6 +372,10 @@ gopts.var('ne2000', val='no|yes',
    16.4            fn=set_bool, default=0,
    16.5            use="Should device models use ne2000?")
    16.6  
    16.7 +gopts.var('audio', val='no|yes',
    16.8 +          fn=set_bool, default=0,
    16.9 +          use="Should device models enable audio?")
   16.10 +
   16.11  gopts.var('vnc', val='',
   16.12            fn=set_value, default=None,
   16.13            use="""Should the device model use VNC?""")
   16.14 @@ -521,7 +525,7 @@ def configure_vmx(config_image, vals):
   16.15      """Create the config for VMX devices.
   16.16      """
   16.17      args = [ 'device_model', 'vcpus', 'cdrom', 'boot', 'fda', 'fdb',
   16.18 -             'localtime', 'serial', 'stdvga', 'isa', 'nographic',
   16.19 +             'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'audio',
   16.20               'vnc', 'vncviewer', 'sdl', 'display', 'ne2000', 'lapic']
   16.21      for a in args:
   16.22          if (vals.__dict__[a]):