Commit 85571bc7415c3fa9390f5edc3720ec7975219a68

Authored by bellard
1 parent 8f46820d

audio merge (malc)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1125 c046a42c-6fe2-441c-8c8c-71466251a162

Too many changes to show.

To preserve performance only 17 of 24 files are displayed.

Makefile.target
1 1 include config.mak
2 2  
  3 +#After enabling Adlib and/or FMOD rebuild QEMU from scratch
  4 +#Uncomment following for adlib support
  5 +#USE_ADLIB=1
  6 +
  7 +#Uncomment following and specify proper paths/names for FMOD support
  8 +#USE_FMOD=1
  9 +#FMOD_INCLUDE=/net/include/fmod
  10 +#FMOD_LIBPATH=/net/lib
  11 +#FMOD_VERSION=3.74
  12 +
3 13 TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH)
4   -VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw
  14 +VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
5 15 DEFINES=-I. -I$(TARGET_PATH) -I$(SRC_PATH)
6 16 ifdef CONFIG_USER_ONLY
7 17 VPATH+=:$(SRC_PATH)/linux-user
... ... @@ -267,16 +277,31 @@ endif
267 277 VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o
268 278 VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
269 279  
  280 +SOUND_HW = sb16.o
  281 +AUDIODRV = audio.o ossaudio.o sdlaudio.o wavaudio.o
  282 +
  283 +ifeq ($(USE_ADLIB),1)
  284 +SOUND_HW += fmopl.o adlib.o
  285 +audio.o: DEFINES := -DUSE_ADLIB $(DEFINES)
  286 +endif
  287 +
  288 +ifeq ($(USE_FMOD),1)
  289 +AUDIODRV += fmodaudio.o
  290 +audio.o fmodaudio.o: DEFINES := -DUSE_FMOD_AUDIO -I$(FMOD_INCLUDE) $(DEFINES)
  291 +LDFLAGS += -L$(FMOD_LIBPATH) -Wl,-rpath,$(FMOD_LIBPATH)
  292 +LIBS += -lfmod-$(FMOD_VERSION)
  293 +endif
  294 +
270 295 ifeq ($(TARGET_ARCH), i386)
271 296 # Hardware support
272   -VL_OBJS+= ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o
273   -VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
274   -VL_OBJS+= cirrus_vga.o
  297 +VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
  298 +VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o
  299 +VL_OBJS+= cirrus_vga.o mixeng.o
275 300 endif
276 301 ifeq ($(TARGET_ARCH), ppc)
277   -VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o
  302 +VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
278 303 VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
279   -VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o
  304 +VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o mixeng.o
280 305 endif
281 306 ifeq ($(TARGET_ARCH), sparc)
282 307 VL_OBJS+= sun4m.o tcx.o lance.o iommu.o sched.o m48t08.o magic-load.o timer.o
... ... @@ -360,6 +385,8 @@ op.o: op.c op_template.h op_mem.h
360 385 op_helper.o: op_helper_mem.h
361 386 endif
362 387  
  388 +mixeng.o: mixeng.c mixeng.h mixeng_template.h
  389 +
