Hello. I extracted the sound code from my 3 years old local dosemu branch and re-diffed it against the current svn. This took lot of a hand-work, so the mistakes are possible. A quick test shows that the adlib now works on x86-64. But many progs (non-adlib ones) are still mute because the cpuemu doesn't exit after every port I/O the way vm86() did. The result is that run_irqs() doesn't come in time. If someone is willing to work on this, here's the patch.
--- src/base/dev/sb16/adlib.c 2009-09-23 13:45:45.000000000 +0400 +++ src/base/dev/sb16/adlib.c 2008-03-06 11:26:38.000000000 +0300 @@ -39,6 +39,7 @@ #define ADLIB_BASE 0x388 #define OPL3_INTERNAL_FREQ 14400000 // The OPL3 operates at 14.4MHz #define OPL3_MAX_BUF 512 +#define ADLIB_CHANNELS 2 #define ADLIB_THRESHOLD 2000000 #define ADLIB_RUNNING() (adlib_time_cur > 0) @@ -64,11 +65,15 @@ Bit8u adlib_io_read_base(ioport_t port) { + Bit8u ret; #ifdef HAS_YMF262 - return YMF262Read(opl3, port); + adlib_timer(); + ret = YMF262Read(opl3, port); #else - return 0xff; + ret = 0xff; #endif + S_printf("Adlib: Read %hhx from port %x\n", ret, port); + return ret; } static Bit8u adlib_io_read(ioport_t port) @@ -79,8 +84,10 @@ void adlib_io_write_base(ioport_t port, Bit8u value) { adlib_time_last = GETusTIME(0); + S_printf("Adlib: Write %hhx to port %x\n", value, port); #ifdef HAS_YMF262 YMF262Write(opl3, port, value); + adlib_timer(); #endif } @@ -93,8 +100,10 @@ static void opl3_set_timer(void *param, int num, double interval_Sec) { long long *timers = param; - timers[num] = - interval_Sec > 0 ? GETusTIME(0) + interval_Sec * 1000000 : 0; + if (interval_Sec > 0) + timers[num] += GETusTIME(0) + interval_Sec * 1000000; + else + timers[num] = 0; S_printf("Adlib: timer %i set to %ius\n", num, (int) (interval_Sec * 1000000)); } @@ -105,6 +114,12 @@ ADLIB_RUN(); run_new_sb(); } + +static void opl3_irq(void *param, int irq) +{ + S_printf("SB: OPL3 IRQ (%i)\n", irq); + /* this IRQ is not wired, nothing to do */ +} #endif void opl3_init(void) @@ -120,7 +135,7 @@ io_device.write_portw = NULL; io_device.read_portd = NULL; io_device.write_portd = NULL; - io_device.handler_name = "Adlib (+ Advanced) Emulation"; + io_device.handler_name = "OPL3"; io_device.start_addr = ADLIB_BASE; io_device.end_addr = ADLIB_BASE + 3; io_device.irq = EMU_NO_IRQ; @@ -130,14 +145,15 @@ } #ifdef HAS_YMF262 opl3 = YMF262Init(OPL3_INTERNAL_FREQ, opl3_rate); - YMF262SetTimerHandler(opl3, opl3_set_timer, &opl3_timers); + YMF262SetTimerHandler(opl3, opl3_set_timer, opl3_timers); YMF262SetUpdateHandler(opl3, opl3_update, NULL); + YMF262SetIRQHandler(opl3, opl3_irq, NULL); #endif } void adlib_init(void) { - adlib_strm = pcm_allocate_stream(2, "Adlib"); + adlib_strm = pcm_allocate_stream(ADLIB_CHANNELS, "Adlib"); } void adlib_reset(void) @@ -157,13 +173,24 @@ } #ifdef HAS_YMF262 -static void adlib_process_samples(int samps) +static void adlib_process_samples(int mono_samps) { - const int chan_map[] = { 0, 1, 0, 1 }; - int i, j, k; + const int chan_map[] = +#if ADLIB_CHANNELS == 2 + { 0, 1, 0, 1 }; +#elif ADLIB_CHANNELS == 1 + { 0, 0, 0, 0 }; +#elif ADLIB_CHANNELS == 4 + { 0, 1, 2, 3 }; +#else +#error ADLIB_CHANNELS is wrong + { -1, -1, -1, -1 }; +#endif + int i, j, k, samps; OPL3SAMPLE *chans[4], buf[4][OPL3_MAX_BUF], buf3; - int buf2[OPL3_MAX_BUF][2]; + int buf2[OPL3_MAX_BUF][ADLIB_CHANNELS]; + samps = mono_samps / ADLIB_CHANNELS; if (samps > OPL3_MAX_BUF) { error("Adlib: too many samples requested (%i)\n", samps); samps = OPL3_MAX_BUF; @@ -174,17 +201,13 @@ YMF262UpdateOne(opl3, chans, samps); for (i = 0; i < samps; i++) { - for (j = 0; j < 2; j++) { + for (j = 0; j < ADLIB_CHANNELS; j++) { buf2[i][j] = 0; for (k = 0; k < ARRAY_SIZE(chan_map); k++) { if (chan_map[k] == j) buf2[i][j] += buf[k][i]; } - if (buf2[i][j] > SHRT_MAX) - buf2[i][j] = SHRT_MAX; - if (buf2[i][j] < SHRT_MIN) - buf2[i][j] = SHRT_MIN; - buf3 = buf2[i][j]; + buf3 = pcm_samp_cutoff(buf2[i][j], opl3_format); pcm_write_samples(&buf3, pcm_format_size(opl3_format), opl3_rate, opl3_format, adlib_strm); } @@ -204,13 +227,13 @@ pcm_flush(adlib_strm); } if (ADLIB_RUNNING()) { - period = pcm_samp_period(opl3_rate, 2); + period = pcm_samp_period(opl3_rate, ADLIB_CHANNELS); nsamps = (now - adlib_time_cur) / period; if (nsamps > OPL3_MAX_BUF) nsamps = OPL3_MAX_BUF; - nsamps -= nsamps % 2; + nsamps -= nsamps % ADLIB_CHANNELS; if (nsamps) { - adlib_process_samples(nsamps / 2); + adlib_process_samples(nsamps); adlib_time_cur += nsamps * period; S_printf("SB: processed %i Adlib samples\n", nsamps); } @@ -219,7 +242,7 @@ for (i = 0; i < 2; i++) { if (opl3_timers[i] > 0 && now > opl3_timers[i]) { S_printf("Adlib: timer %i expired\n", i); - opl3_timers[i] = 0; + opl3_timers[i] = now - opl3_timers[i]; YMF262TimerOver(opl3, i); } } --- src/base/dev/sb16/dspio.c.orig 2009-09-23 13:00:56.000000000 +0400 +++ src/base/dev/sb16/dspio.c 2009-09-23 13:59:19.000000000 +0400 @@ -36,7 +36,7 @@ #include "sound/sndpcm.h" #include "sound/midi.h" #include "adlib.h" -#include "dma.h" +#include "dmanew.h" #include "sb16.h" #include "dspio.h" #include <string.h> @@ -65,22 +65,6 @@ #define DSPIO ((struct dspio_state *)dspio) -static int dma8_get_format(int is_signed) -{ - return is_signed ? PCM_FORMAT_S8 : PCM_FORMAT_U8; -} - -static int dma16_get_format(int is_signed) -{ - return is_signed ? PCM_FORMAT_S16_LE : PCM_FORMAT_U16_LE; -} - -static int dma_get_format(int is_16, int is_signed) -{ - return is_16 ? dma16_get_format(is_signed) : - dma8_get_format(is_signed); -} - static void dma_get_silence(int is_signed, int is16bit, void *ptr) { if (is16bit) { @@ -163,9 +147,10 @@ if (state->output_running) return; S_printf("SB: starting output\n"); - /* We would need real time here, but the HACK is to use stream time instead. + /* We would need real time here, but the HACK is to use stream + * timestamp instead. * That compensates the hack of dspio_process_dma() */ - state->output_time_cur = pcm_get_stream_time(state->dma_strm); + state->output_time_cur = pcm_calc_tstamp(state->dma.rate, state->dma_strm); state->output_running = 1; } @@ -296,6 +281,7 @@ if (state->dma.running) { state->dma.stereo = sb_dma_samp_stereo(); state->dma.rate = sb_get_dma_sampling_rate(); + state->dma.samp_signed = sb_dma_samp_signed(); } while (state->output_running && (state->output_time_cur <= time_dst || @@ -308,13 +294,13 @@ if (state->speaker) { pcm_write_samples(&buf, 1 << state->dma.is16bit, state->dma.rate, - dma_get_format(state->dma.is16bit, + pcm_get_format(state->dma.is16bit, state->dma.samp_signed), state->dma_strm); if (!state->dma.stereo) pcm_write_samples(&buf, 1 << state->dma.is16bit, state->dma.rate, - dma_get_format(state->dma.is16bit, + pcm_get_format(state->dma.is16bit, state->dma. samp_signed), state->dma_strm); --- src/base/dev/sb16/sb16.c 2009-09-23 13:01:30.000000000 +0400 +++ src/base/dev/sb16/sb16.c 2009-09-23 14:13:20.000000000 +0400 @@ -636,6 +636,7 @@ hdma_idx = config.sb_hdma ? 1 << config.sb_hdma : 0; sb.mixer_regs[0x80] = irq_idx; sb.mixer_regs[0x81] = dma_idx | hdma_idx; + sb.mixer_regs[0x82] = SB16_ID82; } static void sb_reset(void) @@ -920,8 +921,8 @@ case 0xE1: /* DSP Version - SB */ S_printf("SB: Query Version\n"); - dsp_write_output(SB_16 >> 8); - dsp_write_output(SB_16 & 0xFF); + dsp_write_output(SB16_ID >> 8); + dsp_write_output(SB16_ID & 0xFF); break; case 0xE2: { --- src/base/dev/sb16/sb16.h 2009-09-23 13:00:56.000000000 +0400 +++ src/base/dev/sb16/sb16.h 2006-12-11 18:07:05.000000000 +0300 @@ -26,11 +26,15 @@ #include "utilities.h" // for rng_s #define SB_NONE 0x000 -#define SB_OLD 0x105 -#define SB_20 0x201 -#define SB_PRO 0x300 -#define SB_16 0x405 -#define SB_AWE32 0x40C +#define SB_ID 0x105 +#define SB20_ID 0x201 +#define SBPRO_ID 0x300 +#define SB16_ID 0x405 +#define SBAWE32_ID 0x40C + +/* bochs and the old dosemu code disagree on that value. + * Of course I trust bochs. :) */ +#define SB16_ID82 (2 << 5) /* * Various Status values Index: dmanew.c =================================================================== --- src/base/dev/dma/dmanew.c (revision 1964) +++ src/base/dev/dma/dmanew.c (working copy) @@ -32,7 +32,8 @@ #include "utilities.h" #include "port.h" #include "timers.h" -#include "dma.h" +#include "dmanew.h" +#include "dmaregs.h" #include <string.h> typedef union { @@ -82,7 +83,7 @@ #define HAVE_SRQ(contr, chan) (dma[contr].request & (1 << (chan))) #define SW_ACTIVE(contr, chan) \ (HAVE_SRQ(contr, chan) && \ - (dma[contr].chans[chan].mode & 0x30) == 0x20) + (DMA_TRANSFER_MODE(dma[contr].chans[chan].mode) == BLOCK)) static void dma_soft_reset(int dma_idx) @@ -105,18 +106,18 @@ static void dma_update_DRQ(int dma_idx, int chan_idx) { - switch (dma[dma_idx].chans[chan_idx].mode & 0x30) { - case 0x00: // demand + switch (DMA_TRANSFER_MODE(dma[dma_idx].chans[chan_idx].mode)) { + case DEMAND: dma_poll_DRQ(dma_idx, chan_idx); break; - case 0x10: // single + case SINGLE: dma[dma_idx].status &= ~(1 << (chan_idx + 4)); break; - case 0x20: // block + case BLOCK: if (REACHED_TC(dma_idx, chan_idx)) dma_poll_DRQ(dma_idx, chan_idx); break; - case 0x30: // cascade + case CASCADE: dma_poll_DRQ(dma_idx, chan_idx); break; } @@ -126,38 +127,37 @@ { struct dma_channel *chan = &dma[dma_idx].chans[chan_idx]; Bit32u addr = (chan->page << 16) | (chan->cur_addr.value << dma_idx); - Bit8u mode = chan->mode; /* first, do the transfer */ - switch (mode & 3) { - case 0: /* verify */ + switch (DMA_TRANSFER_OP(chan->mode)) { + case VERIFY: q_printf("DMA: verify mode does nothing\n"); break; - case 1: /* write */ + case WRITE: MEMCPY_2DOS(addr, dma_data_bus, 1 << dma_idx); break; - case 2: /* read */ + case READ: MEMCPY_2UNIX(dma_data_bus, addr, 1 << dma_idx); break; - case 3: /* invalid */ + case INVALID: q_printf("DMA: invalid mode does nothing\n"); break; } /* now advance the address */ - if (!(dma[dma_idx].command & 2)) - chan->cur_addr.value += (mode & 8) ? -1 : 1; + if ((dma[dma_idx].command & 3) != 3) + chan->cur_addr.value += (DMA_ADDR_DEC(chan->mode) ? -1 : 1); /* and the counter */ chan->cur_count.value--; if (chan->cur_count.value == 0xffff) { /* overflow */ - if (mode & 4) { /* auto-init */ + if (DMA_AUTOINIT(chan->mode)) { q_printf("DMA: controller %i, channel %i reinitialized\n", dma_idx, chan_idx); chan->cur_addr.value = chan->base_addr.value; chan->cur_count.value = chan->base_count.value; - } else { /* eop */ - q_printf("DMA: controller %i, channel %i EOP\n", dma_idx, + } else { /* TC */ + q_printf("DMA: controller %i, channel %i TC\n", dma_idx, chan_idx); dma[dma_idx].status |= 1 << chan_idx; dma[dma_idx].request &= ~(1 << chan_idx); @@ -176,7 +176,7 @@ if (!MASKED(dma_idx, chan_idx) && !REACHED_TC(dma_idx, chan_idx) && !(dma[dma_idx].command & 4) && - ((dma[dma_idx].chans[chan_idx].mode & 0x30) != 0x30)) { + (DMA_TRANSFER_MODE(dma[dma_idx].chans[chan_idx].mode) != CASCADE)) { dma_process_channel(dma_idx, chan_idx); ticks++; } else { @@ -232,66 +232,48 @@ } +/* lets ride on the cpp ass */ #define d(x) (x-1) +#define HANDLE_X(n) \ + HANDLE_##n(1, 1); \ + HANDLE_##n(1, 2); \ + HANDLE_##n(1, 3); \ + HANDLE_##n(1, 4); \ + HANDLE_##n(2, 1); \ + HANDLE_##n(2, 2); \ + HANDLE_##n(2, 3); \ + HANDLE_##n(2, 4) static Bit8u dma_io_read(ioport_t port) { Bit8u r = 0xff; switch (port) { -/* lets ride on the cpp ass */ #define HANDLE_CUR_ADDR_READ(d_n, c_n) \ - case DMA##d_n##_ADDR_##c_n: \ - r = dma[d(d_n)].chans[d(c_n)].cur_addr.byte[dma[d(d_n)].ff]; \ - q_printf("DMA%i: cur_addr read: %#x from Channel %d byte %d\n", \ - d_n, r, d(c_n), dma[d(d_n)].ff); \ - dma[d(d_n)].ff ^= 1; \ - break - HANDLE_CUR_ADDR_READ(1, 1); - HANDLE_CUR_ADDR_READ(1, 2); - HANDLE_CUR_ADDR_READ(1, 3); - HANDLE_CUR_ADDR_READ(1, 4); + case DMA##d_n##_ADDR_##c_n: \ + r = dma[d(d_n)].chans[d(c_n)].cur_addr.byte[dma[d(d_n)].ff]; \ + q_printf("DMA%i: cur_addr read: %#x from Channel %d byte %d\n", \ + d_n, r, d(c_n), dma[d(d_n)].ff); \ + dma[d(d_n)].ff ^= 1; \ + break + HANDLE_X(CUR_ADDR_READ); - HANDLE_CUR_ADDR_READ(2, 1); - HANDLE_CUR_ADDR_READ(2, 2); - HANDLE_CUR_ADDR_READ(2, 3); - HANDLE_CUR_ADDR_READ(2, 4); -#undef HANDLE_CUR_ADDR_READ - #define HANDLE_CUR_CNT_READ(d_n, c_n) \ - case DMA##d_n##_CNT_##c_n: \ - r = dma[d(d_n)].chans[d(c_n)].cur_count.byte[dma[d(d_n)].ff]; \ - q_printf("DMA%i: cur_cnt read: %#x from Channel %d byte %d\n", \ - d_n, r, d(c_n), dma[d(d_n)].ff); \ - dma[d(d_n)].ff ^= 1; \ - break - HANDLE_CUR_CNT_READ(1, 1); - HANDLE_CUR_CNT_READ(1, 2); - HANDLE_CUR_CNT_READ(1, 3); - HANDLE_CUR_CNT_READ(1, 4); + case DMA##d_n##_CNT_##c_n: \ + r = dma[d(d_n)].chans[d(c_n)].cur_count.byte[dma[d(d_n)].ff]; \ + q_printf("DMA%i: cur_cnt read: %#x from Channel %d byte %d\n", \ + d_n, r, d(c_n), dma[d(d_n)].ff); \ + dma[d(d_n)].ff ^= 1; \ + break + HANDLE_X(CUR_CNT_READ); - HANDLE_CUR_CNT_READ(2, 1); - HANDLE_CUR_CNT_READ(2, 2); - HANDLE_CUR_CNT_READ(2, 3); - HANDLE_CUR_CNT_READ(2, 4); -#undef HANDLE_CUR_CNT_READ - #define HANDLE_PAGE_READ(d_n, c_n) \ - case DMA##d_n##_PAGE_##c_n: \ - r = dma[d(d_n)].chans[d(c_n)].page; \ - q_printf("DMA%i: page read: %#x from Channel %d\n", \ - d_n, r, d(c_n)); \ - break - HANDLE_PAGE_READ(1, 1); - HANDLE_PAGE_READ(1, 2); - HANDLE_PAGE_READ(1, 3); - HANDLE_PAGE_READ(1, 4); + case DMA##d_n##_PAGE_##c_n: \ + r = dma[d(d_n)].chans[d(c_n)].page; \ + q_printf("DMA%i: page read: %#x from Channel %d\n", \ + d_n, r, d(c_n)); \ + break + HANDLE_X(PAGE_READ); - HANDLE_PAGE_READ(2, 1); - HANDLE_PAGE_READ(2, 2); - HANDLE_PAGE_READ(2, 3); - HANDLE_PAGE_READ(2, 4); -#undef HANDLE_PAGE_READ - case DMA1_STAT_REG: r = dma[DMA1].status; q_printf("DMA1: Read %u from Status reg\n", r); @@ -328,60 +310,33 @@ switch (port) { #define HANDLE_ADDR_WRITE(d_n, c_n) \ - case DMA##d_n##_ADDR_##c_n: \ - dma[d(d_n)].chans[d(c_n)].base_addr.byte[dma[d(d_n)].ff] = value; \ - dma[d(d_n)].chans[d(c_n)].cur_addr.byte[dma[d(d_n)].ff] = value; \ - q_printf("DMA%i: addr write: %#x to Channel %d byte %d\n", \ - d_n, value, d(c_n), dma[d(d_n)].ff); \ - dma[d(d_n)].ff ^= 1; \ - break - HANDLE_ADDR_WRITE(1, 1); - HANDLE_ADDR_WRITE(1, 2); - HANDLE_ADDR_WRITE(1, 3); - HANDLE_ADDR_WRITE(1, 4); + case DMA##d_n##_ADDR_##c_n: \ + dma[d(d_n)].chans[d(c_n)].base_addr.byte[dma[d(d_n)].ff] = value; \ + dma[d(d_n)].chans[d(c_n)].cur_addr.byte[dma[d(d_n)].ff] = value; \ + q_printf("DMA%i: addr write: %#x to Channel %d byte %d\n", \ + d_n, value, d(c_n), dma[d(d_n)].ff); \ + dma[d(d_n)].ff ^= 1; \ + break + HANDLE_X(ADDR_WRITE); - HANDLE_ADDR_WRITE(2, 1); - HANDLE_ADDR_WRITE(2, 2); - HANDLE_ADDR_WRITE(2, 3); - HANDLE_ADDR_WRITE(2, 4); -#undef HANDLE_ADDR_WRITE - #define HANDLE_CNT_WRITE(d_n, c_n) \ - case DMA##d_n##_CNT_##c_n: \ - dma[d(d_n)].chans[d(c_n)].base_count.byte[dma[d(d_n)].ff] = value; \ - dma[d(d_n)].chans[d(c_n)].cur_count.byte[dma[d(d_n)].ff] = value; \ - q_printf("DMA%i: count write: %#x to Channel %d byte %d\n", \ - d_n, value, d(c_n), dma[d(d_n)].ff); \ - dma[d(d_n)].ff ^= 1; \ - break - HANDLE_CNT_WRITE(1, 1); - HANDLE_CNT_WRITE(1, 2); - HANDLE_CNT_WRITE(1, 3); - HANDLE_CNT_WRITE(1, 4); + case DMA##d_n##_CNT_##c_n: \ + dma[d(d_n)].chans[d(c_n)].base_count.byte[dma[d(d_n)].ff] = value; \ + dma[d(d_n)].chans[d(c_n)].cur_count.byte[dma[d(d_n)].ff] = value; \ + q_printf("DMA%i: count write: %#x to Channel %d byte %d\n", \ + d_n, value, d(c_n), dma[d(d_n)].ff); \ + dma[d(d_n)].ff ^= 1; \ + break + HANDLE_X(CNT_WRITE); - HANDLE_CNT_WRITE(2, 1); - HANDLE_CNT_WRITE(2, 2); - HANDLE_CNT_WRITE(2, 3); - HANDLE_CNT_WRITE(2, 4); -#undef HANDLE_CNT_WRITE - #define HANDLE_PAGE_WRITE(d_n, c_n) \ - case DMA##d_n##_PAGE_##c_n: \ - dma[d(d_n)].chans[d(c_n)].page = value; \ - q_printf("DMA%i: page write: %#x to Channel %d\n", \ - d_n, value, d(c_n)); \ - break - HANDLE_PAGE_WRITE(1, 1); - HANDLE_PAGE_WRITE(1, 2); - HANDLE_PAGE_WRITE(1, 3); - HANDLE_PAGE_WRITE(1, 4); + case DMA##d_n##_PAGE_##c_n: \ + dma[d(d_n)].chans[d(c_n)].page = value; \ + q_printf("DMA%i: page write: %#x to Channel %d\n", \ + d_n, value, d(c_n)); \ + break + HANDLE_X(PAGE_WRITE); - HANDLE_PAGE_WRITE(2, 1); - HANDLE_PAGE_WRITE(2, 2); - HANDLE_PAGE_WRITE(2, 3); - HANDLE_PAGE_WRITE(2, 4); -#undef HANDLE_PAGE_WRITE - case DMA1_MASK_REG: if (value & 4) { q_printf("DMA1: mask channel %i\n", value & 3); @@ -489,9 +444,6 @@ dma_process(); // Not needed in fact } -#undef d - - void dma_new_reset(void) { dma_soft_reset(DMA1); --- /dev/null 2009-09-23 16:50:16.994007431 +0400 +++ src/base/dev/dma/dmaregs.h 2007-06-29 10:30:17.000000000 +0400 @@ -0,0 +1,74 @@ +/* + * (C) Copyright 1992, ..., 2005 the "DOSEMU-Development-Team". + * + * for details see file COPYING in the DOSEMU distribution + */ + +#ifndef __DMAREGS_H__ +#define __DMAREGS_H__ + +/* 8237 DMA controllers */ +#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ +#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ + +/* DMA controller registers */ +#define DMA1_CMD_REG 0x08 /* command register (w) */ +#define DMA1_STAT_REG 0x08 /* status register (r) */ +#define DMA1_REQ_REG 0x09 /* request register (w) */ +#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ +#define DMA1_MODE_REG 0x0B /* mode register (w) */ +#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ +#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ +#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ +#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ +#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ + +#define DMA2_CMD_REG 0xD0 /* command register (w) */ +#define DMA2_STAT_REG 0xD0 /* status register (r) */ +#define DMA2_REQ_REG 0xD2 /* request register (w) */ +#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ +#define DMA2_MODE_REG 0xD6 /* mode register (w) */ +#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ +#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ +#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ +#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ +#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ + +#define DMA1_ADDR_1 0x00 /* DMA address registers */ +#define DMA1_ADDR_2 0x02 +#define DMA1_ADDR_3 0x04 +#define DMA1_ADDR_4 0x06 +#define DMA2_ADDR_1 0xC0 +#define DMA2_ADDR_2 0xC4 +#define DMA2_ADDR_3 0xC8 +#define DMA2_ADDR_4 0xCC + +#define DMA1_CNT_1 0x01 /* DMA count registers */ +#define DMA1_CNT_2 0x03 +#define DMA1_CNT_3 0x05 +#define DMA1_CNT_4 0x07 +#define DMA2_CNT_1 0xC2 +#define DMA2_CNT_2 0xC6 +#define DMA2_CNT_3 0xCA +#define DMA2_CNT_4 0xCE + +#define DMA1_PAGE_1 0x87 /* DMA page registers */ +#define DMA1_PAGE_2 0x83 +#define DMA1_PAGE_3 0x81 +#define DMA1_PAGE_4 0x82 +#define DMA2_PAGE_1 0x8F +#define DMA2_PAGE_2 0x8B +#define DMA2_PAGE_3 0x89 +#define DMA2_PAGE_4 0x8A + +#define DMA_TRANSFER_MODE(m) ((m >> 4) & 3) +enum TRMODE { DEMAND, SINGLE, BLOCK, CASCADE }; + +#define DMA_TRANSFER_OP(m) (m & 3) +enum TROP { VERIFY, WRITE, READ, INVALID }; + +#define DMA_ADDR_DEC(m) ((m >> 3) & 1) + +#define DMA_AUTOINIT(m) ((m >> 2) & 1) + +#endif --- src/base/sound/nullsnd.c 2008-03-06 12:39:48.000000000 +0300 +++ src/base/sound/nullsnd.c 2008-03-06 12:35:50.000000000 +0300 @@ -37,7 +37,6 @@ static const char *nullsnd_name = "Sound Output: NULL device"; const int frag_size = 4096; static struct player_params params; -static struct player_callbacks calls; static int running, locked; static double last_time = 0; @@ -83,7 +82,7 @@ time = GETusTIME(0); while (time - last_time > frag_time) { last_time += frag_time; - calls.get_data(NULL, frag_size, ¶ms); + pcm_data_get(NULL, frag_size, ¶ms); } } @@ -99,5 +98,5 @@ player.unlock = nullsnd_unlock; player.timer = nullsnd_timer; running = locked = 0; - return pcm_register_clocked_player(player, &calls); + return pcm_register_clocked_player(player); } --- src/base/sound/sndpcm.c 2009-09-23 12:59:45.000000000 +0400 +++ src/base/sound/sndpcm.c 2008-03-06 12:47:18.000000000 +0300 @@ -39,7 +39,6 @@ #include <string.h> #include <math.h> #include <limits.h> -#include <assert.h> #define SND_BUFFER_SIZE 200000 /* enough to hold 2.2s of 44100/stereo */ @@ -206,6 +199,48 @@ } } +static int pcm_get_format8(int is_signed) +{ + return is_signed ? PCM_FORMAT_S8 : PCM_FORMAT_U8; +} + +static int pcm_get_format16(int is_signed) +{ + return is_signed ? PCM_FORMAT_S16_LE : PCM_FORMAT_U16_LE; +} + +int pcm_get_format(int is_16, int is_signed) +{ + return is_16 ? pcm_get_format16(is_signed) : + pcm_get_format8(is_signed); +} + +static int cutoff(int val, int min, int max) +{ + if (val < min) + return min; + if (val > max) + return max; + return val; +} + +int pcm_samp_cutoff(int val, int format) +{ + switch (format) { + case PCM_FORMAT_U8: + return cutoff(val, 0, UCHAR_MAX); + case PCM_FORMAT_S8: + return cutoff(val, SCHAR_MIN, SCHAR_MAX); + case PCM_FORMAT_U16_LE: + return cutoff(val, 0, USHRT_MAX); + case PCM_FORMAT_S16_LE: + return cutoff(val, SHRT_MIN, SHRT_MAX); + default: + error("PCM: format %i is not supported\n", format); + return 0; + } +} + #define UC2SS(v) ((*(unsigned char *)(v) - 128) * 256) #define SC2SS(v) (*(signed char *)(v) * 256) #define US2SS(v) (*(unsigned short *)(v) - 32768) @@ -402,7 +437,7 @@ return 1; } -double pcm_get_stream_time(int strm_idx) +static double pcm_get_stream_time(int strm_idx) { struct sample samp; long long now = GETusTIME(0); @@ -412,7 +447,7 @@ return samp.tstamp; } -static double pcm_calc_tstamp(double rate, int strm_idx) +double pcm_calc_tstamp(double rate, int strm_idx) { double time, period, tstamp; if (rate == 0) @@ -492,15 +527,14 @@ if (s.tstamp > time) { // S_printf("PCM: stream %i time=%lli, req_time=%lli\n", i, s.tstamp, time); if (samp) - for (j = 0; j < pcm.stream[i].channels; j++) - samp[i][j] = s2[j]; + memcpy(samp[i], s2, sizeof(struct sample) * + pcm.stream[i].channels); if (time >= pcm.stream[i].start_time) ret++; break; } if (shift && idxs[i] >= pcm.stream[i].channels) { - for (j = 0; j < pcm.stream[i].channels; j++) - rng_get(&pcm.stream[i].buffer, NULL); + rng_remove(&pcm.stream[i].buffer, pcm.stream[i].channels, NULL); idxs[i] -= pcm.stream[i].channels; } for (j = 0; j < pcm.stream[i].channels; j++) @@ -531,17 +565,14 @@ continue; value[j] += sample_to_S16(in[i][j].data, in[i][j].format); } - if (value[j] > SHRT_MAX) - value[j] = SHRT_MAX; - if (value[j] < SHRT_MIN) - value[j] = SHRT_MIN; - S16_to_sample(value[j], out + j * pcm_format_size(format), format); + S16_to_sample(pcm_samp_cutoff(value[j], PCM_FORMAT_S16_LE), + out + j * pcm_format_size(format), format); } } /* this is called by the clocked player. It prepares the data for * him, and, just in case, feeds it to all the unclocked players too. */ -static size_t pcm_data_get(void *data, size_t size, +size_t pcm_data_get(void *data, size_t size, struct player_params *params) { int i, samp_sz, have_data, idxs[MAX_STREAMS], ret = 0; @@ -567,7 +598,7 @@ start_time = now - BUFFER_DELAY * 2; stop_time = start_time + frag_period; } - S_printf("PCM: going to process %zu bytes for %i players (st=%f stp=%f d=%f)\n", + S_printf("PCM: going to process %zi bytes for %i players (st=%f stp=%f d=%f)\n", size, players.num_clocked + players.num_unclocked, start_time, stop_time, now - start_time); @@ -634,8 +665,7 @@ return ret; } -int pcm_register_clocked_player(struct clocked_player player, - struct player_callbacks *callbacks) +int pcm_register_clocked_player(struct clocked_player player) { S_printf("PCM: registering clocked player: %s\n", player.name); if (players.num_clocked) { @@ -643,7 +673,6 @@ return 0; } players.clocked.player = player; - callbacks->get_data = pcm_data_get; players.num_clocked++; return 1; } @@ -665,8 +694,6 @@ { int i; for (i = 0; i < players.num_unclocked; i++) - if (players.unclocked[i].player.timer) - players.unclocked[i].player.timer(); if (players.clocked.player.timer) players.clocked.player.timer(); } @@ -689,8 +716,7 @@ pcm_flush(i); if (pcm.playing) pcm_stop_output(); - if (players.clocked.player.close) - players.clocked.player.close(); + players.clocked.player.close(); for (i = 0; i < players.num_unclocked; i++) players.unclocked[i].player.close(); for (i = 0; i < pcm.num_streams; i++) --- src/plugin/midimisc/mid_o_tmdty.c 2009-04-03 11:45:40.000000000 +0400 +++ src/plugin/midimisc/mid_o_tmdty.c 2008-03-06 10:54:34.000000000 +0300 @@ -52,7 +51,7 @@ #define TMDTY_BIN "timidity" #define TMDTY_ARGS "-EFreverb=0 -EFchorus=0 -EFresamp=1 -EFvlpf=0 -EFns=0" -static const char *midotmdty_name = "MIDI Output: midid plugin"; +static const char *midotmdty_name = "MIDI Output: TiMidity++ plugin"; static int ctrl_sock_in, ctrl_sock_out, data_sock, pcm_stream; static pid_t tmdty_pid = -1; @@ -71,7 +70,8 @@ while ((selret = select(data_sock + 1, &rfds, NULL, NULL, &tv)) > 0) { n = RPT_SYSCALL(read(data_sock, buf, sizeof(buf))); if (n > 0) { - pcm_write_samples(buf, n, 44100, PCM_FORMAT_S16_LE, + pcm_write_samples(buf, n, TMDTY_FREQ, pcm_get_format( + TMDTY_8BIT ? 0 : 1, TMDTY_UNS ? 0 : 1), pcm_stream); } else { break; @@ -233,10 +225,10 @@ if (ret) { const char *ver_str = "Server Version "; char *ptr = strstr(buf, ver_str); - int vmin, vmid, vmaj, ver; if (!ptr) { ret = FALSE; } else { + int vmin, vmid, vmaj, ver; ptr += strlen(ver_str); sscanf(ptr, "%d.%d.%d", &vmaj, &vmid, &vmin); ver = vmaj * 10000 + vmid * 100 + vmin; @@ -311,7 +303,7 @@ if (TMDTY_CAPT) { add_to_io_select(data_sock, 1, midotmdty_io); - pcm_stream = pcm_allocate_stream(2, "MIDI"); + pcm_stream = pcm_allocate_stream(TMDTY_MONO ? 1 : 2, "MIDI"); } return TRUE; --- src/plugin/sdl/snd_o_SDL.c 2008-03-06 12:39:48.000000000 +0300 +++ src/plugin/sdl/snd_o_SDL.c 2009-09-23 14:37:44.000000000 +0400 @@ -33,12 +33,11 @@ #include <SDL.h> static const char *sdlsnd_name = "Sound Output: SDL device"; -static struct player_callbacks calls; static struct player_params params; static void sdlsnd_callback(void *userdata, Uint8 * stream, int len) { - calls.get_data(stream, len, ¶ms); + pcm_data_get(stream, len, ¶ms); } static void sdlsnd_start(void) @@ -87,9 +86,8 @@ player.close = sdlsnd_close; player.lock = SDL_LockAudio; player.unlock = SDL_UnlockAudio; - player.timer = NULL; #if 1 - return pcm_register_clocked_player(player, &calls); + return pcm_register_clocked_player(player); #else return 0; #endif --- src/plugin/sndfile/snd_o_wav.c 2007-04-28 22:21:33.000000000 +0400 +++ src/plugin/sndfile/snd_o_wav.c 2006-12-11 18:07:05.000000000 +0300 @@ -34,7 +34,7 @@ #include <stdio.h> #include <sndfile.h> -static const char *wavsnd_name = "Sound Output: WAV writer"; +static const char *wavsnd_name = "Sound Output: WAV file writer"; static SNDFILE *wav; static int wavsnd_open(struct player_params *par) @@ -67,7 +67,6 @@ player.open = wavsnd_open; player.close = wavsnd_close; player.write = wavsnd_write; - player.timer = NULL; #if 0 return pcm_register_unclocked_player(player); #else --- src/include/sound/sndpcm.h 2007-04-28 22:21:23.000000000 +0400 +++ src/include/sound/sndpcm.h 2008-03-06 10:42:33.000000000 +0300 @@ -30,13 +30,15 @@ extern void pcm_set_flag(int strm_idx, int flag); extern void pcm_set_mode(int strm_idx, int mode); extern int pcm_flush(int strm_idx); +extern int pcm_samp_cutoff(int val, int format); +extern int pcm_get_format(int is_16, int is_signed); extern double pcm_samp_period(double rate, int channels); extern double pcm_frag_period(int size, struct player_params *params); extern void pcm_write_samples(void *ptr, size_t size, - double rate, int format, int strm_idx); + double rate, int format, int strm_idx); extern int pcm_format_size(int format); extern void pcm_timer(void); -extern double pcm_get_stream_time(int strm_idx); +extern double pcm_calc_tstamp(double rate, int strm_idx); #define PCM_FLAG_RAW 1 --- src/include/sound/sound.h 2008-03-06 12:39:48.000000000 +0300 +++ src/include/sound/sound.h 2009-09-23 14:43:54.000000000 +0400 @@ -20,8 +20,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _SOUND_H -#define _SOUND_H +#ifndef __SOUND_H__ +#define __SOUND_H__ /* This is the correct way to run an SB timer tick */ extern void run_new_sb(void); @@ -36,9 +36,7 @@ int channels; }; -struct player_callbacks { - size_t (*get_data)(void *buf, size_t size, struct player_params *params); -}; +size_t pcm_data_get(void *data, size_t size, struct player_params *params); struct clocked_player { const char *name; @@ -55,12 +53,10 @@ const char *name; int (*open)(struct player_params *params); void (*close)(void); - void (*timer)(void); size_t (*write)(void *buf, size_t size); }; -extern int pcm_register_clocked_player(struct clocked_player player, - struct player_callbacks *callbacks); +extern int pcm_register_clocked_player(struct clocked_player player); extern int pcm_register_unclocked_player(struct unclocked_player player); /** PCM sample format */ @@ -84,4 +80,4 @@ PCM_FORMAT_IMA_ADPCM, }; -#endif /* EMU_SOUND_H */ +#endif Index: dma.h =================================================================== --- src/include/dma.h (revision 1964) +++ src/include/dma.h (working copy) @@ -9,12 +9,7 @@ void dma_init(void); void dma_reset(void); -void dma_new_init(void); -void dma_new_reset(void); -enum { DMA_NO_DACK, DMA_DACK }; -int dma_pulse_DRQ(int ch, Bit8u *buf); - /* 8237 DMA controllers */ #define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ #define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ --- /dev/null 2009-09-23 16:50:16.994007431 +0400 +++ src/include/dmanew.h 2009-09-23 14:54:16.000000000 +0400 @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2006 Stas Sergeev <stsp@xxxxxxxxxxxxxxxxxxxxx> + * + * The below copyright strings have to be distributed unchanged together + * with this file. This prefix can not be modified or separated. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __DMA_H__ +#define __DMA_H__ + +void dma_new_init(void); +void dma_new_reset(void); + +enum { DMA_NO_DACK, DMA_DACK }; +int dma_pulse_DRQ(int ch, Bit8u *buf); + +#endif Index: dma.c =================================================================== --- src/base/dev/dma/dma.c (revision 1964) +++ src/base/dev/dma/dma.c (working copy) @@ -51,6 +51,7 @@ #include <sys/types.h> #include <unistd.h> #include "dma.h" +#include "dmanew.h" #include "pic.h" #include "port.h"