Attached is a patch to add arts support to qemu, plus the actual driver.

Apply the patch and place artsaudio.c in the qemu/audio directory, and
reconfigure with the --enable-arts option.

artsaudio.c is derived from ossaudio.c and artsdsp.c (from the source code of
arts 1.3.2).

-- 
Infinite complexity begets infinite beauty.
Infinite precision begets infinite perfection.
--- qemu/audio/audio_int.h      Sun Jul 10 22:21:02 2005
+++ qemu/audio/audio_int.h      Wed Jun  1 00:08:36 2005
@@ -58,6 +58,9 @@
 extern struct pcm_ops no_pcm_ops;
 extern struct audio_output_driver no_output_driver;
 
+extern struct pcm_ops arts_pcm_ops;
+extern struct audio_output_driver arts_output_driver;
+
 extern struct pcm_ops oss_pcm_ops;
 extern struct audio_output_driver oss_output_driver;
 
--- qemu/audio/audio.c  Sun Jul 10 22:21:27 2005
+++ qemu/audio/audio.c  Wed Jun  1 00:08:05 2005
@@ -776,6 +776,9 @@
 }
 
 static struct audio_output_driver *drvtab[] = {
+#ifdef CONFIG_ARTS
+    &arts_output_driver,
+#endif
 #ifdef CONFIG_OSS
     &oss_output_driver,
 #endif
--- qemu/Makefile.target        Sun Jul 10 22:25:58 2005
+++ qemu/Makefile.target        Wed Jul  6 23:40:55 2005
@@ -324,6 +324,10 @@
 ifdef CONFIG_OSS
 AUDIODRV += ossaudio.o
 endif
+ifdef CONFIG_ARTS
+AUDIODRV += artsaudio.o
+LIBS += $(CONFIG_ARTS_LIB)
+endif
 
 pc.o: DEFINES := -DUSE_SB16 $(DEFINES)
 
@@ -412,6 +416,9 @@
 
 sdlaudio.o: sdlaudio.c
        $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+artsaudio.o: artsaudio.c
+       $(CC) $(CFLAGS) $(DEFINES) $(CONFIG_ARTS_INC) -c -o $@ $<
 
 depend: $(SRCS)
        $(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
--- qemu/configure      Sun Jul 10 22:29:03 2005
+++ qemu/configure      Sun Jun 12 17:44:24 2005
@@ -77,6 +77,9 @@
 gdbstub="yes"
 slirp="yes"
 adlib="no"
+arts="no"
+arts_lib=""
+arts_inc=""
 oss="no"
 fmod="no"
 fmod_lib=""
@@ -186,6 +189,12 @@
   ;; 
   --disable-slirp) slirp="no"
   ;; 
+  --enable-arts) arts="yes"
+  ;;
+  --arts-lib=*) arts_lib=`echo $opt | cut -d '=' -f 2`
+  ;;
+  --arts-inc=*) arts_inc=`echo $opt | cut -d '=' -f 2`
+  ;;
   --enable-adlib) adlib="yes"
   ;; 
   --disable-kqemu) kqemu="no"
@@ -273,6 +282,40 @@
    have_gcc3_options="yes"
 fi
 
+if [ "$arts" = "yes" ]; then
+
+#dont bother with artsc-config check if both are given
+if [ "$arts_lib" = "" -o "$arts_inc" = "" ]; then
+
+if which artsc-config > /dev/null ; then
+
+if test -z "$arts_lib"; then
+
+arts_lib=`artsc-config --libs`
+
+fi
+
+if test -z "$arts_inc"; then
+
+arts_inc=`artsc-config --cflags`
+
+else
+
+arts_inc="-I$arts_inc"
+
+fi
+
+else
+
+  echo "artsc-config not found. Specify library and include dir manually."
+  arts="no"
+
+fi # artsc-config
+
+fi
+
+fi # arts
+
 ##########################################
 # SDL probe
 
@@ -512,6 +555,11 @@
     echo -n " (lib='$fmod_lib' include='$fmod_inc')"
 fi
 echo ""
+echo -n "Arts support      $arts"
+if test $arts = "yes"; then
+    echo -n " (lib='$arts_lib' include='$arts_inc')"
+fi
+echo ""
 echo "kqemu             $kqemu"
 echo "qvm86             $qvm86"
 if test $kernel_module = "yes" -a $linux = "yes"; then