363 390 %.o: %.c
364 391 $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
365 392  
... ...
audio/audio.c 0 → 100644
  1 +/*
  2 + * QEMU Audio subsystem
  3 + *
  4 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include <assert.h>
  25 +#include <limits.h>
  26 +#include "vl.h"
  27 +
  28 +#define AUDIO_CAP "audio"
  29 +#include "audio/audio.h"
  30 +
  31 +#define USE_SDL_AUDIO
  32 +#define USE_WAV_AUDIO
  33 +
  34 +#if defined __linux__ || (defined _BSD && !defined __APPLE__)
  35 +#define USE_OSS_AUDIO
  36 +#endif
  37 +
  38 +#ifdef USE_OSS_AUDIO
  39 +#include "audio/ossaudio.h"
  40 +#endif
  41 +
  42 +#ifdef USE_SDL_AUDIO
  43 +#include "audio/sdlaudio.h"
  44 +#endif
  45 +
  46 +#ifdef USE_WAV_AUDIO
  47 +#include "audio/wavaudio.h"
  48 +#endif
  49 +
  50 +#ifdef USE_FMOD_AUDIO
  51 +#include "audio/fmodaudio.h"
  52 +#endif
  53 +
  54 +#define QC_AUDIO_DRV "QEMU_AUDIO_DRV"
  55 +#define QC_VOICES "QEMU_VOICES"
  56 +#define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT"
  57 +#define QC_FIXED_FREQ "QEMU_FIXED_FREQ"
  58 +
  59 +extern void SB16_init (void);
  60 +
  61 +#ifdef USE_ADLIB
  62 +extern void Adlib_init (void);
  63 +#endif
  64 +
  65 +#ifdef USE_GUS
  66 +extern void GUS_init (void);
  67 +#endif
  68 +
  69 +static void (*hw_ctors[]) (void) = {
  70 + SB16_init,
  71 +#ifdef USE_ADLIB
  72 + Adlib_init,
  73 +#endif
  74 +#ifdef USE_GUS
  75 + GUS_init,
  76 +#endif
  77 + NULL
  78 +};
  79 +
  80 +static HWVoice *hw_voice;
  81 +
  82 +AudioState audio_state = {
  83 + 1, /* use fixed settings */
  84 + 44100, /* fixed frequency */
  85 + 2, /* fixed channels */
  86 + AUD_FMT_S16, /* fixed format */
  87 + 1, /* number of hw voices */
  88 + -1 /* voice size */
  89 +};
  90 +
  91 +/* http://www.df.lth.se/~john_e/gems/gem002d.html */
  92 +/* http://www.multi-platforms.com/Tips/PopCount.htm */
  93 +uint32_t popcount (uint32_t u)
  94 +{
  95 + u = ((u&0x55555555) + ((u>>1)&0x55555555));
  96 + u = ((u&0x33333333) + ((u>>2)&0x33333333));
  97 + u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
  98 + u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
  99 + u = ( u&0x0000ffff) + (u>>16);
  100 + return u;
  101 +}
  102 +
  103 +inline uint32_t lsbindex (uint32_t u)
  104 +{
  105 + return popcount ((u&-u)-1);
  106 +}
  107 +
  108 +int audio_get_conf_int (const char *key, int defval)
  109 +{
  110 + int val = defval;
  111 + char *strval;
  112 +
  113 + strval = getenv (key);
  114 + if (strval) {
  115 + val = atoi (strval);
  116 + }
  117 +
  118 + return val;
  119 +}
  120 +
  121 +const char *audio_get_conf_str (const char *key, const char *defval)
  122 +{
  123 + const char *val = getenv (key);
  124 + if (!val)
  125 + return defval;
  126 + else
  127 + return val;
  128 +}
  129 +
  130 +void audio_log (const char *fmt, ...)
  131 +{
  132 + va_list ap;
  133 + va_start (ap, fmt);
  134 + vfprintf (stderr, fmt, ap);
  135 + va_end (ap);
  136 +}
  137 +
  138 +/*
  139 + * Soft Voice
  140 + */
  141 +void pcm_sw_free_resources (SWVoice *sw)
  142 +{
  143 + if (sw->buf) qemu_free (sw->buf);
  144 + if (sw->rate) st_rate_stop (sw->rate);
  145 + sw->buf = NULL;
  146 + sw->rate = NULL;
  147 +}
  148 +
  149 +int pcm_sw_alloc_resources (SWVoice *sw)
  150 +{
  151 + sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
  152 + if (!sw->buf)
  153 + return -1;
  154 +
  155 + sw->rate = st_rate_start (sw->freq, sw->hw->freq);
  156 + if (!sw->rate) {
  157 + qemu_free (sw->buf);
  158 + sw->buf = NULL;
  159 + return -1;
  160 + }
  161 + return 0;
  162 +}
  163 +
  164 +void pcm_sw_fini (SWVoice *sw)
  165 +{
  166 + pcm_sw_free_resources (sw);
  167 +}
  168 +
  169 +int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
  170 + int nchannels, audfmt_e fmt)
  171 +{
  172 + int bits = 8, sign = 0;
  173 +
  174 + switch (fmt) {
  175 + case AUD_FMT_S8:
  176 + sign = 1;
  177 + case AUD_FMT_U8:
  178 + break;
  179 +
  180 + case AUD_FMT_S16:
  181 + sign = 1;
  182 + case AUD_FMT_U16:
  183 + bits = 16;
  184 + break;
  185 + }
  186 +
  187 + sw->hw = hw;
  188 + sw->freq = freq;
  189 + sw->fmt = fmt;
  190 + sw->nchannels = nchannels;
  191 + sw->shift = (nchannels == 2) + (bits == 16);
  192 + sw->align = (1 << sw->shift) - 1;
  193 + sw->left = 0;
  194 + sw->pos = 0;
  195 + sw->wpos = 0;
  196 + sw->live = 0;
  197 + sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq;
  198 + sw->bytes_per_second = sw->freq << sw->shift;
  199 + sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16];
  200 +
  201 + pcm_sw_free_resources (sw);
  202 + return pcm_sw_alloc_resources (sw);
  203 +}
  204 +
  205 +/* Hard voice */
  206 +void pcm_hw_free_resources (HWVoice *hw)
  207 +{
  208 + if (hw->mix_buf)
  209 + qemu_free (hw->mix_buf);
  210 + hw->mix_buf = NULL;
  211 +}
  212 +
  213 +int pcm_hw_alloc_resources (HWVoice *hw)
  214 +{
  215 + hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
  216 + if (!hw->mix_buf)
  217 + return -1;
  218 + return 0;
  219 +}
  220 +
  221 +
  222 +void pcm_hw_fini (HWVoice *hw)
  223 +{
  224 + if (hw->active) {
  225 + ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);
  226 + pcm_hw_free_resources (hw);
  227 + hw->pcm_ops->fini (hw);
  228 + memset (hw, 0, audio_state.drv->voice_size);
  229 + }
  230 +}
  231 +
  232 +void pcm_hw_gc (HWVoice *hw)
  233 +{
  234 + if (hw->nb_voices)
  235 + return;
  236 +
  237 + pcm_hw_fini (hw);
  238 +}
  239 +
  240 +int pcm_hw_get_live (HWVoice *hw)
  241 +{
  242 + int i, alive = 0, live = hw->samples;
  243 +
  244 + for (i = 0; i < hw->nb_voices; i++) {
  245 + if (hw->pvoice[i]->live) {
  246 + live = audio_MIN (hw->pvoice[i]->live, live);
  247 + alive += 1;
  248 + }
  249 + }
  250 +
  251 + if (alive)
  252 + return live;
  253 + else
  254 + return -1;
  255 +}
  256 +
  257 +int pcm_hw_get_live2 (HWVoice *hw, int *nb_active)
  258 +{
  259 + int i, alive = 0, live = hw->samples;
  260 +
  261 + *nb_active = 0;
  262 + for (i = 0; i < hw->nb_voices; i++) {
  263 + if (hw->pvoice[i]->live) {
  264 + if (hw->pvoice[i]->live < live) {
  265 + *nb_active = hw->pvoice[i]->active != 0;
  266 + live = hw->pvoice[i]->live;
  267 + }
  268 + alive += 1;
  269 + }
  270 + }
  271 +
  272 + if (alive)
  273 + return live;
  274 + else
  275 + return -1;
  276 +}
  277 +
  278 +void pcm_hw_dec_live (HWVoice *hw, int decr)
  279 +{
  280 + int i;
  281 +
  282 + for (i = 0; i < hw->nb_voices; i++) {
  283 + if (hw->pvoice[i]->live) {
  284 + hw->pvoice[i]->live -= decr;
  285 + }
  286 + }
  287 +}
  288 +
  289 +void pcm_hw_clear (HWVoice *hw, void *buf, int len)
  290 +{
  291 + if (!len)
  292 + return;
  293 +
  294 + switch (hw->fmt) {
  295 + case AUD_FMT_S16:
  296 + case AUD_FMT_S8:
  297 + memset (buf, len << hw->shift, 0x00);
  298 + break;
  299 +
  300 + case AUD_FMT_U8:
  301 + memset (buf, len << hw->shift, 0x80);
  302 + break;
  303 +
  304 + case AUD_FMT_U16:
  305 + {
  306 + unsigned int i;
  307 + uint16_t *p = buf;
  308 + int shift = hw->nchannels - 1;
  309 +
  310 + for (i = 0; i < len << shift; i++) {
  311 + p[i] = INT16_MAX;
  312 + }
  313 + }
  314 + break;
  315 + }
  316 +}
  317 +
  318 +int pcm_hw_write (SWVoice *sw, void *buf, int size)
  319 +{
  320 + int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
  321 + int ret = 0, pos = 0;
  322 + if (!sw)
  323 + return size;
  324 +
  325 + hwsamples = sw->hw->samples;
  326 + samples = size >> sw->shift;
  327 +
  328 + if (!sw->live) {
  329 + sw->wpos = sw->hw->rpos;
  330 + }
  331 + wpos = sw->wpos;
  332 + live = sw->live;
  333 + dead = hwsamples - live;
  334 + swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio;
  335 + swlim = audio_MIN (swlim, samples);
  336 +
  337 + ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",
  338 + size, live, dead, swlim, wpos);
  339 + if (swlim)
  340 + sw->conv (sw->buf, buf, swlim);
  341 +
  342 + while (swlim) {
  343 + dead = hwsamples - live;
  344 + left = hwsamples - wpos;
  345 + blck = audio_MIN (dead, left);
  346 + if (!blck) {
  347 + /* dolog ("swlim=%d\n", swlim); */
  348 + break;
  349 + }
  350 + isamp = swlim;
  351 + osamp = blck;
  352 + st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp);
  353 + ret += isamp;
  354 + swlim -= isamp;
  355 + pos += isamp;
  356 + live += osamp;
  357 + wpos = (wpos + osamp) % hwsamples;
  358 + }
  359 +
  360 + sw->wpos = wpos;
  361 + sw->live = live;
  362 + return ret << sw->shift;
  363 +}
  364 +
  365 +int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
  366 +{
  367 + int sign = 0, bits = 8;
  368 +
  369 + pcm_hw_fini (hw);
  370 + ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);
  371 + if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {
  372 + memset (hw, 0, audio_state.drv->voice_size);
  373 + return -1;
  374 + }
  375 +
  376 + switch (hw->fmt) {
  377 + case AUD_FMT_S8:
  378 + sign = 1;
  379 + case AUD_FMT_U8:
  380 + break;
  381 +
  382 + case AUD_FMT_S16:
  383 + sign = 1;
  384 + case AUD_FMT_U16:
  385 + bits = 16;
  386 + break;
  387 + }
  388 +
  389 + hw->nb_voices = 0;
  390 + hw->active = 1;
  391 + hw->shift = (hw->nchannels == 2) + (bits == 16);
  392 + hw->bytes_per_second = hw->freq << hw->shift;
  393 + hw->align = (1 << hw->shift) - 1;
  394 + hw->samples = hw->bufsize >> hw->shift;
  395 + hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16];
  396 + if (pcm_hw_alloc_resources (hw)) {
  397 + pcm_hw_fini (hw);
  398 + return -1;
  399 + }
  400 + return 0;
  401 +}
  402 +
  403 +static int dist (void *hw)
  404 +{
  405 + if (hw) {
  406 + return (((uint8_t *) hw - (uint8_t *) hw_voice)
  407 + / audio_state.voice_size) + 1;
  408 + }
  409 + else {
  410 + return 0;
  411 + }
  412 +}
  413 +
  414 +#define ADVANCE(hw) hw ? advance (hw, audio_state.voice_size) : hw_voice
  415 +
  416 +HWVoice *pcm_hw_find_any (HWVoice *hw)
  417 +{
  418 + int i = dist (hw);
  419 + for (; i < audio_state.nb_hw_voices; i++) {
  420 + hw = ADVANCE (hw);
  421 + return hw;
  422 + }
  423 + return NULL;
  424 +}
  425 +
  426 +HWVoice *pcm_hw_find_any_active (HWVoice *hw)
  427 +{
  428 + int i = dist (hw);
  429 + for (; i < audio_state.nb_hw_voices; i++) {
  430 + hw = ADVANCE (hw);
  431 + if (hw->active)
  432 + return hw;
  433 + }
  434 + return NULL;
  435 +}
  436 +
  437 +HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw)
  438 +{
  439 + int i = dist (hw);
  440 + for (; i < audio_state.nb_hw_voices; i++) {
  441 + hw = ADVANCE (hw);
  442 + if (hw->active && hw->enabled)
  443 + return hw;
  444 + }
  445 + return NULL;
  446 +}
  447 +
  448 +HWVoice *pcm_hw_find_any_passive (HWVoice *hw)
  449 +{
  450 + int i = dist (hw);
  451 + for (; i < audio_state.nb_hw_voices; i++) {
  452 + hw = ADVANCE (hw);
  453 + if (!hw->active)
  454 + return hw;
  455 + }
  456 + return NULL;
  457 +}
  458 +
  459 +HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,
  460 + int nchannels, audfmt_e fmt)
  461 +{
  462 + while ((hw = pcm_hw_find_any_active (hw))) {
  463 + if (hw->freq == freq &&
  464 + hw->nchannels == nchannels &&
  465 + hw->fmt == fmt)
  466 + return hw;
  467 + }
  468 + return NULL;
  469 +}
  470 +
  471 +HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt)
  472 +{
  473 + HWVoice *hw;
  474 +
  475 + if (audio_state.fixed_format) {
  476 + freq = audio_state.fixed_freq;
  477 + nchannels = audio_state.fixed_channels;
  478 + fmt = audio_state.fixed_fmt;
  479 + }
  480 +
  481 + hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);
  482 +
  483 + if (hw)
  484 + return hw;
  485 +
  486 + hw = pcm_hw_find_any_passive (NULL);
  487 + if (hw) {
  488 + hw->pcm_ops = audio_state.drv->pcm_ops;
  489 + if (!hw->pcm_ops)
  490 + return NULL;
  491 +
  492 + if (pcm_hw_init (hw, freq, nchannels, fmt)) {
  493 + pcm_hw_gc (hw);
  494 + return NULL;
  495 + }
  496 + else
  497 + return hw;
  498 + }
  499 +
  500 + return pcm_hw_find_any (NULL);
  501 +}
  502 +
  503 +int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)
  504 +{
  505 + SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw));
  506 + if (!pvoice)
  507 + return -1;
  508 +
  509 + memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));
  510 + qemu_free (hw->pvoice);
  511 + hw->pvoice = pvoice;
  512 + hw->pvoice[hw->nb_voices++] = sw;
  513 + return 0;
  514 +}
  515 +
  516 +int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)
  517 +{
  518 + int i, j;
  519 + if (hw->nb_voices > 1) {
  520 + SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw));
  521 +
  522 + if (!pvoice) {
  523 + dolog ("Can not maintain consistent state (not enough memory)\n");
  524 + return -1;
  525 + }
  526 +
  527 + for (i = 0, j = 0; i < hw->nb_voices; i++) {
  528 + if (j >= hw->nb_voices - 1) {
  529 + dolog ("Can not maintain consistent state "
  530 + "(invariant violated)\n");
  531 + return -1;
  532 + }
  533 + if (hw->pvoice[i] != sw)
  534 + pvoice[j++] = hw->pvoice[i];
  535 + }
  536 + qemu_free (hw->pvoice);
  537 + hw->pvoice = pvoice;
  538 + hw->nb_voices -= 1;
  539 + }
  540 + else {
  541 + qemu_free (hw->pvoice);
  542 + hw->pvoice = NULL;
  543 + hw->nb_voices = 0;
  544 + }
  545 + return 0;
  546 +}
  547 +
  548 +SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt)
  549 +{
  550 + SWVoice *sw;
  551 + HWVoice *hw;
  552 +
  553 + sw = qemu_mallocz (sizeof (*sw));
  554 + if (!sw)
  555 + goto err1;
  556 +
  557 + hw = pcm_hw_add (freq, nchannels, fmt);
  558 + if (!hw)
  559 + goto err2;
  560 +
  561 + if (pcm_hw_add_sw (hw, sw))
  562 + goto err3;
  563 +
  564 + if (pcm_sw_init (sw, hw, freq, nchannels, fmt))
  565 + goto err4;
  566 +
  567 + return sw;
  568 +
  569 +err4:
  570 + pcm_hw_del_sw (hw, sw);
  571 +err3:
  572 + pcm_hw_gc (hw);
  573 +err2:
  574 + qemu_free (sw);
  575 +err1:
  576 + return NULL;
  577 +}
  578 +
  579 +SWVoice *AUD_open (SWVoice *sw, const char *name,
  580 + int freq, int nchannels, audfmt_e fmt)
  581 +{
  582 + if (!audio_state.drv) {
  583 + return NULL;
  584 + }
  585 +
  586 + if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {
  587 + return sw;
  588 + }
  589 +
  590 + if (sw) {
  591 + ldebug ("Different format %s %d %d %d\n",
  592 + name,
  593 + sw->freq == freq,
  594 + sw->nchannels == nchannels,
  595 + sw->fmt == fmt);
  596 + }
  597 +
  598 + if (nchannels != 1 && nchannels != 2) {
  599 + dolog ("Bogus channel count %d for voice %s\n", nchannels, name);
  600 + return NULL;
  601 + }
  602 +
  603 + if (!audio_state.fixed_format && sw) {
  604 + pcm_sw_fini (sw);
  605 + pcm_hw_del_sw (sw->hw, sw);
  606 + pcm_hw_gc (sw->hw);
  607 + if (sw->name) {
  608 + qemu_free (sw->name);
  609 + sw->name = NULL;
  610 + }
  611 + qemu_free (sw);
  612 + sw = NULL;
  613 + }
  614 +
  615 + if (sw) {
  616 + HWVoice *hw = sw->hw;
  617 + if (!hw) {
  618 + dolog ("Internal logic error voice %s has no hardware store\n",
  619 + name);
  620 + return sw;
  621 + }
  622 +
  623 + if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {
  624 + pcm_sw_fini (sw);
  625 + pcm_hw_del_sw (hw, sw);
  626 + pcm_hw_gc (hw);
  627 + if (sw->name) {
  628 + qemu_free (sw->name);
  629 + sw->name = NULL;
  630 + }
  631 + qemu_free (sw);
  632 + return NULL;
  633 + }
  634 + }
  635 + else {
  636 + sw = pcm_create_voice_pair (freq, nchannels, fmt);
  637 + if (!sw) {
  638 + dolog ("Failed to create voice %s\n", name);
  639 + return NULL;
  640 + }
  641 + }
  642 +
  643 + if (sw->name) {
  644 + qemu_free (sw->name);
  645 + sw->name = NULL;
  646 + }
  647 + sw->name = qemu_strdup (name);
  648 + return sw;
  649 +}
  650 +
  651 +int AUD_write (SWVoice *sw, void *buf, int size)
  652 +{
  653 + int bytes;
  654 +
  655 + if (!sw->hw->enabled)
  656 + dolog ("Writing to disabled voice %s\n", sw->name);
  657 + bytes = sw->hw->pcm_ops->write (sw, buf, size);
  658 + return bytes;
  659 +}
  660 +
  661 +void AUD_run (void)
  662 +{
  663 + HWVoice *hw = NULL;
  664 +
  665 + while ((hw = pcm_hw_find_any_active_enabled (hw))) {
  666 + int i;
  667 + if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) {
  668 + hw->enabled = 0;
  669 + hw->pcm_ops->ctl (hw, VOICE_DISABLE);
  670 + for (i = 0; i < hw->nb_voices; i++) {
  671 + hw->pvoice[i]->live = 0;
  672 + /* hw->pvoice[i]->old_ticks = 0; */
  673 + }
  674 + continue;
  675 + }
  676 +
  677 + hw->pcm_ops->run (hw);
  678 + assert (hw->rpos < hw->samples);
  679 + for (i = 0; i < hw->nb_voices; i++) {
  680 + SWVoice *sw = hw->pvoice[i];
  681 + if (!sw->active && !sw->live && sw->old_ticks) {
  682 + int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks;
  683 + if (delta > audio_state.ticks_threshold) {
  684 + ldebug ("resetting old_ticks for %s\n", sw->name);
  685 + sw->old_ticks = 0;
  686 + }
  687 + }
  688 + }
  689 + }
  690 +}
  691 +
  692 +int AUD_get_free (SWVoice *sw)
  693 +{
  694 + int free;
  695 +
  696 + if (!sw)
  697 + return 4096;
  698 +
  699 + free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio
  700 + / INT_MAX;
  701 +
  702 + free &= ~sw->hw->align;
  703 + if (!free) return 0;
  704 +
  705 + return free;
  706 +}
  707 +
  708 +int AUD_get_buffer_size (SWVoice *sw)
  709 +{
  710 + return sw->hw->bufsize;
  711 +}
  712 +
  713 +void AUD_adjust (SWVoice *sw, int bytes)
  714 +{
  715 + if (!sw)
  716 + return;
  717 + sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second;
  718 +}
  719 +
  720 +void AUD_reset (SWVoice *sw)
  721 +{
  722 + sw->active = 0;
  723 + sw->old_ticks = 0;
  724 +}
  725 +
  726 +int AUD_calc_elapsed (SWVoice *sw)
  727 +{
  728 + int64_t now, delta, bytes;
  729 + int dead, swlim;
  730 +
  731 + if (!sw)
  732 + return 0;
  733 +
  734 + now = qemu_get_clock (vm_clock);
  735 + delta = now - sw->old_ticks;
  736 + bytes = (delta * sw->bytes_per_second) / ticks_per_sec;
  737 + if (delta < 0) {
  738 + dolog ("whoops delta(<0)=%lld\n", delta);
  739 + return 0;
  740 + }
  741 +
  742 + dead = sw->hw->samples - sw->live;
  743 + swlim = ((dead * (int64_t) INT_MAX) / sw->ratio);
  744 +
  745 + if (bytes > swlim) {
  746 + return swlim;
  747 + }
  748 + else {
  749 + return bytes;
  750 + }
  751 +}
  752 +
  753 +void AUD_enable (SWVoice *sw, int on)
  754 +{
  755 + int i;
  756 + HWVoice *hw;
  757 +
  758 + if (!sw)
  759 + return;
  760 +
  761 + hw = sw->hw;
  762 + if (on) {
  763 + if (!sw->live)
  764 + sw->wpos = sw->hw->rpos;
  765 + if (!sw->old_ticks) {
  766 + sw->old_ticks = qemu_get_clock (vm_clock);
  767 + }
  768 + }
  769 +
  770 + if (sw->active != on) {
  771 + if (on) {
  772 + hw->pending_disable = 0;
  773 + if (!hw->enabled) {
  774 + hw->enabled = 1;
  775 + for (i = 0; i < hw->nb_voices; i++) {
  776 + ldebug ("resetting voice\n");
  777 + sw = hw->pvoice[i];
  778 + sw->old_ticks = qemu_get_clock (vm_clock);
  779 + }
  780 + hw->pcm_ops->ctl (hw, VOICE_ENABLE);
  781 + }
  782 + }
  783 + else {
  784 + if (hw->enabled && !hw->pending_disable) {
  785 + int nb_active = 0;
  786 + for (i = 0; i < hw->nb_voices; i++) {
  787 + nb_active += hw->pvoice[i]->active != 0;
  788 + }
  789 +
  790 + if (nb_active == 1) {
  791 + hw->pending_disable = 1;
  792 + }
  793 + }
  794 + }
  795 + sw->active = on;
  796 + }
  797 +}
  798 +
  799 +static struct audio_output_driver *drvtab[] = {
  800 +#ifdef USE_OSS_AUDIO
  801 + &oss_output_driver,
  802 +#endif
  803 +#ifdef USE_FMOD_AUDIO
  804 + &fmod_output_driver,
  805 +#endif
  806 +#ifdef USE_SDL_AUDIO
  807 + &sdl_output_driver,
  808 +#endif
  809 +#ifdef USE_WAV_AUDIO
  810 + &wav_output_driver,
  811 +#endif
  812 +};
  813 +
  814 +static int voice_init (struct audio_output_driver *drv)
  815 +{
  816 + audio_state.opaque = drv->init ();
  817 + if (audio_state.opaque) {
  818 + if (audio_state.nb_hw_voices > drv->max_voices) {
  819 + dolog ("`%s' does not support %d multiple hardware channels\n"
  820 + "Resetting to %d\n",
  821 + drv->name, audio_state.nb_hw_voices, drv->max_voices);
  822 + audio_state.nb_hw_voices = drv->max_voices;
  823 + }
  824 + hw_voice = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size);
  825 + if (hw_voice) {
  826 + audio_state.drv = drv;
  827 + return 1;
  828 + }
  829 + else {
  830 + dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",
  831 + audio_state.nb_hw_voices, drv->name, drv->voice_size);
  832 + drv->fini (audio_state.opaque);
  833 + return 0;
  834 + }
  835 + }
  836 + else {
  837 + dolog ("Could not init `%s' audio\n", drv->name);
  838 + return 0;
  839 + }
  840 +}
  841 +
  842 +static void audio_vm_stop_handler (void *opaque, int reason)
  843 +{
  844 + HWVoice *hw = NULL;
  845 +
  846 + while ((hw = pcm_hw_find_any (hw))) {
  847 + if (!hw->pcm_ops)
  848 + continue;
  849 +
  850 + hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE);
  851 + }
  852 +}
  853 +
  854 +static void audio_atexit (void)
  855 +{
  856 + HWVoice *hw = NULL;
  857 +
  858 + while ((hw = pcm_hw_find_any (hw))) {
  859 + if (!hw->pcm_ops)
  860 + continue;
  861 +
  862 + hw->pcm_ops->ctl (hw, VOICE_DISABLE);
  863 + hw->pcm_ops->fini (hw);
  864 + }
  865 + audio_state.drv->fini (audio_state.opaque);
  866 +}
  867 +
  868 +static void audio_save (QEMUFile *f, void *opaque)
  869 +{
  870 +}
  871 +
  872 +static int audio_load (QEMUFile *f, void *opaque, int version_id)
  873 +{
  874 + if (version_id != 1)
  875 + return -EINVAL;
  876 +
  877 + return 0;
  878 +}
  879 +
  880 +void AUD_init (void)
  881 +{
  882 + int i;
  883 + int done = 0;
  884 + const char *drvname;
  885 +
  886 + audio_state.fixed_format =
  887 + !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format);
  888 + audio_state.fixed_freq =
  889 + audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq);
  890 + audio_state.nb_hw_voices =
  891 + audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices);
  892 +
  893 + if (audio_state.nb_hw_voices <= 0) {
  894 + dolog ("Bogus number of voices %d, resetting to 1\n",
  895 + audio_state.nb_hw_voices);
  896 + }
  897 +
  898 + drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);
  899 + if (drvname) {
  900 + int found = 0;
  901 + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
  902 + if (!strcmp (drvname, drvtab[i]->name)) {
  903 + done = voice_init (drvtab[i]);
  904 + found = 1;
  905 + break;
  906 + }
  907 + }
  908 + if (!found) {
  909 + dolog ("Unknown audio driver `%s'\n", drvname);
  910 + }
  911 + }
  912 +
  913 + qemu_add_vm_stop_handler (audio_vm_stop_handler, NULL);
  914 + atexit (audio_atexit);
  915 +
  916 + if (!done) {
  917 + for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
  918 + if (drvtab[i]->can_be_default)
  919 + done = voice_init (drvtab[i]);
  920 + }
  921 + }
  922 +
  923 + audio_state.ticks_threshold = ticks_per_sec / 50;
  924 + audio_state.freq_threshold = 100;
  925 +
  926 + register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);
  927 + if (!done) {
  928 + dolog ("Can not initialize audio subsystem\n");
  929 + return;
  930 + }
  931 +
  932 + for (i = 0; hw_ctors[i]; i++) {
  933 + hw_ctors[i] ();
  934 + }
  935 +}
... ...
audio/audio.h 0 → 100644
  1 +/*
  2 + * QEMU Audio subsystem header
  3 + *
  4 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#ifndef QEMU_AUDIO_H
  25 +#define QEMU_AUDIO_H
  26 +
  27 +#include "mixeng.h"
  28 +
  29 +#define dolog(...) fprintf (stderr, AUDIO_CAP ": " __VA_ARGS__)
  30 +#ifdef DEBUG
  31 +#define ldebug(...) dolog (__VA_ARGS__)
  32 +#else
  33 +#define ldebug(...)
  34 +#endif
  35 +
  36 +typedef enum {
  37 + AUD_FMT_U8,
  38 + AUD_FMT_S8,
  39 + AUD_FMT_U16,
  40 + AUD_FMT_S16
  41 +} audfmt_e;
  42 +
  43 +typedef struct HWVoice HWVoice;
  44 +struct audio_output_driver;
  45 +
  46 +typedef struct AudioState {
  47 + int fixed_format;
  48 + int fixed_freq;
  49 + int fixed_channels;
  50 + int fixed_fmt;
  51 + int nb_hw_voices;
  52 + int voice_size;
  53 + int64_t ticks_threshold;
  54 + int freq_threshold;
  55 + void *opaque;
  56 + struct audio_output_driver *drv;
  57 +} AudioState;
  58 +
  59 +extern AudioState audio_state;
  60 +
  61 +typedef struct SWVoice {
  62 + int freq;
  63 + audfmt_e fmt;
  64 + int nchannels;
  65 +
  66 + int shift;
  67 + int align;
  68 +
  69 + t_sample *conv;
  70 +
  71 + int left;
  72 + int pos;
  73 + int bytes_per_second;
  74 + int64_t ratio;
  75 + st_sample_t *buf;
  76 + void *rate;
  77 +
  78 + int wpos;
  79 + int live;
  80 + int active;
  81 + int64_t old_ticks;
  82 + HWVoice *hw;
  83 + char *name;
  84 +} SWVoice;
  85 +
  86 +#define VOICE_ENABLE 1
  87 +#define VOICE_DISABLE 2
  88 +
  89 +struct pcm_ops {
  90 + int (*init) (HWVoice *hw, int freq, int nchannels, audfmt_e fmt);
  91 + void (*fini) (HWVoice *hw);
  92 + void (*run) (HWVoice *hw);
  93 + int (*write) (SWVoice *sw, void *buf, int size);
  94 + int (*ctl) (HWVoice *hw, int cmd, ...);
  95 +};
  96 +
  97 +struct audio_output_driver {
  98 + const char *name;
  99 + void *(*init) (void);
  100 + void (*fini) (void *);
  101 + struct pcm_ops *pcm_ops;
  102 + int can_be_default;
  103 + int max_voices;
  104 + int voice_size;
  105 +};
  106 +
  107 +struct HWVoice {
  108 + int active;
  109 + int enabled;
  110 + int pending_disable;
  111 + int valid;
  112 + int freq;
  113 +
  114 + f_sample *clip;
  115 + audfmt_e fmt;
  116 + int nchannels;
  117 +
  118 + int align;
  119 + int shift;
  120 +
  121 + int rpos;
  122 + int bufsize;
  123 +
  124 + int bytes_per_second;
  125 + st_sample_t *mix_buf;
  126 +
  127 + int samples;
  128 + int64_t old_ticks;
  129 + int nb_voices;
  130 + struct SWVoice **pvoice;
  131 + struct pcm_ops *pcm_ops;
  132 +};
  133 +
  134 +void audio_log (const char *fmt, ...);
  135 +void pcm_sw_free_resources (SWVoice *sw);
  136 +int pcm_sw_alloc_resources (SWVoice *sw);
  137 +void pcm_sw_fini (SWVoice *sw);
  138 +int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,
  139 + int nchannels, audfmt_e fmt);
  140 +
  141 +void pcm_hw_clear (HWVoice *hw, void *buf, int len);
  142 +HWVoice * pcm_hw_find_any (HWVoice *hw);
  143 +HWVoice * pcm_hw_find_any_active (HWVoice *hw);
  144 +HWVoice * pcm_hw_find_any_passive (HWVoice *hw);
  145 +HWVoice * pcm_hw_find_specific (HWVoice *hw, int freq,
  146 + int nchannels, audfmt_e fmt);
  147 +HWVoice * pcm_hw_add (int freq, int nchannels, audfmt_e fmt);
  148 +int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw);
  149 +int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw);
  150 +SWVoice * pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt);
  151 +
  152 +void pcm_hw_free_resources (HWVoice *hw);
  153 +int pcm_hw_alloc_resources (HWVoice *hw);
  154 +void pcm_hw_fini (HWVoice *hw);
  155 +void pcm_hw_gc (HWVoice *hw);
  156 +int pcm_hw_get_live (HWVoice *hw);
  157 +int pcm_hw_get_live2 (HWVoice *hw, int *nb_active);
  158 +void pcm_hw_dec_live (HWVoice *hw, int decr);
  159 +int pcm_hw_write (SWVoice *sw, void *buf, int len);
  160 +
  161 +int audio_get_conf_int (const char *key, int defval);
  162 +const char *audio_get_conf_str (const char *key, const char *defval);
  163 +
  164 +/* Public API */
  165 +SWVoice * AUD_open (SWVoice *sw, const char *name, int freq,
  166 + int nchannels, audfmt_e fmt);
  167 +int AUD_write (SWVoice *sw, void *pcm_buf, int size);
  168 +void AUD_adjust (SWVoice *sw, int leftover);
  169 +void AUD_reset (SWVoice *sw);
  170 +int AUD_get_free (SWVoice *sw);
  171 +int AUD_get_buffer_size (SWVoice *sw);
  172 +void AUD_run (void);
  173 +void AUD_enable (SWVoice *sw, int on);
  174 +int AUD_calc_elapsed (SWVoice *sw);
  175 +
  176 +static inline void *advance (void *p, int incr)
  177 +{
  178 + uint8_t *d = p;
  179 + return (d + incr);
  180 +}
  181 +
  182 +uint32_t popcount (uint32_t u);
  183 +inline uint32_t lsbindex (uint32_t u);
  184 +
  185 +#define audio_MIN(a, b) ((a)>(b)?(b):(a))
  186 +#define audio_MAX(a, b) ((a)<(b)?(b):(a))
  187 +
  188 +#endif /* audio.h */
... ...
audio/fmodaudio.c 0 → 100644
  1 +/*
  2 + * QEMU FMOD audio output driver
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include <fmod.h>
  25 +#include <fmod_errors.h>
  26 +#include "vl.h"
  27 +
  28 +#define AUDIO_CAP "fmod"
  29 +#include "audio/audio.h"
  30 +#include "audio/fmodaudio.h"
  31 +
  32 +#define QC_FMOD_DRV "QEMU_FMOD_DRV"
  33 +#define QC_FMOD_FREQ "QEMU_FMOD_FREQ"
  34 +#define QC_FMOD_SAMPLES "QEMU_FMOD_SAMPLES"
  35 +#define QC_FMOD_CHANNELS "QEMU_FMOD_CHANNELS"
  36 +#define QC_FMOD_BUFSIZE "QEMU_FMOD_BUFSIZE"
  37 +#define QC_FMOD_THRESHOLD "QEMU_FMOD_THRESHOLD"
  38 +
  39 +static struct {
  40 + int nb_samples;
  41 + int freq;
  42 + int nb_channels;
  43 + int bufsize;
  44 + int threshold;
  45 +} conf = {
  46 + 2048,
  47 + 44100,
  48 + 1,
  49 + 0,
  50 + 128
  51 +};
  52 +
  53 +#define errstr() FMOD_ErrorString (FSOUND_GetError ())
  54 +
  55 +static int fmod_hw_write (SWVoice *sw, void *buf, int len)
  56 +{
  57 + return pcm_hw_write (sw, buf, len);
  58 +}
  59 +
  60 +static void fmod_clear_sample (FMODVoice *fmd)
  61 +{
  62 + HWVoice *hw = &fmd->hw;
  63 + int status;
  64 + void *p1 = 0, *p2 = 0;
  65 + unsigned int len1 = 0, len2 = 0;
  66 +
  67 + status = FSOUND_Sample_Lock (
  68 + fmd->fmod_sample,
  69 + 0,
  70 + hw->samples << hw->shift,
  71 + &p1,
  72 + &p2,
  73 + &len1,
  74 + &len2
  75 + );
  76 +
  77 + if (!status) {
  78 + dolog ("Failed to lock sample\nReason: %s\n", errstr ());
  79 + return;
  80 + }
  81 +
  82 + if ((len1 & hw->align) || (len2 & hw->align)) {
  83 + dolog ("Locking sample returned unaligned length %d, %d\n",
  84 + len1, len2);
  85 + goto fail;
  86 + }
  87 +
  88 + if (len1 + len2 != hw->samples << hw->shift) {
  89 + dolog ("Locking sample returned incomplete length %d, %d\n",
  90 + len1 + len2, hw->samples << hw->shift);
  91 + goto fail;
  92 + }
  93 + pcm_hw_clear (hw, p1, hw->samples);
  94 +
  95 + fail:
  96 + status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2);
  97 + if (!status) {
  98 + dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
  99 + }
  100 +}
  101 +
  102 +static int fmod_write_sample (HWVoice *hw, uint8_t *dst, st_sample_t *src,
  103 + int src_size, int src_pos, int dst_len)
  104 +{
  105 + int src_len1 = dst_len, src_len2 = 0, pos = src_pos + dst_len;
  106 + st_sample_t *src1 = src + src_pos, *src2 = 0;
  107 +
  108 + if (src_pos + dst_len > src_size) {
  109 + src_len1 = src_size - src_pos;
  110 + src2 = src;
  111 + src_len2 = dst_len - src_len1;
  112 + pos = src_len2;
  113 + }
  114 +
  115 + if (src_len1) {
  116 + hw->clip (dst, src1, src_len1);
  117 + memset (src1, 0, src_len1 * sizeof (st_sample_t));
  118 + advance (dst, src_len1);
  119 + }
  120 +
  121 + if (src_len2) {
  122 + hw->clip (dst, src2, src_len2);
  123 + memset (src2, 0, src_len2 * sizeof (st_sample_t));
  124 + }
  125 + return pos;
  126 +}
  127 +
  128 +static int fmod_unlock_sample (FMODVoice *fmd, void *p1, void *p2,
  129 + unsigned int blen1, unsigned int blen2)
  130 +{
  131 + int status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, blen1, blen2);
  132 + if (!status) {
  133 + dolog ("Failed to unlock sample\nReason: %s\n", errstr ());
  134 + return -1;
  135 + }
  136 + return 0;
  137 +}
  138 +
  139 +static int fmod_lock_sample (FMODVoice *fmd, int pos, int len,
  140 + void **p1, void **p2,
  141 + unsigned int *blen1, unsigned int *blen2)
  142 +{
  143 + HWVoice *hw = &fmd->hw;
  144 + int status;
  145 +
  146 + status = FSOUND_Sample_Lock (
  147 + fmd->fmod_sample,
  148 + pos << hw->shift,
  149 + len << hw->shift,
  150 + p1,
  151 + p2,
  152 + blen1,
  153 + blen2
  154 + );
  155 +
  156 + if (!status) {
  157 + dolog ("Failed to lock sample\nReason: %s\n", errstr ());
  158 + return -1;
  159 + }
  160 +
  161 + if ((*blen1 & hw->align) || (*blen2 & hw->align)) {
  162 + dolog ("Locking sample returned unaligned length %d, %d\n",
  163 + *blen1, *blen2);
  164 + fmod_unlock_sample (fmd, *p1, *p2, *blen1, *blen2);
  165 + return -1;
  166 + }
  167 + return 0;
  168 +}
  169 +
  170 +static void fmod_hw_run (HWVoice *hw)
  171 +{
  172 + FMODVoice *fmd = (FMODVoice *) hw;
  173 + int rpos, live, decr;
  174 + void *p1 = 0, *p2 = 0;
  175 + unsigned int blen1 = 0, blen2 = 0;
  176 + unsigned int len1 = 0, len2 = 0;
  177 + int nb_active;
  178 +
  179 + live = pcm_hw_get_live2 (hw, &nb_active);
  180 + if (live <= 0) {
  181 + return;
  182 + }
  183 +
  184 + if (!hw->pending_disable
  185 + && nb_active
  186 + && conf.threshold
  187 + && live <= conf.threshold) {
  188 + ldebug ("live=%d nb_active=%d\n", live, nb_active);
  189 + return;
  190 + }
  191 +
  192 + decr = live;
  193 +
  194 +#if 1
  195 + if (fmd->channel >= 0) {
  196 + int pos2 = (fmd->old_pos + decr) % hw->samples;
  197 + int pos = FSOUND_GetCurrentPosition (fmd->channel);
  198 +
  199 + if (fmd->old_pos < pos && pos2 >= pos) {
  200 + decr = pos - fmd->old_pos - (pos2 == pos) - 1;
  201 + }
  202 + else if (fmd->old_pos > pos && pos2 >= pos && pos2 < fmd->old_pos) {
  203 + decr = (hw->samples - fmd->old_pos) + pos - (pos2 == pos) - 1;
  204 + }
  205 +/* ldebug ("pos=%d pos2=%d old=%d live=%d decr=%d\n", */
  206 +/* pos, pos2, fmd->old_pos, live, decr); */
  207 + }
  208 +#endif
  209 +
  210 + if (decr <= 0) {
  211 + return;
  212 + }
  213 +
  214 + if (fmod_lock_sample (fmd, fmd->old_pos, decr, &p1, &p2, &blen1, &blen2)) {
  215 + return;
  216 + }
  217 +
  218 + len1 = blen1 >> hw->shift;
  219 + len2 = blen2 >> hw->shift;
  220 + ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2);
  221 + decr = len1 + len2;
  222 + rpos = hw->rpos;
  223 +
  224 + if (len1) {
  225 + rpos = fmod_write_sample (hw, p1, hw->mix_buf, hw->samples, rpos, len1);
  226 + }
  227 +
  228 + if (len2) {
  229 + rpos = fmod_write_sample (hw, p2, hw->mix_buf, hw->samples, rpos, len2);
  230 + }
  231 +
  232 + fmod_unlock_sample (fmd, p1, p2, blen1, blen2);
  233 +
  234 + pcm_hw_dec_live (hw, decr);
  235 + hw->rpos = rpos % hw->samples;
  236 + fmd->old_pos = (fmd->old_pos + decr) % hw->samples;
  237 +}
  238 +
  239 +static int AUD_to_fmodfmt (audfmt_e fmt, int stereo)
  240 +{
  241 + int mode = FSOUND_LOOP_NORMAL;
  242 +
  243 + switch (fmt) {
  244 + case AUD_FMT_S8:
  245 + mode |= FSOUND_SIGNED | FSOUND_8BITS;
  246 + break;
  247 +
  248 + case AUD_FMT_U8:
  249 + mode |= FSOUND_UNSIGNED | FSOUND_8BITS;
  250 + break;
  251 +
  252 + case AUD_FMT_S16:
  253 + mode |= FSOUND_SIGNED | FSOUND_16BITS;
  254 + break;
  255 +
  256 + case AUD_FMT_U16:
  257 + mode |= FSOUND_UNSIGNED | FSOUND_16BITS;
  258 + break;
  259 +
  260 + default:
  261 + dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
  262 + exit (EXIT_FAILURE);
  263 + }
  264 + mode |= stereo ? FSOUND_STEREO : FSOUND_MONO;
  265 + return mode;
  266 +}
  267 +
  268 +static void fmod_hw_fini (HWVoice *hw)
  269 +{
  270 + FMODVoice *fmd = (FMODVoice *) hw;
  271 +
  272 + if (fmd->fmod_sample) {
  273 + FSOUND_Sample_Free (fmd->fmod_sample);
  274 + fmd->fmod_sample = 0;
  275 +
  276 + if (fmd->channel >= 0) {
  277 + FSOUND_StopSound (fmd->channel);
  278 + }
  279 + }
  280 +}
  281 +
  282 +static int fmod_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
  283 +{
  284 + int bits16, mode, channel;
  285 + FMODVoice *fmd = (FMODVoice *) hw;
  286 +
  287 + mode = AUD_to_fmodfmt (fmt, nchannels == 2 ? 1 : 0);
  288 + fmd->fmod_sample = FSOUND_Sample_Alloc (
  289 + FSOUND_FREE, /* index */
  290 + conf.nb_samples, /* length */
  291 + mode, /* mode */
  292 + freq, /* freq */
  293 + 255, /* volume */
  294 + 128, /* pan */
  295 + 255 /* priority */
  296 + );
  297 +
  298 + if (!fmd->fmod_sample) {
  299 + dolog ("Failed to allocate FMOD sample\nReason: %s\n", errstr ());
  300 + return -1;
  301 + }
  302 +
  303 + channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1);
  304 + if (channel < 0) {
  305 + dolog ("Failed to start playing sound\nReason: %s\n", errstr ());
  306 + FSOUND_Sample_Free (fmd->fmod_sample);
  307 + return -1;
  308 + }
  309 + fmd->channel = channel;
  310 +
  311 + hw->freq = freq;
  312 + hw->fmt = fmt;
  313 + hw->nchannels = nchannels;
  314 + bits16 = fmt == AUD_FMT_U16 || fmt == AUD_FMT_S16;
  315 + hw->bufsize = conf.nb_samples << (nchannels == 2) << bits16;
  316 + return 0;
  317 +}
  318 +
  319 +static int fmod_hw_ctl (HWVoice *hw, int cmd, ...)
  320 +{
  321 + int status;
  322 + FMODVoice *fmd = (FMODVoice *) hw;
  323 +
  324 + switch (cmd) {
  325 + case VOICE_ENABLE:
  326 + fmod_clear_sample (fmd);
  327 + status = FSOUND_SetPaused (fmd->channel, 0);
  328 + if (!status) {
  329 + dolog ("Failed to resume channel %d\nReason: %s\n",
  330 + fmd->channel, errstr ());
  331 + }
  332 + break;
  333 +
  334 + case VOICE_DISABLE:
  335 + status = FSOUND_SetPaused (fmd->channel, 1);
  336 + if (!status) {
  337 + dolog ("Failed to pause channel %d\nReason: %s\n",
  338 + fmd->channel, errstr ());
  339 + }
  340 + break;
  341 + }
  342 + return 0;
  343 +}
  344 +
  345 +static struct {
  346 + const char *name;
  347 + int type;
  348 +} drvtab[] = {
  349 + {"none", FSOUND_OUTPUT_NOSOUND},
  350 +#ifdef _WIN32
  351 + {"winmm", FSOUND_OUTPUT_WINMM},
  352 + {"dsound", FSOUND_OUTPUT_DSOUND},
  353 + {"a3d", FSOUND_OUTPUT_A3D},
  354 + {"asio", FSOUND_OUTPUT_ASIO},
  355 +#endif
  356 +#ifdef __linux__
  357 + {"oss", FSOUND_OUTPUT_OSS},
  358 + {"alsa", FSOUND_OUTPUT_ALSA},
  359 + {"esd", FSOUND_OUTPUT_ESD},
  360 +#endif
  361 +#ifdef __APPLE__
  362 + {"mac", FSOUND_OUTPUT_MAC},
  363 +#endif
  364 +#if 0
  365 + {"xbox", FSOUND_OUTPUT_XBOX},
  366 + {"ps2", FSOUND_OUTPUT_PS2},
  367 + {"gcube", FSOUND_OUTPUT_GC},
  368 +#endif
  369 + {"nort", FSOUND_OUTPUT_NOSOUND_NONREALTIME}
  370 +};
  371 +
  372 +static void *fmod_audio_init (void)
  373 +{
  374 + int i;
  375 + double ver;
  376 + int status;
  377 + int output_type = -1;
  378 + const char *drv = audio_get_conf_str (QC_FMOD_DRV, NULL);
  379 +
  380 + ver = FSOUND_GetVersion ();
  381 + if (ver < FMOD_VERSION) {
  382 + dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION);
  383 + return NULL;
  384 + }
  385 +
  386 + if (drv) {
  387 + int found = 0;
  388 + for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
  389 + if (!strcmp (drv, drvtab[i].name)) {
  390 + output_type = drvtab[i].type;
  391 + found = 1;
  392 + break;
  393 + }
  394 + }
  395 + if (!found) {
  396 + dolog ("Unknown FMOD output driver `%s'\n", drv);
  397 + }
  398 + }
  399 +
  400 + if (output_type != -1) {
  401 + status = FSOUND_SetOutput (output_type);
  402 + if (!status) {
  403 + dolog ("FSOUND_SetOutput(%d) failed\nReason: %s\n",
  404 + output_type, errstr ());
  405 + return NULL;
  406 + }
  407 + }
  408 +
  409 + conf.freq = audio_get_conf_int (QC_FMOD_FREQ, conf.freq);
  410 + conf.nb_samples = audio_get_conf_int (QC_FMOD_SAMPLES, conf.nb_samples);
  411 + conf.nb_channels =
  412 + audio_get_conf_int (QC_FMOD_CHANNELS,
  413 + (audio_state.nb_hw_voices > 1
  414 + ? audio_state.nb_hw_voices
  415 + : conf.nb_channels));
  416 + conf.bufsize = audio_get_conf_int (QC_FMOD_BUFSIZE, conf.bufsize);
  417 + conf.threshold = audio_get_conf_int (QC_FMOD_THRESHOLD, conf.threshold);
  418 +
  419 + if (conf.bufsize) {
  420 + status = FSOUND_SetBufferSize (conf.bufsize);
  421 + if (!status) {
  422 + dolog ("FSOUND_SetBufferSize (%d) failed\nReason: %s\n",
  423 + conf.bufsize, errstr ());
  424 + }
  425 + }
  426 +
  427 + status = FSOUND_Init (conf.freq, conf.nb_channels, 0);
  428 + if (!status) {
  429 + dolog ("FSOUND_Init failed\nReason: %s\n", errstr ());
  430 + return NULL;
  431 + }
  432 +
  433 + return &conf;
  434 +}
  435 +
  436 +static void fmod_audio_fini (void *opaque)
  437 +{
  438 + FSOUND_Close ();
  439 +}
  440 +
  441 +struct pcm_ops fmod_pcm_ops = {
  442 + fmod_hw_init,
  443 + fmod_hw_fini,
  444 + fmod_hw_run,
  445 + fmod_hw_write,
  446 + fmod_hw_ctl
  447 +};
  448 +
  449 +struct audio_output_driver fmod_output_driver = {
  450 + "fmod",
  451 + fmod_audio_init,
  452 + fmod_audio_fini,
  453 + &fmod_pcm_ops,
  454 + 1,
  455 + INT_MAX,
  456 + sizeof (FMODVoice)
  457 +};