@@ -636,6 +684,12 @@
 if test "$oss" = "yes" ; then
   echo "CONFIG_OSS=yes" >> $config_mak
   echo "#define CONFIG_OSS 1" >> $config_h
+fi
+if test "$arts" = "yes" ; then
+  echo "CONFIG_ARTS=yes" >> $config_mak
+  echo "CONFIG_ARTS_LIB=$arts_lib" >> $config_mak
+  echo "CONFIG_ARTS_INC=$arts_inc" >> $config_mak
+  echo "#define CONFIG_ARTS 1" >> $config_h
 fi
 if test "$fmod" = "yes" ; then
   echo "CONFIG_FMOD=yes" >> $config_mak
/*
 * QEMU Arts audio output driver
 * 
 * Copyright (c) 2005 Jim Brown 
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <sys/types.h>
#include <sys/soundcard.h>
#include <assert.h>
#include <artsc.h>
#include "vl.h"

#include "audio/audio_int.h"

typedef struct ArtsVoice {
    HWVoice hw;
    void *pcm_buf;
    arts_stream_t stream;
    int nfrags;
    int fragsize;
    int stream_inited;
    int old_optr;
    int paused;
} ArtsVoice;

#define dolog(...) AUD_log ("arts", __VA_ARGS__)
#ifdef DEBUG
#define ldebug(...) dolog (__VA_ARGS__)
#else
#define ldebug(...)
#endif

#define QC_ARTS_FRAGSIZE "QEMU_ARTS_FRAGSIZE"
#define QC_ARTS_NFRAGS   "QEMU_ARTS_NFRAGS"

static struct {
    int nfrags;
    int fragsize;
} conf = {
    .nfrags = 4,
    .fragsize = 4096,
};

struct arts_params {
    int freq;
    audfmt_e fmt;
    int nchannels;
    int nfrags;
    int fragsize;
};

static int arts_hw_write (SWVoice *sw, void *buf, int len)
{
    return pcm_hw_write(sw, buf, len);
}

static int AUD_to_artsfmt (audfmt_e fmt)
{
    switch (fmt) {
    case AUD_FMT_S8: return -8;
    case AUD_FMT_U8: return 8;
    case AUD_FMT_S16: return -16;
    case AUD_FMT_U16: return 16;
    default:
        dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
        exit (EXIT_FAILURE);
    }
}

static int arts_to_audfmt (int fmt)
{
    switch (fmt) {
    case -8: return AUD_FMT_S8;
    case 8: return AUD_FMT_U8;
    case -16: return AUD_FMT_S16;
    case 16: return AUD_FMT_U16;
    default:
        dolog ("Internal logic error: Unrecognized Arts audio format %d\n"
               "Aborting\n",
               fmt);
        exit (EXIT_FAILURE);
    }
}

static int arts_open (struct arts_params *req, struct arts_params *obt, 
arts_stream_t *pstream)
{
    arts_stream_t stream;
    int fmt;

    /* TODO: support signed vs unsigned data */
    fmt = req->fmt;
    if (fmt < 0)
        fmt = -fmt;

    stream = arts_play_stream(req->freq, fmt, req->nchannels, "qemu-arts");

    arts_stream_set(stream, ARTS_P_BLOCKING, 1);
    int mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
    int fragSize = (mmmmssss & 0x7fff);
    int fragCount = (mmmmssss & 0x7fff0000) >> 16;
    if(fragSize > 1 && fragSize < 16)
    { 
        if(fragCount < 2 || fragCount > 8192 || (fragCount * (1 << fragSize)) > 
128*1024)
        { 
            mmmmssss = 0x00030000+fragSize;
        }
        arts_stream_set(stream,ARTS_P_PACKET_SETTINGS,mmmmssss);
    }

    obt->nfrags = arts_stream_get(stream, ARTS_P_PACKET_COUNT);
    obt->fragsize = arts_stream_get(stream, ARTS_P_PACKET_SIZE);
    obt->freq = req->freq;
    obt->fmt = req->fmt;
    obt->nchannels = req->nchannels;

    *pstream = stream;

    if ((req->fmt != obt->fmt) ||
        (req->nchannels != obt->nchannels) ||
        (req->freq != obt->freq) ||
        (req->fragsize != obt->fragsize) ||
        (req->nfrags != obt->nfrags)) {
        /* error - mismatch */
    }

    return 0;
}