... ...
audio/fmodaudio.h 0 → 100644
  1 +/*
  2 + * QEMU FMOD audio output driver header
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#ifndef QEMU_FMODAUDIO_H
  25 +#define QEMU_FMODAUDIO_H
  26 +
  27 +#include <fmod.h>
  28 +
  29 +typedef struct FMODVoice {
  30 + struct HWVoice hw;
  31 + unsigned int old_pos;
  32 + FSOUND_SAMPLE *fmod_sample;
  33 + int channel;
  34 +} FMODVoice;
  35 +
  36 +extern struct pcm_ops fmod_pcm_ops;
  37 +extern struct audio_output_driver fmod_output_driver;
  38 +
  39 +#endif /* fmodaudio.h */
... ...
audio/mixeng.c 0 → 100644
  1 +/*
  2 + * QEMU Mixing engine
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + * Copyright (c) 1998 Fabrice Bellard
  6 + *
  7 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  8 + * of this software and associated documentation files (the "Software"), to deal
  9 + * in the Software without restriction, including without limitation the rights
  10 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 + * copies of the Software, and to permit persons to whom the Software is
  12 + * furnished to do so, subject to the following conditions:
  13 + *
  14 + * The above copyright notice and this permission notice shall be included in
  15 + * all copies or substantial portions of the Software.
  16 + *
  17 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 + * THE SOFTWARE.
  24 + */
  25 +#include "vl.h"
  26 +//#define DEBUG_FP
  27 +#include "audio/mixeng.h"
  28 +
  29 +#define IN_T int8_t
  30 +#define IN_MIN CHAR_MIN
  31 +#define IN_MAX CHAR_MAX
  32 +#define SIGNED
  33 +#include "mixeng_template.h"
  34 +#undef SIGNED
  35 +#undef IN_MAX
  36 +#undef IN_MIN
  37 +#undef IN_T
  38 +
  39 +#define IN_T uint8_t
  40 +#define IN_MIN 0
  41 +#define IN_MAX UCHAR_MAX
  42 +#include "mixeng_template.h"
  43 +#undef IN_MAX
  44 +#undef IN_MIN
  45 +#undef IN_T
  46 +
  47 +#define IN_T int16_t
  48 +#define IN_MIN SHRT_MIN
  49 +#define IN_MAX SHRT_MAX
  50 +#define SIGNED
  51 +#include "mixeng_template.h"
  52 +#undef SIGNED
  53 +#undef IN_MAX
  54 +#undef IN_MIN
  55 +#undef IN_T
  56 +
  57 +#define IN_T uint16_t
  58 +#define IN_MIN 0
  59 +#define IN_MAX USHRT_MAX
  60 +#include "mixeng_template.h"
  61 +#undef IN_MAX
  62 +#undef IN_MIN
  63 +#undef IN_T
  64 +
  65 +t_sample *mixeng_conv[2][2][2] = {
  66 + {
  67 + {
  68 + conv_uint8_t_to_mono,
  69 + conv_uint16_t_to_mono
  70 + },
  71 + {
  72 + conv_int8_t_to_mono,
  73 + conv_int16_t_to_mono
  74 + }
  75 + },
  76 + {
  77 + {
  78 + conv_uint8_t_to_stereo,
  79 + conv_uint16_t_to_stereo
  80 + },
  81 + {
  82 + conv_int8_t_to_stereo,
  83 + conv_int16_t_to_stereo
  84 + }
  85 + }
  86 +};
  87 +
  88 +f_sample *mixeng_clip[2][2][2] = {
  89 + {
  90 + {
  91 + clip_uint8_t_from_mono,
  92 + clip_uint16_t_from_mono
  93 + },
  94 + {
  95 + clip_int8_t_from_mono,
  96 + clip_int16_t_from_mono
  97 + }
  98 + },
  99 + {
  100 + {
  101 + clip_uint8_t_from_stereo,
  102 + clip_uint16_t_from_stereo
  103 + },
  104 + {
  105 + clip_int8_t_from_stereo,
  106 + clip_int16_t_from_stereo
  107 + }
  108 + }
  109 +};
  110 +
  111 +/*
  112 + * August 21, 1998
  113 + * Copyright 1998 Fabrice Bellard.
  114 + *
  115 + * [Rewrote completly the code of Lance Norskog And Sundry
  116 + * Contributors with a more efficient algorithm.]
  117 + *
  118 + * This source code is freely redistributable and may be used for
  119 + * any purpose. This copyright notice must be maintained.
  120 + * Lance Norskog And Sundry Contributors are not responsible for
  121 + * the consequences of using this software.
  122 + */
  123 +
  124 +/*
  125 + * Sound Tools rate change effect file.
  126 + */
  127 +/*
  128 + * Linear Interpolation.
  129 + *
  130 + * The use of fractional increment allows us to use no buffer. It
  131 + * avoid the problems at the end of the buffer we had with the old
  132 + * method which stored a possibly big buffer of size
  133 + * lcm(in_rate,out_rate).
  134 + *
  135 + * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If
  136 + * the input & output frequencies are equal, a delay of one sample is
  137 + * introduced. Limited to processing 32-bit count worth of samples.
  138 + *
  139 + * 1 << FRAC_BITS evaluating to zero in several places. Changed with
  140 + * an (unsigned long) cast to make it safe. MarkMLl 2/1/99
  141 + */
  142 +
  143 +/* Private data */
  144 +typedef struct ratestuff {
  145 + uint64_t opos;
  146 + uint64_t opos_inc;
  147 + uint32_t ipos; /* position in the input stream (integer) */
  148 + st_sample_t ilast; /* last sample in the input stream */
  149 +} *rate_t;
  150 +
  151 +/*
  152 + * Prepare processing.
  153 + */
  154 +void *st_rate_start (int inrate, int outrate)
  155 +{
  156 + rate_t rate = (rate_t) qemu_mallocz (sizeof (struct ratestuff));
  157 +
  158 + if (!rate) {
  159 + exit (EXIT_FAILURE);
  160 + }
  161 +
  162 + if (inrate == outrate) {
  163 + // exit (EXIT_FAILURE);
  164 + }
  165 +
  166 + if (inrate >= 65535 || outrate >= 65535) {
  167 + // exit (EXIT_FAILURE);
  168 + }
  169 +
  170 + rate->opos = 0;
  171 +
  172 + /* increment */
  173 + rate->opos_inc = (inrate * ((int64_t) UINT_MAX)) / outrate;
  174 +
  175 + rate->ipos = 0;
  176 + rate->ilast.l = 0;
  177 + rate->ilast.r = 0;
  178 + return rate;
  179 +}
  180 +
  181 +/*
  182 + * Processed signed long samples from ibuf to obuf.
  183 + * Return number of samples processed.
  184 + */
  185 +void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
  186 + int *isamp, int *osamp)
  187 +{
  188 + rate_t rate = (rate_t) opaque;
  189 + st_sample_t *istart, *iend;
  190 + st_sample_t *ostart, *oend;
  191 + st_sample_t ilast, icur, out;
  192 + int64_t t;
  193 +
  194 + ilast = rate->ilast;
  195 +
  196 + istart = ibuf;
  197 + iend = ibuf + *isamp;
  198 +
  199 + ostart = obuf;
  200 + oend = obuf + *osamp;
  201 +
  202 + if (rate->opos_inc == 1ULL << 32) {
  203 + int i, n = *isamp > *osamp ? *osamp : *isamp;
  204 + for (i = 0; i < n; i++) {
  205 + obuf[i].l += ibuf[i].r;
  206 + obuf[i].r += ibuf[i].r;
  207 + }
  208 + *isamp = n;
  209 + *osamp = n;
  210 + return;
  211 + }
  212 +
  213 + while (obuf < oend) {
  214 +
  215 + /* Safety catch to make sure we have input samples. */
  216 + if (ibuf >= iend)
  217 + break;
  218 +
  219 + /* read as many input samples so that ipos > opos */
  220 +
  221 + while (rate->ipos <= (rate->opos >> 32)) {
  222 + ilast = *ibuf++;
  223 + rate->ipos++;
  224 + /* See if we finished the input buffer yet */
  225 + if (ibuf >= iend) goto the_end;
  226 + }
  227 +
  228 + icur = *ibuf;
  229 +
  230 + /* interpolate */
  231 + t = rate->opos & 0xffffffff;
  232 + out.l = (ilast.l * (INT_MAX - t) + icur.l * t) / INT_MAX;
  233 + out.r = (ilast.r * (INT_MAX - t) + icur.r * t) / INT_MAX;
  234 +
  235 + /* output sample & increment position */
  236 +#if 0
  237 + *obuf++ = out;
  238 +#else
  239 + obuf->l += out.l;
  240 + obuf->r += out.r;
  241 + obuf += 1;
  242 +#endif
  243 + rate->opos += rate->opos_inc;
  244 + }
  245 +
  246 +the_end:
  247 + *isamp = ibuf - istart;
  248 + *osamp = obuf - ostart;
  249 + rate->ilast = ilast;
  250 +}
  251 +
  252 +void st_rate_stop (void *opaque)
  253 +{
  254 + qemu_free (opaque);
  255 +}
... ...
audio/mixeng.h 0 → 100644
  1 +/*
  2 + * QEMU Mixing engine header
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#ifndef QEMU_MIXENG_H
  25 +#define QEMU_MIXENG_H
  26 +
  27 +typedef void (t_sample) (void *dst, const void *src, int samples);
  28 +typedef void (f_sample) (void *dst, const void *src, int samples);
  29 +typedef struct { int64_t l; int64_t r; } st_sample_t;
  30 +
  31 +extern t_sample *mixeng_conv[2][2][2];
  32 +extern f_sample *mixeng_clip[2][2][2];
  33 +
  34 +void *st_rate_start (int inrate, int outrate);
  35 +void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
  36 + int *isamp, int *osamp);
  37 +void st_rate_stop (void *opaque);
  38 +
  39 +#endif /* mixeng.h */
... ...
audio/mixeng_template.h 0 → 100644
  1 +/*
  2 + * QEMU Mixing engine
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +/*
  26 + * Tusen tack till Mike Nordell
  27 + * dec++'ified by Dscho
  28 + */
  29 +
  30 +#ifdef SIGNED
  31 +#define HALFT IN_MAX
  32 +#define HALF IN_MAX
  33 +#else
  34 +#define HALFT ((IN_MAX)>>1)
  35 +#define HALF HALFT
  36 +#endif
  37 +
  38 +static int64_t inline glue(conv_,IN_T) (IN_T v)
  39 +{
  40 +#ifdef SIGNED
  41 + return (INT_MAX*(int64_t)v)/HALF;
  42 +#else
  43 + return (INT_MAX*((int64_t)v-HALFT))/HALF;
  44 +#endif
  45 +}
  46 +
  47 +static IN_T inline glue(clip_,IN_T) (int64_t v)
  48 +{
  49 + if (v >= INT_MAX)
  50 + return IN_MAX;
  51 + else if (v < -INT_MAX)
  52 + return IN_MIN;
  53 +
  54 +#ifdef SIGNED
  55 + return (IN_T) (v*HALF/INT_MAX);
  56 +#else
  57 + return (IN_T) (v+INT_MAX/2)*HALF/INT_MAX;
  58 +#endif
  59 +}
  60 +
  61 +static void glue(glue(conv_,IN_T),_to_stereo) (void *dst, const void *src,
  62 + int samples)
  63 +{
  64 + st_sample_t *out = (st_sample_t *) dst;
  65 + IN_T *in = (IN_T *) src;
  66 + while (samples--) {
  67 + out->l = glue(conv_,IN_T) (*in++);
  68 + out->r = glue(conv_,IN_T) (*in++);
  69 + out += 1;
  70 + }
  71 +}
  72 +
  73 +static void glue(glue(conv_,IN_T),_to_mono) (void *dst, const void *src,
  74 + int samples)
  75 +{
  76 + st_sample_t *out = (st_sample_t *) dst;
  77 + IN_T *in = (IN_T *) src;
  78 + while (samples--) {
  79 + out->l = glue(conv_,IN_T) (in[0]);
  80 + out->r = out->l;
  81 + out += 1;
  82 + in += 1;
  83 + }
  84 +}
  85 +
  86 +static void glue(glue(clip_,IN_T),_from_stereo) (void *dst, const void *src,
  87 + int samples)
  88 +{
  89 + st_sample_t *in = (st_sample_t *) src;
  90 + IN_T *out = (IN_T *) dst;
  91 + while (samples--) {
  92 + *out++ = glue(clip_,IN_T) (in->l);
  93 + *out++ = glue(clip_,IN_T) (in->r);
  94 + in += 1;
  95 + }
  96 +}
  97 +
  98 +static void glue(glue(clip_,IN_T),_from_mono) (void *dst, const void *src,
  99 + int samples)
  100 +{
  101 + st_sample_t *in = (st_sample_t *) src;
  102 + IN_T *out = (IN_T *) dst;
  103 + while (samples--) {
  104 + *out++ = glue(clip_,IN_T) (in->l + in->r);
  105 + in += 1;
  106 + }
  107 +}
  108 +
  109 +#undef HALF
  110 +#undef HALFT
  111 +
... ...
audio/ossaudio.c 0 → 100644
  1 +/*
  2 + * QEMU OSS audio output driver
  3 + *
  4 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +
  25 +/* Temporary kludge */
  26 +#if defined __linux__ || (defined _BSD && !defined __APPLE__)
  27 +#include <assert.h>
  28 +#include "vl.h"
  29 +
  30 +#include <sys/mman.h>
  31 +#include <sys/types.h>
  32 +#include <sys/ioctl.h>
  33 +#include <sys/soundcard.h>
  34 +
  35 +#define AUDIO_CAP "oss"
  36 +#include "audio/audio.h"
  37 +#include "audio/ossaudio.h"
  38 +
  39 +#define QC_OSS_FRAGSIZE "QEMU_OSS_FRAGSIZE"
  40 +#define QC_OSS_NFRAGS "QEMU_OSS_NFRAGS"
  41 +#define QC_OSS_MMAP "QEMU_OSS_MMAP"
  42 +#define QC_OSS_DEV "QEMU_OSS_DEV"
  43 +
  44 +#define errstr() strerror (errno)
  45 +
  46 +static struct {
  47 + int try_mmap;
  48 + int nfrags;
  49 + int fragsize;
  50 + const char *dspname;
  51 +} conf = {
  52 + .try_mmap = 0,
  53 + .nfrags = 4,
  54 + .fragsize = 4096,
  55 + .dspname = "/dev/dsp"
  56 +};
  57 +
  58 +struct oss_params {
  59 + int freq;
  60 + audfmt_e fmt;
  61 + int nchannels;
  62 + int nfrags;
  63 + int fragsize;
  64 +};
  65 +
  66 +static int oss_hw_write (SWVoice *sw, void *buf, int len)
  67 +{
  68 + return pcm_hw_write (sw, buf, len);
  69 +}
  70 +
  71 +static int AUD_to_ossfmt (audfmt_e fmt)
  72 +{
  73 + switch (fmt) {
  74 + case AUD_FMT_S8: return AFMT_S8;
  75 + case AUD_FMT_U8: return AFMT_U8;
  76 + case AUD_FMT_S16: return AFMT_S16_LE;
  77 + case AUD_FMT_U16: return AFMT_U16_LE;
  78 + default:
  79 + dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
  80 + exit (EXIT_FAILURE);
  81 + }
  82 +}
  83 +
  84 +static int oss_to_audfmt (int fmt)
  85 +{
  86 + switch (fmt) {
  87 + case AFMT_S8: return AUD_FMT_S8;
  88 + case AFMT_U8: return AUD_FMT_U8;
  89 + case AFMT_S16_LE: return AUD_FMT_S16;
  90 + case AFMT_U16_LE: return AUD_FMT_U16;
  91 + default:
  92 + dolog ("Internal logic error: Unrecognized OSS audio format %d\n"
  93 + "Aborting\n",
  94 + fmt);
  95 + exit (EXIT_FAILURE);
  96 + }
  97 +}
  98 +
  99 +#ifdef DEBUG_PCM
  100 +static void oss_dump_pcm_info (struct oss_params *req, struct oss_params *obt)
  101 +{
  102 + dolog ("parameter | requested value | obtained value\n");
  103 + dolog ("format | %10d | %10d\n", req->fmt, obt->fmt);
  104 + dolog ("channels | %10d | %10d\n", req->nchannels, obt->nchannels);
  105 + dolog ("frequency | %10d | %10d\n", req->freq, obt->freq);
  106 + dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags);
  107 + dolog ("fragsize | %10d | %10d\n", req->fragsize, obt->fragsize);
  108 +}
  109 +#endif
  110 +
  111 +static int oss_open (struct oss_params *req, struct oss_params *obt, int *pfd)
  112 +{
  113 + int fd;
  114 + int mmmmssss;
  115 + audio_buf_info abinfo;
  116 + int fmt, freq, nchannels;
  117 + const char *dspname = conf.dspname;
  118 +
  119 + fd = open (dspname, O_RDWR | O_NONBLOCK);
  120 + if (-1 == fd) {
  121 + dolog ("Could not initialize audio hardware. Failed to open `%s':\n"
  122 + "Reason:%s\n",
  123 + dspname,
  124 + errstr ());
  125 + return -1;
  126 + }
  127 +
  128 + freq = req->freq;
  129 + nchannels = req->nchannels;
  130 + fmt = req->fmt;
  131 +
  132 + if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) {
  133 + dolog ("Could not initialize audio hardware\n"
  134 + "Failed to set sample size\n"
  135 + "Reason: %s\n",
  136 + errstr ());
  137 + goto err;
  138 + }
  139 +
  140 + if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) {
  141 + dolog ("Could not initialize audio hardware\n"
  142 + "Failed to set number of channels\n"
  143 + "Reason: %s\n",
  144 + errstr ());
  145 + goto err;
  146 + }
  147 +
  148 + if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) {
  149 + dolog ("Could not initialize audio hardware\n"
  150 + "Failed to set frequency\n"
  151 + "Reason: %s\n",
  152 + errstr ());
  153 + goto err;
  154 + }
  155 +
  156 + if (ioctl (fd, SNDCTL_DSP_NONBLOCK)) {
  157 + dolog ("Could not initialize audio hardware\n"
  158 + "Failed to set non-blocking mode\n"
  159 + "Reason: %s\n",
  160 + errstr ());
  161 + goto err;
  162 + }
  163 +
  164 + mmmmssss = (req->nfrags << 16) | lsbindex (req->fragsize);
  165 + if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) {
  166 + dolog ("Could not initialize audio hardware\n"
  167 + "Failed to set buffer length (%d, %d)\n"
  168 + "Reason:%s\n",
  169 + conf.nfrags, conf.fragsize,
  170 + errstr ());
  171 + goto err;
  172 + }
  173 +
  174 + if (ioctl (fd, SNDCTL_DSP_GETOSPACE, &abinfo)) {
  175 + dolog ("Could not initialize audio hardware\n"
  176 + "Failed to get buffer length\n"
  177 + "Reason:%s\n",
  178 + errstr ());
  179 + goto err;
  180 + }
  181 +
  182 + obt->fmt = fmt;
  183 + obt->nchannels = nchannels;
  184 + obt->freq = freq;
  185 + obt->nfrags = abinfo.fragstotal;
  186 + obt->fragsize = abinfo.fragsize;
  187 + *pfd = fd;
  188 +
  189 + if ((req->fmt != obt->fmt) ||
  190 + (req->nchannels != obt->nchannels) ||
  191 + (req->freq != obt->freq) ||
  192 + (req->fragsize != obt->fragsize) ||
  193 + (req->nfrags != obt->nfrags)) {
  194 +#ifdef DEBUG_PCM
  195 + dolog ("Audio parameters mismatch\n");
  196 + oss_dump_pcm_info (req, obt);
  197 +#endif
  198 + }
  199 +
  200 +#ifdef DEBUG_PCM
  201 + oss_dump_pcm_info (req, obt);
  202 +#endif
  203 + return 0;
  204 +
  205 +err:
  206 + close (fd);
  207 + return -1;
  208 +}
  209 +
  210 +static void oss_hw_run (HWVoice *hw)
  211 +{
  212 + OSSVoice *oss = (OSSVoice *) hw;
  213 + int err, rpos, live, decr;
  214 + int samples;
  215 + uint8_t *dst;
  216 + st_sample_t *src;
  217 + struct audio_buf_info abinfo;
  218 + struct count_info cntinfo;
  219 +
  220 + live = pcm_hw_get_live (hw);
  221 + if (live <= 0)
  222 + return;
  223 +
  224 + if (oss->mmapped) {
  225 + int bytes;
  226 +
  227 + err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo);
  228 + if (err < 0) {
  229 + dolog ("SNDCTL_DSP_GETOPTR failed\nReason: %s\n", errstr ());
  230 + return;
  231 + }
  232 +
  233 + if (cntinfo.ptr == oss->old_optr) {
  234 + if (abs (hw->samples - live) < 64)
  235 + dolog ("overrun\n");
  236 + return;
  237 + }
  238 +
  239 + if (cntinfo.ptr > oss->old_optr) {
  240 + bytes = cntinfo.ptr - oss->old_optr;
  241 + }
  242 + else {
  243 + bytes = hw->bufsize + cntinfo.ptr - oss->old_optr;
  244 + }
  245 +
  246 + decr = audio_MIN (bytes >> hw->shift, live);
  247 + }
  248 + else {
  249 + err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo);
  250 + if (err < 0) {
  251 + dolog ("SNDCTL_DSP_GETOSPACE failed\nReason: %s\n", errstr ());
  252 + return;
  253 + }
  254 +
  255 + decr = audio_MIN (abinfo.bytes >> hw->shift, live);
  256 + if (decr <= 0)
  257 + return;
  258 + }
  259 +
  260 + samples = decr;
  261 + rpos = hw->rpos;
  262 + while (samples) {
  263 + int left_till_end_samples = hw->samples - rpos;
  264 + int convert_samples = audio_MIN (samples, left_till_end_samples);
  265 +
  266 + src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
  267 + dst = advance (oss->pcm_buf, rpos << hw->shift);
  268 +
  269 + hw->clip (dst, src, convert_samples);
  270 + if (!oss->mmapped) {
  271 + int written;
  272 +
  273 + written = write (oss->fd, dst, convert_samples << hw->shift);
  274 + /* XXX: follow errno recommendations ? */
  275 + if (written == -1) {
  276 + dolog ("Failed to write audio\nReason: %s\n", errstr ());
  277 + continue;
  278 + }
  279 +
  280 + if (written != convert_samples << hw->shift) {
  281 + int wsamples = written >> hw->shift;
  282 + int wbytes = wsamples << hw->shift;
  283 + if (wbytes != written) {
  284 + dolog ("Unaligned write %d, %d\n", wbytes, written);
  285 + }
  286 + memset (src, 0, wbytes);
  287 + decr -= samples;
  288 + rpos = (rpos + wsamples) % hw->samples;
  289 + break;
  290 + }
  291 + }
  292 + memset (src, 0, convert_samples * sizeof (st_sample_t));
  293 +
  294 + rpos = (rpos + convert_samples) % hw->samples;
  295 + samples -= convert_samples;
  296 + }
  297 + if (oss->mmapped) {
  298 + oss->old_optr = cntinfo.ptr;
  299 + }
  300 +
  301 + pcm_hw_dec_live (hw, decr);
  302 + hw->rpos = rpos;
  303 +}
  304 +
  305 +static void oss_hw_fini (HWVoice *hw)
  306 +{
  307 + int err;
  308 + OSSVoice *oss = (OSSVoice *) hw;
  309 +
  310 + ldebug ("oss_hw_fini\n");
  311 + err = close (oss->fd);
  312 + if (err) {
  313 + dolog ("Failed to close OSS descriptor\nReason: %s\n", errstr ());
  314 + }
  315 + oss->fd = -1;
  316 +
  317 + if (oss->pcm_buf) {
  318 + if (oss->mmapped) {
  319 + err = munmap (oss->pcm_buf, hw->bufsize);
  320 + if (err) {
  321 + dolog ("Failed to unmap OSS buffer\nReason: %s\n",
  322 + errstr ());
  323 + }
  324 + }
  325 + else {
  326 + qemu_free (oss->pcm_buf);
  327 + }
  328 + oss->pcm_buf = NULL;
  329 + }
  330 +}
  331 +
  332 +static int oss_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
  333 +{
  334 + OSSVoice *oss = (OSSVoice *) hw;
  335 + struct oss_params req, obt;
  336 +
  337 + assert (!oss->fd);
  338 + req.fmt = AUD_to_ossfmt (fmt);
  339 + req.freq = freq;
  340 + req.nchannels = nchannels;
  341 + req.fragsize = conf.fragsize;
  342 + req.nfrags = conf.nfrags;
  343 +
  344 + if (oss_open (&req, &obt, &oss->fd))
  345 + return -1;
  346 +
  347 + hw->freq = obt.freq;
  348 + hw->fmt = oss_to_audfmt (obt.fmt);
  349 + hw->nchannels = obt.nchannels;
  350 +
  351 + oss->nfrags = obt.nfrags;
  352 + oss->fragsize = obt.fragsize;
  353 + hw->bufsize = obt.nfrags * obt.fragsize;
  354 +
  355 + oss->mmapped = 0;
  356 + if (conf.try_mmap) {
  357 + oss->pcm_buf = mmap (0, hw->bufsize, PROT_READ | PROT_WRITE,
  358 + MAP_SHARED, oss->fd, 0);
  359 + if (oss->pcm_buf == MAP_FAILED) {
  360 + dolog ("Failed to mmap OSS device\nReason: %s\n",
  361 + errstr ());
  362 + }
  363 +
  364 + for (;;) {
  365 + int err;
  366 + int trig = 0;
  367 + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  368 + dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
  369 + errstr ());
  370 + goto fail;
  371 + }
  372 +
  373 + trig = PCM_ENABLE_OUTPUT;
  374 + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  375 + dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
  376 + "Reason: %s\n", errstr ());
  377 + goto fail;
  378 + }
  379 + oss->mmapped = 1;
  380 + break;
  381 +
  382 + fail:
  383 + err = munmap (oss->pcm_buf, hw->bufsize);
  384 + if (err) {
  385 + dolog ("Failed to unmap OSS device\nReason: %s\n",
  386 + errstr ());
  387 + }
  388 + }
  389 + }
  390 +
  391 + if (!oss->mmapped) {
  392 + oss->pcm_buf = qemu_mallocz (hw->bufsize);
  393 + if (!oss->pcm_buf) {
  394 + close (oss->fd);
  395 + oss->fd = -1;
  396 + return -1;
  397 + }
  398 + }
  399 +
  400 + return 0;
  401 +}
  402 +
  403 +static int oss_hw_ctl (HWVoice *hw, int cmd, ...)
  404 +{
  405 + int trig;
  406 + OSSVoice *oss = (OSSVoice *) hw;
  407 +
  408 + if (!oss->mmapped)
  409 + return 0;
  410 +
  411 + switch (cmd) {
  412 + case VOICE_ENABLE:
  413 + ldebug ("enabling voice\n");
  414 + pcm_hw_clear (hw, oss->pcm_buf, hw->samples);
  415 + trig = PCM_ENABLE_OUTPUT;
  416 + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  417 + dolog ("SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
  418 + "Reason: %s\n", errstr ());
  419 + return -1;
  420 + }
  421 + break;
  422 +
  423 + case VOICE_DISABLE:
  424 + ldebug ("disabling voice\n");
  425 + trig = 0;
  426 + if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
  427 + dolog ("SNDCTL_DSP_SETTRIGGER 0 failed\nReason: %s\n",
  428 + errstr ());
  429 + return -1;
  430 + }
  431 + break;
  432 + }
  433 + return 0;
  434 +}
  435 +
  436 +static void *oss_audio_init (void)
  437 +{
  438 + conf.fragsize = audio_get_conf_int (QC_OSS_FRAGSIZE, conf.fragsize);
  439 + conf.nfrags = audio_get_conf_int (QC_OSS_NFRAGS, conf.nfrags);
  440 + conf.try_mmap = audio_get_conf_int (QC_OSS_MMAP, conf.try_mmap);
  441 + conf.dspname = audio_get_conf_str (QC_OSS_DEV, conf.dspname);
  442 + return &conf;
  443 +}
  444 +
  445 +static void oss_audio_fini (void *opaque)
  446 +{
  447 +}
  448 +
  449 +struct pcm_ops oss_pcm_ops = {
  450 + oss_hw_init,
  451 + oss_hw_fini,
  452 + oss_hw_run,
  453 + oss_hw_write,
  454 + oss_hw_ctl
  455 +};
  456 +
  457 +struct audio_output_driver oss_output_driver = {
  458 + "oss",
  459 + oss_audio_init,
  460 + oss_audio_fini,
  461 + &oss_pcm_ops,
  462 + 1,
  463 + INT_MAX,
  464 + sizeof (OSSVoice)
  465 +};
  466 +#endif