static void arts_hw_run (HWVoice *hw)
{
    ArtsVoice *arts = (ArtsVoice *) hw;
    int rpos, live, decr;
    int samples;
    uint8_t *dst;
    st_sample_t *src;
    int written=0;
    int bytes = 0;

    live = pcm_hw_get_live (hw);
    if ((live <= 0) || arts->paused)
        return;

    bytes = arts_stream_get(arts->stream, ARTS_P_BUFFER_SPACE);
    decr = audio_MIN(bytes >> hw->shift, live);
    if (decr <= 0) return;

    samples = decr;
    rpos = hw->rpos;
    while (samples) {
        int left_till_end_samples = hw->samples - rpos;
        int convert_samples = audio_MIN (samples, left_till_end_samples);

        src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
        dst = advance (arts->pcm_buf, rpos << hw->shift);

        hw->clip (dst, src, convert_samples);

        written = arts_write (arts->stream, dst, convert_samples << hw->shift);
        if (written < 0) {
            dolog ("Failed to write audio\nReason: %d\n", written);
            continue;
        }
        if (written != convert_samples << hw->shift) {
            int wsamples = written >> hw->shift;
            int wbytes = wsamples << hw->shift;
            if (wbytes != written) {
                dolog ("Unaligned write %d, %d\n", wbytes, written);
            }
            memset (src, 0, wbytes);
            decr -= samples;
            rpos = (rpos + wsamples) % hw->samples;
            break;
        }
        memset (src, 0, convert_samples * sizeof (st_sample_t));

        rpos = (rpos + convert_samples) % hw->samples;
        samples -= convert_samples;
    }

    pcm_hw_dec_live (hw, decr);
    hw->rpos = rpos;
}

static void arts_hw_fini (HWVoice *hw)
{
    ArtsVoice *arts = (ArtsVoice *) hw;

    ldebug ("arts_hw_fini\n");
    arts_close_stream(arts->stream);
    arts->stream_inited = 0;

    if (arts->pcm_buf) {
        qemu_free (arts->pcm_buf);
        arts->pcm_buf = NULL;
    }
}

static int arts_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
{
    ArtsVoice *arts = (ArtsVoice *) hw;
    struct arts_params req, obt;


    assert(!arts->stream_inited);
    req.fmt = AUD_to_artsfmt (fmt);
    req.freq = freq;
    req.nchannels = nchannels;
    req.fragsize = conf.fragsize;
    req.nfrags = conf.nfrags;

    if (arts_open (&req, &obt, &arts->stream))
        return -1;

    arts->stream_inited = 1;
    arts->paused = 0;
    hw->freq = obt.freq;
    hw->fmt = arts_to_audfmt (obt.fmt);
    hw->nchannels = obt.nchannels;

    arts->nfrags = obt.nfrags;
    arts->fragsize = obt.fragsize;
    hw->bufsize = obt.nfrags * obt.fragsize;

    arts->pcm_buf = qemu_mallocz (hw->bufsize);
    if (!arts->pcm_buf) {
        arts_close_stream (arts->stream);
        arts->stream_inited = 0;
        return -1;
    }

    return 0;
}

static int arts_hw_ctl (HWVoice *hw, int cmd, ...)
{
    ArtsVoice *arts = (ArtsVoice *) hw;

    switch (cmd) {
    case VOICE_ENABLE:
        ldebug ("enabling voice\n");
        pcm_hw_clear (hw, arts->pcm_buf, hw->samples);
        arts->paused = 0;
        break;

    case VOICE_DISABLE:
        ldebug ("disabling voice\n");
        arts->paused = 0;
        break;
    }
    return 0;
}

static void *arts_audio_init (void)
{
    conf.fragsize = audio_get_conf_int (QC_ARTS_FRAGSIZE, conf.fragsize);
    conf.nfrags = audio_get_conf_int (QC_ARTS_NFRAGS, conf.nfrags);
    assert(!(arts_init() < 0));
    return &conf;
}

static void arts_audio_fini (void *opaque)
{
    arts_free();
}

struct pcm_ops arts_pcm_ops = {
    arts_hw_init,
    arts_hw_fini,
    arts_hw_run,
    arts_hw_write,
    arts_hw_ctl
};

struct audio_output_driver arts_output_driver = {
    "arts",
    arts_audio_init,
    arts_audio_fini,
    &arts_pcm_ops,
    1,
    INT_MAX,
    sizeof (ArtsVoice)
};
_______________________________________________
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel

Reply via email to