... ...
audio/ossaudio.h 0 → 100644
  1 +/*
  2 + * QEMU OSS audio output driver header
  3 + *
  4 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#ifndef QEMU_OSSAUDIO_H
  25 +#define QEMU_OSSAUDIO_H
  26 +
  27 +typedef struct OSSVoice {
  28 + struct HWVoice hw;
  29 + void *pcm_buf;
  30 + int fd;
  31 + int nfrags;
  32 + int fragsize;
  33 + int mmapped;
  34 + int old_optr;
  35 +} OSSVoice;
  36 +
  37 +extern struct pcm_ops oss_pcm_ops;
  38 +extern struct audio_output_driver oss_output_driver;
  39 +
  40 +#endif /* ossaudio.h */
... ...
audio/sdlaudio.c 0 → 100644
  1 +/*
  2 + * QEMU SDL audio output driver
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include <SDL/SDL.h>
  25 +#include <SDL/SDL_thread.h>
  26 +#include "vl.h"
  27 +
  28 +#define AUDIO_CAP "sdl"
  29 +#include "audio/audio.h"
  30 +#include "audio/sdlaudio.h"
  31 +
  32 +#define QC_SDL_SAMPLES "QEMU_SDL_SAMPLES"
  33 +
  34 +#define errstr() SDL_GetError ()
  35 +
  36 +static struct {
  37 + int nb_samples;
  38 +} conf = {
  39 + 1024
  40 +};
  41 +
  42 +struct SDLAudioState {
  43 + int exit;
  44 + SDL_mutex *mutex;
  45 + SDL_sem *sem;
  46 + int initialized;
  47 +} glob_sdl;
  48 +typedef struct SDLAudioState SDLAudioState;
  49 +
  50 +static void sdl_hw_run (HWVoice *hw)
  51 +{
  52 + (void) hw;
  53 +}
  54 +
  55 +static int sdl_lock (SDLAudioState *s)
  56 +{
  57 + if (SDL_LockMutex (s->mutex)) {
  58 + dolog ("SDL_LockMutex failed\nReason: %s\n", errstr ());
  59 + return -1;
  60 + }
  61 + return 0;
  62 +}
  63 +
  64 +static int sdl_unlock (SDLAudioState *s)
  65 +{
  66 + if (SDL_UnlockMutex (s->mutex)) {
  67 + dolog ("SDL_UnlockMutex failed\nReason: %s\n", errstr ());
  68 + return -1;
  69 + }
  70 + return 0;
  71 +}
  72 +
  73 +static int sdl_post (SDLAudioState *s)
  74 +{
  75 + if (SDL_SemPost (s->sem)) {
  76 + dolog ("SDL_SemPost failed\nReason: %s\n", errstr ());
  77 + return -1;
  78 + }
  79 + return 0;
  80 +}
  81 +
  82 +static int sdl_wait (SDLAudioState *s)
  83 +{
  84 + if (SDL_SemWait (s->sem)) {
  85 + dolog ("SDL_SemWait failed\nReason: %s\n", errstr ());
  86 + return -1;
  87 + }
  88 + return 0;
  89 +}
  90 +
  91 +static int sdl_unlock_and_post (SDLAudioState *s)
  92 +{
  93 + if (sdl_unlock (s))
  94 + return -1;
  95 +
  96 + return sdl_post (s);
  97 +}
  98 +
  99 +static int sdl_hw_write (SWVoice *sw, void *buf, int len)
  100 +{
  101 + int ret;
  102 + SDLAudioState *s = &glob_sdl;
  103 + sdl_lock (s);
  104 + ret = pcm_hw_write (sw, buf, len);
  105 + sdl_unlock_and_post (s);
  106 + return ret;
  107 +}
  108 +
  109 +static int AUD_to_sdlfmt (audfmt_e fmt, int *shift)
  110 +{
  111 + *shift = 0;
  112 + switch (fmt) {
  113 + case AUD_FMT_S8: return AUDIO_S8;
  114 + case AUD_FMT_U8: return AUDIO_U8;
  115 + case AUD_FMT_S16: *shift = 1; return AUDIO_S16LSB;
  116 + case AUD_FMT_U16: *shift = 1; return AUDIO_U16LSB;
  117 + default:
  118 + dolog ("Internal logic error: Bad audio format %d\nAborting\n", fmt);
  119 + exit (EXIT_FAILURE);
  120 + }
  121 +}
  122 +
  123 +static int sdl_to_audfmt (int fmt)
  124 +{
  125 + switch (fmt) {
  126 + case AUDIO_S8: return AUD_FMT_S8;
  127 + case AUDIO_U8: return AUD_FMT_U8;
  128 + case AUDIO_S16LSB: return AUD_FMT_S16;
  129 + case AUDIO_U16LSB: return AUD_FMT_U16;
  130 + default:
  131 + dolog ("Internal logic error: Unrecognized SDL audio format %d\n"
  132 + "Aborting\n", fmt);
  133 + exit (EXIT_FAILURE);
  134 + }
  135 +}
  136 +
  137 +static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
  138 +{
  139 + int status;
  140 +
  141 + status = SDL_OpenAudio (req, obt);
  142 + if (status) {
  143 + dolog ("SDL_OpenAudio failed\nReason: %s\n", errstr ());
  144 + }
  145 + return status;
  146 +}
  147 +
  148 +static void sdl_close (SDLAudioState *s)
  149 +{
  150 + if (s->initialized) {
  151 + sdl_lock (s);
  152 + s->exit = 1;
  153 + sdl_unlock_and_post (s);
  154 + SDL_PauseAudio (1);
  155 + SDL_CloseAudio ();
  156 + s->initialized = 0;
  157 + }
  158 +}
  159 +
  160 +static void sdl_callback (void *opaque, Uint8 *buf, int len)
  161 +{
  162 + SDLVoice *sdl = opaque;
  163 + SDLAudioState *s = &glob_sdl;
  164 + HWVoice *hw = &sdl->hw;
  165 + int samples = len >> hw->shift;
  166 +
  167 + if (s->exit) {
  168 + return;
  169 + }
  170 +
  171 + while (samples) {
  172 + int to_mix, live, decr;
  173 +
  174 + /* dolog ("in callback samples=%d\n", samples); */
  175 + sdl_wait (s);
  176 + if (s->exit) {
  177 + return;
  178 + }
  179 +
  180 + sdl_lock (s);
  181 + live = pcm_hw_get_live (hw);
  182 + if (live <= 0)
  183 + goto again;
  184 +
  185 + /* dolog ("in callback live=%d\n", live); */
  186 + to_mix = audio_MIN (samples, live);
  187 + decr = to_mix;
  188 + while (to_mix) {
  189 + int chunk = audio_MIN (to_mix, hw->samples - hw->rpos);
  190 + st_sample_t *src = hw->mix_buf + hw->rpos;
  191 +
  192 + /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
  193 + hw->clip (buf, src, chunk);
  194 + memset (src, 0, chunk * sizeof (st_sample_t));
  195 + hw->rpos = (hw->rpos + chunk) % hw->samples;
  196 + to_mix -= chunk;
  197 + buf += chunk << hw->shift;
  198 + }
  199 + samples -= decr;
  200 + pcm_hw_dec_live (hw, decr);
  201 +
  202 + again:
  203 + sdl_unlock (s);
  204 + }
  205 + /* dolog ("done len=%d\n", len); */
  206 +}
  207 +
  208 +static void sdl_hw_fini (HWVoice *hw)
  209 +{
  210 + ldebug ("sdl_hw_fini %d fixed=%d\n",
  211 + glob_sdl.initialized, audio_conf.fixed_format);
  212 + sdl_close (&glob_sdl);
  213 +}
  214 +
  215 +static int sdl_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
  216 +{
  217 + SDLVoice *sdl = (SDLVoice *) hw;
  218 + SDLAudioState *s = &glob_sdl;
  219 + SDL_AudioSpec req, obt;
  220 + int shift;
  221 +
  222 + ldebug ("sdl_hw_init %d freq=%d fixed=%d\n",
  223 + s->initialized, freq, audio_conf.fixed_format);
  224 +
  225 + if (nchannels != 2) {
  226 + dolog ("Bogus channel count %d\n", nchannels);
  227 + return -1;
  228 + }
  229 +
  230 + req.freq = freq;
  231 + req.format = AUD_to_sdlfmt (fmt, &shift);
  232 + req.channels = nchannels;
  233 + req.samples = conf.nb_samples;
  234 + shift <<= nchannels == 2;
  235 +
  236 + req.callback = sdl_callback;
  237 + req.userdata = sdl;
  238 +
  239 + if (sdl_open (&req, &obt))
  240 + return -1;
  241 +
  242 + hw->freq = obt.freq;
  243 + hw->fmt = sdl_to_audfmt (obt.format);
  244 + hw->nchannels = obt.channels;
  245 + hw->bufsize = obt.samples << shift;
  246 +
  247 + s->initialized = 1;
  248 + s->exit = 0;
  249 + SDL_PauseAudio (0);
  250 + return 0;
  251 +}
  252 +
  253 +static int sdl_hw_ctl (HWVoice *hw, int cmd, ...)
  254 +{
  255 + (void) hw;
  256 +
  257 + switch (cmd) {
  258 + case VOICE_ENABLE:
  259 + SDL_PauseAudio (0);
  260 + break;
  261 +
  262 + case VOICE_DISABLE:
  263 + SDL_PauseAudio (1);
  264 + break;
  265 + }
  266 + return 0;
  267 +}
  268 +
  269 +static void *sdl_audio_init (void)
  270 +{
  271 + SDLAudioState *s = &glob_sdl;
  272 + conf.nb_samples = audio_get_conf_int (QC_SDL_SAMPLES, conf.nb_samples);
  273 +
  274 + if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
  275 + dolog ("SDL failed to initialize audio subsystem\nReason: %s\n",
  276 + errstr ());
  277 + return NULL;
  278 + }
  279 +
  280 + s->mutex = SDL_CreateMutex ();
  281 + if (!s->mutex) {
  282 + dolog ("Failed to create SDL mutex\nReason: %s\n", errstr ());
  283 + SDL_QuitSubSystem (SDL_INIT_AUDIO);
  284 + return NULL;
  285 + }
  286 +
  287 + s->sem = SDL_CreateSemaphore (0);
  288 + if (!s->sem) {
  289 + dolog ("Failed to create SDL semaphore\nReason: %s\n", errstr ());
  290 + SDL_DestroyMutex (s->mutex);
  291 + SDL_QuitSubSystem (SDL_INIT_AUDIO);
  292 + return NULL;
  293 + }
  294 +
  295 + return s;
  296 +}
  297 +
  298 +static void sdl_audio_fini (void *opaque)
  299 +{
  300 + SDLAudioState *s = opaque;
  301 + sdl_close (s);
  302 + SDL_DestroySemaphore (s->sem);
  303 + SDL_DestroyMutex (s->mutex);
  304 + SDL_QuitSubSystem (SDL_INIT_AUDIO);
  305 +}
  306 +
  307 +struct pcm_ops sdl_pcm_ops = {
  308 + sdl_hw_init,
  309 + sdl_hw_fini,
  310 + sdl_hw_run,
  311 + sdl_hw_write,
  312 + sdl_hw_ctl
  313 +};
  314 +
  315 +struct audio_output_driver sdl_output_driver = {
  316 + "sdl",
  317 + sdl_audio_init,
  318 + sdl_audio_fini,
  319 + &sdl_pcm_ops,
  320 + 1,
  321 + 1,
  322 + sizeof (SDLVoice)
  323 +};
... ...
audio/sdlaudio.h 0 → 100644
  1 +/*
  2 + * QEMU SDL audio output driver header
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#ifndef QEMU_SDLAUDIO_H
  25 +#define QEMU_SDLAUDIO_H
  26 +
  27 +typedef struct SDLVoice {
  28 + struct HWVoice hw;
  29 +} SDLVoice;
  30 +
  31 +extern struct pcm_ops sdl_pcm_ops;
  32 +extern struct audio_output_driver sdl_output_driver;
  33 +
  34 +#endif /* sdlaudio.h */
... ...
audio/wavaudio.c 0 → 100644
  1 +/*
  2 + * QEMU WAV audio output driver
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include "vl.h"
  25 +
  26 +#define AUDIO_CAP "wav"
  27 +#include "audio/audio.h"
  28 +#include "audio/wavaudio.h"
  29 +
  30 +static struct {
  31 + const char *wav_path;
  32 +} conf = {
  33 + .wav_path = "qemu.wav"
  34 +};
  35 +
  36 +static void wav_hw_run (HWVoice *hw)
  37 +{
  38 + WAVVoice *wav = (WAVVoice *) hw;
  39 + int rpos, live, decr, samples;
  40 + uint8_t *dst;
  41 + st_sample_t *src;
  42 + int64_t now = qemu_get_clock (vm_clock);
  43 + int64_t ticks = now - wav->old_ticks;
  44 + int64_t bytes = (ticks * hw->bytes_per_second) / ticks_per_sec;
  45 + wav->old_ticks = now;
  46 +
  47 + if (bytes > INT_MAX)
  48 + samples = INT_MAX >> hw->shift;
  49 + else
  50 + samples = bytes >> hw->shift;
  51 +
  52 + live = pcm_hw_get_live (hw);
  53 + if (live <= 0)
  54 + return;
  55 +
  56 + decr = audio_MIN (live, samples);
  57 + samples = decr;
  58 + rpos = hw->rpos;
  59 + while (samples) {
  60 + int left_till_end_samples = hw->samples - rpos;
  61 + int convert_samples = audio_MIN (samples, left_till_end_samples);
  62 +
  63 + src = advance (hw->mix_buf, rpos * sizeof (st_sample_t));
  64 + dst = advance (wav->pcm_buf, rpos << hw->shift);
  65 +
  66 + hw->clip (dst, src, convert_samples);
  67 + qemu_put_buffer (wav->f, dst, convert_samples << hw->shift);
  68 + memset (src, 0, convert_samples * sizeof (st_sample_t));
  69 +
  70 + rpos = (rpos + convert_samples) % hw->samples;
  71 + samples -= convert_samples;
  72 + wav->total_samples += convert_samples;
  73 + }
  74 +
  75 + pcm_hw_dec_live (hw, decr);
  76 + hw->rpos = rpos;
  77 +}
  78 +
  79 +static int wav_hw_write (SWVoice *sw, void *buf, int len)
  80 +{
  81 + return pcm_hw_write (sw, buf, len);
  82 +}
  83 +
  84 +
  85 +/* VICE code: Store number as little endian. */
  86 +static void le_store (uint8_t *buf, uint32_t val, int len)
  87 +{
  88 + int i;
  89 + for (i = 0; i < len; i++) {
  90 + buf[i] = (uint8_t) (val & 0xff);
  91 + val >>= 8;
  92 + }
  93 +}
  94 +
  95 +static int wav_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)
  96 +{
  97 + WAVVoice *wav = (WAVVoice *) hw;
  98 + int bits16 = 0, stereo = audio_state.fixed_channels == 2;
  99 + uint8_t hdr[] = {
  100 + 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56,
  101 + 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00,
  102 + 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
  103 + 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
  104 + };
  105 +
  106 + switch (audio_state.fixed_fmt) {
  107 + case AUD_FMT_S8:
  108 + case AUD_FMT_U8:
  109 + break;
  110 +
  111 + case AUD_FMT_S16:
  112 + case AUD_FMT_U16:
  113 + bits16 = 1;
  114 + break;
  115 + }
  116 +
  117 + hdr[34] = bits16 ? 0x10 : 0x08;
  118 + hw->freq = 44100;
  119 + hw->nchannels = stereo ? 2 : 1;
  120 + hw->fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
  121 + hw->bufsize = 4096;
  122 + wav->pcm_buf = qemu_mallocz (hw->bufsize);
  123 + if (!wav->pcm_buf)
  124 + return -1;
  125 +
  126 + le_store (hdr + 22, hw->nchannels, 2);
  127 + le_store (hdr + 24, hw->freq, 4);
  128 + le_store (hdr + 28, hw->freq << (bits16 + stereo), 4);
  129 + le_store (hdr + 32, 1 << (bits16 + stereo), 2);
  130 +
  131 + wav->f = fopen (conf.wav_path, "wb");
  132 + if (!wav->f) {
  133 + dolog ("failed to open wave file `%s'\nReason: %s\n",
  134 + conf.wav_path, strerror (errno));
  135 + return -1;
  136 + }
  137 +
  138 + qemu_put_buffer (wav->f, hdr, sizeof (hdr));
  139 + return 0;
  140 +}
  141 +
  142 +static void wav_hw_fini (HWVoice *hw)
  143 +{
  144 + WAVVoice *wav = (WAVVoice *) hw;
  145 + int stereo = hw->nchannels == 2;
  146 + uint8_t rlen[4];
  147 + uint8_t dlen[4];
  148 + uint32_t rifflen = (wav->total_samples << stereo) + 36;
  149 + uint32_t datalen = wav->total_samples << stereo;
  150 +
  151 + if (!wav->f || !hw->active)
  152 + return;
  153 +
  154 + le_store (rlen, rifflen, 4);
  155 + le_store (dlen, datalen, 4);
  156 +
  157 + qemu_fseek (wav->f, 4, SEEK_SET);
  158 + qemu_put_buffer (wav->f, rlen, 4);
  159 +
  160 + qemu_fseek (wav->f, 32, SEEK_CUR);
  161 + qemu_put_buffer (wav->f, dlen, 4);
  162 +
  163 + fclose (wav->f);
  164 + wav->f = NULL;
  165 +}
  166 +
  167 +static int wav_hw_ctl (HWVoice *hw, int cmd, ...)
  168 +{
  169 + (void) hw;
  170 + (void) cmd;
  171 + return 0;
  172 +}
  173 +
  174 +static void *wav_audio_init (void)
  175 +{
  176 + return &conf;
  177 +}
  178 +
  179 +static void wav_audio_fini (void *opaque)
  180 +{
  181 + ldebug ("wav_fini");
  182 +}
  183 +
  184 +struct pcm_ops wav_pcm_ops = {
  185 + wav_hw_init,
  186 + wav_hw_fini,
  187 + wav_hw_run,
  188 + wav_hw_write,
  189 + wav_hw_ctl
  190 +};
  191 +
  192 +struct audio_output_driver wav_output_driver = {
  193 + "wav",
  194 + wav_audio_init,
  195 + wav_audio_fini,
  196 + &wav_pcm_ops,
  197 + 1,
  198 + 1,
  199 + sizeof (WAVVoice)
  200 +};
... ...
audio/wavaudio.h 0 → 100644
  1 +/*
  2 + * QEMU WAV audio output driver header
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#ifndef QEMU_WAVAUDIO_H
  25 +#define QEMU_WAVAUDIO_H
  26 +
  27 +typedef struct WAVVoice {
  28 + struct HWVoice hw;
  29 + QEMUFile *f;
  30 + int64_t old_ticks;
  31 + void *pcm_buf;
  32 + int total_samples;
  33 +} WAVVoice;
  34 +
  35 +extern struct pcm_ops wav_pcm_ops;
  36 +extern struct audio_output_driver wav_output_driver;
  37 +
  38 +#endif /* wavaudio.h */
... ...
hw/adlib.c 0 → 100644
  1 +/*
  2 + * QEMU Adlib emulation
  3 + *
  4 + * Copyright (c) 2004 Vassili Karpov (malc)
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include "vl.h"
  25 +
  26 +#define AUDIO_CAP "adlib"
  27 +#include "audio/audio.h"
  28 +
  29 +#ifdef USE_YMF262
  30 +#define HAS_YMF262 1
  31 +#include "ymf262.h"
  32 +void YMF262UpdateOneQEMU(int which, INT16 *dst, int length);
  33 +#define SHIFT 2
  34 +#else
  35 +#include "fmopl.h"
  36 +#define SHIFT 1
  37 +#endif
  38 +
  39 +#ifdef _WIN32
  40 +#include <windows.h>
  41 +#define small_delay() Sleep (1)
  42 +#else
  43 +#define small_delay() usleep (1)
  44 +#endif
  45 +
  46 +#define IO_READ_PROTO(name) \
  47 + uint32_t name (void *opaque, uint32_t nport)
  48 +#define IO_WRITE_PROTO(name) \
  49 + void name (void *opaque, uint32_t nport, uint32_t val)
  50 +
  51 +static struct {
  52 + int port;
  53 + int freq;
  54 +} conf = {0x220, 44100};
  55 +
  56 +typedef struct {
  57 + int enabled;
  58 + int active;
  59 + int cparam;
  60 + int64_t ticks;
  61 + int bufpos;
  62 + int16_t *mixbuf;
  63 + double interval;
  64 + QEMUTimer *ts, *opl_ts;
  65 + SWVoice *voice;
  66 + int left, pos, samples, bytes_per_second, old_free;
  67 + int refcount;
  68 +#ifndef USE_YMF262
  69 + FM_OPL *opl;
  70 +#endif
  71 +} AdlibState;
  72 +
  73 +static AdlibState adlib;
  74 +
  75 +static IO_WRITE_PROTO(adlib_write)
  76 +{
  77 + AdlibState *s = opaque;
  78 + int a = nport & 3;
  79 + int status;
  80 +
  81 + s->ticks = qemu_get_clock (vm_clock);
  82 + s->active = 1;
  83 + AUD_enable (s->voice, 1);
  84 +
  85 +#ifdef USE_YMF262
  86 + status = YMF262Write (0, a, val);
  87 +#else
  88 + status = OPLWrite (s->opl, a, val);
  89 +#endif
  90 +}
  91 +
  92 +static IO_READ_PROTO(adlib_read)
  93 +{
  94 + AdlibState *s = opaque;
  95 + uint8_t data;
  96 + int a = nport & 3;
  97 +
  98 +#ifdef USE_YMF262
  99 + (void) s;
  100 + data = YMF262Read (0, a);
  101 +#else
  102 + data = OPLRead (s->opl, a);
  103 +#endif
  104 + return data;
  105 +}
  106 +
  107 +static void OPL_timer (void *opaque)
  108 +{
  109 + AdlibState *s = opaque;
  110 +#ifdef USE_YMF262
  111 + YMF262TimerOver (s->cparam >> 1, s->cparam & 1);
  112 +#else
  113 + OPLTimerOver (s->opl, s->cparam);
  114 +#endif
  115 + qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
  116 +}
  117 +
  118 +static void YMF262TimerHandler (int c, double interval_Sec)
  119 +{
  120 + AdlibState *s = &adlib;
  121 + if (interval_Sec == 0.0) {
  122 + qemu_del_timer (s->opl_ts);
  123 + return;
  124 + }
  125 + s->cparam = c;
  126 + s->interval = ticks_per_sec * interval_Sec;
  127 + qemu_mod_timer (s->opl_ts, qemu_get_clock (vm_clock) + s->interval);
  128 + small_delay ();
  129 +}
  130 +
  131 +static int write_audio (AdlibState *s, int samples)
  132 +{
  133 + int net = 0;
  134 + int ss = samples;
  135 + while (samples) {
  136 + int nbytes = samples << SHIFT;
  137 + int wbytes = AUD_write (s->voice,
  138 + s->mixbuf + (s->pos << (SHIFT - 1)),
  139 + nbytes);
  140 + int wsampl = wbytes >> SHIFT;
  141 + samples -= wsampl;
  142 + s->pos = (s->pos + wsampl) % s->samples;
  143 + net += wsampl;
  144 + if (!wbytes)
  145 + break;
  146 + }
  147 + if (net > ss) {
  148 + dolog ("WARNING: net > ss\n");
  149 + }
  150 + return net;
  151 +}
  152 +
  153 +static void timer (void *opaque)
  154 +{
  155 + AdlibState *s = opaque;
  156 + int elapsed, samples, net = 0;
  157 +
  158 + if (s->refcount)
  159 + dolog ("refcount=%d\n", s->refcount);
  160 +
  161 + s->refcount += 1;
  162 + if (!(s->active && s->enabled))
  163 + goto reset;
  164 +
  165 + AUD_run ();
  166 +
  167 + while (s->left) {
  168 + int written = write_audio (s, s->left);
  169 + net += written;
  170 + if (!written)
  171 + goto reset2;
  172 + s->left -= written;
  173 + }
  174 + s->pos = 0;
  175 +
  176 + elapsed = AUD_calc_elapsed (s->voice);
  177 + if (!elapsed)
  178 + goto reset2;
  179 +
  180 + /* elapsed = AUD_get_free (s->voice); */
  181 + samples = elapsed >> SHIFT;
  182 + if (!samples)
  183 + goto reset2;
  184 +
  185 + samples = audio_MIN (samples, s->samples - s->pos);
  186 + if (s->left)
  187 + dolog ("left=%d samples=%d elapsed=%d free=%d\n",
  188 + s->left, samples, elapsed, AUD_get_free (s->voice));
  189 +
  190 + if (!samples)
  191 + goto reset2;
  192 +
  193 +#ifdef USE_YMF262
  194 + YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
  195 +#else
  196 + YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
  197 +#endif
  198 +
  199 + while (samples) {
  200 + int written = write_audio (s, samples);
  201 + net += written;
  202 + if (!written)
  203 + break;
  204 + samples -= written;
  205 + }
  206 + if (!samples)
  207 + s->pos = 0;
  208 + s->left = samples;
  209 +
  210 +reset2:
  211 + AUD_adjust (s->voice, net << SHIFT);
  212 +reset:
  213 + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + ticks_per_sec / 1024);
  214 + s->refcount -= 1;
  215 +}
  216 +
  217 +static void Adlib_fini (AdlibState *s)
  218 +{
  219 +#ifdef USE_YMF262
  220 + YMF262Shutdown ();
  221 +#else
  222 + if (s->opl) {
  223 + OPLDestroy (s->opl);
  224 + s->opl = NULL;
  225 + }
  226 +#endif
  227 +
  228 + if (s->opl_ts)
  229 + qemu_free_timer (s->opl_ts);
  230 +
  231 + if (s->ts)
  232 + qemu_free_timer (s->ts);
  233 +
  234 +#define maybe_free(p) if (p) qemu_free (p)
  235 + maybe_free (s->mixbuf);
  236 +#undef maybe_free
  237 +
  238 + s->active = 0;
  239 + s->enabled = 0;
  240 +}
  241 +
  242 +void Adlib_init (void)
  243 +{
  244 + AdlibState *s = &adlib;
  245 +
  246 + memset (s, 0, sizeof (*s));
  247 +
  248 +#ifdef USE_YMF262
  249 + if (YMF262Init (1, 14318180, conf.freq)) {
  250 + dolog ("YMF262Init %d failed\n", conf.freq);
  251 + return;
  252 + }
  253 + else {
  254 + YMF262SetTimerHandler (0, YMF262TimerHandler, 0);
  255 + s->enabled = 1;
  256 + }
  257 +#else
  258 + s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
  259 + if (!s->opl) {
  260 + dolog ("OPLCreate %d failed\n", conf.freq);
  261 + return;
  262 + }
  263 + else {
  264 + OPLSetTimerHandler (s->opl, YMF262TimerHandler, 0);
  265 + s->enabled = 1;
  266 + }
  267 +#endif
  268 +
  269 + s->opl_ts = qemu_new_timer (vm_clock, OPL_timer, s);
  270 + if (!s->opl_ts) {
  271 + dolog ("Can not get timer for adlib emulation\n");
  272 + Adlib_fini (s);
  273 + return;
  274 + }
  275 +
  276 + s->ts = qemu_new_timer (vm_clock, timer, s);
  277 + if (!s->opl_ts) {
  278 + dolog ("Can not get timer for adlib emulation\n");
  279 + Adlib_fini (s);
  280 + return;
  281 + }
  282 +
  283 + s->voice = AUD_open (s->voice, "adlib", conf.freq, SHIFT, AUD_FMT_S16);
  284 + if (!s->voice) {
  285 + Adlib_fini (s);
  286 + return;
  287 + }
  288 +
  289 + s->bytes_per_second = conf.freq << SHIFT;
  290 + s->samples = AUD_get_buffer_size (s->voice) >> SHIFT;
  291 + s->mixbuf = qemu_mallocz (s->samples << SHIFT);
  292 +
  293 + if (!s->mixbuf) {
  294 + dolog ("not enough memory for adlib mixing buffer (%d)\n",
  295 + s->samples << SHIFT);
  296 + Adlib_fini (s);
  297 + return;
  298 + }
  299 + register_ioport_read (0x388, 4, 1, adlib_read, s);
  300 + register_ioport_write (0x388, 4, 1, adlib_write, s);
  301 +
  302 + register_ioport_read (conf.port, 4, 1, adlib_read, s);
  303 + register_ioport_write (conf.port, 4, 1, adlib_write, s);
  304 +
  305 + register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
  306 + register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
  307 +
  308 + qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + 1);
  309 +}
... ...
hw/dma.c
1 1 /*
2 2 * QEMU DMA emulation
3   - *
4   - * Copyright (c) 2003 Vassili Karpov (malc)
5   - *
  3 + *
  4 + * Copyright (c) 2003-2004 Vassili Karpov (malc)
  5 + *
6 6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 7 * of this software and associated documentation files (the "Software"), to deal
8 8 * in the Software without restriction, including without limitation the rights
... ... @@ -23,9 +23,9 @@
23 23 */
24 24 #include "vl.h"
25 25  
26   -//#define DEBUG_DMA
  26 +/* #define DEBUG_DMA */
27 27  
28   -#define log(...) fprintf (stderr, "dma: " __VA_ARGS__)
  28 +#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
29 29 #ifdef DEBUG_DMA
30 30 #define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
31 31 #define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
... ... @@ -86,7 +86,7 @@ static void write_page (void *opaque, uint32_t nport, uint32_t data)
86 86  
87 87 ichan = channels[nport & 7];
88 88 if (-1 == ichan) {
89   - log ("invalid channel %#x %#x\n", nport, data);
  89 + dolog ("invalid channel %#x %#x\n", nport, data);
90 90 return;
91 91 }
92 92 d->regs[ichan].page = data;
... ... @@ -99,7 +99,7 @@ static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
99 99  
100 100 ichan = channels[nport & 7];
101 101 if (-1 == ichan) {
102   - log ("invalid channel %#x %#x\n", nport, data);
  102 + dolog ("invalid channel %#x %#x\n", nport, data);
103 103 return;
104 104 }
105 105 d->regs[ichan].pageh = data;
... ... @@ -112,7 +112,7 @@ static uint32_t read_page (void *opaque, uint32_t nport)
112 112  
113 113 ichan = channels[nport & 7];
114 114 if (-1 == ichan) {
115   - log ("invalid channel read %#x\n", nport);
  115 + dolog ("invalid channel read %#x\n", nport);
116 116 return 0;
117 117 }
118 118 return d->regs[ichan].page;
... ... @@ -125,7 +125,7 @@ static uint32_t read_pageh (void *opaque, uint32_t nport)
125 125  
126 126 ichan = channels[nport & 7];
127 127 if (-1 == ichan) {
128   - log ("invalid channel read %#x\n", nport);
  128 + dolog ("invalid channel read %#x\n", nport);
129 129 return 0;
130 130 }
131 131 return d->regs[ichan].pageh;
... ... @@ -136,7 +136,7 @@ static inline void init_chan (struct dma_cont *d, int ichan)
136 136 struct dma_regs *r;
137 137  
138 138 r = d->regs + ichan;
139   - r->now[ADDR] = r->base[0] << d->dshift;
  139 + r->now[ADDR] = r->base[ADDR] << d->dshift;
140 140 r->now[COUNT] = 0;
141 141 }
142 142  
... ... @@ -152,7 +152,7 @@ static inline int getff (struct dma_cont *d)
152 152 static uint32_t read_chan (void *opaque, uint32_t nport)
153 153 {
154 154 struct dma_cont *d = opaque;
155   - int ichan, nreg, iport, ff, val;
  155 + int ichan, nreg, iport, ff, val, dir;
156 156 struct dma_regs *r;
157 157  
158 158 iport = (nport >> d->dshift) & 0x0f;
... ... @@ -160,12 +160,14 @@ static uint32_t read_chan (void *opaque, uint32_t nport)
160 160 nreg = iport & 1;
161 161 r = d->regs + ichan;
162 162  
  163 + dir = ((r->mode >> 5) & 1) ? -1 : 1;
163 164 ff = getff (d);
164 165 if (nreg)
165 166 val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
166 167 else
167   - val = r->now[ADDR] + r->now[COUNT];
  168 + val = r->now[ADDR] + r->now[COUNT] * dir;
168 169  
  170 + ldebug ("read_chan %#x -> %d\n", iport, val);
169 171 return (val >> (d->dshift + (ff << 3))) & 0xff;
170 172 }
171 173  
... ... @@ -190,19 +192,19 @@ static void write_chan (void *opaque, uint32_t nport, uint32_t data)
190 192 static void write_cont (void *opaque, uint32_t nport, uint32_t data)
191 193 {
192 194 struct dma_cont *d = opaque;
193   - int iport, ichan;
  195 + int iport, ichan = 0;
194 196  
195 197 iport = (nport >> d->dshift) & 0x0f;
196 198 switch (iport) {
197   - case 8: /* command */
  199 + case 0x08: /* command */
198 200 if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
199   - log ("command %#x not supported\n", data);
  201 + dolog ("command %#x not supported\n", data);
200 202 return;
201 203 }
202 204 d->command = data;
203 205 break;
204 206  
205   - case 9:
  207 + case 0x09:
206 208 ichan = data & 3;
207 209 if (data & 4) {
208 210 d->status |= 1 << (ichan + 4);
... ... @@ -213,22 +215,19 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data)
213 215 d->status &= ~(1 << ichan);
214 216 break;
215 217  
216   - case 0xa: /* single mask */
  218 + case 0x0a: /* single mask */
217 219 if (data & 4)
218 220 d->mask |= 1 << (data & 3);
219 221 else
220 222 d->mask &= ~(1 << (data & 3));
221 223 break;
222 224  
223   - case 0xb: /* mode */
  225 + case 0x0b: /* mode */
224 226 {
225 227 ichan = data & 3;
226 228 #ifdef DEBUG_DMA
227   - int op;
228   - int ai;
229   - int dir;
230   - int opmode;
231   -
  229 + {
  230 + int op, ai, dir, opmode;
232 231 op = (data >> 2) & 3;
233 232 ai = (data >> 4) & 1;
234 233 dir = (data >> 5) & 1;
... ... @@ -236,39 +235,39 @@ static void write_cont (void *opaque, uint32_t nport, uint32_t data)
236 235  
237 236 linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
238 237 ichan, op, ai, dir, opmode);
  238 + }
239 239 #endif
240   -
241 240 d->regs[ichan].mode = data;
242 241 break;
243 242 }
244 243  
245   - case 0xc: /* clear flip flop */
  244 + case 0x0c: /* clear flip flop */
246 245 d->flip_flop = 0;
247 246 break;
248 247  
249   - case 0xd: /* reset */
  248 + case 0x0d: /* reset */
250 249 d->flip_flop = 0;
251 250 d->mask = ~0;
252 251 d->status = 0;
253 252 d->command = 0;
254 253 break;
255 254  
256   - case 0xe: /* clear mask for all channels */
  255 + case 0x0e: /* clear mask for all channels */
257 256 d->mask = 0;
258 257 break;
259 258  
260   - case 0xf: /* write mask for all channels */
  259 + case 0x0f: /* write mask for all channels */
261 260 d->mask = data;
262 261 break;
263 262  
264 263 default:
265   - log ("dma: unknown iport %#x\n", iport);
  264 + dolog ("unknown iport %#x\n", iport);
266 265 break;
267 266 }
268 267  
269 268 #ifdef DEBUG_DMA
270 269 if (0xc != iport) {
271   - linfo ("nport %#06x, ichan % 2d, val %#06x\n",
  270 + linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
272 271 nport, ichan, data);
273 272 }
274 273 #endif
... ... @@ -278,20 +277,22 @@ static uint32_t read_cont (void *opaque, uint32_t nport)
278 277 {
279 278 struct dma_cont *d = opaque;
280 279 int iport, val;
281   -
  280 +
282 281 iport = (nport >> d->dshift) & 0x0f;
283 282 switch (iport) {
284   - case 0x08: /* status */
  283 + case 0x08: /* status */
285 284 val = d->status;
286 285 d->status &= 0xf0;
287 286 break;
288   - case 0x0f: /* mask */
  287 + case 0x0f: /* mask */
289 288 val = d->mask;
290 289 break;
291 290 default:
292 291 val = 0;
293 292 break;
294 293 }
  294 +
  295 + ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
295 296 return val;
296 297 }
297 298  
... ... @@ -322,23 +323,27 @@ void DMA_release_DREQ (int nchan)
322 323  
323 324 static void channel_run (int ncont, int ichan)
324 325 {
325   - struct dma_regs *r;
326 326 int n;
327   - target_ulong addr;
328   -/* int ai, dir; */
  327 + struct dma_regs *r = &dma_controllers[ncont].regs[ichan];
  328 +#ifdef DEBUG_DMA
  329 + int dir, opmode;
329 330  
330   - r = dma_controllers[ncont].regs + ichan;
331   -/* ai = r->mode & 16; */
332   -/* dir = r->mode & 32 ? -1 : 1; */
  331 + dir = (r->mode >> 5) & 1;
  332 + opmode = (r->mode >> 6) & 3;
333 333  
334   - /* NOTE: pageh is only used by PPC PREP */
335   - addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
336   - n = r->transfer_handler (r->opaque, addr,
337   - (r->base[COUNT] << ncont) + (1 << ncont));
338   - r->now[COUNT] = n;
  334 + if (dir) {
  335 + dolog ("DMA in address decrement mode\n");
  336 + }
  337 + if (opmode != 1) {
  338 + dolog ("DMA not in single mode select %#x\n", opmode);
  339 + }
  340 +#endif
339 341  
340   - ldebug ("dma_pos %d size %d\n",
341   - n, (r->base[1] << ncont) + (1 << ncont));
  342 + r = dma_controllers[ncont].regs + ichan;
  343 + n = r->transfer_handler (r->opaque, ichan + (ncont << 2),
  344 + r->now[COUNT], (r->base[COUNT] + 1) << ncont);
  345 + r->now[COUNT] = n;
  346 + ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
342 347 }
343 348  
344 349 void DMA_run (void)
... ... @@ -361,7 +366,7 @@ void DMA_run (void)
361 366 }
362 367  
363 368 void DMA_register_channel (int nchan,
364   - DMA_transfer_handler transfer_handler,
  369 + DMA_transfer_handler transfer_handler,
365 370 void *opaque)
366 371 {
367 372 struct dma_regs *r;
... ... @@ -375,6 +380,50 @@ void DMA_register_channel (int nchan,
375 380 r->opaque = opaque;
376 381 }
377 382  
  383 +int DMA_read_memory (int nchan, void *buf, int pos, int len)
  384 +{
  385 + struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
  386 + target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
  387 +
  388 + if (r->mode & 0x20) {
  389 + int i;
  390 + uint8_t *p = buf;
  391 +
  392 + cpu_physical_memory_read (addr - pos - len, buf, len);
  393 + /* What about 16bit transfers? */
  394 + for (i = 0; i < len >> 1; i++) {
  395 + uint8_t b = p[len - i - 1];
  396 + p[i] = b;
  397 + }
  398 + }
  399 + else
  400 + cpu_physical_memory_read (addr + pos, buf, len);
  401 +
  402 + return len;
  403 +}
  404 +
  405 +int DMA_write_memory (int nchan, void *buf, int pos, int len)
  406 +{
  407 + struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
  408 + target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
  409 +
  410 + if (r->mode & 0x20) {
  411 + int i;
  412 + uint8_t *p = buf;
  413 +
  414 + cpu_physical_memory_write (addr - pos - len, buf, len);
  415 + /* What about 16bit transfers? */
  416 + for (i = 0; i < len; i++) {
  417 + uint8_t b = p[len - i - 1];
  418 + p[i] = b;
  419 + }
  420 + }
  421 + else
  422 + cpu_physical_memory_write (addr + pos, buf, len);
  423 +
  424 + return len;
  425 +}
  426 +
378 427 /* request the emulator to transfer a new DMA memory block ASAP */
379 428 void DMA_schedule(int nchan)
380 429 {
... ... @@ -388,7 +437,7 @@ static void dma_reset(void *opaque)
388 437 }
389 438  
390 439 /* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
391   -static void dma_init2(struct dma_cont *d, int base, int dshift,
  440 +static void dma_init2(struct dma_cont *d, int base, int dshift,
392 441 int page_base, int pageh_base)
393 442 {
394 443 const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
... ... @@ -400,31 +449,87 @@ static void dma_init2(struct dma_cont *d, int base, int dshift,
400 449 register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
401 450 }
402 451 for (i = 0; i < LENOFA (page_port_list); i++) {
403   - register_ioport_write (page_base + page_port_list[i], 1, 1,
  452 + register_ioport_write (page_base + page_port_list[i], 1, 1,
404 453 write_page, d);
405   - register_ioport_read (page_base + page_port_list[i], 1, 1,
  454 + register_ioport_read (page_base + page_port_list[i], 1, 1,
406 455 read_page, d);
407 456 if (pageh_base >= 0) {
408   - register_ioport_write (pageh_base + page_port_list[i], 1, 1,
  457 + register_ioport_write (pageh_base + page_port_list[i], 1, 1,
409 458 write_pageh, d);
410   - register_ioport_read (pageh_base + page_port_list[i], 1, 1,
  459 + register_ioport_read (pageh_base + page_port_list[i], 1, 1,
411 460 read_pageh, d);
412 461 }
413 462 }
414 463 for (i = 0; i < 8; i++) {
415   - register_ioport_write (base + ((i + 8) << dshift), 1, 1,
  464 + register_ioport_write (base + ((i + 8) << dshift), 1, 1,
416 465 write_cont, d);
417   - register_ioport_read (base + ((i + 8) << dshift), 1, 1,
  466 + register_ioport_read (base + ((i + 8) << dshift), 1, 1,
418 467 read_cont, d);
419 468 }
420 469 qemu_register_reset(dma_reset, d);
421 470 dma_reset(d);
422 471 }
423 472  
  473 +static void dma_save (QEMUFile *f, void *opaque)
  474 +{
  475 + struct dma_cont *d = opaque;
  476 + int i;
  477 +
  478 + /* qemu_put_8s (f, &d->status); */
  479 + qemu_put_8s (f, &d->command);
  480 + qemu_put_8s (f, &d->mask);
  481 + qemu_put_8s (f, &d->flip_flop);
  482 + qemu_put_be32s (f, &d->dshift);
  483 +
  484 + for (i = 0; i < 4; ++i) {
  485 + struct dma_regs *r = &d->regs[i];
  486 + qemu_put_be32s (f, &r->now[0]);
  487 + qemu_put_be32s (f, &r->now[1]);
  488 + qemu_put_be16s (f, &r->base[0]);
  489 + qemu_put_be16s (f, &r->base[1]);
  490 + qemu_put_8s (f, &r->mode);
  491 + qemu_put_8s (f, &r->page);
  492 + qemu_put_8s (f, &r->pageh);
  493 + qemu_put_8s (f, &r->dack);
  494 + qemu_put_8s (f, &r->eop);
  495 + }
  496 +}
  497 +
  498 +static int dma_load (QEMUFile *f, void *opaque, int version_id)
  499 +{
  500 + struct dma_cont *d = opaque;
  501 + int i;
  502 +
  503 + if (version_id != 1)
  504 + return -EINVAL;
  505 +
  506 + /* qemu_get_8s (f, &d->status); */
  507 + qemu_get_8s (f, &d->command);
  508 + qemu_get_8s (f, &d->mask);
  509 + qemu_get_8s (f, &d->flip_flop);
  510 + qemu_get_be32s (f, &d->dshift);
  511 +
  512 + for (i = 0; i < 4; ++i) {
  513 + struct dma_regs *r = &d->regs[i];
  514 + qemu_get_be32s (f, &r->now[0]);
  515 + qemu_get_be32s (f, &r->now[1]);
  516 + qemu_get_be16s (f, &r->base[0]);
  517 + qemu_get_be16s (f, &r->base[1]);
  518 + qemu_get_8s (f, &r->mode);
  519 + qemu_get_8s (f, &r->page);
  520 + qemu_get_8s (f, &r->pageh);
  521 + qemu_get_8s (f, &r->dack);
  522 + qemu_get_8s (f, &r->eop);
  523 + }
  524 + return 0;
  525 +}
  526 +
424 527 void DMA_init (int high_page_enable)
425 528 {
426   - dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
  529 + dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
427 530 high_page_enable ? 0x480 : -1);
428 531 dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
429 532 high_page_enable ? 0x488 : -1);
  533 + register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
  534 + register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
430 535 }
... ...
hw/fdc.c
... ... @@ -313,7 +313,8 @@ static void fd_reset (fdrive_t *drv)
313 313  
314 314 static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
315 315 static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
316   -static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size);
  316 +static int fdctrl_transfer_handler (void *opaque, int nchan,
  317 + int dma_pos, int dma_len);
317 318 static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
318 319 static void fdctrl_result_timer(void *opaque);
319 320  
... ... @@ -908,7 +909,8 @@ static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
908 909 }
909 910  
910 911 /* handlers for DMA transfers */
911   -static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size)
  912 +static int fdctrl_transfer_handler (void *opaque, int nchan,
  913 + int dma_pos, int dma_len)
912 914 {
913 915 fdctrl_t *fdctrl;
914 916 fdrive_t *cur_drv;
... ... @@ -924,8 +926,8 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size)
924 926 if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
925 927 fdctrl->data_dir == FD_DIR_SCANH)
926 928 status2 = 0x04;
927   - if (size > fdctrl->data_len)
928   - size = fdctrl->data_len;
  929 + if (dma_len > fdctrl->data_len)
  930 + dma_len = fdctrl->data_len;
929 931 if (cur_drv->bs == NULL) {
930 932 if (fdctrl->data_dir == FD_DIR_WRITE)
931 933 fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
... ... @@ -935,8 +937,8 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size)
935 937 goto transfer_error;
936 938 }
937 939 rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
938   - for (start_pos = fdctrl->data_pos; fdctrl->data_pos < size;) {
939   - len = size - fdctrl->data_pos;
  940 + for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
  941 + len = dma_len - fdctrl->data_pos;
940 942 if (len + rel_pos > FD_SECTOR_LEN)
941 943 len = FD_SECTOR_LEN - rel_pos;
942 944 FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x %02x "
... ... @@ -958,13 +960,17 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size)
958 960 switch (fdctrl->data_dir) {
959 961 case FD_DIR_READ:
960 962 /* READ commands */
961   - cpu_physical_memory_write(addr + fdctrl->data_pos,
962   - fdctrl->fifo + rel_pos, len);
  963 + DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
  964 + fdctrl->data_pos, len);
  965 +/* cpu_physical_memory_write(addr + fdctrl->data_pos, */
  966 +/* fdctrl->fifo + rel_pos, len); */
963 967 break;
964 968 case FD_DIR_WRITE:
965 969 /* WRITE commands */
966   - cpu_physical_memory_read(addr + fdctrl->data_pos,
967   - fdctrl->fifo + rel_pos, len);
  970 + DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
  971 + fdctrl->data_pos, len);
  972 +/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
  973 +/* fdctrl->fifo + rel_pos, len); */
968 974 if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
969 975 fdctrl->fifo, 1) < 0) {
970 976 FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
... ... @@ -977,8 +983,9 @@ static int fdctrl_transfer_handler (void *opaque, target_ulong addr, int size)
977 983 {
978 984 uint8_t tmpbuf[FD_SECTOR_LEN];
979 985 int ret;
980   - cpu_physical_memory_read(addr + fdctrl->data_pos,
981   - tmpbuf, len);
  986 + DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
  987 +/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
  988 +/* tmpbuf, len); */
982 989 ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
983 990 if (ret == 0) {
984 991 status2 = 0x08;
... ...