]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
imported winuaesrc1520b4.zip
authorToni Wilen <twilen@winuae.net>
Sat, 30 Aug 2008 09:09:17 +0000 (12:09 +0300)
committerToni Wilen <twilen@winuae.net>
Mon, 22 Feb 2010 19:42:53 +0000 (21:42 +0200)
12 files changed:
catweasel.c
include/catweasel.h
jit/compemu_raw_x86.c
od-win32/ahidsound_new.c
od-win32/ahidsoundx_new.c [new file with mode: 0755]
od-win32/dinput.c
od-win32/direct3d.c
od-win32/sounddep/sound.c
od-win32/win32.c
od-win32/win32.h
od-win32/win32gfx.c
od-win32/winuaechangelog.txt

index 5f10cc02d6c4131825c73a4d6cd341c6c72ebb7a..01a51ea8aa65cb0c9dd55c05602286503ebde599 100755 (executable)
@@ -24,9 +24,11 @@ static int mouse_x[2], mouse_y[2], mouse_px[2], mouse_py[2];
 
 static HANDLE handle = INVALID_HANDLE_VALUE;
 
-int catweasel_isjoystick(void)
+int catweasel_isjoystick (void)
 {
     uae_u8 b = cwc.can_joy;
+    if (!cwc.direct_access)
+       return 0;
     if (b) {
        if (cwc.type == CATWEASEL_TYPE_MK3 && cwc.sid[0])
            b |= 0x80;
@@ -35,18 +37,20 @@ int catweasel_isjoystick(void)
     }
     return b;
 }
-int catweasel_ismouse(void)
+int catweasel_ismouse (void)
 {
+    if (!cwc.direct_access)
+       return 0;
     return cwc.can_mouse;
 }
 
 static int hsync_requested;
-static void hsync_request(void)
+static void hsync_request (void)
 {
     hsync_requested = 10;
 };
 
-static void sid_write(uae_u8 reg, uae_u8 val, int sidnum)
+static void sid_write (uae_u8 reg, uae_u8 val, int sidnum)
 {
     if (sidnum >= cwc.can_sid)
        return;
@@ -56,7 +60,7 @@ static void sid_write(uae_u8 reg, uae_u8 val, int sidnum)
     catweasel_do_bget(0xd8); // dummy read
 }
 
-static uae_u8 sid_read(uae_u8 reg, int sidnum)
+static uae_u8 sid_read (uae_u8 reg, int sidnum)
 {
     if (sidnum >= cwc.can_sid)
        return 0;
@@ -66,12 +70,12 @@ static uae_u8 sid_read(uae_u8 reg, int sidnum)
     return catweasel_do_bget(0xd8);
 }
 
-static uae_u8 get_buttons(void)
+static uae_u8 get_buttons (void)
 {
     uae_u8 b, b2;
 
     b = 0;
-    if (cwc.type < CATWEASEL_TYPE_MK3)
+    if (cwc.type < CATWEASEL_TYPE_MK3 || !cwc.direct_access)
        return b;
     hsync_request();
     b2 = catweasel_do_bget(0xc8) & (0x80 | 0x40);
@@ -108,9 +112,9 @@ static uae_u8 get_buttons(void)
     return b;
 }
 
-int catweasel_read_mouse(int port, int *dx, int *dy, int *buttons)
+int catweasel_read_mouse (int port, int *dx, int *dy, int *buttons)
 {
-    if (!cwc.can_mouse)
+    if (!cwc.can_mouse || !cwc.direct_access)
        return 0;
     hsync_request();
     *dx = mouse_x[port];
@@ -121,7 +125,7 @@ int catweasel_read_mouse(int port, int *dx, int *dy, int *buttons)
     return 1;
 }
 
-static void sid_reset(void)
+static void sid_reset (void)
 {
     int i;
     for (i = 0; i < 0x19; i++) {
@@ -130,13 +134,13 @@ static void sid_reset(void)
     }
 }
 
-static void catweasel_detect_sid(void)
+static void catweasel_detect_sid (void)
 {
     int i, j;
     uae_u8 b1, b2;
 
     cwc.sid[0] = cwc.sid[1] = 0;
-    if (!cwc.can_sid)
+    if (!cwc.can_sid || !cwc.direct_access)
        return;
     sid_reset();
     if (cwc.type >= CATWEASEL_TYPE_MK4) {
@@ -181,7 +185,7 @@ void catweasel_hsync (void)
 {
     int i;
 
-    if (cwc.type < CATWEASEL_TYPE_MK3)
+    if (cwc.type < CATWEASEL_TYPE_MK3 || !cwc.direct_access)
        return;
     cwhsync--;
     if (cwhsync > 0)
@@ -244,7 +248,7 @@ void catweasel_hsync (void)
 
 int catweasel_read_joystick (uae_u8 *dir, uae_u8 *buttons)
 {
-    if (!cwc.can_joy)
+    if (!cwc.can_joy || !cwc.direct_access)
        return 0;
     hsync_request();
     *dir = catweasel_do_bget(0xc0);
@@ -256,7 +260,7 @@ int catweasel_read_keyboard (uae_u8 *keycode)
 {
     uae_u8 v;
 
-    if (!cwc.can_kb)
+    if (!cwc.can_kb || !cwc.direct_access)
        return 0;
     if (!currprefs.catweasel)
        return 0;
@@ -309,15 +313,15 @@ void catweasel_do_bput (uaecptr   addr, uae_u32 b)
 
 #include "core.cw4.c"
 
-static int cw_config_done(void)
+static int cw_config_done (void)
 {
     return ioport_read (cwc.iobase + 7) & 4;
 }
-static int cw_fpga_ready(void)
+static int cw_fpga_ready (void)
 {
     return ioport_read (cwc.iobase + 7) & 8;
 }
-static void cw_resetFPGA(void)
+static void cw_resetFPGA (void)
 {
     ioport_write (cwc.iobase + 2, 227);
     ioport_write (cwc.iobase + 3, 0);
@@ -325,7 +329,7 @@ static void cw_resetFPGA(void)
     ioport_write (cwc.iobase + 3, 65);
 }
 
-static int catweasel3_configure(void)
+static int catweasel3_configure (void)
 {
     ioport_write (cwc.iobase, 241);
     ioport_write (cwc.iobase + 1, 0);
@@ -337,7 +341,7 @@ static int catweasel3_configure(void)
     return 1;
 }
 
-static int catweasel4_configure(void)
+static int catweasel4_configure (void)
 {
     struct zfile *f;
     time_t t;
@@ -534,12 +538,15 @@ int catweasel_init(void)
        } else {
            cwc.direct_type = force_direct_catweasel >= 0x400 ? 3 : 1;
        }
+       cwc.direct_access = 1;
 
     } else {
 
        for (i = 0; i < 4; i++) {
            if (currprefs.catweasel > 0)
                i = currprefs.catweasel;
+           if (currprefs.catweasel < 0)
+               i = -currprefs.catweasel + 1;
            sprintf (name, "\\\\.\\CAT%d_F0", i);
            handle = CreateFile (name, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, 0,
                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
@@ -548,11 +555,15 @@ int catweasel_init(void)
        }
        if (handle == INVALID_HANDLE_VALUE)
            catweasel_detect();
+       cwc.direct_access = 0;
+       if (currprefs.catweasel < 0)
+           cwc.direct_access = 1;
     }
 
     if (handle == INVALID_HANDLE_VALUE) {
        strcpy(name, "[DIRECT]");
        if (cwc.direct_type && ioport_init()) {
+           cwc.direct_access = 1;
            if (cwc.direct_type == 4 && catweasel4_configure()) {
                cwc.type = 4;
                cwc.can_joy = 2;
@@ -590,44 +601,53 @@ int catweasel_init(void)
        cwc.can_sid = buffer[6] ? 1 : 0;
        cwc.can_kb = buffer[7] & 1;
        cwc.can_mouse = (buffer[4] & 2) ? 2 : 0;
-       if (!DeviceIoControl (handle, CW_LOCK_EXCLUSIVE, 0, 0, buffer, sizeof (buffer), &len, 0)) {
-           write_log ("CW: CW_LOCK_EXCLUSIVE failed %d\n", GetLastError());
+        if (!DeviceIoControl (handle, CW_LOCK_EXCLUSIVE, 0, 0, buffer, sizeof (buffer), &len, 0)) {
+           write_log ("CW: CW_LOCK_EXCLUSIVE failed %d\n", GetLastError ());
            goto fail;
        }
        model = *((uae_u32*)(buffer + 4));
        base = *((uae_u32*)(buffer + 0));
        cwc.type = model == 0 ? 1 : model == 2 ? 4 : 3;
        cwc.iobase = base;
+       if (!cwc.direct_access) {
+           if (!DeviceIoControl (handle, CW_UNLOCK_EXCLUSIVE, 0, 0, 0, 0, &len, 0)) {
+               write_log ("CW: CW_UNLOCK_EXCLUSIVE failed %d\n", GetLastError ());
+           }
+       }
        if (cwc.type == CATWEASEL_TYPE_MK4 && cwc.can_sid)
            cwc.can_sid = 2;
     }
 
-    if (cwc.type == CATWEASEL_TYPE_MK4) {
-       if (cwc.can_mouse) {
-           int i;
-           catweasel_do_bput(3, 0x81);
-           catweasel_do_bput(0xd0, 4|8); // amiga mouse + pullups
-           // clear mouse counters
-           for (i = 0; i < 2; i++) {
-               catweasel_do_bput(0xc4 + i * 8, 0);
-               catweasel_do_bput(0xc0 + i * 8, 0);
+    if (cwc.direct_access) {
+       if (cwc.type == CATWEASEL_TYPE_MK4) {
+           if (cwc.can_mouse) {
+               int i;
+               catweasel_do_bput (3, 0x81);
+               catweasel_do_bput (0xd0, 4|8); // amiga mouse + pullups
+               // clear mouse counters
+               for (i = 0; i < 2; i++) {
+                   catweasel_do_bput (0xc4 + i * 8, 0);
+                   catweasel_do_bput (0xc0 + i * 8, 0);
+               }
            }
+           catweasel_do_bput (3, 0x41); /* enable MK3-mode */
        }
-       catweasel_do_bput(3, 0x41); /* enable MK3-mode */
+       if (cwc.can_joy)
+           catweasel_do_bput (0xcc, 0); // joystick buttons = input
     }
-    if (cwc.can_joy)
-       catweasel_do_bput(0xcc, 0); // joystick buttons = input
 
     //catweasel_init_controller(&cwc);
-    sprintf(tmp, "CW: Catweasel MK%d @%p (%s) enabled.",
-       cwc.type, (uae_u8*)cwc.iobase, name);
-    if (cwc.can_sid) {
-       char *p = tmp + strlen(tmp);
-       catweasel_detect_sid();
-       sprintf(p, " SID0=%d", cwc.sid[0]);
-       if (cwc.can_sid > 1) {
-           p += strlen(p);
-           sprintf(p, " SID1=%d", cwc.sid[1]);
+    sprintf(tmp, "CW: Catweasel MK%d @%p (%s) enabled. %s.",
+       cwc.type, (uae_u8*)cwc.iobase, name, cwc.direct_access ? "DIRECTIO": "API");
+    if (cwc.direct_access) {
+       if (cwc.can_sid) {
+           char *p = tmp + strlen(tmp);
+           catweasel_detect_sid ();
+           sprintf(p, " SID0=%d", cwc.sid[0]);
+           if (cwc.can_sid > 1) {
+               p += strlen(p);
+               sprintf(p, " SID1=%d", cwc.sid[1]);
+           }
        }
     }
     write_log ("%s\n", tmp);
@@ -642,12 +662,14 @@ fail:
 
 void catweasel_free (void)
 {
-    if (cwc.type == 4)
-       catweasel_do_bput(3, 0x61); // enable floppy passthrough
+    if (cwc.direct_access) {
+       if (cwc.type == 4)
+           catweasel_do_bput(3, 0x61); // enable floppy passthrough
+    }
     if (handle != INVALID_HANDLE_VALUE)
        CloseHandle (handle);
     handle = INVALID_HANDLE_VALUE;
-    ioport_free();
+    ioport_free ();
     memset (&cwc, 0, sizeof cwc);
     mouse_x[0] = mouse_x[1] = mouse_y[0] = mouse_y[1] = 0;
     mouse_px[0] = mouse_px[1] = mouse_py[0] = mouse_py[1] = 0;
@@ -678,11 +700,11 @@ int catweasel_detect (void)
     }
     if (h == INVALID_HANDLE_VALUE) {
        if (force_direct_catweasel >= 100) {
-           if (ioport_init())
+           if (ioport_init ())
                return TRUE;
            return FALSE;
        }
-       if (direct_detect()) {
+       if (direct_detect ()) {
            detected = 1;
            return TRUE;
        }
@@ -690,677 +712,4 @@ int catweasel_detect (void)
     return FALSE;
 }
 
-#if 0
-
-#define outb(v,port) catweasel_do_bput(port,v)
-#define inb(port) catweasel_do_bget(port)
-
-#define LONGEST_TRACK 16000
-
-static uae_u8 mfmbuf[LONGEST_TRACK * 4];
-static uae_u8 tmpmfmbuffer[LONGEST_TRACK * 2];
-
-static int bitshiftcompare(uae_u8 *src,int bit,int len,uae_u8 *comp)
-{
-       uae_u8 b;
-       int ones,zeros,len2;
-
-       ones=zeros=0;
-       len2=len;
-       while(len--) {
-               b = (comp[0] << bit) | (comp[1] >> (8 - bit));
-               if(b != *src) return 1;
-               if(b==0x00) zeros++;
-               if(b==0xff) ones++;
-               src++;
-               comp++;
-       }
-       if(ones==len2||zeros==len2) return 1;
-       return 0;
-}
-
-static uae_u8 *mergepieces(uae_u8 *start,int len,int bits,uae_u8 *sync)
-{
-       uae_u8 *dst=tmpmfmbuffer;
-       uae_u8 b;
-       int size;
-       int shift;
-
-       size=len-(sync-start);
-       memcpy(dst,sync,size);
-       dst+=size;
-       b=start[len];
-       b&=~(255>>bits);
-       b|=start[0]>>bits;
-       *dst++=b;
-       shift=8-bits;
-       while(start<=sync+2000) {
-               *dst++=(start[0]<<shift)|(start[1]>>(8-shift));
-               start++;
-       }
-       return tmpmfmbuffer;
-}
-
-#define SCANOFFSET 1 /*        scanning range in bytes, -SCANOFFSET to SCANOFFSET */
-#define SCANOFFSET2 20
-#define SCANLENGHT 200 /* scanning length in bytes */
-
-static uae_u8* scantrack(uae_u8 *sync1,uae_u8 *sync2,int *trackbytes,int *trackbits)
-{
-       int i,bits,bytes,matched;
-       uae_u8 *sync2bak=sync2;
-
-       sync1+=SCANOFFSET2;
-       sync2+=SCANOFFSET2;
-       while(sync1 < sync2bak - 2*SCANOFFSET - SCANOFFSET2 - SCANLENGHT) {
-               matched=0x7fff;
-               for(i=0;i<2*SCANOFFSET*8;i++) {
-                       bits=i&7;
-                       bytes=-SCANOFFSET+(i>>3);
-                       if(!bitshiftcompare(sync1,bits,SCANLENGHT,sync2+bytes)) {
-                               if(matched==0x7fff) {
-                                       matched=i;
-                               } else {
-                                       break;
-                               }
-                       }
-               }
-               if(matched!=0x7fff && i>=2*SCANOFFSET*8) {
-                       bits=matched&7;
-                       bytes=-SCANOFFSET+(matched>>3);
-                       *trackbytes=sync2+bytes-sync1;
-                       *trackbits=bits;
-                       return mergepieces(sync1,*trackbytes,*trackbits,sync2bak);
-               }
-               sync1++;
-               sync2++;
-       }
-       return 0;
-}
-
-static unsigned char threshtab[128];
-
-static void codec_makethresh(int trycnt, const unsigned char *origt, unsigned char *t, int numthresh)
-{
-    static unsigned char tab[10] = { 0, 0, 0, 0, -1, -2, 1, 2, -1, 1 };
-
-    if (trycnt >= sizeof (tab))
-       trycnt = sizeof (tab) - 1;
-    while(numthresh--)
-       t[numthresh] = origt[numthresh] + tab[trycnt];
-}
-
-static void codec_init_threshtab(int trycnt, const unsigned char *origt)
-{
-    static unsigned char old_thresholds[2] = { 0, 0 };
-    unsigned char t[2];
-    int a, i;
-
-    codec_makethresh(trycnt, origt, t, 2);
-
-    if(*(unsigned short*)t == *(unsigned short*)old_thresholds)
-       return;
-
-    for(i=0,a=2; i<128; i++) {
-       if(i == t[0] || i == t[1])
-           a++;
-       threshtab[i] = a;
-    }
-
-    *(unsigned short*)&old_thresholds = *(unsigned short*)t;
-}
-
-static __inline__ void CWSetCReg(catweasel_contr *c, unsigned char clear, unsigned char set)
-{
-    c->control_register = (c->control_register & ~clear) | set;
-    outb(c->control_register, c->io_sr);
-}
-
-static void CWTriggerStep(catweasel_contr *c)
-{
-    CWSetCReg(c, c->crm_step, 0);
-    CWSetCReg(c, 0, c->crm_step);
-}
-
-void catweasel_init_controller(catweasel_contr *c)
-{
-    int i, j;
-
-    if(!c->iobase)
-       return;
-
-    switch(c->type) {
-    case CATWEASEL_TYPE_MK1:
-       c->crm_sel0 = 1 << 5;
-       c->crm_sel1 = 1 << 4;
-       c->crm_mot0 = 1 << 3;
-       c->crm_mot1 = 1 << 7;
-       c->crm_dir  = 1 << 1;
-       c->crm_step = 1 << 0;
-       c->srm_trk0 = 1 << 4;
-       c->srm_dchg = 1 << 5;
-       c->srm_writ = 1 << 1;
-       c->io_sr    = c->iobase + 2;
-       c->io_mem   = c->iobase;
-       break;
-    case CATWEASEL_TYPE_MK3:
-    case CATWEASEL_TYPE_MK4:
-       c->crm_sel0 = 1 << 2;
-       c->crm_sel1 = 1 << 3;
-       c->crm_mot0 = 1 << 1;
-       c->crm_mot1 = 1 << 5;
-       c->crm_dir  = 1 << 4;
-       c->crm_step = 1 << 7;
-       c->srm_trk0 = 1 << 2;
-       c->srm_dchg = 1 << 5;
-       c->srm_writ = 1 << 6;
-       c->srm_dskready = 1 << 4;
-       c->io_sr    = c->iobase + 0xe8;
-       c->io_mem   = c->iobase + 0xe0;
-       break;
-    default:
-       return;
-    }
-
-    c->control_register = 255;
-
-    /* select all drives, step inside */
-    CWSetCReg(c, c->crm_dir | c->crm_sel0 | c->crm_sel1, 0);
-    for(i=0;i<2;i++) {
-       c->drives[i].number = i;
-       c->drives[i].contr = c;
-       c->drives[i].diskindrive = 0;
-
-       /* select only the respective drive, step to track 0 */
-       if(i == 0) {
-           CWSetCReg(c, c->crm_sel0, c->crm_dir | c->crm_sel1);
-       } else {
-           CWSetCReg(c, c->crm_sel1, c->crm_dir | c->crm_sel0);
-       }
-
-       for(j = 0; j < 86 && (inb(c->io_sr) & c->srm_trk0); j++) {
-           CWTriggerStep(c);
-           sleep_millis(6);
-       }
-
-       if(j < 86) {
-           c->drives[i].type = 1;
-           c->drives[i].track = 0;
-       } else {
-           c->drives[i].type = 0;
-       }
-    }
-    c->drives[0].sel = c->crm_sel0;
-    c->drives[0].mot = c->crm_mot0;
-    c->drives[1].sel = c->crm_sel1;
-    c->drives[1].mot = c->crm_mot1;
-    CWSetCReg(c, 0, c->crm_sel0 | c->crm_sel1); /* deselect all drives */
-}
-
-void catweasel_free_controller(catweasel_contr *c)
-{
-    if(!c->iobase)
-       return;
-
-    /* all motors off, deselect all drives */
-    CWSetCReg(c, 0, c->crm_mot0 | c->crm_mot1 | c->crm_sel0 | c->crm_sel1);
-}
-
-void catweasel_set_motor(catweasel_drive *d, int on)
-{
-    CWSetCReg(d->contr, d->sel, 0);
-    if (on)
-       CWSetCReg(d->contr, d->mot, 0);
-    else
-       CWSetCReg(d->contr, 0, d->mot);
-    CWSetCReg(d->contr, 0, d->sel);
-}
-
-int catweasel_step(catweasel_drive *d, int dir)
-{
-    catweasel_contr *c = d->contr;
-    CWSetCReg(c, d->sel, 0);
-    if (dir > 0)
-       CWSetCReg(c, c->crm_dir, 0);
-    else
-       CWSetCReg(c, 0, c->crm_dir);
-    CWTriggerStep (c);
-    CWSetCReg(c, 0, d->sel);
-    d->track += dir > 0 ? 1 : -1;
-    return 1;
-}
-
-int catweasel_disk_changed(catweasel_drive *d)
-{
-    int ret;
-    CWSetCReg(d->contr, d->sel, 0);
-    ret = (inb(d->contr->io_sr) & d->contr->srm_dchg) ? 0 : 1;
-    CWSetCReg(d->contr, 0, d->sel);
-    return ret;
-}
-
-int catweasel_diskready(catweasel_drive        *d)
-{
-    int ret;
-    CWSetCReg(d->contr, d->sel, 0);
-    ret = (inb(d->contr->io_sr) & d->contr->srm_dskready) ? 0 : 1;
-    CWSetCReg(d->contr, 0, d->sel);
-    return ret;
-}
-
-int catweasel_track0(catweasel_drive *d)
-{
-    int ret;
-    CWSetCReg(d->contr, d->sel, 0);
-    ret = (inb(d->contr->io_sr) & d->contr->srm_trk0) ? 0 : 1;
-    CWSetCReg(d->contr, 0, d->sel);
-    if (ret)
-       d->track = 0;
-    return ret;
-}
-
-int catweasel_write_protected(catweasel_drive *d)
-{
-    int ret;
-    CWSetCReg(d->contr, d->sel, 0);
-    ret = !(inb(d->contr->io_sr) & 8);
-    CWSetCReg(d->contr, 0, d->sel);
-    return ret;
-}
-
-uae_u8 catweasel_read_byte(catweasel_drive *d)
-{
-    return inb(d->contr->io_mem);
-}
-
-static const unsigned char amiga_thresholds[] = { 0x22, 0x30 }; // 27, 38 for 5.25"
-
-#define FLOPPY_WRITE_LEN 6250
-
-#define MFMMASK 0x55555555
-static uae_u32 getmfmlong (uae_u16 * mbuf)
-{
-       return (uae_u32)(((*mbuf << 16) | *(mbuf + 1)) & MFMMASK);
-}
-
-static int drive_write_adf_amigados (uae_u16 *mbuf, uae_u16 *mend, uae_u8 *writebuffer, int track)
-{
-       int i, secwritten = 0;
-       uae_u32 odd, even, chksum, id, dlong;
-       uae_u8 *secdata;
-       uae_u8 secbuf[544];
-       char sectable[22];
-       int num_sectors = 11;
-       int ec = 0;
-
-       memset (sectable, 0, sizeof (sectable));
-       mend -= (4 + 16 + 8 + 512);
-       while (secwritten < num_sectors) {
-               int trackoffs;
-
-               do {
-                       while (*mbuf++ != 0x4489) {
-                           if (mbuf >= mend) {
-                               ec = 1;
-                               goto err;
-                           }
-                       }
-               } while (*mbuf++ != 0x4489);
-
-               odd = getmfmlong (mbuf);
-               even = getmfmlong (mbuf + 2);
-               mbuf += 4;
-               id = (odd << 1) | even;
-
-               trackoffs = (id & 0xff00) >> 8;
-               if (trackoffs > 10) {
-                   ec = 2;
-                   goto err;
-               }
-               chksum = odd ^ even;
-               for (i = 0; i < 4; i++) {
-                       odd = getmfmlong (mbuf);
-                       even = getmfmlong (mbuf + 8);
-                       mbuf += 2;
-
-                       dlong = (odd << 1) | even;
-                       if (dlong) {
-                           ec = 6;
-                           goto err;
-                       }
-                       chksum ^= odd ^ even;
-               } /* could check here if the label is nonstandard */
-               mbuf += 8;
-               odd = getmfmlong (mbuf);
-               even = getmfmlong (mbuf + 2);
-               mbuf += 4;
-               if (((odd << 1) | even) != chksum) {
-                   ec = 3;
-                   goto err;
-               }
-               odd = (id & 0x00ff0000) >> 16;
-               if (odd != track) {
-                   ec = 7;
-                   goto err;
-               }
-               odd = getmfmlong (mbuf);
-               even = getmfmlong (mbuf + 2);
-               mbuf += 4;
-               chksum = (odd << 1) | even;
-               secdata = secbuf + 32;
-               for (i = 0; i < 128; i++) {
-                       odd = getmfmlong (mbuf);
-                       even = getmfmlong (mbuf + 256);
-                       mbuf += 2;
-                       dlong = (odd << 1) | even;
-                       *secdata++ = dlong >> 24;
-                       *secdata++ = dlong >> 16;
-                       *secdata++ = dlong >> 8;
-                       *secdata++ = dlong;
-                       chksum ^= odd ^ even;
-               }
-               mbuf += 256;
-               if (chksum) {
-                   ec = 4;
-                   goto err;
-               }
-               sectable[trackoffs] = 1;
-               secwritten++;
-               memcpy (writebuffer + trackoffs * 512, secbuf + 32, 512);
-       }
-       if (secwritten == 0 || secwritten < 0) {
-           ec = 5;
-           goto err;
-       }
-       return 0;
-err:
-       write_log ("mfm decode error %d. secwritten=%d\n", ec, secwritten);
-       for (i = 0; i < num_sectors; i++)
-           write_log ("%d:%d ", i, sectable[i]);
-       write_log ("\n");
-       return ec;
-}
-
-static void mfmcode (uae_u16 * mfm, int words)
-{
-    uae_u32 lastword = 0;
-
-    while (words--) {
-       uae_u32 v = *mfm;
-       uae_u32 lv = (lastword << 16) | v;
-       uae_u32 nlv = 0x55555555 & ~lv;
-       uae_u32 mfmbits = (nlv << 1) & (nlv >> 1);
-
-       *mfm++ = v | mfmbits;
-       lastword = v;
-    }
-}
-
-#define        FLOPPY_GAP_LEN 360
-
-static int amigados_mfmcode (uae_u8 *src, uae_u16 *dst, int num_secs, int track)
-{
-       int sec;
-       memset (dst, 0xaa, FLOPPY_GAP_LEN * 2);
-
-       for (sec = 0; sec < num_secs; sec++) {
-           uae_u8 secbuf[544];
-           int i;
-           uae_u16 *mfmbuf = dst + 544 * sec + FLOPPY_GAP_LEN;
-           uae_u32 deven, dodd;
-           uae_u32 hck = 0, dck = 0;
-
-           secbuf[0] = secbuf[1] = 0x00;
-           secbuf[2] = secbuf[3] = 0xa1;
-           secbuf[4] = 0xff;
-           secbuf[5] = track;
-           secbuf[6] = sec;
-           secbuf[7] = num_secs - sec;
-
-           for (i = 8; i < 24; i++)
-               secbuf[i] = 0;
-
-           mfmbuf[0] = mfmbuf[1] = 0xaaaa;
-           mfmbuf[2] = mfmbuf[3] = 0x4489;
-
-           memcpy (secbuf + 32, src + sec * 512, 512);
-           deven = ((secbuf[4] << 24) | (secbuf[5] << 16)
-                    | (secbuf[6] << 8) | (secbuf[7]));
-           dodd = deven >> 1;
-           deven &= 0x55555555;
-           dodd &= 0x55555555;
-
-           mfmbuf[4] = dodd >> 16;
-           mfmbuf[5] = dodd;
-           mfmbuf[6] = deven >> 16;
-           mfmbuf[7] = deven;
-
-           for (i = 8; i < 48; i++)
-               mfmbuf[i] = 0xaaaa;
-           for (i = 0; i < 512; i += 4) {
-               deven = ((secbuf[i + 32] << 24) | (secbuf[i + 33] << 16)
-                        | (secbuf[i + 34] << 8) | (secbuf[i + 35]));
-               dodd = deven >> 1;
-               deven &= 0x55555555;
-               dodd &= 0x55555555;
-               mfmbuf[(i >> 1) + 32] = dodd >> 16;
-               mfmbuf[(i >> 1) + 33] = dodd;
-               mfmbuf[(i >> 1) + 256 + 32] = deven >> 16;
-               mfmbuf[(i >> 1) + 256 + 33] = deven;
-           }
-
-           for (i = 4; i < 24; i += 2)
-               hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
-
-           deven = dodd = hck;
-           dodd >>= 1;
-           mfmbuf[24] = dodd >> 16;
-           mfmbuf[25] = dodd;
-           mfmbuf[26] = deven >> 16;
-           mfmbuf[27] = deven;
-
-           for (i = 32; i < 544; i += 2)
-               dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1];
-
-           deven = dodd = dck;
-           dodd >>= 1;
-           mfmbuf[28] = dodd >> 16;
-           mfmbuf[29] = dodd;
-           mfmbuf[30] = deven >> 16;
-           mfmbuf[31] = deven;
-           mfmcode (mfmbuf + 4, 544 - 4);
-
-       }
-    return (num_secs * 544 + FLOPPY_GAP_LEN) * 2 * 8;
-}
-
-static uae_u16 amigamfmbuffer[LONGEST_TRACK];
-static uae_u8 amigabuffer[512*22];
-
-/* search and align to 0x4489 WORDSYNC markers */
-static int isamigatrack(uae_u8 *mfmdata, uae_u8 *mfmdatae, uae_u16 *mfmdst, int track)
-{
-       uae_u16 *dst = amigamfmbuffer;
-       int len;
-       int shift, syncshift, sync,ret;
-       uae_u32 l;
-       uae_u16 w;
-
-       sync = syncshift = shift = 0;
-       len = (mfmdatae - mfmdata) * 8;
-       if (len > LONGEST_TRACK * 8)
-           len = LONGEST_TRACK * 8;
-       while (len--) {
-               l = (mfmdata[0] << 16) | (mfmdata[1] << 8) | (mfmdata[2] << 0);
-               w = l >> (8 - shift);
-               if (w == 0x4489) {
-                       sync = 1;
-                       syncshift = 0;
-               }
-               if (sync) {
-                       if (syncshift == 0) *dst++ = w;
-                       syncshift ++;
-                       if (syncshift == 16) syncshift = 0;
-               }
-               shift++;
-               if (shift == 8) {
-                       mfmdata++;
-                       shift = 0;
-               }
-       }
-       if (sync) {
-               ret=drive_write_adf_amigados (amigamfmbuffer, dst, amigabuffer, track);
-               if(!ret)
-                   return amigados_mfmcode (amigabuffer, mfmdst, 11, track);
-               write_log ("decode error %d\n", ret);
-       } else {
-           write_log ("decode error: no sync found\n");
-       }
-       return 0;
-}
-
-
-
-int catweasel_fillmfm (catweasel_drive *d, uae_u16 *mfm, int side, int clock, int rawmode)
-{
-    int i, j, oldsync, syncs[10], synccnt, endcnt;
-    uae_u32 tt1 = 0, tt2 = 0;
-    uae_u8 *p1;
-    int bytes = 0, bits = 0;
-    static int lasttrack, trycnt;
-
-    if (cwc.type == 0)
-       return 0;
-    if (d->contr->control_register & d->mot)
-       return 0;
-    if (!catweasel_read (d, side, 1, rawmode))
-       return 0;
-    if(d->contr->type == CATWEASEL_TYPE_MK1) {
-       inb(d->contr->iobase + 1);
-       inb(d->contr->io_mem); /* ignore first byte */
-    } else {
-       outb(0, d->contr->iobase + 0xe4);
-    }
-    catweasel_read_byte (d);
-    if (lasttrack == d->track)
-       trycnt++;
-    else
-       trycnt = 0;
-    lasttrack = d->track;
-    codec_init_threshtab(trycnt, amiga_thresholds);
-    i = 0; j = 0;
-    synccnt = 0;
-    oldsync = -1;
-    endcnt = 0;
-    while (j < LONGEST_TRACK * 4) {
-       uae_u8 b = catweasel_read_byte (d);
-       if (b >= 250) {
-           if (b == 255 - endcnt) {
-               endcnt++;
-               if (endcnt == 5)
-                   break;
-           } else
-               endcnt = 0;
-       }
-       if (rawmode) {
-           if (b & 0x80) {
-               if (oldsync < j) {
-                   syncs[synccnt++] = j;
-                   oldsync = j + 300;
-               }
-           }
-           if (synccnt >= 3 && j > oldsync)
-               break;
-       }
-       b = threshtab[b & 0x7f];
-       tt1 = (tt1 << b) + 1;
-       tt2 += b;
-
-       if (tt2 >= 16) {
-           tt2 -= 16;
-           mfmbuf[j++] = tt1 >> (tt2 + 8);
-           mfmbuf[j++] = tt1 >> tt2;
-       }
-       i++;
-    }
-    write_log ("cyl=%d, side=%d, length %d, syncs %d\n", d->track, side, j, synccnt);
-    if (rawmode) {
-       if (synccnt >= 3) {
-           p1 = scantrack (mfmbuf + syncs[1], mfmbuf + syncs[2], &bytes, &bits);
-           if (p1) {
-               j = 0;
-               for (i = 0; i < bytes + 2; i+=2) {
-                   mfm[j++] = (p1[i] << 8) | p1[i + 1];
-               }
-               return bytes * 8 + bits;
-           }
-       }
-    } else {
-       return isamigatrack (mfmbuf, mfmbuf + j, mfm, d->track * 2 + side);
-    }
-    return 0;
-}
-
-int catweasel_read(catweasel_drive *d, int side, int clock, int rawmode)
-{
-    int iobase = d->contr->iobase;
-
-    CWSetCReg(d->contr, d->sel, 0);
-    if(d->contr->type == CATWEASEL_TYPE_MK1) {
-       CWSetCReg(d->contr, 1<<2, (!side)<<2); /* set disk side */
-
-       inb(iobase+1); /* ra reset */
-       outb(clock*128, iobase+3);
-
-       inb(iobase+1);
-       inb(iobase+0);
-//     inb(iobase+0);
-//     outb(0, iobase+3); /* don't store index pulse */
-
-       inb(iobase+1);
-
-       inb(iobase+7); /* start reading */
-       sleep_millis(rawmode ? 550 : 225);
-       outb(0, iobase+1); /* stop reading, don't reset RAM pointer */
-
-       outb(128, iobase+0); /* add data end mark */
-       outb(128, iobase+0);
-
-       inb(iobase+1); /* Reset RAM pointer */
-    } else {
-       CWSetCReg(d->contr, 1<<6, (!side)<<6); /* set disk side */
-
-       outb(0, iobase + 0xe4); /* Reset memory pointer */
-       switch(clock) {
-       case 0: /* 28MHz */
-           outb(128, iobase + 0xec);
-           break;
-       case 1: /* 14MHz */
-           outb(0, iobase + 0xec);
-           break;
-       }
-       inb(iobase + 0xe0);
-       inb(iobase + 0xe0);
-       outb(0, iobase + 0xec); /* no IRQs, no MFM predecode */
-       inb(iobase + 0xe0);
-       outb(0, iobase + 0xec); /* don't store index pulse */
-
-       outb(0, iobase + 0xe4); /* Reset memory pointer */
-       inb(iobase + 0xf0); /* start reading */
-       sleep_millis(rawmode ? 550 : 225);
-       inb(iobase + 0xe4); /* stop reading, don't reset RAM pointer */
-
-       outb(255, iobase + 0xe0); /* add data end mark */
-       outb(254, iobase + 0xe0); /* add data end mark */
-       outb(253, iobase + 0xe0); /* add data end mark */
-       outb(252, iobase + 0xe0); /* add data end mark */
-       outb(251, iobase + 0xe0); /* add data end mark */
-       outb(0, iobase + 0xe4); /* Reset memory pointer */
-    }
-    CWSetCReg(d->contr, 0, d->sel);
-    return 1;
-}
-
-#endif
-
 #endif
\ No newline at end of file
index 7ae6c458071243d155df41a4eb40e948c384c767..acee5bd8ef0508fa6b392eebed5dcc44f10ca5d7 100755 (executable)
@@ -27,6 +27,7 @@ typedef struct catweasel_drive {
 
 typedef struct catweasel_contr {
     int type;                      /* see CATWEASEL_TYPE_* defines below */
+    int direct_access;
     int direct_type;
     int iobase;                    /* 0 = not present (factory default is 0x320) */
     void (*msdelay)(int ms);       /* microseconds delay routine, provided by host program */
index 5639b7e5eb75ed3e706297e95705362c55b34d7f..e86cea6fb43703ec87f29398f187d75dc240e784 100755 (executable)
@@ -1973,7 +1973,7 @@ int EvalException (LPEXCEPTION_POINTERS blah, int n_except)
            return EXCEPTION_CONTINUE_EXECUTION;
        }
     }
-    write_log ("JIT: Can't handle access %08.8X!\n", i);
+    write_log ("JIT: Can't handle access %08X!\n", i);
 #if 0
     if (i)
     {
index bb2ff3bb912317ba1739eae19b437f62287c02f4..168450f95adbc290eed6b0340b09fd22e97a55e0 100755 (executable)
@@ -1,7 +1,7 @@
 /*
  * UAE - The Un*x Amiga Emulator
  *
- * DirectSound AHI 7.1 wrapper
+ * OpenAL AHI 7.1 wrapper
  *
  * Copyright 2008 Toni Wilen
  */
 #include "ahidsound_new.h"
 #include "dxwrap.h"
 
-#include <mmsystem.h>
-#include <mmreg.h>
-#include <dsound.h>
-#include <ks.h>
-#include <ksmedia.h>
+#include <al.h>
+#include <alc.h>
 
 #define AHI_STRUCT_VERSION 1
 
@@ -49,6 +46,7 @@ static int ahi_debug = 1;
 #define UAE_MAXCHANNELS 24
 #define UAE_MAXSOUNDS 256
 #define RECORDSAMPLES 2048
+#define PLAYSAMPLES 1536
 
 #define ub_Flags 34
 #define ub_Pad1 (ub_Flags + 1)
@@ -321,7 +319,7 @@ struct dssample {
     uae_u32 len;
     uae_u32 type;
     uae_u32 sampletype;
-    uae_u32 offset;
+    ALuint al_buffer[2];
 };
 
 struct chsample {
@@ -332,24 +330,16 @@ struct chsample {
     struct dssample *ds;
     int srcplayoffset;
     int srcplaylen;
-    int stopit;
 };
 
 struct dschannel {
     int num;
     struct chsample cs;
     struct chsample csnext;
-    LPDIRECTSOUNDBUFFER8 dsb;
-
-    uae_u8 *buffer;
-    int mixlength;
-    int buffercursor;
-    int hsync;
     int channelsignal;
-    int srcoffset;
-
     int dsplaying;
-    int dscursor;
+    ALuint al_source;
+    int samplecounter;
 };
 
 struct DSAHI {
@@ -371,17 +361,17 @@ struct DSAHI {
     int playing, recording;
     evt evttime;
     uae_u32 signalchannelmask;
-    LPDIRECTSOUND8 DS;
 
-    LPDIRECTSOUNDCAPTURE DSC;
-    LPDIRECTSOUNDCAPTUREBUFFER dscb;
+    ALCdevice *al_dev;
+    ALCcontext *al_ctx;
+    int al_bufferformat;
+    uae_u8 *tmpbuffer;
+    int tmpbuffer_size;
     int dsrecording;
-    int recordingcursor;
     int record_ch;
     int record_bytespersample;
-    int channellength_record;
-    int mixlength_record;
     int record_wait;
+    int maxplaysamples;
 };
 
 static struct DSAHI dsahi[1];
@@ -460,8 +450,11 @@ static int sendsignal (struct DSAHI *dsahip)
        ch = get_word (channelinfo + ahieci_Channels);
        if (ch > UAE_MAXCHANNELS)
            ch = UAE_MAXCHANNELS;
-       for (i = 0; i < ch; i++)
-           put_long (channelinfo + ahieci_Offset + i * 4, dsahip->channel[i].srcoffset);
+       for (i = 0; i < ch; i++) {
+           int v;
+           alGetSourcei (dsahip->channel[i].al_source, AL_SAMPLE_OFFSET, &v);
+           put_long (channelinfo + ahieci_Offset + i * 4, v);
+       }
     }
 
     uae_Signal (task, signalmask);
@@ -475,7 +468,7 @@ static void setchannelevent (struct DSAHI *dsahip, struct dschannel *dc)
     int ch = dc - &dsahip->channel[0];
     uae_u32 mask;
 
-    if (!dsahip->playing || ahi_paused || dc->dsb == NULL)
+    if (!dsahip->playing || ahi_paused || !dc->al_source)
        return;
     mask = get_long (puaebase + pub_ChannelSignal);
     if (mask & (1 << ch))
@@ -523,172 +516,136 @@ static void setevent (struct DSAHI *dsahip)
     event2_newevent2 (t, dsahip - &dsahi[0], evtfunc);
 }
 
+static void alClear (void)
+{
+    alGetError ();
+}
+static int alError (const char *format,...)
+{
+    char buffer[1000];
+    va_list parms;
+    int err;
 
-
-const static GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010,
-    {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}};
+    err = alGetError ();
+    if (err == AL_NO_ERROR)
+       return 0;
+    va_start (parms, format);
+    _vsnprintf (buffer, sizeof buffer -1, format, parms);
+    sprintf (buffer + strlen (buffer), ": ERR=%x\n", err);
+    write_log ("%s", buffer);
+    return err;
+}
 
 static void ds_freechannel (struct DSAHI *ahidsp, struct dschannel *dc)
 {
     if (!dc)
        return;
-    if (dc->dsb)
-       IDirectSoundBuffer8_Release (dc->dsb);
-    xfree (dc->buffer);
+    alDeleteSources (1, &dc->al_source);
     memset (dc, 0, sizeof (struct dschannel));
+    dc->al_source = -1;
+}
+
+static void ds_freesample (struct DSAHI *ahidsp, struct dssample *ds)
+{
+    if (!ds)
+       return;
+    alDeleteBuffers (2, ds->al_buffer);
+    memset (ds, 0, sizeof (struct dssample));
+    ds->al_buffer[0] = -1;
+    ds->al_buffer[1] = -1;
 }
 
 static void ds_free (struct DSAHI *dsahip)
 {
     int i;
 
+    if (!ahi_active)
+       return;
     for (i = 0; i < dsahip->channels; i++) {
        struct dschannel *dc = &dsahip->channel[i];
        ds_freechannel (dsahip, dc);
     }
-    if (dsahip->DS)
-       IDirectSound_Release (dsahip->DS);
-    dsahip->DS = NULL;
+    for (i = 0; i < dsahip->sounds; i++) {
+       struct dssample *ds = &dsahip->sample[i];
+       ds_freesample (dsahip, ds);
+    }
+    alcMakeContextCurrent (NULL);
+    alcDestroyContext (dsahip->al_ctx);
+    dsahip->al_ctx = 0;
+    alcCloseDevice (dsahip->al_dev);
+    dsahip->al_dev = 0;
     if (ahi_debug && ahi_active)
-       write_log ("AHI: DSOUND freed\n");
+       write_log ("AHI: OpenAL freed\n");
     ahi_active = 0;
 }
 
-DWORD fillsupportedmodes (LPDIRECTSOUND8 lpDS, int freq, struct dsaudiomodes *dsam);
-static struct dsaudiomodes supportedmodes[16];
-
 static void ds_free_record (struct DSAHI *dsahip)
 {
-    if (dsahip->dscb)
-       IDirectSoundCaptureBuffer_Release (dsahip->dscb);
-    if (dsahip->DSC)
-       IDirectSoundCapture_Release (dsahip->DSC);
-    dsahip->dscb = NULL;
-    dsahip->DSC = NULL;
 }
 
 static int ds_init_record (struct DSAHI *dsahip)
 {
-    HRESULT hr;
-    WAVEFORMATEXTENSIBLE wavfmt;
-    DSCBUFFERDESC dbd;
     uae_u32 pbase = get_long (dsahip->audioctrl + ahiac_DriverData);
     int freq = get_long (dsahip->audioctrl + ahiac_MixFreq);
 
-    if (dsahip->DSC)
-       return 1;
     if (!freq)
        return 0;
-    dsahip->mixlength_record = RECORDSAMPLES; // in sample units, not bytes
-    dsahip->record_ch = 2;
-    dsahip->record_bytespersample = 2;
-    dsahip->channellength_record = freq * dsahip->record_bytespersample * dsahip->record_ch * 10;
-    put_long (pbase + pub_RecordBufferSize, dsahip->mixlength_record);
-    put_long (pbase + pub_RecordBufferSizeBytes, dsahip->mixlength_record * dsahip->record_ch * dsahip->record_bytespersample);
-    put_long (pbase + pub_RecordSampleType, AHIST_S16S);
-    put_word (pbase + pub_RecordHookDone, 0);
-
-    hr = DirectSoundCaptureCreate (&record_devices[dsahip->input].guid, &dsahip->DSC, NULL);
-    if (FAILED (hr)) {
-       write_log ("AHI: DirectSoundCaptureCreate() failure %dHz: %s\n", freq, DXError (hr));
-       goto end;
-    }
-    memset (&dbd, 0, sizeof dbd);
-    dbd.dwSize = sizeof dbd;
-    dbd.dwBufferBytes = dsahip->channellength_record;
-    dbd.lpwfxFormat = &wavfmt.Format;
-    dbd.dwFlags = 0 ;
-    memset (&wavfmt, 0, sizeof wavfmt);
-    wavfmt.Format.nChannels = dsahip->record_ch;
-    wavfmt.Format.nSamplesPerSec = freq;
-    wavfmt.Format.wBitsPerSample = dsahip->record_bytespersample * 8;
-    wavfmt.Format.wFormatTag = WAVE_FORMAT_PCM;
-    wavfmt.Format.nBlockAlign = wavfmt.Format.wBitsPerSample / 8 * wavfmt.Format.nChannels;
-    wavfmt.Format.nAvgBytesPerSec = wavfmt.Format.nBlockAlign * wavfmt.Format.nSamplesPerSec;
-    hr = IDirectSoundCapture_CreateCaptureBuffer (dsahip->DSC, &dbd, &dsahip->dscb, NULL);
-    if (FAILED (hr)) {
-       write_log ("AHI: CreateCaptureSoundBuffer() failure: %s\n", DXError(hr));
-       goto end;
-    }
-    if (ahi_debug)
-       write_log ("AHI: DSOUND Recording initialized. %dHz, %s\n", freq, record_devices[dsahip->input].name);
-
-    put_word (pbase + pub_FuncMode, get_word (pbase + pub_FuncMode) | FUNCMODE_RECORDALLOC);
-    sendsignal (dsahip);
-    return 1;
-end:
-    ds_free_record (dsahip);
     return 0;
 }
 
 static int ds_init (struct DSAHI *dsahip)
 {
     int freq = 44100;
-    DSCAPS DSCaps;
-    HRESULT hr;
-    DWORD speakerconfig;
-
-    hr = DirectSoundCreate8 (&sound_devices[dsahip->output].guid, &dsahip->DS, NULL);
-    if (FAILED (hr))  {
-       write_log ("AHI: DirectSoundCreate8() failure: %s\n", DXError (hr));
-       return 0;
+    int v, wrapped;
+    struct sound_device *sd;
+
+    sd = &sound_devices[currprefs.win32_soundcard];
+    wrapped = 0;
+    while (sd->type != SOUND_DEVICE_AL) {
+       sd++;
+       if (sd->name == NULL) {
+           if (wrapped)
+               return 0;
+           wrapped = 1;
+           sd = sound_devices;
+       }
     }
-
-    hr = IDirectSound_SetCooperativeLevel (dsahip->DS, hMainWnd, DSSCL_PRIORITY);
-    if (FAILED (hr)) {
-       write_log ("AHI: Can't set cooperativelevel: %s\n", DXError (hr));
+    dsahip->al_dev = alcOpenDevice (sd->alname);
+    if (!dsahip->al_dev)
        goto error;
-    }
+    dsahip->al_ctx = alcCreateContext (dsahip->al_dev, NULL);
+    if (!dsahip->al_ctx)
+       goto error;
+    alcMakeContextCurrent (dsahip->al_ctx);
 
-    fillsupportedmodes (dsahip->DS, default_freq, supportedmodes);
     dsahip->chout = 2;
-    if (SUCCEEDED (IDirectSound8_GetSpeakerConfig (dsahip->DS, &speakerconfig))) {
-       if (speakerconfig >= DSSPEAKER_CONFIG (DSSPEAKER_5POINT1)) {
-           cansurround = 1;
-           dsahip->chout = 6;
-           if (speakerconfig >= DSSPEAKER_CONFIG (DSSPEAKER_7POINT1))
-               dsahip->chout = 8;
-       }
+    dsahip->al_bufferformat = AL_FORMAT_STEREO16;
+    if (v = alGetEnumValue ("AL_FORMAT_QUAD16")) {
+       dsahip->chout = 4;
+       cansurround = 1;
+       dsahip->al_bufferformat = v;
+    }
+    if (v = alGetEnumValue ("AL_FORMAT_51CHN16")) {
+       dsahip->chout = 6;
+       cansurround = 1;
+       dsahip->al_bufferformat = v;
     }
-
     dsahip->bitspersampleout = dsahip->bits24 ? 24 : 16;
     dsahip->bytespersampleout = dsahip->bitspersampleout / 8;
     dsahip->channellength = 65536 * dsahip->chout * dsahip->bytespersampleout;
-    dsahip->mixlength = 4000 * dsahip->chout * dsahip->bytespersampleout;
     if (ahi_debug)
-       write_log("AHI: CH=%d BLEN=%d MLEN=%d SC=%08x\n",
-           dsahip->chout, dsahip->channellength, dsahip->mixlength, speakerconfig);
-
-    memset (&DSCaps, 0, sizeof (DSCaps));
-    DSCaps.dwSize = sizeof (DSCaps);
-    hr = IDirectSound_GetCaps (dsahip->DS, &DSCaps);
-    if (FAILED(hr)) {
-       write_log ("AHI: Error getting DirectSound capabilities: %s\n", DXError (hr));
-       goto error;
-    }
-    if (DSCaps.dwFlags & DSCAPS_EMULDRIVER) {
-       write_log ("AHI: Emulated DirectSound driver detected, don't complain if sound quality is crap :)\n");
-    }
-    if (DSCaps.dwFlags & DSCAPS_CONTINUOUSRATE) {
-       int minfreq = DSCaps.dwMinSecondarySampleRate;
-       int maxfreq = DSCaps.dwMaxSecondarySampleRate;
-       if (minfreq > freq && freq < 22050) {
-           freq = minfreq;
-           write_log ("AHI: minimum supported frequency: %d\n", minfreq);
-       }
-       if (maxfreq < freq && freq > 44100) {
-           freq = maxfreq;
-           write_log ("AHI: maximum supported frequency: %d\n", maxfreq);
-       }
-    }
+       write_log("AHI: CH=%d BLEN=%d\n",
+           dsahip->chout, dsahip->channellength);
 
+    dsahip->tmpbuffer_size = 2000000;
+    dsahip->tmpbuffer = xmalloc (dsahip->tmpbuffer_size);
     if (ahi_debug)
-       write_log ("AHI: DSOUND initialized: %s\n", sound_devices[dsahip->output].name);
+       write_log ("AHI: OpenAL initialized: %s\n", sound_devices[dsahip->output].name);
 
     return 1;
 error:
     if (ahi_debug)
-       write_log ("AHI: DSOUND initialization failed\n");
+       write_log ("AHI: OpenAL initialization failed\n");
     ds_free (dsahip);
     return 0;
 }
@@ -699,24 +656,17 @@ static int ds_reinit (struct DSAHI *dsahip)
     return ds_init (dsahip);
 }
 
-
 static void ds_setvolume (struct DSAHI *dsahip, struct dschannel *dc)
 {
-    HRESULT hr;
-    LONG vol, pan;
-
-    if (dc->dsb) {
+    if (dc->al_source != -1) {
        if (abs (dc->cs.volume) != abs (dc->csnext.volume)) {
-           vol = (LONG)((DSBVOLUME_MIN / 2) + (-DSBVOLUME_MIN / 2) * log (1 + (2.718281828 - 1) * (abs (dc->csnext.volume) / 65536.0)));
-           hr = IDirectSoundBuffer_SetVolume (dc->dsb, vol);
-           if (FAILED (hr))
-               write_log ("AHI: SetVolume(%d,%d) failed: %s\n", dc->num, vol, DXError (hr));
+           float vol = (float)(abs (dc->csnext.volume) / 65536.0);
+           alClear ();
+           alSourcef (dc->al_source, AL_GAIN, vol);
+           alError ("AHI: SetVolume(%d,%d)", dc->num, vol);
        }
        if (abs (dc->cs.panning) != abs (dc->csnext.panning)) {
-           pan = (abs (dc->csnext.panning) - 0x8000) * DSBPAN_RIGHT / 32768;
-           hr = IDirectSoundBuffer_SetPan (dc->dsb, pan);
-           if (FAILED (hr))
-               write_log ("AHI: SetPan(%d,%d) failed: %s\n", dc->num, pan, DXError (hr));
+;//        pan = (abs (dc->csnext.panning) - 0x8000) * DSBPAN_RIGHT / 32768;
        }
     }
     dc->cs.volume = dc->csnext.volume;
@@ -725,96 +675,30 @@ static void ds_setvolume (struct DSAHI *dsahip, struct dschannel *dc)
 
 static void ds_setfreq (struct DSAHI *dsahip, struct dschannel *dc)
 {
-    HRESULT hr;
-
-    if (dc->cs.frequency != dc->csnext.frequency && dc->csnext.frequency > 0 && dc->dsb) {
-       hr = IDirectSoundBuffer8_SetFrequency (dc->dsb, dc->csnext.frequency);
-       if (FAILED (hr))
-           write_log ("AHI: SetFrequency(%d,%d) failed: %s\n", dc->num, dc->csnext.frequency, DXError (hr));
+    if (dc->dsplaying && dc->cs.frequency != dc->csnext.frequency && dc->csnext.frequency > 0 && dc->al_source != -1) {
+       //alClear ();
+       //alSourcei (dc->al_source, AL_FREQUENCY, dc->csnext.frequency);
+       //alError ("AHI: SetFrequency(%d,%d)", dc->num, dc->csnext.frequency);
     }
     dc->cs.frequency = dc->csnext.frequency;
 }
 
 static int ds_allocchannel (struct DSAHI *dsahip, struct dschannel *dc)
 {
-    HRESULT hr;
-    DSBUFFERDESC dd;
-    WAVEFORMATEXTENSIBLE wavfmt;
-    LPDIRECTSOUNDBUFFER pdsb;
-    LPDIRECTSOUNDBUFFER8 pdsb8;
-    int round;
-
-    if (dc->dsb)
+    if (dc->al_source != -1)
        return 1;
-    pdsb = NULL;
-    for (round = 0; supportedmodes[round].ch; round++) {
-        DWORD ksmode = 0;
-
-        pdsb = NULL;
-        if (supportedmodes[round].ch != dsahip->chout)
-           continue;
-
-       memset (&wavfmt, 0, sizeof (WAVEFORMATEXTENSIBLE));
-       wavfmt.Format.nChannels = dsahip->chout;
-       wavfmt.Format.nSamplesPerSec = default_freq;
-       wavfmt.Format.wBitsPerSample = dsahip->bitspersampleout;
-       if (dsahip->chout <= 2) {
-           wavfmt.Format.wFormatTag = WAVE_FORMAT_PCM;
-       } else {
-           DWORD ksmode = 0;
-           wavfmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
-           wavfmt.Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
-           wavfmt.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
-           wavfmt.Samples.wValidBitsPerSample = dsahip->bitspersampleout;
-           wavfmt.dwChannelMask = supportedmodes[round].ksmode;
-       }
-       wavfmt.Format.nBlockAlign = dsahip->bytespersampleout * wavfmt.Format.nChannels;
-       wavfmt.Format.nAvgBytesPerSec = wavfmt.Format.nBlockAlign * wavfmt.Format.nSamplesPerSec;
-
-       memset (&dd, 0, sizeof dd);
-       dd.dwSize = sizeof dd;
-       dd.dwBufferBytes = dsahip->channellength;
-       dd.lpwfxFormat = &wavfmt.Format;
-       dd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY;
-       dd.dwFlags |= DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY;
-       dd.dwFlags |= dsahip->chout >= 4 ? DSBCAPS_LOCHARDWARE : DSBCAPS_LOCSOFTWARE;
-       dd.guid3DAlgorithm = GUID_NULL;
-
-       hr = IDirectSound_CreateSoundBuffer (dsahip->DS, &dd, &pdsb, NULL);
-       if (SUCCEEDED (hr))
-           break;
-       if (dd.dwFlags & DSBCAPS_LOCHARDWARE) {
-           HRESULT hr2 = hr;
-           dd.dwFlags &= ~DSBCAPS_LOCHARDWARE;
-           dd.dwFlags |=  DSBCAPS_LOCSOFTWARE;
-           hr = IDirectSound_CreateSoundBuffer (dsahip->DS, &dd, &pdsb, NULL);
-           if (SUCCEEDED (hr))
-               break;
-       }
-       write_log ("AHI: DS sound buffer failed (ch=%d,bps=%d): %s\n",
-           dsahip->chout, dsahip->bitspersampleout, DXError (hr));
-    }
-    if (pdsb == NULL)
-       goto error;
-
-    hr = IDirectSound_QueryInterface (pdsb, &IID_IDirectSoundBuffer8, (LPVOID*)&pdsb8);
-    if (FAILED (hr))  {
-       write_log ("AHI: Secondary QueryInterface(IID_IDirectSoundBuffer8) failure: %s\n", DXError (hr));
+    alClear ();
+    alGenSources (1, &dc->al_source);
+    if (alError ("alGenSources()"))
        goto error;
-    }
-    IDirectSound_Release (pdsb);
-    dc->dsb = pdsb8;
-
     dc->cs.frequency = -1;
     dc->cs.volume = -1;
     dc->cs.panning = -1;
     ds_setvolume (dsahip, dc);
     ds_setfreq (dsahip, dc);
-    dc->mixlength = dsahip->mixlength;
-    dc->buffer = xcalloc (dc->mixlength, 1);
-    dc->buffercursor = 0;
     if (ahi_debug)
-       write_log ("AHI: allocated directsound buffer for channel %d\n", dc->num);
+       write_log ("AHI: allocated OpenAL source for channel %d. vol=%d pan=%d freq=%d\n",
+       dc->num, dc->cs.volume, dc->cs.panning, dc->cs.frequency);
     return 1;
 error:
     ds_freechannel (dsahip, dc);
@@ -855,7 +739,8 @@ STATIC_INLINE void makexch (struct DSAHI *dsahip, struct dschannel *dc, uae_u8 *
     }
 }
 
-static void copysampledata (struct DSAHI *dsahip, struct dschannel *dc, struct dssample *ds, uae_u8 **psrcp, uae_u8 *srce, uae_u8 *srcp, void *dstp, int dstlen)
+/* sample conversion routines */
+static int copysampledata (struct DSAHI *dsahip, struct dschannel *dc, struct dssample *ds, uae_u8 **psrcp, uae_u8 *srce, uae_u8 *srcp, void *dstp, int dstlen)
 {
     int i;
     uae_u8 *src = *psrcp;
@@ -1011,10 +896,12 @@ static void copysampledata (struct DSAHI *dsahip, struct dschannel *dc, struct d
        break;
     }
     *psrcp = src;
+    return dstlen * och2;
 }
 
 static void dorecord (struct DSAHI *dsahip)
 {
+#if 0
     uae_u32 pbase = get_long (dsahip->audioctrl + ahiac_DriverData);
     HRESULT hr;
     DWORD cpos, rpos, diff;
@@ -1074,228 +961,118 @@ static void dorecord (struct DSAHI *dsahip)
     dsahip->recordingcursor += mixlength_bytes;
     if (dsahip->recordingcursor >= dsahip->channellength_record)
        dsahip->recordingcursor -= dsahip->channellength_record;
+#endif
 }
 
-static int ds_copysample (struct DSAHI *dsahip, struct dschannel *dc)
-{
-    HRESULT hr;
-    DWORD playc, writec;
-    DWORD size1, size2;
-    DWORD diff;
-    void *buf1, *buf2;
-
-    hr = IDirectSoundBuffer8_GetCurrentPosition (dc->dsb, &playc, &writec);
-    if (FAILED (hr)) {
-        write_log ("AHI: GetCurrentPosition(%d) failed, %s\n", dc->num, DXError (hr));
-        return 0;
-    }
-
-    if (dc->dscursor >= writec)
-       diff = dc->dscursor - writec;
-    else
-        diff = dsahip->channellength - writec + dc->dscursor;
-
-    if (diff > dsahip->channellength / 2) {
-       dc->dscursor = writec + dc->mixlength;
-       write_log ("AHI: Resync\n");
-    }
-    if (diff > dc->mixlength)
-       return 0;
 
-    hr = IDirectSoundBuffer8_Lock (dc->dsb, dc->dscursor, dc->mixlength, &buf1, &size1, &buf2, &size2, 0);
-    if (hr == DSERR_BUFFERLOST) {
-       IDirectSoundBuffer8_Restore (dc->dsb);
-       hr = IDirectSoundBuffer8_Lock (dc->dsb, dc->dscursor, dc->mixlength, &buf1, &size1, &buf2, &size2, 0);
-    }
-    if (SUCCEEDED (hr)) {
-       memcpy (buf1, dc->buffer, size1);
-       if (buf2) 
-           memcpy (buf2, dc->buffer + size1, size2);
-       IDirectSoundBuffer8_Unlock (dc->dsb, buf1, size1, buf2, size2);
-    }
-
-    if (ahi_debug > 1)
-       write_log ("%d playc=%08d writec=%08d dscursor=%08d\n",
-           diff / (dsahip->chout * dsahip->bytespersampleout),
-           playc, writec, dc->dscursor);
-
-    dc->dscursor += dc->mixlength;
-    if (dc->dscursor >= dsahip->channellength)
-       dc->dscursor -= dsahip->channellength;
-
-    return 1;
-}
-
-static int calcdelay (struct dschannel *dc, int len)
+static void al_setloop (struct dschannel *dc, int state)
 {
-    int rate = vblank_hz * maxvpos;
-    int freq = dc->cs.frequency;
-    int hsyncs = rate * len / freq;
-    hsyncs = hsyncs * 2 / 3;
-    if (hsyncs > 0)
-       hsyncs--;
-    return hsyncs;
+    alClear ();
+    alSourcei (dc->al_source, AL_LOOPING, state ? AL_TRUE : AL_FALSE);
+    alError ("AHI: ds_play() alSourcei(AL_LOOPING)");
 }
 
-#if 0
-static void checkvolfreq (struct DSAHI *dsahip, struct dschannel *dc)
+static void al_startplay (struct dschannel *dc)
 {
-    if (dc->cs.frequency != dc->csnext.frequency)
-       ds_setfreq (dsahip, dc);
-    if (dc->cs.volume != dc->csnext.volume || dc->cs.panning != dc->csnext.panning)
-       ds_setvolume (dsahip, dc);
+    al_setloop (dc, TRUE);
+    alClear ();
+    alSourcePlay (dc->al_source);
+    alError ("AHI: ds_play() alSourcePlay");
 }
 
-static void getmixbufferlen (struct DSAHI *dsahip, struct dschannel *dc)
+static void preparesample (struct DSAHI *dsahip, struct dschannel *dc)
 {
-    int olen = dc->mixlength;
-    dc->mixlength = (dc->csnext.frequency / 24) * dsahip->bytespersampleout * dsahip->chout;
-    if (dc->mixlength > dsahip->mixlength)
-       dc->mixlength = dsahip->mixlength;
-    if (dc->mixlength < 100)
-       dc->mixlength = 100;
-    if (ahi_debug && olen != dc->mixlength)
-       write_log ("AHI: channel %d: buffer %d frames\n",
-           dc->num, dc->mixlength / (dsahip->bytespersampleout * dsahip->chout));
+    uae_u8 *p, *ps, *pe;
+    struct dssample *ds;
+    int num, slen, dlen, offset;
+
+    memcpy (&dc->cs, &dc->csnext, sizeof (struct chsample));
+    dc->csnext.ds = NULL;
+    ds = dc->cs.ds;
+    ps = p = get_real_address (ds->addr);
+    pe = ps + ds->len * ds->bytespersample * ds->ch;
+    num = ds->len / dsahip->maxplaysamples;
+    offset = dsahip->maxplaysamples * dc->samplecounter;
+    slen = dsahip->maxplaysamples;
+    if (dc->samplecounter == num - 1)
+       slen = ds->len - dsahip->maxplaysamples * (num - 1);
+    p += (offset + dc->cs.srcplayoffset) * ds->bytespersample * ds->ch;
+    dlen = copysampledata (dsahip, dc, ds, &p, pe, ps, dsahip->tmpbuffer, slen);
+    alClear ();
+    alBufferData (ds->al_buffer[dc->samplecounter], dsahip->al_bufferformat, dsahip->tmpbuffer, dlen, dc->cs.frequency);
+    alError ("AHI: preparesample:alBufferData()");
 }
 
-static void copysample (struct DSAHI *dsahip, struct dschannel *dc)
+static void al_initsample (struct DSAHI *dsahip, struct dschannel *dc)
 {
-    int dstlen, dstlenbytes;
     struct dssample *ds;
-    int srclen, srclendstbytes;
-    int chbytesout;
-    uae_u8 *dstbuf;
-    uae_u32 addr, addre, addrs;
-    int chbytesin;
-    int waitlen;
-
-    assert (dc->buffercursor < dc->mixlength);
-
-    chbytesout = dsahip->chout * dsahip->bytespersampleout;
-    dstbuf = dc->buffer + dc->buffercursor;
-    dstlenbytes = dc->mixlength - dc->buffercursor;
-    dstlen = dstlenbytes / chbytesout;
-    
-    ds = dc->cs.ds;
-    if (ds == NULL) {
-       ds = dc->ds = dc->nextds;
-       dc->srcplaylen = dc->nextsrcplaylen;
-       dc->srcplayoffset = dc->nextsrcplayoffset;
-       dc->nextds = NULL;
-       dc->nextsrcplaylen = 0;
-       dc->nextsrcplayoffset = 0;
-       dc->srcoffset = 0;
-       if (ds != NULL) { // sample started
-           int len;
-           setchannelevent (dsahip, dc);
-           len = dc->srcplaylen;
-           if (len > dstlen)
-               len = dstlen;
-           dc->hsync = calcdelay (dc, len);
-           return;
-       }
-    }
-    if (ds == NULL)
-       goto cempty;
-
-    chbytesin = ds->ch * ds->bytespersample;
-    if (ds->addr == 0 && ds->len == 0xffffffff) {
-        addrs = addr = ds->offset;
-    } else {
-        addr = ds->addr;
-        addr += dc->srcplayoffset * chbytesin;
-        addrs = addr;
-    }
-    addre = addr + dc->srcplaylen * chbytesin;
-    addr += dc->srcoffset * chbytesin;
-
-    srclen = dc->srcplaylen - dc->srcoffset;
-    assert (srclen > 0);
-    srclendstbytes = srclen * chbytesout;
 
-    if (srclendstbytes > dstlenbytes) {
-        srclendstbytes = dstlenbytes;
-        srclen = srclendstbytes / chbytesout;
-    }
-    if (dstlenbytes > srclendstbytes) {
-        dstlenbytes = srclendstbytes;
-        dstlen = dstlenbytes / chbytesout;
+    alSourceStop (dc->al_source);
+    alClear ();
+    alSourcei (dc->al_source, AL_BUFFER, AL_NONE);
+    alError ("AHI: al_initsample:AL_BUFFER=AL_NONE");
+    dc->samplecounter = 0;
+    preparesample (dsahip, dc);
+    ds = dc->cs.ds;
+    alClear ();
+    alSourceQueueBuffers (dc->al_source, 1, &ds->al_buffer[dc->samplecounter]);
+    alError ("AHI: al_initsample:alSourceQueueBuffers(freq=%d)", dc->cs.frequency);
+    if (dc->dsplaying) {
+       dc->dsplaying = 1;
+       al_startplay (dc);
+       setchannelevent (dsahip, dc);
     }
+    dc->samplecounter++;
+}
 
-    waitlen = dstlen;
-
-    assert (dstlen > 0);
-
-    if (valid_address (addrs, addre - addrs)) {
-        uae_u8 *naddr = get_real_address (addr);
-        uae_u8 *naddre = get_real_address (addre);
-        uae_u8 *naddrs = get_real_address (addrs);
-        copysampledata (dsahip, dc, ds, &naddr, naddre, naddrs, dstbuf, dstlen);
-        dc->srcoffset = (naddr - naddrs) / chbytesin;
-        if (dc->srcoffset == 0) {
-           // looping or next sample
-           if (dc->nextsrcplaylen < 0) { // stop sample
-               int off = dstlenbytes;
-               dc->nextsrcplaylen = 0;
-               dc->nextds = NULL;
-               setchannelevent (dsahip, dc);
-               dstlenbytes = dc->mixlength - off - dc->buffercursor;
-               dstlen = dstlenbytes / chbytesout;
-               memset (dstbuf + off, 0, dstlenbytes);
-               goto empty;
-           }
-           if (dc->nextds) {
-               dc->ds = NULL;
-               dc->buffercursor += dstlenbytes;
-               dc->hsync = 0;
-               return;
-           }
-           setchannelevent (dsahip, dc);
+static void al_queuesample (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    int v, restart;
 
+    al_setloop (dc, FALSE);
+    if (!dc->csnext.ds)
+       return;
+    restart = 0;
+    if (dc->dsplaying) {
+       alClear ();
+       alGetSourcei (dc->al_source, AL_SOURCE_STATE, &v);
+       alError ("AHI: queuesample AL_SOURCE_STATE");
+       if (v != AL_PLAYING) {
+           alClear ();
+           alSourceRewind (dc->al_source);
+           alError ("AHI: queuesample:restart");
+           restart = 1;
+           if (ahi_debug)
+               write_log ("AHI: queuesample, play restart\n");
        }
-
-    } else {
-       goto cempty;
     }
-
-    dc->hsync = calcdelay (dc, waitlen);
-    dc->buffercursor += dstlenbytes;
-    checkvolfreq (dsahip, dc);
-    //write_log ("%d ", dstlen / (dsahip->chout * dsahip->bytespersampleout));
-    return;
-
-cempty:
-    memset (dstbuf, 0, dstlenbytes);
-empty:
-    dc->ds = NULL;
-    dc->hsync = calcdelay (dc, waitlen);
-    dc->buffercursor += dstlenbytes;
-    checkvolfreq (dsahip, dc);
+    dc->samplecounter = 0;
+    preparesample (dsahip, dc);
+    alClear ();
+    alSourceQueueBuffers (dc->al_source, 1, &dc->cs.ds->al_buffer[dc->samplecounter]);
+    alError ("AHI: al_queuesample:alSourceQueueBuffers(freq=%d)", dc->cs.frequency);
+    if (dc->dsplaying)
+       dc->dsplaying = 1;
+    if (restart)
+       al_startplay (dc);
+    al_setloop (dc, FALSE);
+    if (ahi_debug)
+       write_log ("AHI: sample %d queued to channel %d\n", dc->cs.ds->num, dc->num);
 }
-#endif
 
-static void incchannel (struct DSAHI *dsahip, struct dschannel *dc, int samplecnt)
+static int unqueuebuffers (struct dschannel *dc)
 {
-    struct chsample *cs = &dc->cs;
-
-    if (cs->ds == NULL)
-       return;
-    dc->srcoffset += samplecnt;
-    while (dc->srcoffset >= cs->srcplaylen) {
-       dc->srcoffset -= cs->srcplaylen;
-        setchannelevent (dsahip, dc);
-       if (dc->csnext.stopit) {
-           memset (cs, 0, sizeof (struct chsample));
-           memset (&dc->csnext, 0, sizeof (struct chsample));
-           dc->srcoffset = 0;
-           return;
-       }
-       if (dc->csnext.ds) {
-           memcpy (cs, &dc->csnext, sizeof (struct chsample));
-           memset (&dc->csnext, 0, sizeof (struct chsample));
-           continue;
-       }
+    int v, cnt = 0;
+    for (;;) {
+       ALuint tmp;
+       alClear ();
+       alGetSourcei (dc->al_source, AL_BUFFERS_PROCESSED, &v);
+       if (alError ("AHI: hsync AL_BUFFERS_PROCESSED %d", dc->num))
+           return cnt;
+       if (v == 0)
+           return cnt;
+       alSourceUnqueueBuffers (dc->al_source, 1, &tmp);
+       cnt++;
     }
 }
 
@@ -1321,141 +1098,66 @@ void ahi_hsync (void)
        return;
     flags = get_long (pbase + pub_ChannelSignalAck);
     for (i = 0; i < UAE_MAXCHANNELS; i++) {
+       int v, removed;
        struct dschannel *dc = &dsahip->channel[i];
-       HRESULT hr;
-       DWORD playc, writec, diff, samplediff;
-
-       if (dc->dsb == NULL)
-           continue;
-       if (dc->dsplaying == 0)
-           continue;
-        hr = IDirectSoundBuffer8_GetCurrentPosition (dc->dsb, &playc, &writec);
-       if (FAILED (hr)) {
-           write_log ("AHI: GetCurrentPosition(%d) failed, %s\n", dc->num, DXError (hr));
-           continue;
-       }
-       if (dc->dscursor >= writec)
-           diff = dc->dscursor - writec;
-       else
-           diff = dsahip->channellength - writec + dc->dscursor;
-       if (diff > dsahip->channellength / 2) {
-           dc->dscursor = writec + dc->mixlength;
-           write_log ("AHI: Resync %d\n", dc->num);
-       }
-
-       if (dc->dscursor < 0) {
-           dc->dscursor = writec;
-           memcpy (&dc->cs, &dc->csnext, sizeof (struct chsample));
-       }
-       samplediff = diff / (dsahip->chout * dsahip->bytespersampleout);
-       incchannel (dsahip, dc, samplediff);
-//     copysample (dsahip, dc, &dc->cs);
-
-
-
-
-       if (diff > dc->mixlength)
+       if (dc->dsplaying != 1 || dc->al_source == -1)
            continue;
-
-
-#if 0
-       if (dc->buffer == NULL)
-           continue;
-       if (dc->hsync > 0) {
-           dc->hsync--;
-           continue;
-       }
-       if (dc->channelsignal) {
-           if (!(flags & (1 << dc->num)))
-               continue;
-           dc->channelsignal = 0;
-           flags &= ~(1 << dc->num);
+       removed = unqueuebuffers (dc);
+       v = 0;
+        alClear ();
+       alGetSourcei (dc->al_source, AL_SOURCE_STATE, &v);
+       alError ("AHI: hsync AL_SOURCE_STATE");
+       if (v != AL_PLAYING) {
+           setchannelevent (dsahip, dc);
+           if (ahi_debug)
+               write_log ("AHI: channel %d stopped state=%d\n", dc->num, v);
+           if (dc->csnext.ds)
+               al_queuesample (dsahip, dc);
+           else
+               dc->dsplaying = 2;
        }
-       if (dsahip->enabledisable)
-           continue;
-       if (dc->buffercursor < dc->mixlength)
-           copysample (dsahip, dc);
-       assert (dc->buffercursor <= dc->mixlength);
-       if (dc->buffercursor == dc->mixlength) {
-           if (ds_copysample (dsahip, dc)) {
-               getmixbufferlen (dsahip, dc);
-               dc->buffercursor = 0;
-           } else {
-               dc->hsync = 100;
-           }
+       if (removed) {
+           if (ahi_debug)
+               write_log ("sample end channel %d\n", dc->num);
+           setchannelevent (dsahip, dc);
+           if (dc->csnext.ds)
+               al_queuesample (dsahip, dc);
        }
-#endif
     }
     put_long (pbase + pub_ChannelSignalAck, flags);
 }
 
 static void ds_record (struct DSAHI *dsahip, int start)
 {
-    HRESULT hr;
-
-    if (dsahip->dscb == NULL)
-       return;
-    if (dsahip->dsrecording && start)
-       return;
-    dsahip->dsrecording = 0;
-    if (start) {
-       hr = IDirectSoundCaptureBuffer_Start (dsahip->dscb, DSCBSTART_LOOPING);
-       if (FAILED (hr)) {
-           write_log ("AHI: DirectSoundCaptureBuffer_Start failed: %s\n", DXError (hr));
-           return;
-       }
-       dsahip->dsrecording = 1;
-    } else {
-       hr = IDirectSoundCaptureBuffer_Stop (dsahip->dscb);
-       if (FAILED (hr)) {
-           write_log ("AHI: DirectSoundCaptureBuffer_Stop failed: %s\n", DXError (hr));
-           return;
-       }
-    }
 }
 
 static void ds_stop (struct DSAHI *dsahip, struct dschannel *dc)
 {
-    HRESULT hr;
-
     dc->dsplaying = 0;
-    if (dc->dsb == NULL)
+    if (dc->al_source == -1)
        return;
     if (ahi_debug)
        write_log ("AHI: ds_stop(%d)\n", dc->num);
-    hr = IDirectSoundBuffer8_Stop (dc->dsb);
-    if (FAILED (hr))
-       write_log ("AHI: IDirectSoundBuffer8_Stop() failed, %s\n", DXError (hr));
+    alClear ();
+    alSourceStop (dc->al_source);
+    alError ("AHI: alSourceStop");
+    unqueuebuffers (dc);
 }
 
 static void ds_play (struct DSAHI *dsahip, struct dschannel *dc)
 {
-    HRESULT hr;
-    DWORD status, playc, writec;
-
-    if (dc->dsb == NULL)
-       return;
-    if (dc->dsplaying)
+    if (dc->dsplaying) {
+       dc->dsplaying = 1;
        return;
+    }
+    dc->dsplaying = 1;
     if (dc->cs.frequency == 0)
        return;
-    dc->dsplaying = 1;
+    if (dc->al_source == -1)
+       return;
     if (ahi_debug)
        write_log ("AHI: ds_play(%d)\n", dc->num);
-    hr = IDirectSoundBuffer8_GetStatus (dc->dsb, &status);
-    if (FAILED (hr))
-       write_log ("AHI: ds_play() IDirectSoundBuffer8_GetStatus() failed, %s\n", DXError (hr));
-    hr = IDirectSoundBuffer8_Play (dc->dsb, 0, 0, DSBPLAY_LOOPING);
-    if (FAILED (hr))
-       write_log ("AHI: ds_play() IDirectSoundBuffer8_Play() failed, %s\n", DXError (hr));
-    hr = IDirectSoundBuffer8_GetCurrentPosition (dc->dsb, &playc, &writec);
-    if (FAILED (hr))
-       write_log ("AHI: ds_play() IDirectSoundBuffer8_GetCurrentPosition() failed, %s\n", DXError (hr));
-    dc->dscursor = writec + dc->mixlength;
-    if (dc->dscursor >= dsahip->channellength)
-       dc->dscursor -= dsahip->channellength;
-    if (ahi_debug)
-       write_log("AHI: ds_play(%d) Start=%d->%d\n", dc->num, writec, dc->dscursor);
+    al_startplay (dc);
 }
 
 void ahi2_pause_sound (int paused)
@@ -1468,30 +1170,37 @@ void ahi2_pause_sound (int paused)
        return;
     for (i = 0; i < UAE_MAXCHANNELS; i++) {
        struct dschannel *dc = &dsahip->channel[i];
-       if (dc->dsb == NULL)
+       if (dc->al_source == -1)
            continue;
        if (paused) {
            ds_stop (dsahip, dc);
        } else {
            ds_play (dsahip, dc);
+           setchannelevent (dsahip, dc);
        }
     }
 }
 
 static uae_u32 init (TrapContext *ctx)
 {
-    int i;
+    int i, j;
     
     enumerate_sound_devices ();
     xahi_author = ds ("Toni Wilen");
     xahi_copyright = ds ("GPL");
-    xahi_version = ds ("uae2 0.1 (xx.xx.2008)\r\n");
-    for (i = 0; sound_devices[i].name; i++)
-       xahi_output[i] = ds (sound_devices[i].name);
-    xahi_output_num = i;
-    for (i = 0; record_devices[i].name; i++)
-       xahi_input[i] = ds (record_devices[i].name);
-    xahi_input_num = i;
+    xahi_version = ds ("uae2 0.2 (xx.xx.2008)\r\n");
+    j = 0;
+    for (i = 0; sound_devices[i].name; i++) {
+       if (sound_devices[i].type == SOUND_DEVICE_AL)
+           xahi_output[j++] = ds (sound_devices[i].name);
+    }
+    xahi_output_num = j;
+    j = 0;
+    for (i = 0; record_devices[i].name; i++) {
+       if (record_devices[i].type == SOUND_DEVICE_AL)
+           xahi_input[j++] = ds (record_devices[i].name);
+    }
+    xahi_input_num = j;
     return 1;
 }
 
@@ -1530,6 +1239,7 @@ static uae_u32 AHIsub_AllocAudio (TrapContext *ctx)
 
     if (!ds_init (dsahip))
        return AHISF_ERROR;
+    dsahip->maxplaysamples = PLAYSAMPLES;
     dsahip->sounds = UAE_MAXSOUNDS;
     dsahip->channels = UAE_MAXCHANNELS;
 
@@ -1552,10 +1262,13 @@ static uae_u32 AHIsub_AllocAudio (TrapContext *ctx)
     for (i = 0; i < dsahip->channels; i++) {
        struct dschannel *dc = &dsahip->channel[i];
        dc->num = i;
+       dc->al_source = -1;
     }
     for (i = 0; i < dsahip->sounds; i++) {
        struct dssample *ds = &dsahip->sample[i];
        ds->num = -1;
+       ds->al_buffer[0] = -1;
+       ds->al_buffer[1] = -1;
     }
     ahi_active = 1;
     return ret;
@@ -1604,7 +1317,7 @@ static void AHIsub_FreeAudio (TrapContext *ctx)
 static uae_u32 frequencies[] = { 48000, 44100 };
 #define MAX_FREQUENCIES (sizeof (frequencies) / sizeof (uae_u32))
 
-static uae_u32 getattr2 (uae_u32 attribute, uae_u32 argument, uae_u32 def)
+static uae_u32 getattr2 (struct DSAHI *dsahip, uae_u32 attribute, uae_u32 argument, uae_u32 def)
 {
     int i;
 
@@ -1672,6 +1385,10 @@ static uae_u32 getattr2 (uae_u32 attribute, uae_u32 argument, uae_u32 def)
        return -1;
        case AHIDB_MaxRecordSamples:
        return RECORDSAMPLES;
+       case AHIDB_MaxPlaySamples:
+       if (def < dsahip->maxplaysamples)
+           def = dsahip->maxplaysamples;
+       return def;
        default:
        return def;
     }
@@ -1684,9 +1401,10 @@ static uae_u32 AHIsub_GetAttr (TrapContext *ctx)
     uae_u32 def = m68k_dreg (&ctx->regs, 2);
     uae_u32 taglist = m68k_areg (&ctx->regs, 1);
     uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
     uae_u32 v;
 
-    v = getattr2 (attribute, argument, def);
+    v = getattr2 (dsahip, attribute, argument, def);
     if (ahi_debug)
        write_log ("AHI: GetAttr(%08x=%d,%08x,%08x)=%08x\n", attribute, attribute & 0x7fff, argument, def, v);
 
@@ -1706,7 +1424,7 @@ static uae_u32 AHIsub_HardwareControl (TrapContext *ctx)
        case AHIC_Input:
        if (dsahip->input != argument) {
            dsahip->input = argument;
-           if (dsahip->dscb) {
+           if (dsahip->al_dev) {
                ds_free_record (dsahip);
                ds_init_record (dsahip);
                if (dsahip->recording)
@@ -1719,7 +1437,7 @@ static uae_u32 AHIsub_HardwareControl (TrapContext *ctx)
        case AHIC_Output:
        if (dsahip->output != argument) {
            dsahip->output = argument;
-           if (dsahip->DS)
+           if (dsahip->al_dev)
                ds_reinit (dsahip);
        }
        break;
@@ -1853,16 +1571,15 @@ static uae_u32 AHIsub_SetSound (TrapContext *ctx)
            channel, sound, offset, length, audioctrl, flags);
     if (dc == NULL)
        return AHIE_UNKNOWN;
-    if (ds->num < 0)
-       return AHIE_UNKNOWN;
     if (sound == 0xffff) {
        if (flags & AHISF_IMM) {
            dc->cs.ds = NULL;
            dc->csnext.ds = NULL;
        }
-       dc->csnext.srcplaylen = -1;
        return 0;
     }
+    if (ds == NULL || ds->num < 0)
+       return AHIE_UNKNOWN;
     ds_allocchannel (dsahip, dc);
     dc->cs.backwards = length < 0;
     length = abs (length);
@@ -1875,13 +1592,12 @@ static uae_u32 AHIsub_SetSound (TrapContext *ctx)
     dc->csnext.srcplayoffset = offset;
     if (flags & AHISF_IMM)
        dc->cs.ds = NULL;
-    if (dc->cs.ds == NULL) {
-       dc->buffercursor = 0;
-       dc->hsync = 0;
-    }
     ds_setfreq (dsahip, dc);
     ds_setvolume (dsahip, dc);
-    ds_play (dsahip, dc);
+    if (dc->cs.ds == NULL)
+       al_initsample (dsahip, dc);
+    else
+       al_queuesample (dsahip, dc);
     return 0;
 }
 
@@ -1981,6 +1697,14 @@ static uae_u32 AHIsub_LoadSound (TrapContext *ctx)
     ds->bitspersample = bps;
     ds->ch = ch;
     ds->bytespersample = bps / 8;
+    if (ds->al_buffer[0] == -1) {
+       alClear ();
+       alGenBuffers (2, ds->al_buffer);
+       if (alError ("AHI: alGenBuffers"))
+           return AHIE_NOMEM;
+       if (ahi_debug)
+           write_log ("AHI:LoadSound:allocated OpenAL buffer\n");
+    }
     return AHIE_OK;
 }
 
@@ -2065,7 +1789,7 @@ void init_ahi_v2 (void)
 {
     uaecptr a = here ();
     org (rtarea_base + 0xFFC8);
-    calltrap (deftrapres (ahi_demux, 0, "ahi_winuae_v2"));
+    calltrap (deftrapres (ahi_demux, 0, "ahi_v2"));
     dw (RTS);
     org (a);
 }
diff --git a/od-win32/ahidsoundx_new.c b/od-win32/ahidsoundx_new.c
new file mode 100755 (executable)
index 0000000..99e324d
--- /dev/null
@@ -0,0 +1,2080 @@
+/*
+ * UAE - The Un*x Amiga Emulator
+ *
+ * DirectSound AHI 7.1 wrapper
+ *
+ * Copyright 2008 Toni Wilen
+ */
+
+#include "sysconfig.h"
+
+#if defined(AHI)
+
+#include <ctype.h>
+#include <assert.h>
+
+#include <windows.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <math.h>
+#include <process.h>
+
+#include "sysdeps.h"
+#include "options.h"
+#include "audio.h"
+#include "memory.h"
+#include "events.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "autoconf.h"
+#include "traps.h"
+#include "threaddep/thread.h"
+#include "native2amiga.h"
+#include "od-win32/win32.h"
+#include "sounddep/sound.h"
+#include "ahidsound_new.h"
+#include "dxwrap.h"
+
+#include <mmsystem.h>
+#include <mmreg.h>
+#include <dsound.h>
+#include <ks.h>
+#include <ksmedia.h>
+
+#define AHI_STRUCT_VERSION 1
+
+static int ahi_debug = 1;
+
+#define UAE_MAXCHANNELS 24
+#define UAE_MAXSOUNDS 256
+#define RECORDSAMPLES 2048
+
+#define ub_Flags 34
+#define ub_Pad1 (ub_Flags + 1)
+#define ub_Pad2 (ub_Pad1 + 1)
+#define ub_SysLib (ub_Pad2 + 2)
+#define ub_SegList (ub_SysLib + 4)
+#define ub_DOSBase (ub_SegList + 4)
+#define ub_AHIFunc (ub_DOSBase + 4)
+
+#define pub_SizeOf 0
+#define pub_Version (pub_SizeOf + 4)
+#define pub_Index (pub_Version + 4)
+#define pub_Base (pub_Index + 4)
+#define pub_audioctrl (pub_Base + 4)
+#define pub_FuncTask (pub_audioctrl + 4)
+#define pub_WaitMask (pub_FuncTask + 4)
+#define pub_WaitSigBit (pub_WaitMask + 4)
+#define pub_FuncMode (pub_WaitSigBit +4)
+#define pub_TaskMode (pub_FuncMode + 2)
+#define pub_ChannelSignal (pub_TaskMode + 2)
+#define pub_ChannelSignalAck (pub_ChannelSignal + 4)
+#define pub_ahism_Channel (pub_ChannelSignalAck + 4)
+#define pub_RecordHookDone (pub_ahism_Channel + 2)
+#define pub_RecordSampleType (pub_RecordHookDone + 2)
+#define pub_RecordBufferSize (pub_RecordSampleType + 4)
+#define pub_RecordBufferSizeBytes (pub_RecordBufferSize + 4)
+#define pub_RecordBuffer (pub_RecordBufferSizeBytes + 4)
+#define pub_ChannelInfo (pub_RecordBuffer + 4 + 4 + 4 + 4)
+#define pub_End (pub_ChannelInfo + 4)
+
+#define FUNCMODE_PLAY 1
+#define FUNCMODE_RECORD 2
+#define FUNCMODE_RECORDALLOC 4
+
+#define ahie_Effect 0
+#define ahieci_Func 4
+#define ahieci_Channels 8
+#define ahieci_Pad 10
+#define ahieci_Offset 12
+
+#if 0
+struct AHISampleInfo
+{
+       ULONG   ahisi_Type;                     /* Format of samples */
+       APTR    ahisi_Address;                  /* Address to array of samples */
+       ULONG   ahisi_Length;                   /* Number of samples in array */
+};
+#endif
+
+#define ahisi_Type 0
+#define ahisi_Address 4
+#define ahisi_Length 8
+
+#if 0
+struct AHIAudioCtrlDrv
+{
+       struct AHIAudioCtrl ahiac_AudioCtrl;
+       ULONG        ahiac_Flags;               /* See below for definition     */
+       struct Hook *ahiac_SoundFunc;           /* AHIA_SoundFunc               */
+       struct Hook *ahiac_PlayerFunc;          /* AHIA_PlayerFunc              */
+       Fixed        ahiac_PlayerFreq;          /* AHIA_PlayerFreq              */
+       Fixed        ahiac_MinPlayerFreq;       /* AHIA_MinPlayerFreq           */
+       Fixed        ahiac_MaxPlayerFreq;       /* AHIA_MaxPlayerFreq           */
+       ULONG        ahiac_MixFreq;             /* AHIA_MixFreq                 */
+       UWORD        ahiac_Channels;            /* AHIA_Channels                */
+       UWORD        ahiac_Sounds;              /* AHIA_Sounds                  */
+
+       APTR         ahiac_DriverData;          /* Unused. Store whatever you want here. */
+
+       struct Hook *ahiac_MixerFunc;           /* Mixing routine Hook          */
+       struct Hook *ahiac_SamplerFunc;         /* Sampler routine Hook         */
+       ULONG        ahiac_Obsolete;
+       ULONG        ahiac_BuffSamples;         /* Samples to mix this pass.    */
+       ULONG        ahiac_MinBuffSamples;      /* Min. samples to mix each pass. */
+       ULONG        ahiac_MaxBuffSamples;      /* Max. samples to mix each pass. */
+       ULONG        ahiac_BuffSize;            /* Buffer size ahiac_MixerFunc needs. */
+       ULONG        ahiac_BuffType;            /* Buffer format (V2)           */
+       BOOL       (*ahiac_PreTimer)(void);     /* Call before mixing (V4)      */
+       void       (*ahiac_PostTimer)(void);    /* Call after mixing (V4)       */
+       ULONG        ahiac_AntiClickSamples;    /* AntiClick samples (V6)       */
+       struct Hook *ahiac_PreTimerFunc;        /* A Hook wrapper for ahiac_PreTimer (V6) */
+       struct Hook *ahiac_PostTimerFunc;       /* A Hook wrapper for ahiac_PostTimer (V6) */
+#endif
+
+#define ahiac_AudioCtrl 0
+#define ahiac_Flags ahiac_AudioCtrl + 4
+#define ahiac_SoundFunc ahiac_Flags + 4
+#define ahiac_PlayerFunc ahiac_SoundFunc + 4
+#define ahiac_PlayerFreq ahiac_PlayerFunc + 4
+#define ahiac_MinPlayerFreq ahiac_PlayerFreq + 4
+#define ahiac_MaxPlayerFreq ahiac_MinPlayerFreq + 4
+#define ahiac_MixFreq ahiac_MaxPlayerFreq + 4
+#define ahiac_Channels ahiac_MixFreq + 4
+#define ahiac_Sounds ahiac_Channels + 2
+#define ahiac_DriverData ahiac_Sounds + 2
+#define ahiac_MixerFunc ahiac_DriverData + 4
+#define ahiac_SamplerFunc ahiac_MixerFunc + 4 
+#define ahiac_Obsolete ahiac_SamplerFunc + 4 
+#define ahiac_BuffSamples ahiac_Obsolete + 4 
+#define ahiac_MinBuffSamples ahiac_BuffSamples + 4 
+#define ahiac_MaxBuffSamples ahiac_MinBuffSamples + 4 
+#define ahiac_BuffSize ahiac_MaxBuffSamples + 4 
+#define ahiac_BuffType ahiac_BuffSize + 4 
+#define ahiac_PreTimer ahiac_BuffType + 4 
+#define ahiac_PostTimer ahiac_PreTimer + 4 
+#define ahiac_AntiClickSamples ahiac_PostTimer + 4 
+#define ahiac_PreTimerFunc ahiac_AntiClickSamples + 4 
+#define ahiac_PostTimerFunc ahiac_PreTimerFunc + 4 
+
+/* AHIsub_AllocAudio return flags */
+#define AHISF_ERROR            (1<<0)
+#define AHISF_MIXING           (1<<1)
+#define AHISF_TIMING           (1<<2)
+#define AHISF_KNOWSTEREO       (1<<3)
+#define AHISF_KNOWHIFI         (1<<4)
+#define AHISF_CANRECORD        (1<<5)
+#define AHISF_CANPOSTPROCESS   (1<<6)
+#define AHISF_KNOWMULTICHANNEL (1<<7)
+
+#define AHISB_ERROR            (0)
+#define AHISB_MIXING           (1)
+#define AHISB_TIMING           (2)
+#define AHISB_KNOWSTEREO       (3)
+#define AHISB_KNOWHIFI         (4)
+#define AHISB_CANRECORD                (5)
+#define AHISB_CANPOSTPROCESS   (6)
+#define AHISB_KNOWMULTICHANNEL (7)
+
+ /* AHIsub_Start() and AHIsub_Stop() flags */
+#define        AHISF_PLAY              (1<<0)
+#define        AHISF_RECORD            (1<<1)
+
+#define        AHISB_PLAY              (0)
+#define        AHISB_RECORD            (1)
+
+ /* ahiac_Flags */
+#define        AHIACF_VOL              (1<<0)
+#define        AHIACF_PAN              (1<<1)
+#define        AHIACF_STEREO           (1<<2)
+#define        AHIACF_HIFI             (1<<3)
+#define        AHIACF_PINGPONG         (1<<4)
+#define        AHIACF_RECORD           (1<<5)
+#define AHIACF_MULTTAB         (1<<6)
+#define        AHIACF_MULTICHANNEL     (1<<7)
+
+#define        AHIACB_VOL              (0)
+#define        AHIACB_PAN              (1)
+#define        AHIACB_STEREO           (2)
+#define        AHIACB_HIFI             (3)
+#define        AHIACB_PINGPONG         (4)
+#define        AHIACB_RECORD           (5)
+#define AHIACB_MULTTAB         (6)
+#define        AHIACB_MULTICHANNEL     (7)
+
+#define AHISB_IMM              0
+#define AHISB_NODELAY          1
+#define AHISF_IMM              (1 << AHISB_IMM)
+#define AHISF_NODELAY          (1 << SHISB_NODELAY)
+
+#define AHIET_CANCEL           (1 << 31)
+#define AHIET_MASTERVOLUME     1
+#define AHIET_OUTPUTBUFFER     2
+#define AHIET_DSPMASK          3
+#define AHIET_DSPECHO          4
+#define AHIET_CHANNELINFO      5
+
+#define AHI_TagBase            (0x80000000)
+#define AHI_TagBaseR           (AHI_TagBase|0x8000)
+
+ /* AHI_ControlAudioA tags */
+#define AHIC_Play              (AHI_TagBase+80)        /* Boolean */
+#define AHIC_Record            (AHI_TagBase+81)        /* Boolean */
+#define AHIC_MonitorVolume     (AHI_TagBase+82)
+#define AHIC_MonitorVolume_Query (AHI_TagBase+83)      /* ti_Data is pointer to Fixed (LONG) */
+#define AHIC_MixFreq_Query     (AHI_TagBase+84)        /* ti_Data is pointer to ULONG */
+/* --- New for V2, they will be ignored by V1 --- */
+#define AHIC_InputGain         (AHI_TagBase+85)
+#define AHIC_InputGain_Query   (AHI_TagBase+86)        /* ti_Data is pointer to Fixed (LONG) */
+#define AHIC_OutputVolume      (AHI_TagBase+87)
+#define AHIC_OutputVolume_Query        (AHI_TagBase+88)        /* ti_Data is pointer to Fixed (LONG) */
+#define AHIC_Input             (AHI_TagBase+89)
+#define AHIC_Input_Query       (AHI_TagBase+90)        /* ti_Data is pointer to ULONG */
+#define AHIC_Output            (AHI_TagBase+91)
+#define AHIC_Output_Query      (AHI_TagBase+92)        /* ti_Data is pointer to ULONG */
+
+ /* AHI_GetAudioAttrsA tags */
+#define AHIDB_AudioID          (AHI_TagBase+100)
+#define AHIDB_Driver           (AHI_TagBaseR+101)      /* Pointer to name of driver */
+#define AHIDB_Flags            (AHI_TagBase+102)       /* Private! */
+#define AHIDB_Volume           (AHI_TagBase+103)       /* Boolean */
+#define AHIDB_Panning          (AHI_TagBase+104)       /* Boolean */
+#define AHIDB_Stereo           (AHI_TagBase+105)       /* Boolean */
+#define AHIDB_HiFi             (AHI_TagBase+106)       /* Boolean */
+#define AHIDB_PingPong         (AHI_TagBase+107)       /* Boolean */
+#define AHIDB_MultTable                (AHI_TagBase+108)       /* Private! */
+#define AHIDB_Name             (AHI_TagBaseR+109)      /* Pointer to name of this mode */
+#define AHIDB_Bits             (AHI_TagBase+110)       /* Output bits */
+#define AHIDB_MaxChannels      (AHI_TagBase+111)       /* Max supported channels */
+#define AHIDB_MinMixFreq       (AHI_TagBase+112)       /* Min mixing freq. supported */
+#define AHIDB_MaxMixFreq       (AHI_TagBase+113)       /* Max mixing freq. supported */
+#define AHIDB_Record           (AHI_TagBase+114)       /* Boolean */
+#define AHIDB_Frequencies      (AHI_TagBase+115)
+#define AHIDB_FrequencyArg     (AHI_TagBase+116)       /* ti_Data is frequency index */
+#define AHIDB_Frequency                (AHI_TagBase+117)
+#define AHIDB_Author           (AHI_TagBase+118)       /* Pointer to driver author name */
+#define AHIDB_Copyright                (AHI_TagBase+119)       /* Pointer to driver copyright notice */
+#define AHIDB_Version          (AHI_TagBase+120)       /* Pointer to driver version string */
+#define AHIDB_Annotation       (AHI_TagBase+121)       /* Pointer to driver annotation text */
+#define AHIDB_BufferLen                (AHI_TagBase+122)       /* Specifies the string buffer size */
+#define AHIDB_IndexArg         (AHI_TagBase+123)       /* ti_Data is frequency! */
+#define AHIDB_Index            (AHI_TagBase+124)
+#define AHIDB_Realtime         (AHI_TagBase+125)       /* Boolean */
+#define AHIDB_MaxPlaySamples   (AHI_TagBase+126)       /* It's sample *frames* */
+#define AHIDB_MaxRecordSamples (AHI_TagBase+127)       /* It's sample *frames* */
+#define AHIDB_FullDuplex       (AHI_TagBase+129)       /* Boolean */
+/* --- New for V2, they will be ignored by V1 --- */
+#define AHIDB_MinMonitorVolume (AHI_TagBase+130)
+#define AHIDB_MaxMonitorVolume (AHI_TagBase+131)
+#define AHIDB_MinInputGain     (AHI_TagBase+132)
+#define AHIDB_MaxInputGain     (AHI_TagBase+133)
+#define AHIDB_MinOutputVolume  (AHI_TagBase+134)
+#define AHIDB_MaxOutputVolume  (AHI_TagBase+135)
+#define AHIDB_Inputs           (AHI_TagBase+136)
+#define AHIDB_InputArg         (AHI_TagBase+137)       /* ti_Data is input index */
+#define AHIDB_Input            (AHI_TagBase+138)
+#define AHIDB_Outputs          (AHI_TagBase+139)
+#define AHIDB_OutputArg                (AHI_TagBase+140)       /* ti_Data is input index */
+#define AHIDB_Output           (AHI_TagBase+141)
+/* --- New for V4, they will be ignored by V2 and earlier --- */
+#define AHIDB_Data             (AHI_TagBaseR+142)      /* Private! */
+#define AHIDB_DriverBaseName   (AHI_TagBaseR+143)      /* Private! */
+/* --- New for V6, they will be ignored by V4 and earlier --- */
+#define AHIDB_MultiChannel     (AHI_TagBase+144)       /* Boolean */
+
+/* Sound Types */
+#define AHIST_NOTYPE           (~0UL)                  /* Private */
+#define AHIST_SAMPLE           (0UL)                   /* 8 or 16 bit sample */
+#define AHIST_DYNAMICSAMPLE    (1UL)                   /* Dynamic sample */
+#define AHIST_INPUT            (1UL<<29)               /* The input from your sampler */
+#define AHIST_BW               (1UL<<30)               /* Private */
+
+ /* Sample types */
+/* Note that only AHIST_M8S, AHIST_S8S, AHIST_M16S and AHIST_S16S
+   (plus AHIST_M32S, AHIST_S32S and AHIST_L7_1 in V6)
+   are supported by AHI_LoadSound(). */
+#define AHIST_M8S              (0UL)                   /* Mono, 8 bit signed (BYTE) */
+#define AHIST_M16S             (1UL)                   /* Mono, 16 bit signed (WORD) */
+#define AHIST_S8S              (2UL)                   /* Stereo, 8 bit signed (2×BYTE) */
+#define AHIST_S16S             (3UL)                   /* Stereo, 16 bit signed (2×WORD) */
+#define AHIST_M32S             (8UL)                   /* Mono, 32 bit signed (LONG) */
+#define AHIST_S32S             (10UL)                  /* Stereo, 32 bit signed (2×LONG) */
+#define AHIST_M8U              (4UL)                   /* OBSOLETE! */
+#define AHIST_L7_1             (0x00c3000aUL)          /* 7.1, 32 bit signed (8×LONG) */
+
+ /* Error codes */
+#define AHIE_OK                        (0UL)                   /* No error */
+#define AHIE_NOMEM             (1UL)                   /* Out of memory */
+#define AHIE_BADSOUNDTYPE      (2UL)                   /* Unknown sound type */
+#define AHIE_BADSAMPLETYPE     (3UL)                   /* Unknown/unsupported sample type */
+#define AHIE_ABORTED           (4UL)                   /* User-triggered abortion */
+#define AHIE_UNKNOWN           (5UL)                   /* Error, but unknown */
+#define AHIE_HALFDUPLEX                (6UL)                   /* CMD_WRITE/CMD_READ failure */
+
+struct dssample {
+    int num;
+    int ch;
+    int bitspersample;
+    int bytespersample;
+    uae_u32 addr;
+    uae_u32 len;
+    uae_u32 type;
+    uae_u32 sampletype;
+    uae_u32 offset;
+};
+
+struct chsample {
+    int frequency;
+    int volume;
+    int panning;
+    int backwards;
+    struct dssample *ds;
+    int srcplayoffset;
+    int srcplaylen;
+    int stopit;
+};
+
+struct dschannel {
+    int num;
+    struct chsample cs;
+    struct chsample csnext;
+    LPDIRECTSOUNDBUFFER8 dsb;
+
+    uae_u8 *buffer;
+    int mixlength;
+    int buffercursor;
+    int hsync;
+    int channelsignal;
+    int srcoffset;
+
+    int dsplaying;
+    int dscursor;
+};
+
+struct DSAHI {
+    uae_u32 audioctrl;
+    int chout;
+    int bits24;
+    int bitspersampleout;
+    int bytespersampleout;
+    int channellength;
+    int mixlength;
+    int input;
+    int output;
+    int channels;
+    int sounds;
+    int playerfreq;
+    int enabledisable;
+    struct dssample *sample;
+    struct dschannel *channel;
+    int playing, recording;
+    evt evttime;
+    uae_u32 signalchannelmask;
+    LPDIRECTSOUND8 DS;
+
+    LPDIRECTSOUNDCAPTURE DSC;
+    LPDIRECTSOUNDCAPTUREBUFFER dscb;
+    int dsrecording;
+    int recordingcursor;
+    int record_ch;
+    int record_bytespersample;
+    int channellength_record;
+    int mixlength_record;
+    int record_wait;
+};
+
+static struct DSAHI dsahi[1];
+
+#define GETAHI (&dsahi[get_long(get_long(audioctrl + ahiac_DriverData) + pub_Index)])
+#define GETSAMPLE (dsahip && sound >= 0 && sound < UAE_MAXSOUNDS ? &dsahip->sample[sound] : NULL)
+#define GETCHANNEL (dsahip && channel >= 0 && channel < UAE_MAXCHANNELS ? &dsahip->channel[channel] : NULL)
+
+static int default_freq = 44100;
+static int cansurround;
+static uae_u32 xahi_author, xahi_copyright, xahi_version;
+static uae_u32 xahi_output[MAX_SOUND_DEVICES], xahi_output_num;
+static uae_u32 xahi_input[MAX_SOUND_DEVICES], xahi_input_num;
+static int ahi_paused;
+static int ahi_active;
+
+#define TAG_DONE   (0L)                /* terminates array of TagItems. ti_Data unused */
+#define TAG_IGNORE (1L)                /* ignore this item, not end of array */
+#define TAG_MORE   (2L)                /* ti_Data is pointer to another array of TagItems */
+#define TAG_SKIP   (3L)                /* skip this and the next ti_Data items */
+#define TAG_USER   ((uae_u32)(1L << 31))
+
+static uae_u32 gettag (uae_u32 *tagpp, uae_u32 *datap)
+{
+    uae_u32 tagp = *tagpp;
+    for (;;) {
+       uae_u32 tag = get_long (tagp);
+       uae_u32 data = get_long (tagp + 4);
+       switch (tag)
+       {
+           case TAG_DONE:
+           return 0;
+           case TAG_IGNORE:
+           tagp += 8;
+           break;
+           case TAG_MORE:
+           tagp = data;
+           break;
+           case TAG_SKIP:
+           tagp += data * 8;
+           break;
+           default:
+           tagp += 8;
+           *tagpp = tagp;
+           *datap = data;
+           return tag;
+       }
+    }
+}
+
+
+static int sendsignal (struct DSAHI *dsahip)
+{
+    uae_u32 audioctrl = dsahip->audioctrl;
+    uae_u32 puaebase = get_long (audioctrl + ahiac_DriverData);
+    uae_u32 channelinfo;
+    uae_u32 task, signalmask;
+    uae_s16 taskmode = get_word (puaebase + pub_TaskMode);
+    uae_s16 funcmode = get_word (puaebase + pub_FuncMode);
+    task = get_long (puaebase + pub_FuncTask);
+    signalmask = get_long (puaebase + pub_WaitMask);
+
+    if ((!dsahip->playing && !dsahip->recording) || ahi_paused)
+       return 0;
+    if (taskmode <= 0)
+       return 0;
+    if (dsahip->enabledisable) {
+       // allocate Amiga-side recordingbuffer
+       funcmode &= FUNCMODE_RECORDALLOC;
+       put_word (puaebase + pub_FuncMode, funcmode);
+    }
+
+    channelinfo = get_long (puaebase + pub_ChannelInfo);
+    if (channelinfo) {
+       int i, ch;
+       ch = get_word (channelinfo + ahieci_Channels);
+       if (ch > UAE_MAXCHANNELS)
+           ch = UAE_MAXCHANNELS;
+       for (i = 0; i < ch; i++)
+           put_long (channelinfo + ahieci_Offset + i * 4, dsahip->channel[i].srcoffset);
+    }
+
+    uae_Signal (task, signalmask);
+    return 1;
+}
+
+static void setchannelevent (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    uae_u32 audioctrl = dsahip->audioctrl;
+    uae_u32 puaebase = get_long (audioctrl + ahiac_DriverData);
+    int ch = dc - &dsahip->channel[0];
+    uae_u32 mask;
+
+    if (!dsahip->playing || ahi_paused || dc->dsb == NULL)
+       return;
+    mask = get_long (puaebase + pub_ChannelSignal);
+    if (mask & (1 << ch))
+       return;
+    dc->channelsignal = 1;
+    put_long (puaebase + pub_ChannelSignal, mask | (1 << ch));
+    sendsignal (dsahip);
+}
+
+static void evtfunc (uae_u32 v)
+{
+    if (ahi_active) {
+       struct DSAHI *dsahip = &dsahi[v];
+       uae_u32 audioctrl = dsahip->audioctrl;
+       uae_u32 puaebase = get_long (audioctrl + ahiac_DriverData);
+       
+       put_word (puaebase + pub_FuncMode, get_word (puaebase + pub_FuncMode) | FUNCMODE_PLAY);
+       if (sendsignal (dsahip)) {
+           event2_newevent2 (dsahip->evttime, v, evtfunc);
+       } else {
+           dsahip->evttime = 0;
+       }
+    }
+}
+
+static void setevent (struct DSAHI *dsahip)
+{
+    uae_u32 audioctrl = dsahip->audioctrl;
+    uae_u32 freq = get_long (audioctrl + ahiac_PlayerFreq);
+    double f;
+    uae_u32 cycles;
+    evt t;
+    
+    f = ((double)(freq >> 16)) + ((double)(freq & 0xffff)) / 65536.0;
+    if (f < 1)
+       return;
+    cycles = maxhpos * maxvpos * vblank_hz;
+    t = (evt)(cycles / f);
+    if (dsahip->evttime == t)
+       return;
+    write_log ("AHI: playerfunc freq = %.2fHz\n", f);
+    dsahip->evttime = t;
+    if (t < 10)
+       return;
+    event2_newevent2 (t, dsahip - &dsahi[0], evtfunc);
+}
+
+
+
+const static GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010,
+    {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}};
+
+static void ds_freechannel (struct DSAHI *ahidsp, struct dschannel *dc)
+{
+    if (!dc)
+       return;
+    if (dc->dsb)
+       IDirectSoundBuffer8_Release (dc->dsb);
+    xfree (dc->buffer);
+    memset (dc, 0, sizeof (struct dschannel));
+}
+
+static void ds_free (struct DSAHI *dsahip)
+{
+    int i;
+
+    for (i = 0; i < dsahip->channels; i++) {
+       struct dschannel *dc = &dsahip->channel[i];
+       ds_freechannel (dsahip, dc);
+    }
+    if (dsahip->DS)
+       IDirectSound_Release (dsahip->DS);
+    dsahip->DS = NULL;
+    if (ahi_debug && ahi_active)
+       write_log ("AHI: DSOUND freed\n");
+    ahi_active = 0;
+}
+
+DWORD fillsupportedmodes (LPDIRECTSOUND8 lpDS, int freq, struct dsaudiomodes *dsam);
+static struct dsaudiomodes supportedmodes[16];
+
+static void ds_free_record (struct DSAHI *dsahip)
+{
+    if (dsahip->dscb)
+       IDirectSoundCaptureBuffer_Release (dsahip->dscb);
+    if (dsahip->DSC)
+       IDirectSoundCapture_Release (dsahip->DSC);
+    dsahip->dscb = NULL;
+    dsahip->DSC = NULL;
+}
+
+static int ds_init_record (struct DSAHI *dsahip)
+{
+    HRESULT hr;
+    WAVEFORMATEXTENSIBLE wavfmt;
+    DSCBUFFERDESC dbd;
+    uae_u32 pbase = get_long (dsahip->audioctrl + ahiac_DriverData);
+    int freq = get_long (dsahip->audioctrl + ahiac_MixFreq);
+
+    if (dsahip->DSC)
+       return 1;
+    if (!freq)
+       return 0;
+    dsahip->mixlength_record = RECORDSAMPLES; // in sample units, not bytes
+    dsahip->record_ch = 2;
+    dsahip->record_bytespersample = 2;
+    dsahip->channellength_record = freq * dsahip->record_bytespersample * dsahip->record_ch * 10;
+    put_long (pbase + pub_RecordBufferSize, dsahip->mixlength_record);
+    put_long (pbase + pub_RecordBufferSizeBytes, dsahip->mixlength_record * dsahip->record_ch * dsahip->record_bytespersample);
+    put_long (pbase + pub_RecordSampleType, AHIST_S16S);
+    put_word (pbase + pub_RecordHookDone, 0);
+
+    hr = DirectSoundCaptureCreate (&record_devices[dsahip->input].guid, &dsahip->DSC, NULL);
+    if (FAILED (hr)) {
+       write_log ("AHI: DirectSoundCaptureCreate() failure %dHz: %s\n", freq, DXError (hr));
+       goto end;
+    }
+    memset (&dbd, 0, sizeof dbd);
+    dbd.dwSize = sizeof dbd;
+    dbd.dwBufferBytes = dsahip->channellength_record;
+    dbd.lpwfxFormat = &wavfmt.Format;
+    dbd.dwFlags = 0 ;
+    memset (&wavfmt, 0, sizeof wavfmt);
+    wavfmt.Format.nChannels = dsahip->record_ch;
+    wavfmt.Format.nSamplesPerSec = freq;
+    wavfmt.Format.wBitsPerSample = dsahip->record_bytespersample * 8;
+    wavfmt.Format.wFormatTag = WAVE_FORMAT_PCM;
+    wavfmt.Format.nBlockAlign = wavfmt.Format.wBitsPerSample / 8 * wavfmt.Format.nChannels;
+    wavfmt.Format.nAvgBytesPerSec = wavfmt.Format.nBlockAlign * wavfmt.Format.nSamplesPerSec;
+    hr = IDirectSoundCapture_CreateCaptureBuffer (dsahip->DSC, &dbd, &dsahip->dscb, NULL);
+    if (FAILED (hr)) {
+       write_log ("AHI: CreateCaptureSoundBuffer() failure: %s\n", DXError(hr));
+       goto end;
+    }
+    if (ahi_debug)
+       write_log ("AHI: DSOUND Recording initialized. %dHz, %s\n", freq, record_devices[dsahip->input].name);
+
+    put_word (pbase + pub_FuncMode, get_word (pbase + pub_FuncMode) | FUNCMODE_RECORDALLOC);
+    sendsignal (dsahip);
+    return 1;
+end:
+    ds_free_record (dsahip);
+    return 0;
+}
+
+static int ds_init (struct DSAHI *dsahip)
+{
+    int freq = 44100;
+    DSCAPS DSCaps;
+    HRESULT hr;
+    DWORD speakerconfig;
+
+    hr = DirectSoundCreate8 (&sound_devices[dsahip->output].guid, &dsahip->DS, NULL);
+    if (FAILED (hr))  {
+       write_log ("AHI: DirectSoundCreate8() failure: %s\n", DXError (hr));
+       return 0;
+    }
+
+    hr = IDirectSound_SetCooperativeLevel (dsahip->DS, hMainWnd, DSSCL_PRIORITY);
+    if (FAILED (hr)) {
+       write_log ("AHI: Can't set cooperativelevel: %s\n", DXError (hr));
+       goto error;
+    }
+
+    fillsupportedmodes (dsahip->DS, default_freq, supportedmodes);
+    dsahip->chout = 2;
+    if (SUCCEEDED (IDirectSound8_GetSpeakerConfig (dsahip->DS, &speakerconfig))) {
+       if (speakerconfig >= DSSPEAKER_CONFIG (DSSPEAKER_5POINT1)) {
+           cansurround = 1;
+           dsahip->chout = 6;
+           if (speakerconfig >= DSSPEAKER_CONFIG (DSSPEAKER_7POINT1))
+               dsahip->chout = 8;
+       }
+    }
+
+    dsahip->bitspersampleout = dsahip->bits24 ? 24 : 16;
+    dsahip->bytespersampleout = dsahip->bitspersampleout / 8;
+    dsahip->channellength = 65536 * dsahip->chout * dsahip->bytespersampleout;
+    dsahip->mixlength = 4000 * dsahip->chout * dsahip->bytespersampleout;
+    if (ahi_debug)
+       write_log("AHI: CH=%d BLEN=%d MLEN=%d SC=%08x\n",
+           dsahip->chout, dsahip->channellength, dsahip->mixlength, speakerconfig);
+
+    memset (&DSCaps, 0, sizeof (DSCaps));
+    DSCaps.dwSize = sizeof (DSCaps);
+    hr = IDirectSound_GetCaps (dsahip->DS, &DSCaps);
+    if (FAILED(hr)) {
+       write_log ("AHI: Error getting DirectSound capabilities: %s\n", DXError (hr));
+       goto error;
+    }
+    if (DSCaps.dwFlags & DSCAPS_EMULDRIVER) {
+       write_log ("AHI: Emulated DirectSound driver detected, don't complain if sound quality is crap :)\n");
+    }
+    if (DSCaps.dwFlags & DSCAPS_CONTINUOUSRATE) {
+       int minfreq = DSCaps.dwMinSecondarySampleRate;
+       int maxfreq = DSCaps.dwMaxSecondarySampleRate;
+       if (minfreq > freq && freq < 22050) {
+           freq = minfreq;
+           write_log ("AHI: minimum supported frequency: %d\n", minfreq);
+       }
+       if (maxfreq < freq && freq > 44100) {
+           freq = maxfreq;
+           write_log ("AHI: maximum supported frequency: %d\n", maxfreq);
+       }
+    }
+
+    if (ahi_debug)
+       write_log ("AHI: DSOUND initialized: %s\n", sound_devices[dsahip->output].name);
+
+    return 1;
+error:
+    if (ahi_debug)
+       write_log ("AHI: DSOUND initialization failed\n");
+    ds_free (dsahip);
+    return 0;
+}
+
+static int ds_reinit (struct DSAHI *dsahip)
+{
+    ds_free (dsahip);
+    return ds_init (dsahip);
+}
+
+
+static void ds_setvolume (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    HRESULT hr;
+    LONG vol, pan;
+
+    if (dc->dsb) {
+       if (abs (dc->cs.volume) != abs (dc->csnext.volume)) {
+           vol = (LONG)((DSBVOLUME_MIN / 2) + (-DSBVOLUME_MIN / 2) * log (1 + (2.718281828 - 1) * (abs (dc->csnext.volume) / 65536.0)));
+           hr = IDirectSoundBuffer_SetVolume (dc->dsb, vol);
+           if (FAILED (hr))
+               write_log ("AHI: SetVolume(%d,%d) failed: %s\n", dc->num, vol, DXError (hr));
+       }
+       if (abs (dc->cs.panning) != abs (dc->csnext.panning)) {
+           pan = (abs (dc->csnext.panning) - 0x8000) * DSBPAN_RIGHT / 32768;
+           hr = IDirectSoundBuffer_SetPan (dc->dsb, pan);
+           if (FAILED (hr))
+               write_log ("AHI: SetPan(%d,%d) failed: %s\n", dc->num, pan, DXError (hr));
+       }
+    }
+    dc->cs.volume = dc->csnext.volume;
+    dc->cs.panning = dc->csnext.panning;
+}
+
+static void ds_setfreq (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    HRESULT hr;
+
+    if (dc->cs.frequency != dc->csnext.frequency && dc->csnext.frequency > 0 && dc->dsb) {
+       hr = IDirectSoundBuffer8_SetFrequency (dc->dsb, dc->csnext.frequency);
+       if (FAILED (hr))
+           write_log ("AHI: SetFrequency(%d,%d) failed: %s\n", dc->num, dc->csnext.frequency, DXError (hr));
+    }
+    dc->cs.frequency = dc->csnext.frequency;
+}
+
+static int ds_allocchannel (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    HRESULT hr;
+    DSBUFFERDESC dd;
+    WAVEFORMATEXTENSIBLE wavfmt;
+    LPDIRECTSOUNDBUFFER pdsb;
+    LPDIRECTSOUNDBUFFER8 pdsb8;
+    int round;
+
+    if (dc->dsb)
+       return 1;
+    pdsb = NULL;
+    for (round = 0; supportedmodes[round].ch; round++) {
+        DWORD ksmode = 0;
+
+        pdsb = NULL;
+        if (supportedmodes[round].ch != dsahip->chout)
+           continue;
+
+       memset (&wavfmt, 0, sizeof (WAVEFORMATEXTENSIBLE));
+       wavfmt.Format.nChannels = dsahip->chout;
+       wavfmt.Format.nSamplesPerSec = default_freq;
+       wavfmt.Format.wBitsPerSample = dsahip->bitspersampleout;
+       if (dsahip->chout <= 2) {
+           wavfmt.Format.wFormatTag = WAVE_FORMAT_PCM;
+       } else {
+           DWORD ksmode = 0;
+           wavfmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+           wavfmt.Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
+           wavfmt.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+           wavfmt.Samples.wValidBitsPerSample = dsahip->bitspersampleout;
+           wavfmt.dwChannelMask = supportedmodes[round].ksmode;
+       }
+       wavfmt.Format.nBlockAlign = dsahip->bytespersampleout * wavfmt.Format.nChannels;
+       wavfmt.Format.nAvgBytesPerSec = wavfmt.Format.nBlockAlign * wavfmt.Format.nSamplesPerSec;
+
+       memset (&dd, 0, sizeof dd);
+       dd.dwSize = sizeof dd;
+       dd.dwBufferBytes = dsahip->channellength;
+       dd.lpwfxFormat = &wavfmt.Format;
+       dd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY;
+       dd.dwFlags |= DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY;
+       dd.dwFlags |= dsahip->chout >= 4 ? DSBCAPS_LOCHARDWARE : DSBCAPS_LOCSOFTWARE;
+       dd.guid3DAlgorithm = GUID_NULL;
+
+       hr = IDirectSound_CreateSoundBuffer (dsahip->DS, &dd, &pdsb, NULL);
+       if (SUCCEEDED (hr))
+           break;
+       if (dd.dwFlags & DSBCAPS_LOCHARDWARE) {
+           HRESULT hr2 = hr;
+           dd.dwFlags &= ~DSBCAPS_LOCHARDWARE;
+           dd.dwFlags |=  DSBCAPS_LOCSOFTWARE;
+           hr = IDirectSound_CreateSoundBuffer (dsahip->DS, &dd, &pdsb, NULL);
+           if (SUCCEEDED (hr))
+               break;
+       }
+       write_log ("AHI: DS sound buffer failed (ch=%d,bps=%d): %s\n",
+           dsahip->chout, dsahip->bitspersampleout, DXError (hr));
+    }
+    if (pdsb == NULL)
+       goto error;
+
+    hr = IDirectSound_QueryInterface (pdsb, &IID_IDirectSoundBuffer8, (LPVOID*)&pdsb8);
+    if (FAILED (hr))  {
+       write_log ("AHI: Secondary QueryInterface(IID_IDirectSoundBuffer8) failure: %s\n", DXError (hr));
+       goto error;
+    }
+    IDirectSound_Release (pdsb);
+    dc->dsb = pdsb8;
+
+    dc->cs.frequency = -1;
+    dc->cs.volume = -1;
+    dc->cs.panning = -1;
+    ds_setvolume (dsahip, dc);
+    ds_setfreq (dsahip, dc);
+    dc->mixlength = dsahip->mixlength;
+    dc->buffer = xcalloc (dc->mixlength, 1);
+    dc->buffercursor = 0;
+    if (ahi_debug)
+       write_log ("AHI: allocated directsound buffer for channel %d\n", dc->num);
+    return 1;
+error:
+    ds_freechannel (dsahip, dc);
+    return 0;
+}
+
+#define MAKEXCH makexch (dsahip, dc, dst, i, och2, l, r)
+
+STATIC_INLINE void makexch (struct DSAHI *dsahip, struct dschannel *dc, uae_u8 *dst, int idx, int och2, uae_s32 l, uae_s32 r)
+{
+    if (dsahip->bits24) {
+    } else {
+       uae_s16 *dst2 = (uae_u16*)(&dst[idx * och2]);
+       l >>= 8;
+       r >>= 8;
+       if (dc->cs.volume < 0) {
+           l = -l;
+           r = -r;
+       }
+       dst2[0] = l;
+       dst2[1] = r;
+       if (dsahip->chout <= 2)
+           return;
+       dst2[4] = dst2[0];
+       dst2[5] = dst2[1];
+       if (dc->cs.panning < 0) {
+           // surround only
+           dst2[2] = 0; // center
+           dst2[3] = (dst2[0] + dst2[1]) / 4; // lfe
+           dst2[0] = dst2[1] = 0;
+           return;
+       }
+       dst2[2] = dst2[3] = (dst2[0] + dst2[1]) / 4;
+       if (dsahip->chout <= 6)
+           return;
+       dst2[6] = dst2[4];
+       dst2[7] = dst2[5];
+    }
+}
+
+/* sample conversion routines */
+static void copysampledata (struct DSAHI *dsahip, struct dschannel *dc, struct dssample *ds, uae_u8 **psrcp, uae_u8 *srce, uae_u8 *srcp, void *dstp, int dstlen)
+{
+    int i;
+    uae_u8 *src = *psrcp;
+    uae_u8 *dst = (uae_u8*)dstp;
+    int och = dsahip->chout;
+    int och2 = och * 2;
+    int ich = ds->ch;
+    int len;
+
+    len = dstlen;
+    switch (ds->sampletype)
+    {
+       case AHIST_M8S:
+           for (i = 0; i < len; i++) {
+               uae_u32 l = (src[0] << 16) | (src[0] << 8) | src[0] ;
+               uae_u32 r = (src[0] << 16) | (src[0] << 8) | src[0];
+               src += 1;
+               if (src >= srce)
+                   src = srcp;
+               MAKEXCH;
+           }
+       break;
+       case AHIST_S8S:
+           for (i = 0; i < len; i++) {
+               uae_u32 l = (src[0] << 16) | (src[0] << 8) | src[0] ;
+               uae_u32 r = (src[1] << 16) | (src[1] << 8) | src[1];
+               src += 2;
+               if (src >= srce)
+                   src = srcp;
+               MAKEXCH;
+           }
+       break;
+       case AHIST_M16S:
+           for (i = 0; i < len; i++) {
+               uae_u32 l = (src[0] << 16) | (src[1] << 8) | src[1];
+               uae_u32 r = (src[0] << 16) | (src[1] << 8) | src[1];
+               src += 2;
+               if (src >= srce)
+                   src = srcp;
+               MAKEXCH;
+           }
+       break;
+       case AHIST_S16S:
+           for (i = 0; i < len; i++) {
+               uae_u32 l = (src[0] << 16) | (src[1] << 8) | src[1];
+               uae_u32 r = (src[2] << 16) | (src[3] << 8) | src[3];
+               src += 4;
+               if (src >= srce)
+                   src = srcp;
+               MAKEXCH;
+           }
+       break;
+       case AHIST_M32S:
+           for (i = 0; i < len; i++) {
+               uae_u32 l = (src[3] << 16) | (src[2] << 8) | src[1];
+               uae_u32 r = (src[3] << 16) | (src[2] << 8) | src[1];
+               src += 4;
+               if (src >= srce)
+                   src = srcp;
+               MAKEXCH;
+           }
+       break;
+       case AHIST_S32S:
+           for (i = 0; i < len; i++) {
+               uae_u32 l = (src[3] << 16) | (src[2] << 8) | src[1];
+               uae_u32 r = (src[7] << 16) | (src[6] << 8) | src[5];
+               src += 8;
+               if (src >= srce)
+                   src = srcp;
+               MAKEXCH;
+           }
+       break;
+       case AHIST_L7_1:
+           if (och == 8) {
+               for (i = 0; i < len; i++) {
+                   if (dsahip->bits24) {
+                       uae_u32 fl = (src[0 * 4 + 3] << 16) | (src[0 * 4 + 2] << 8) | src[0 * 4 + 1];
+                       uae_u32 fr = (src[1 * 4 + 3] << 16) | (src[1 * 4 + 2] << 8) | src[1 * 4 + 1];
+                       uae_u32 cc = (src[6 * 4 + 3] << 16) | (src[6 * 4 + 2] << 8) | src[6 * 4 + 1];
+                       uae_u32 lf = (src[7 * 4 + 3] << 16) | (src[7 * 4 + 2] << 8) | src[7 * 4 + 1];
+                       uae_u32 bl = (src[2 * 4 + 3] << 16) | (src[2 * 4 + 2] << 8) | src[2 * 4 + 1];
+                       uae_u32 br = (src[3 * 4 + 3] << 16) | (src[3 * 4 + 2] << 8) | src[3 * 4 + 1];
+                       uae_u32 sl = (src[4 * 4 + 3] << 16) | (src[4 * 4 + 2] << 8) | src[4 * 4 + 1];
+                       uae_u32 sr = (src[5 * 4 + 3] << 16) | (src[5 * 4 + 2] << 8) | src[5 * 4 + 1];
+                       uae_s32 *dst2 = (uae_s32*)(&dst[i * och2]);
+                       dst2[0] = fl;
+                       dst2[1] = fr;
+                       dst2[2] = cc;
+                       dst2[3] = lf;
+                       dst2[4] = bl;
+                       dst2[5] = br;
+                       dst2[6] = sl;
+                       dst2[7] = sr;
+                   } else {
+                       uae_u16 fl = (src[0 * 4 + 3] << 8) | src[0 * 4 + 2];
+                       uae_u16 fr = (src[1 * 4 + 3] << 8) | src[1 * 4 + 2];
+                       uae_u16 cc = (src[6 * 4 + 3] << 8) | src[6 * 4 + 2];
+                       uae_u16 lf = (src[7 * 4 + 3] << 8) | src[7 * 4 + 2];
+                       uae_u16 bl = (src[2 * 4 + 3] << 8) | src[2 * 4 + 2];
+                       uae_u16 br = (src[3 * 4 + 3] << 8) | src[3 * 4 + 2];
+                       uae_u16 sl = (src[4 * 4 + 3] << 8) | src[4 * 4 + 2];
+                       uae_u16 sr = (src[5 * 4 + 3] << 8) | src[5 * 4 + 2];
+                       uae_s16 *dst2 = (uae_s16*)(&dst[i * och2]);
+                       dst2[0] = fl;
+                       dst2[1] = fr;
+                       dst2[2] = cc;
+                       dst2[3] = lf;
+                       dst2[4] = bl;
+                       dst2[5] = br;
+                       dst2[6] = sl;
+                       dst2[7] = sr;
+                   }
+                   dst += och2;
+                   src += 8 * 4;
+                   if (src >= srce)
+                       src = srcp;
+               }
+           } else if (och == 6) { /* 7.1 -> 5.1 */
+               for (i = 0; i < len; i++) {
+                   if (dsahip->bits24) {
+                       uae_s32 *dst2 = (uae_s32*)(&dst[i * och2]);
+                       uae_u32 fl = (src[0 * 4 + 3] << 16) | (src[0 * 4 + 2] << 8) | src[0 * 4 + 1];
+                       uae_u32 fr = (src[1 * 4 + 3] << 16) | (src[1 * 4 + 2] << 8) | src[1 * 4 + 1];
+                       uae_u32 cc = (src[6 * 4 + 3] << 16) | (src[6 * 4 + 2] << 8) | src[6 * 4 + 1];
+                       uae_u32 lf = (src[7 * 4 + 3] << 16) | (src[7 * 4 + 2] << 8) | src[7 * 4 + 1];
+                       uae_u32 bl = (src[2 * 4 + 3] << 16) | (src[2 * 4 + 2] << 8) | src[2 * 4 + 1];
+                       uae_u32 br = (src[3 * 4 + 3] << 16) | (src[3 * 4 + 2] << 8) | src[3 * 4 + 1];
+                       uae_u32 sl = (src[4 * 4 + 3] << 16) | (src[4 * 4 + 2] << 8) | src[4 * 4 + 1];
+                       uae_u32 sr = (src[5 * 4 + 3] << 16) | (src[5 * 4 + 2] << 8) | src[5 * 4 + 1];
+                   } else {
+                       uae_s16 *dst2 = (uae_s16*)(&dst[i * och2]);
+                       uae_u16 fl = (src[0 * 4 + 3] << 8) | src[0 * 4 + 2];
+                       uae_u16 fr = (src[1 * 4 + 3] << 8) | src[1 * 4 + 2];
+                       uae_u16 cc = (src[6 * 4 + 3] << 8) | src[6 * 4 + 2];
+                       uae_u16 lf = (src[7 * 4 + 3] << 8) | src[7 * 4 + 2];
+                       uae_u16 bl = (src[2 * 4 + 3] << 8) | src[2 * 4 + 2];
+                       uae_u16 br = (src[3 * 4 + 3] << 8) | src[3 * 4 + 2];
+                       uae_u16 sl = (src[4 * 4 + 3] << 8) | src[4 * 4 + 2];
+                       uae_u16 sr = (src[5 * 4 + 3] << 8) | src[5 * 4 + 2];
+                       dst2[0] = fl;
+                       dst2[1] = fr;
+                       dst2[2] = cc;
+                       dst2[3] = lf;
+                       dst2[4] = (bl + sl) / 2;
+                       dst2[5] = (br + sr) / 2;
+                   }
+                   dst += och2;
+                   src += 8 * 4;
+                   if (src >= srce)
+                       src = srcp;
+               }
+           }
+       break;
+    }
+    *psrcp = src;
+}
+
+static void dorecord (struct DSAHI *dsahip)
+{
+    uae_u32 pbase = get_long (dsahip->audioctrl + ahiac_DriverData);
+    HRESULT hr;
+    DWORD cpos, rpos, diff;
+    void *buf1, *buf2;
+    DWORD size1, size2;
+    uae_u32 recordbuf;
+    int mixlength_bytes;
+
+    if (dsahip->dscb == NULL)
+       return;
+    if (dsahip->record_wait && !get_word (pbase + pub_RecordHookDone))
+       return;
+    dsahip->record_wait = 0;
+    mixlength_bytes = dsahip->mixlength_record * dsahip->record_ch * dsahip->record_bytespersample;
+    recordbuf = get_long (pbase + pub_RecordBuffer);
+    if (recordbuf == 0 || !valid_address (recordbuf, mixlength_bytes))
+       return;
+    hr = IDirectSoundCaptureBuffer_GetCurrentPosition (dsahip->dscb, &cpos, &rpos);
+    if (FAILED (hr)) {
+       write_log ("AHI: IDirectSoundCaptureBuffer_GetCurrentPosition() failed %s\n", DXError (hr));
+       return;
+    }
+    if (rpos < dsahip->recordingcursor)
+       rpos += dsahip->channellength_record;
+    diff = rpos - dsahip->recordingcursor;
+    if (diff < mixlength_bytes)
+       return;
+    hr = IDirectSoundCaptureBuffer_Lock (dsahip->dscb, dsahip->recordingcursor, mixlength_bytes, &buf1, &size1, &buf2, &size2, 0);
+    if (SUCCEEDED (hr)) {
+       uae_u8 *addr = get_real_address (recordbuf);
+       uae_u8 *b = (uae_u8*)buf1;
+       int s;
+       b = (uae_u8*)buf1;
+       s = size1;
+       while (s > 0) {
+           addr[0] = b[1];
+           addr[1] = b[0];
+           addr += 2;
+           b += 2;
+           s -= 2;
+       }
+       b = (uae_u8*)buf2;
+       s = size2;
+       while (s > 0) {
+           addr[0] = b[1];
+           addr[1] = b[0];
+           addr += 2;
+           b += 2;
+           s -= 2;
+       }
+       IDirectSoundCaptureBuffer_Unlock (dsahip->dscb, buf1, size1, buf2, size2);
+       put_word (pbase + pub_RecordHookDone, 0);
+       dsahip->record_wait = 1;
+       put_word (pbase + pub_FuncMode, get_word (pbase + pub_FuncMode) | FUNCMODE_RECORD);
+       sendsignal (dsahip);
+    }
+    dsahip->recordingcursor += mixlength_bytes;
+    if (dsahip->recordingcursor >= dsahip->channellength_record)
+       dsahip->recordingcursor -= dsahip->channellength_record;
+}
+
+static int ds_copysample (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    HRESULT hr;
+    DWORD playc, writec;
+    DWORD size1, size2;
+    DWORD diff;
+    void *buf1, *buf2;
+
+    hr = IDirectSoundBuffer8_GetCurrentPosition (dc->dsb, &playc, &writec);
+    if (FAILED (hr)) {
+        write_log ("AHI: GetCurrentPosition(%d) failed, %s\n", dc->num, DXError (hr));
+        return 0;
+    }
+
+    if (dc->dscursor >= writec)
+       diff = dc->dscursor - writec;
+    else
+        diff = dsahip->channellength - writec + dc->dscursor;
+
+    if (diff > dsahip->channellength / 2) {
+       dc->dscursor = writec + dc->mixlength;
+       write_log ("AHI: Resync\n");
+    }
+    if (diff > dc->mixlength)
+       return 0;
+
+    hr = IDirectSoundBuffer8_Lock (dc->dsb, dc->dscursor, dc->mixlength, &buf1, &size1, &buf2, &size2, 0);
+    if (hr == DSERR_BUFFERLOST) {
+       IDirectSoundBuffer8_Restore (dc->dsb);
+       hr = IDirectSoundBuffer8_Lock (dc->dsb, dc->dscursor, dc->mixlength, &buf1, &size1, &buf2, &size2, 0);
+    }
+    if (SUCCEEDED (hr)) {
+       memcpy (buf1, dc->buffer, size1);
+       if (buf2) 
+           memcpy (buf2, dc->buffer + size1, size2);
+       IDirectSoundBuffer8_Unlock (dc->dsb, buf1, size1, buf2, size2);
+    }
+
+    if (ahi_debug > 1)
+       write_log ("%d playc=%08d writec=%08d dscursor=%08d\n",
+           diff / (dsahip->chout * dsahip->bytespersampleout),
+           playc, writec, dc->dscursor);
+
+    dc->dscursor += dc->mixlength;
+    if (dc->dscursor >= dsahip->channellength)
+       dc->dscursor -= dsahip->channellength;
+
+    return 1;
+}
+
+static int calcdelay (struct dschannel *dc, int len)
+{
+    int rate = vblank_hz * maxvpos;
+    int freq = dc->cs.frequency;
+    int hsyncs = rate * len / freq;
+    hsyncs = hsyncs * 2 / 3;
+    if (hsyncs > 0)
+       hsyncs--;
+    return hsyncs;
+}
+
+#if 0
+static void checkvolfreq (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    if (dc->cs.frequency != dc->csnext.frequency)
+       ds_setfreq (dsahip, dc);
+    if (dc->cs.volume != dc->csnext.volume || dc->cs.panning != dc->csnext.panning)
+       ds_setvolume (dsahip, dc);
+}
+
+static void getmixbufferlen (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    int olen = dc->mixlength;
+    dc->mixlength = (dc->csnext.frequency / 24) * dsahip->bytespersampleout * dsahip->chout;
+    if (dc->mixlength > dsahip->mixlength)
+       dc->mixlength = dsahip->mixlength;
+    if (dc->mixlength < 100)
+       dc->mixlength = 100;
+    if (ahi_debug && olen != dc->mixlength)
+       write_log ("AHI: channel %d: buffer %d frames\n",
+           dc->num, dc->mixlength / (dsahip->bytespersampleout * dsahip->chout));
+}
+
+static void copysample (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    int dstlen, dstlenbytes;
+    struct dssample *ds;
+    int srclen, srclendstbytes;
+    int chbytesout;
+    uae_u8 *dstbuf;
+    uae_u32 addr, addre, addrs;
+    int chbytesin;
+    int waitlen;
+
+    assert (dc->buffercursor < dc->mixlength);
+
+    chbytesout = dsahip->chout * dsahip->bytespersampleout;
+    dstbuf = dc->buffer + dc->buffercursor;
+    dstlenbytes = dc->mixlength - dc->buffercursor;
+    dstlen = dstlenbytes / chbytesout;
+    
+    ds = dc->cs.ds;
+    if (ds == NULL) {
+       ds = dc->ds = dc->nextds;
+       dc->srcplaylen = dc->nextsrcplaylen;
+       dc->srcplayoffset = dc->nextsrcplayoffset;
+       dc->nextds = NULL;
+       dc->nextsrcplaylen = 0;
+       dc->nextsrcplayoffset = 0;
+       dc->srcoffset = 0;
+       if (ds != NULL) { // sample started
+           int len;
+           setchannelevent (dsahip, dc);
+           len = dc->srcplaylen;
+           if (len > dstlen)
+               len = dstlen;
+           dc->hsync = calcdelay (dc, len);
+           return;
+       }
+    }
+    if (ds == NULL)
+       goto cempty;
+
+    chbytesin = ds->ch * ds->bytespersample;
+    if (ds->addr == 0 && ds->len == 0xffffffff) {
+        addrs = addr = ds->offset;
+    } else {
+        addr = ds->addr;
+        addr += dc->srcplayoffset * chbytesin;
+        addrs = addr;
+    }
+    addre = addr + dc->srcplaylen * chbytesin;
+    addr += dc->srcoffset * chbytesin;
+
+    srclen = dc->srcplaylen - dc->srcoffset;
+    assert (srclen > 0);
+    srclendstbytes = srclen * chbytesout;
+
+    if (srclendstbytes > dstlenbytes) {
+        srclendstbytes = dstlenbytes;
+        srclen = srclendstbytes / chbytesout;
+    }
+    if (dstlenbytes > srclendstbytes) {
+        dstlenbytes = srclendstbytes;
+        dstlen = dstlenbytes / chbytesout;
+    }
+
+    waitlen = dstlen;
+
+    assert (dstlen > 0);
+
+    if (valid_address (addrs, addre - addrs)) {
+        uae_u8 *naddr = get_real_address (addr);
+        uae_u8 *naddre = get_real_address (addre);
+        uae_u8 *naddrs = get_real_address (addrs);
+        copysampledata (dsahip, dc, ds, &naddr, naddre, naddrs, dstbuf, dstlen);
+        dc->srcoffset = (naddr - naddrs) / chbytesin;
+        if (dc->srcoffset == 0) {
+           // looping or next sample
+           if (dc->nextsrcplaylen < 0) { // stop sample
+               int off = dstlenbytes;
+               dc->nextsrcplaylen = 0;
+               dc->nextds = NULL;
+               setchannelevent (dsahip, dc);
+               dstlenbytes = dc->mixlength - off - dc->buffercursor;
+               dstlen = dstlenbytes / chbytesout;
+               memset (dstbuf + off, 0, dstlenbytes);
+               goto empty;
+           }
+           if (dc->nextds) {
+               dc->ds = NULL;
+               dc->buffercursor += dstlenbytes;
+               dc->hsync = 0;
+               return;
+           }
+           setchannelevent (dsahip, dc);
+
+       }
+
+    } else {
+       goto cempty;
+    }
+
+    dc->hsync = calcdelay (dc, waitlen);
+    dc->buffercursor += dstlenbytes;
+    checkvolfreq (dsahip, dc);
+    //write_log ("%d ", dstlen / (dsahip->chout * dsahip->bytespersampleout));
+    return;
+
+cempty:
+    memset (dstbuf, 0, dstlenbytes);
+empty:
+    dc->ds = NULL;
+    dc->hsync = calcdelay (dc, waitlen);
+    dc->buffercursor += dstlenbytes;
+    checkvolfreq (dsahip, dc);
+}
+#endif
+
+static void incchannel (struct DSAHI *dsahip, struct dschannel *dc, int samplecnt)
+{
+    struct chsample *cs = &dc->cs;
+
+    if (cs->ds == NULL)
+       return;
+    dc->srcoffset += samplecnt;
+    while (dc->srcoffset >= cs->srcplaylen) {
+       dc->srcoffset -= cs->srcplaylen;
+        setchannelevent (dsahip, dc);
+       if (dc->csnext.stopit) {
+           memset (cs, 0, sizeof (struct chsample));
+           memset (&dc->csnext, 0, sizeof (struct chsample));
+           dc->srcoffset = 0;
+           return;
+       }
+       if (dc->csnext.ds) {
+           memcpy (cs, &dc->csnext, sizeof (struct chsample));
+           memset (&dc->csnext, 0, sizeof (struct chsample));
+           continue;
+       }
+    }
+}
+
+void ahi_hsync (void)
+{
+    struct DSAHI *dsahip = &dsahi[0];
+    static int cnt;
+    uae_u32 pbase;
+    int i, flags;
+
+    if (ahi_paused || !ahi_active)
+       return;
+    pbase = get_long (dsahip->audioctrl + ahiac_DriverData);
+    if (cnt >= 0)
+       cnt--;
+    if (cnt < 0) {
+       if (dsahip->dsrecording && dsahip->enabledisable == 0) {
+           dorecord (dsahip);
+           cnt = 100;
+       }
+    }
+    if (!dsahip->playing)
+       return;
+    flags = get_long (pbase + pub_ChannelSignalAck);
+    for (i = 0; i < UAE_MAXCHANNELS; i++) {
+       struct dschannel *dc = &dsahip->channel[i];
+       HRESULT hr;
+       DWORD playc, writec, diff, samplediff;
+
+       if (dc->dsb == NULL)
+           continue;
+       if (dc->dsplaying == 0)
+           continue;
+        hr = IDirectSoundBuffer8_GetCurrentPosition (dc->dsb, &playc, &writec);
+       if (FAILED (hr)) {
+           write_log ("AHI: GetCurrentPosition(%d) failed, %s\n", dc->num, DXError (hr));
+           continue;
+       }
+       if (dc->dscursor >= writec)
+           diff = dc->dscursor - writec;
+       else
+           diff = dsahip->channellength - writec + dc->dscursor;
+       if (diff > dsahip->channellength / 2) {
+           dc->dscursor = writec + dc->mixlength;
+           write_log ("AHI: Resync %d\n", dc->num);
+       }
+
+       if (dc->dscursor < 0) {
+           dc->dscursor = writec;
+           memcpy (&dc->cs, &dc->csnext, sizeof (struct chsample));
+       }
+       samplediff = diff / (dsahip->chout * dsahip->bytespersampleout);
+       incchannel (dsahip, dc, samplediff);
+//     copysample (dsahip, dc, &dc->cs);
+
+
+
+
+       if (diff > dc->mixlength)
+           continue;
+
+
+#if 0
+       if (dc->buffer == NULL)
+           continue;
+       if (dc->hsync > 0) {
+           dc->hsync--;
+           continue;
+       }
+       if (dc->channelsignal) {
+           if (!(flags & (1 << dc->num)))
+               continue;
+           dc->channelsignal = 0;
+           flags &= ~(1 << dc->num);
+       }
+       if (dsahip->enabledisable)
+           continue;
+       if (dc->buffercursor < dc->mixlength)
+           copysample (dsahip, dc);
+       assert (dc->buffercursor <= dc->mixlength);
+       if (dc->buffercursor == dc->mixlength) {
+           if (ds_copysample (dsahip, dc)) {
+               getmixbufferlen (dsahip, dc);
+               dc->buffercursor = 0;
+           } else {
+               dc->hsync = 100;
+           }
+       }
+#endif
+    }
+    put_long (pbase + pub_ChannelSignalAck, flags);
+}
+
+static void ds_record (struct DSAHI *dsahip, int start)
+{
+    HRESULT hr;
+
+    if (dsahip->dscb == NULL)
+       return;
+    if (dsahip->dsrecording && start)
+       return;
+    dsahip->dsrecording = 0;
+    if (start) {
+       hr = IDirectSoundCaptureBuffer_Start (dsahip->dscb, DSCBSTART_LOOPING);
+       if (FAILED (hr)) {
+           write_log ("AHI: DirectSoundCaptureBuffer_Start failed: %s\n", DXError (hr));
+           return;
+       }
+       dsahip->dsrecording = 1;
+    } else {
+       hr = IDirectSoundCaptureBuffer_Stop (dsahip->dscb);
+       if (FAILED (hr)) {
+           write_log ("AHI: DirectSoundCaptureBuffer_Stop failed: %s\n", DXError (hr));
+           return;
+       }
+    }
+}
+
+static void ds_stop (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    HRESULT hr;
+
+    dc->dsplaying = 0;
+    if (dc->dsb == NULL)
+       return;
+    if (ahi_debug)
+       write_log ("AHI: ds_stop(%d)\n", dc->num);
+    hr = IDirectSoundBuffer8_Stop (dc->dsb);
+    if (FAILED (hr))
+       write_log ("AHI: IDirectSoundBuffer8_Stop() failed, %s\n", DXError (hr));
+}
+
+static void ds_play (struct DSAHI *dsahip, struct dschannel *dc)
+{
+    HRESULT hr;
+    DWORD status, playc, writec;
+
+    if (dc->dsb == NULL)
+       return;
+    if (dc->dsplaying)
+       return;
+    if (dc->cs.frequency == 0)
+       return;
+    dc->dsplaying = 1;
+    if (ahi_debug)
+       write_log ("AHI: ds_play(%d)\n", dc->num);
+    hr = IDirectSoundBuffer8_GetStatus (dc->dsb, &status);
+    if (FAILED (hr))
+       write_log ("AHI: ds_play() IDirectSoundBuffer8_GetStatus() failed, %s\n", DXError (hr));
+    hr = IDirectSoundBuffer8_Play (dc->dsb, 0, 0, DSBPLAY_LOOPING);
+    if (FAILED (hr))
+       write_log ("AHI: ds_play() IDirectSoundBuffer8_Play() failed, %s\n", DXError (hr));
+    hr = IDirectSoundBuffer8_GetCurrentPosition (dc->dsb, &playc, &writec);
+    if (FAILED (hr))
+       write_log ("AHI: ds_play() IDirectSoundBuffer8_GetCurrentPosition() failed, %s\n", DXError (hr));
+    dc->dscursor = writec + dc->mixlength;
+    if (dc->dscursor >= dsahip->channellength)
+       dc->dscursor -= dsahip->channellength;
+    if (ahi_debug)
+       write_log("AHI: ds_play(%d) Start=%d->%d\n", dc->num, writec, dc->dscursor);
+}
+
+void ahi2_pause_sound (int paused)
+{
+    int i;
+    struct DSAHI *dsahip = &dsahi[0];
+
+    ahi_paused = paused;
+    if (!dsahip->playing && !dsahip->recording)
+       return;
+    for (i = 0; i < UAE_MAXCHANNELS; i++) {
+       struct dschannel *dc = &dsahip->channel[i];
+       if (dc->dsb == NULL)
+           continue;
+       if (paused) {
+           ds_stop (dsahip, dc);
+       } else {
+           ds_play (dsahip, dc);
+       }
+    }
+}
+
+static uae_u32 init (TrapContext *ctx)
+{
+    int i;
+    
+    enumerate_sound_devices ();
+    xahi_author = ds ("Toni Wilen");
+    xahi_copyright = ds ("GPL");
+    xahi_version = ds ("uae2 0.1 (xx.xx.2008)\r\n");
+    for (i = 0; sound_devices[i].name; i++)
+       xahi_output[i] = ds (sound_devices[i].name);
+    xahi_output_num = i;
+    for (i = 0; record_devices[i].name; i++)
+       xahi_input[i] = ds (record_devices[i].name);
+    xahi_input_num = i;
+    return 1;
+}
+
+static uae_u32 AHIsub_AllocAudio (TrapContext *ctx)
+{
+    int i;
+    uae_u32 tags = m68k_areg (&ctx->regs, 1);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    uae_u32 pbase = get_long (audioctrl + ahiac_DriverData);
+    uae_u32 tag, data, v, ver, size;
+    uae_u32 ret = AHISF_KNOWSTEREO | AHISF_KNOWHIFI;
+    struct DSAHI *dsahip = &dsahi[0];
+
+    if (ahi_debug)
+       write_log ("AHI: AllocAudio(%08x,%08x)\n", tags, audioctrl);
+
+    ver = get_long (pbase + pub_Version);
+    size = get_long (pbase + pub_SizeOf);
+    if (ver != AHI_STRUCT_VERSION) {
+       gui_message ("AHI: Incompatible DEVS:AHI/uae2.audio\nVersion mismatch %d<>%d.", ver, AHI_STRUCT_VERSION);
+       return AHISF_ERROR;
+    }
+    if (size < pub_End) {
+       gui_message ("AHI: Incompatible DEVS:AHI/uae2.audio.\nInternal structure size %d<%d.", size, pub_End);
+       return AHISF_ERROR;
+    }
+
+
+    v = get_long (pbase + pub_Index);
+    if (v != -1) {
+       write_log ("AHI: corrupted memory\n");
+       return AHISF_ERROR;
+    }
+    put_long (pbase + pub_Index, dsahip - dsahi);
+    dsahip->audioctrl = audioctrl;
+
+    if (!ds_init (dsahip))
+       return AHISF_ERROR;
+    dsahip->sounds = UAE_MAXSOUNDS;
+    dsahip->channels = UAE_MAXCHANNELS;
+
+    if (xahi_input_num)
+       ret |= AHISF_CANRECORD;
+    if (cansurround)
+       ret |= AHISF_KNOWMULTICHANNEL;
+
+    while ((tag = gettag (&tags, &data))) {
+       if (ahi_debug)
+           write_log ("- TAG %08x=%d: %08x=%u\n", tag, tag & 0x7fff, data, data);
+    }
+    if (dsahip->sounds < 0 || dsahip->sounds > 1000) {
+       ds_free (dsahip);
+       ds_free_record (dsahip);
+       return AHISF_ERROR;
+    }
+    dsahip->sample = xcalloc (sizeof (struct dssample), dsahip->sounds);
+    dsahip->channel = xcalloc (sizeof (struct dschannel), dsahip->channels);
+    for (i = 0; i < dsahip->channels; i++) {
+       struct dschannel *dc = &dsahip->channel[i];
+       dc->num = i;
+    }
+    for (i = 0; i < dsahip->sounds; i++) {
+       struct dssample *ds = &dsahip->sample[i];
+       ds->num = -1;
+    }
+    ahi_active = 1;
+    return ret;
+}
+
+static void AHIsub_Disable (TrapContext *ctx)
+{
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
+    if (ahi_debug)
+       write_log ("AHI: Disable(%08x)\n", audioctrl);
+    dsahip->enabledisable++;
+}
+
+static void AHIsub_Enable (TrapContext *ctx)
+{
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
+    if (ahi_debug)
+       write_log ("AHI: Enable(%08x)\n", audioctrl);
+    dsahip->enabledisable--;
+    if (dsahip->enabledisable == 0 && dsahip->playing)
+       setevent (dsahip);
+}
+
+static void AHIsub_FreeAudio (TrapContext *ctx)
+{
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    uae_u32 pbase = get_long (audioctrl + ahiac_DriverData);
+    struct DSAHI *dsahip = GETAHI;
+    if (ahi_debug)
+       write_log ("AHI: FreeAudio(%08x)\n", audioctrl);
+    if (ahi_active == 0)
+       return;
+    ahi_active = 0;
+    put_long (pbase + pub_Index, -1);
+    if (dsahip) {
+       ds_free (dsahip);
+       ds_free_record (dsahip);
+       xfree (dsahip->channel);
+       xfree (dsahip->sample);
+       memset (dsahip, 0, sizeof (struct DSAHI));
+    }
+}
+
+static uae_u32 frequencies[] = { 48000, 44100 };
+#define MAX_FREQUENCIES (sizeof (frequencies) / sizeof (uae_u32))
+
+static uae_u32 getattr2 (uae_u32 attribute, uae_u32 argument, uae_u32 def)
+{
+    int i;
+
+    switch (attribute)
+    {
+       case AHIDB_Bits:
+       return 32;
+       case AHIDB_Frequencies:
+       return MAX_FREQUENCIES;
+       case AHIDB_Frequency:
+       if (argument < 0 || argument >= MAX_FREQUENCIES)
+           argument = 0;
+       return frequencies[argument];
+       case AHIDB_Index:
+       if (argument <= frequencies[0])
+           return 0;
+       if (argument >= frequencies[MAX_FREQUENCIES - 1])
+           return MAX_FREQUENCIES - 1;
+       for (i = 1; i < MAX_FREQUENCIES; i++) {
+           if (frequencies[i] > argument) {
+             if (argument - frequencies[i - 1] < frequencies[i] - argument)
+               return i - 1;
+             else
+               return i;
+           }
+       }
+       return 0;
+       case AHIDB_Author:
+       return xahi_author;
+       case AHIDB_Copyright:
+       return xahi_copyright;
+       case AHIDB_Version:
+       return xahi_version;
+       case AHIDB_Record:
+       return -1;
+       case AHIDB_Realtime:
+       return -1;
+       case AHIDB_MinOutputVolume:
+       return 0x00000;
+       case AHIDB_MaxOutputVolume:
+       return 0x10000;
+       case AHIDB_Outputs:
+       return xahi_output_num;
+       case AHIDB_Output:
+       if (argument >= 0 && argument < xahi_output_num)
+           return xahi_output[argument];
+       return 0;
+       case AHIDB_Inputs:
+       return xahi_input_num;
+       case AHIDB_Input:
+       if (argument >= 0 && argument < xahi_input_num)
+           return xahi_input[argument];
+       return 0;
+       case AHIDB_Volume:
+       return -1;
+       case AHIDB_Panning:
+       return -1;
+       case AHIDB_HiFi:
+       return -1;
+       case AHIDB_MultiChannel:
+       return cansurround ? -1 : 0;
+       case AHIDB_MaxChannels:
+       return UAE_MAXCHANNELS;
+       case AHIDB_FullDuplex:
+       return -1;
+       case AHIDB_MaxRecordSamples:
+       return RECORDSAMPLES;
+       default:
+       return def;
+    }
+}
+
+static uae_u32 AHIsub_GetAttr (TrapContext *ctx)
+{
+    uae_u32 attribute = m68k_dreg (&ctx->regs, 0);
+    uae_u32 argument = m68k_dreg (&ctx->regs, 1);
+    uae_u32 def = m68k_dreg (&ctx->regs, 2);
+    uae_u32 taglist = m68k_areg (&ctx->regs, 1);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    uae_u32 v;
+
+    v = getattr2 (attribute, argument, def);
+    if (ahi_debug)
+       write_log ("AHI: GetAttr(%08x=%d,%08x,%08x)=%08x\n", attribute, attribute & 0x7fff, argument, def, v);
+
+    return v;
+}
+
+static uae_u32 AHIsub_HardwareControl (TrapContext *ctx)
+{
+    uae_u32 attribute = m68k_dreg (&ctx->regs, 0);
+    uae_u32 argument = m68k_dreg (&ctx->regs, 1);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
+    if (ahi_debug)
+       write_log ("AHI: HardwareControl(%08x=%d,%08x,%08x)\n", attribute, attribute & 0x7fff, argument, audioctrl);
+    switch (attribute)
+    {
+       case AHIC_Input:
+       if (dsahip->input != argument) {
+           dsahip->input = argument;
+           if (dsahip->dscb) {
+               ds_free_record (dsahip);
+               ds_init_record (dsahip);
+               if (dsahip->recording)
+                   ds_record (dsahip, 1);
+           }
+       }
+       break;
+       case AHIC_Input_Query:
+       return dsahip->input;
+       case AHIC_Output:
+       if (dsahip->output != argument) {
+           dsahip->output = argument;
+           if (dsahip->DS)
+               ds_reinit (dsahip);
+       }
+       break;
+       case AHIC_Output_Query:
+       return dsahip->output;
+    }
+    return 0;
+}
+
+static uae_u32 AHIsub_Start (TrapContext *ctx)
+{
+    uae_u32 flags = m68k_dreg (&ctx->regs, 0);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
+    int i;
+
+    if (ahi_debug)
+       write_log ("AHI: Play(%08x,%08x)\n",
+           flags, audioctrl);
+    if ((flags & AHISF_PLAY) && !dsahip->playing) {
+       dsahip->playing = 1;
+       setevent (dsahip);
+       for (i = 0; i < dsahip->channels; i++) {
+           struct dschannel *dc = &dsahip->channel[i];
+           ds_play (dsahip, dc);
+       }
+    }
+    if ((flags & AHISF_RECORD) && !dsahip->recording) {
+       dsahip->recording = 1;
+       ds_init_record (dsahip);
+       ds_record (dsahip, 1);
+    }
+    return 0;
+}
+
+static uae_u32 AHIsub_Stop (TrapContext *ctx)
+{
+    uae_u32 flags = m68k_dreg (&ctx->regs, 0);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
+    int i;
+
+    if (ahi_debug)
+       write_log ("AHI: Stop(%08x,%08x)\n",
+           flags, audioctrl);
+    if ((flags & AHISF_PLAY) && dsahip->playing) {
+       dsahip->playing = 0;
+       for (i = 0; i < dsahip->channels; i++) {
+           struct dschannel *dc = &dsahip->channel[i];
+           ds_stop (dsahip, dc);
+       }
+    }
+    if ((flags & AHISF_RECORD) && dsahip->recording) {
+       dsahip->recording = 0;
+       ds_record (dsahip, 0);
+       ds_free_record (dsahip);
+    }
+    return 0;
+}
+
+static uae_u32 AHIsub_Update (TrapContext *ctx)
+{
+    uae_u32 flags = m68k_dreg (&ctx->regs, 0);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
+    if (ahi_debug)
+       write_log ("AHI: Update(%08x,%08x)\n", flags, audioctrl);
+    setevent (dsahip);
+    return 0;
+}
+
+static uae_u32 AHIsub_SetVol (TrapContext *ctx)
+{
+    uae_u16 channel = m68k_dreg (&ctx->regs, 0);
+    uae_u32 volume = m68k_dreg (&ctx->regs, 1);
+    uae_u32 pan = m68k_dreg (&ctx->regs, 2);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    uae_u32 flags = m68k_dreg (&ctx->regs, 3);
+    struct DSAHI *dsahip = GETAHI;
+    struct dschannel *dc = GETCHANNEL;
+
+    if (ahi_debug)
+       write_log ("AHI: SetVol(%d,%d,%d,%08x,%08x)\n",
+           channel, volume, pan, audioctrl, flags);
+    if (dc) {
+       dc->csnext.volume = volume;
+       dc->csnext.panning = pan;
+       if (flags & AHISF_IMM) {
+           ds_setvolume (dsahip, dc);
+       }
+    }
+    return 0;
+}
+
+static uae_u32 AHIsub_SetFreq (TrapContext *ctx)
+{
+    uae_u16 channel = m68k_dreg (&ctx->regs, 0);
+    uae_u32 frequency = m68k_dreg (&ctx->regs, 1);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    uae_u32 flags = m68k_dreg (&ctx->regs, 3);
+    struct DSAHI *dsahip = GETAHI;
+    struct dschannel *dc = GETCHANNEL;
+
+    if (ahi_debug)
+       write_log ("AHI: SetFreq(%d,%d,%08x,%08x)\n",
+           channel, frequency, audioctrl, flags);
+    if (dc) {
+       dc->csnext.frequency = frequency;
+       if (flags & AHISF_IMM) {
+           ds_setfreq (dsahip, dc);
+           ds_play (dsahip, dc);
+       }
+    }
+    return 0;
+}
+
+static uae_u32 AHIsub_SetSound (TrapContext *ctx)
+{
+    uae_u16 channel = m68k_dreg (&ctx->regs, 0);
+    uae_u16 sound = m68k_dreg (&ctx->regs, 1);
+    uae_u32 offset = m68k_dreg (&ctx->regs, 2);
+    uae_u32 length  = m68k_dreg (&ctx->regs, 3);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    uae_u32 flags = m68k_dreg (&ctx->regs, 4);
+    struct DSAHI *dsahip = GETAHI;
+    struct dssample *ds = GETSAMPLE;
+    struct dschannel *dc = GETCHANNEL;
+
+    if (ahi_debug)
+       write_log ("AHI: SetSound(%d,%d,%08x,%d,%08x,%08x)\n",
+           channel, sound, offset, length, audioctrl, flags);
+    if (dc == NULL)
+       return AHIE_UNKNOWN;
+    if (ds->num < 0)
+       return AHIE_UNKNOWN;
+    if (sound == 0xffff) {
+       if (flags & AHISF_IMM) {
+           dc->cs.ds = NULL;
+           dc->csnext.ds = NULL;
+       }
+       dc->csnext.srcplaylen = -1;
+       return 0;
+    }
+    ds_allocchannel (dsahip, dc);
+    dc->cs.backwards = length < 0;
+    length = abs (length);
+    if (length == 0)
+        length = ds->len;
+    if (length > ds->len)
+       length = ds->len;
+    dc->csnext.ds = ds;
+    dc->csnext.srcplaylen = length;
+    dc->csnext.srcplayoffset = offset;
+    if (flags & AHISF_IMM)
+       dc->cs.ds = NULL;
+    if (dc->cs.ds == NULL) {
+       dc->buffercursor = 0;
+       dc->hsync = 0;
+    }
+    ds_setfreq (dsahip, dc);
+    ds_setvolume (dsahip, dc);
+    ds_play (dsahip, dc);
+    return 0;
+}
+
+static uae_u32 AHIsub_SetEffect (TrapContext *ctx)
+{
+    uae_u32 effect = m68k_areg (&ctx->regs, 0);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    uae_u32 effectype = get_long (effect);
+    uae_u32 puaebase = get_long (audioctrl + ahiac_DriverData);
+    struct DSAHI *dsahip = GETAHI;
+
+    if (ahi_debug)
+       write_log ("AHI: SetEffect(%08x (%08x),%08x)\n", effect, effectype, audioctrl);
+    switch (effectype)
+    {
+       case AHIET_CHANNELINFO:
+       put_long (puaebase + pub_ChannelInfo, effect);
+       break;
+       case AHIET_CHANNELINFO | AHIET_CANCEL:
+       put_long (puaebase + pub_ChannelInfo, 0);
+       break;
+       case AHIET_MASTERVOLUME:
+       case AHIET_MASTERVOLUME | AHIET_CANCEL:
+       break;
+       default:
+       return AHIE_UNKNOWN;
+    }
+    return AHIE_OK;
+}
+
+static uae_u32 AHIsub_LoadSound (TrapContext *ctx)
+{
+    uae_u16 sound = m68k_dreg (&ctx->regs, 0);
+    uae_u32 type = m68k_dreg (&ctx->regs, 1);
+    uae_u32 info = m68k_areg (&ctx->regs, 0);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
+    uae_u32 ret = AHIE_BADSOUNDTYPE;
+    int sampletype = get_long (info + ahisi_Type);
+    uae_u32 addr = get_long (info + ahisi_Address);
+    uae_u32 len = get_long (info + ahisi_Length);
+    struct dssample *ds = GETSAMPLE;
+    int ch;
+    int bps;
+
+    if (ahi_debug)
+       write_log ("AHI: LoadSound(%d,%d,%08x,%08x,SMP=%d,ADDR=%08x,LEN=%d)\n",
+           sound, type, info, audioctrl, sampletype, addr, len);
+
+    if (!ds)
+       return AHIE_BADSOUNDTYPE;
+
+    ds->num = sound;
+    if (!cansurround && sampletype == AHIST_L7_1)
+        return AHIE_BADSOUNDTYPE;
+    ds->addr = addr;
+    ds->sampletype = sampletype;
+    ds->type = type;
+    ds->len = len;
+
+    switch (sampletype)
+    {
+       case AHIST_M8S:
+       case AHIST_M16S:
+       case AHIST_M32S:
+       ch = 1;
+       break;
+       case AHIST_S8S:
+       case AHIST_S16S:
+       case AHIST_S32S:
+       ch = 2;
+       break;
+       case AHIST_L7_1:
+       ch = 8;
+       break;
+       default:
+       return 0;
+    }
+    switch (sampletype)
+    {
+       case AHIST_M8S:
+       case AHIST_S8S:
+       bps = 8;
+       break;
+       case AHIST_M16S:
+       case AHIST_S16S:
+       bps = 16;
+       break;
+       case AHIST_M32S:
+       case AHIST_S32S:
+       case AHIST_L7_1:
+        bps = 24;
+       break;
+       default:
+       return 0;
+    }
+    ds->bitspersample = bps;
+    ds->ch = ch;
+    ds->bytespersample = bps / 8;
+    return AHIE_OK;
+}
+
+static uae_u32 AHIsub_UnloadSound (TrapContext *ctx)
+{
+    uae_u16 sound = m68k_dreg (&ctx->regs, 0);
+    uae_u32 audioctrl = m68k_areg (&ctx->regs, 2);
+    struct DSAHI *dsahip = GETAHI;
+    struct dssample *ds = GETSAMPLE;
+
+    if (ahi_debug)
+       write_log ("AHI: UnloadSound(%d,%08x)\n",
+           sound, audioctrl);
+    ds->num = -1;
+    return AHIE_OK;
+}
+
+static uae_u32 REGPARAM2 ahi_demux (TrapContext *ctx)
+{
+    uae_u32 ret = 0;
+    uae_u32 sp = m68k_areg (&ctx->regs, 7);
+    uae_u32 offset = get_long (sp + 4);
+
+    if (0 && ahi_debug)
+       write_log ("AHI: %d\n", offset);
+
+    switch (offset)
+    {
+       case 0xffffffff:
+           ret = init (ctx);
+       break;
+       case 0:
+           ret = AHIsub_AllocAudio (ctx);
+       break;
+       case 1:
+           AHIsub_FreeAudio (ctx);
+       break;
+       case 2:
+           AHIsub_Disable (ctx);
+       break;
+       case 3:
+           AHIsub_Enable (ctx);
+       break;
+       case 4:
+           ret = AHIsub_Start (ctx);
+       break;
+       case 5:
+           ret = AHIsub_Update (ctx);
+       break;
+       case 6:
+           ret = AHIsub_Stop (ctx);
+       break;
+       case 7:
+           ret = AHIsub_SetVol (ctx);
+       break;
+       case 8:
+           ret = AHIsub_SetFreq (ctx);
+       break;
+       case 9:
+           ret = AHIsub_SetSound (ctx);
+       break;
+       case 10:
+           ret = AHIsub_SetEffect (ctx);
+       break;
+       case 11:
+           ret = AHIsub_LoadSound (ctx);
+       break;
+       case 12:
+           ret = AHIsub_UnloadSound (ctx);
+       break;
+       case 13:
+           ret = AHIsub_GetAttr (ctx);
+       break;
+       case 14:
+           ret = AHIsub_HardwareControl (ctx);
+       break;
+    }
+    return ret;
+}
+
+void init_ahi_v2 (void)
+{
+    uaecptr a = here ();
+    org (rtarea_base + 0xFFC8);
+    calltrap (deftrapres (ahi_demux, 0, "ahi_winuae_v2"));
+    dw (RTS);
+    org (a);
+}
+
+void free_ahi_v2 (void)
+{
+    ds_free_record (&dsahi[0]);
+    ds_free (&dsahi[0]);
+}
+
+#endif
index 683241100ef053cb9418e65ce1f00f2599ab2292..133326f82f842421123f555e8e3026556fb1e7be 100755 (executable)
@@ -365,7 +365,7 @@ static int initialize_catweasel(void)
     char tmp[MAX_DPATH];
     struct didata *did;
 
-    if (catweasel_ismouse()) {
+    if (catweasel_ismouse ()) {
        for (i = 0; i < 2 && num_mouse < MAX_INPUT_DEVICES; i++) {
            did = di_mouse;
            did += num_mouse;
@@ -392,7 +392,7 @@ static int initialize_catweasel(void)
            num_mouse++;
        }
     }
-    if (catweasel_isjoystick()) {
+    if (catweasel_isjoystick ()) {
        for (i = 0; i < 2 && num_joystick < MAX_INPUT_DEVICES; i++) {
            did = di_joystick;
            did += num_joystick;
index c2afc8306c150c054b92c72d09c53183aac23893..00eb0cb4f53ae460b28bb828e34e29f7629484f0 100755 (executable)
@@ -961,7 +961,7 @@ void D3D_free (void)
 
 const char *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth)
 {
-    HRESULT ret;
+    HRESULT ret, hr;
     static char errmsg[100] = { 0 };
     D3DDISPLAYMODE mode;
     D3DDISPLAYMODEEX modeex;
@@ -972,9 +972,6 @@ const char *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth)
 
     D3D_free ();
     D3D_canshaders ();
-    adapter = currprefs.gfx_display - 1;
-    if (adapter < 0)
-       adapter = 0;
     d3d_enabled = 0;
     scanlines_ok = 0;
     if (currprefs.gfx_filter != UAE_FILTER_DIRECT3D) {
@@ -1010,11 +1007,19 @@ const char *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth)
         }
     }
 
+    adapter = currprefs.gfx_display - 1;
+    if (adapter < 0)
+       adapter = 0;
+    if (adapter >= IDirect3D9_GetAdapterCount (d3d))
+       adapter = 0;
+
     modeex.Size = sizeof modeex;
     if (d3dex && D3DEX)
        IDirect3D9Ex_GetAdapterDisplayModeEx (d3dex, adapter, &modeex, NULL);
-    IDirect3D9_GetAdapterDisplayMode (d3d, adapter, &mode);
-    IDirect3D9_GetDeviceCaps (d3d, adapter, D3DDEVTYPE_HAL, &d3dCaps);
+    if (FAILED (hr = IDirect3D9_GetAdapterDisplayMode (d3d, adapter, &mode)))
+        write_log ("D3D: IDirect3D9_GetAdapterDisplayMode failed %s\n", D3D_ErrorString (hr));
+    if (FAILED (hr = IDirect3D9_GetDeviceCaps (d3d, adapter, D3DDEVTYPE_HAL, &d3dCaps)))
+        write_log ("D3D: IDirect3D9_GetDeviceCaps failed %s\n", D3D_ErrorString (hr));
 
     memset (&dpp, 0, sizeof (dpp));
     dpp.Windowed = isfullscreen() <= 0;
@@ -1057,13 +1062,13 @@ const char *D3D_init (HWND ahwnd, int w_w, int w_h, int t_w, int t_h, int depth)
     flags |= D3DCREATE_NOWINDOWCHANGES | D3DCREATE_FPU_PRESERVE;
 
     if (d3d_ex && D3DEX) {
-       ret = IDirect3D9Ex_CreateDeviceEx (d3dex, adapter, D3DDEVTYPE_HAL, ahwnd, flags, &dpp, &modeex, &d3ddevex);
+       ret = IDirect3D9Ex_CreateDeviceEx (d3dex, adapter, D3DDEVTYPE_HAL, d3dhwnd, flags, &dpp, &modeex, &d3ddevex);
        d3ddev = (LPDIRECT3DDEVICE9)d3ddevex;
     } else {
-       ret = IDirect3D9_CreateDevice (d3d, adapter, D3DDEVTYPE_HAL, ahwnd, flags, &dpp, &d3ddev);
+       ret = IDirect3D9_CreateDevice (d3d, adapter, D3DDEVTYPE_HAL, d3dhwnd, flags, &dpp, &d3ddev);
     }
-    if(FAILED (ret)) {
-       sprintf (errmsg, "%s failed, %s\n", d3d_ex ? "CreateDeviceEx" : "CreateDevice", D3D_ErrorString (ret));
+    if (FAILED (ret)) {
+       sprintf (errmsg, "%s failed, %s\n", d3d_ex && D3DEX ? "CreateDeviceEx" : "CreateDevice", D3D_ErrorString (ret));
        D3D_free ();
        return errmsg;
     }
index 735711c8aa5759ecba69637a687911965845f7ec..4319d52012f00bd14745a5f694cd9c608c78de11 100755 (executable)
@@ -351,7 +351,7 @@ static int open_audio_al (int size)
        sndbufsize = SND_MAX_BUFFER;
     al_bufsize = size;
     al_bigbuffer = xcalloc (al_bufsize, 1);
-    al_dev = alcOpenDevice (sound_devices[currprefs.win32_soundcard].name);
+    al_dev = alcOpenDevice (sound_devices[currprefs.win32_soundcard].alname);
     if (!al_dev)
        goto error;
     al_ctx = alcCreateContext (al_dev, NULL);
@@ -381,7 +381,7 @@ static int open_audio_al (int size)
        goto error;
 
     write_log ("SOUND: %08X,CH=%d,FREQ=%d '%s' buffer %d (%d)\n",
-           al_format, ch, freq, sound_devices[currprefs.win32_soundcard].name,
+           al_format, ch, freq, sound_devices[currprefs.win32_soundcard].alname,
            sndbufsize, al_bufsize);
     return 1;
 
@@ -739,6 +739,7 @@ static void finish_sound_buffer_al (void)
     memcpy (al_bigbuffer + al_offset, sndbuffer, sndbufsize);
     al_offset += sndbufsize;
     if (al_offset >= al_bufsize) {
+       ALuint tmp;
        alGetSourcei (al_Source, AL_BUFFERS_PROCESSED, &v);
        while (v == 0 && waiting_for_buffer < 0) {
            sleep_millis (1);
@@ -748,7 +749,7 @@ static void finish_sound_buffer_al (void)
            alGetSourcei (al_Source, AL_BUFFERS_PROCESSED, &v);
        }
 
-        alSourceUnqueueBuffers (al_Source, 1, &al_Buffers[al_toggle]);
+        alSourceUnqueueBuffers (al_Source, 1, &tmp);
        alGetError ();
 
 //     write_log ("           %d %08x %08x %08x %d %d\n",
@@ -1101,48 +1102,108 @@ static BOOL CALLBACK DSEnumProc (LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDr
     return TRUE;
 }
 
+static void OpenALEnumerate (struct sound_device *sds, const char *pDeviceNames, const char *ppDefaultDevice, int skipdetect)
+{
+    struct sound_device *sd;
+    while (pDeviceNames && *pDeviceNames) {
+       ALCdevice *pDevice;
+       const char *devname;
+       int i, ok;
+       for (i = 0; i < MAX_SOUND_DEVICES; i++) {
+           sd = &sds[i];
+           if (sd->name == NULL)
+               break;
+       }
+       if (i >= MAX_SOUND_DEVICES)
+           return;
+        devname = pDeviceNames;
+       if (ppDefaultDevice)
+           devname = ppDefaultDevice;
+       ok = 0;
+       if (!skipdetect) {
+           pDevice = alcOpenDevice (devname);
+           if (pDevice) {
+               ALCcontext *context = alcCreateContext (pDevice, NULL);
+               if (context) {
+                   ALint iMajorVersion = 0, iMinorVersion = 0;
+                   alcMakeContextCurrent (context);
+                   alcGetIntegerv (pDevice, ALC_MAJOR_VERSION, sizeof (ALint), &iMajorVersion);
+                   alcGetIntegerv (pDevice, ALC_MINOR_VERSION, sizeof (ALint), &iMinorVersion);
+                   if (iMajorVersion > 1 || (iMajorVersion == 1 && iMinorVersion > 0)) {
+                       ok = 1;
+                   }
+               }
+               alcMakeContextCurrent (NULL);
+               alcDestroyContext (context);
+           }
+           alcCloseDevice (pDevice);
+       } else {
+           ok = 1;
+       }
+       if (ok) {
+           sd->type = SOUND_DEVICE_AL;
+           if (ppDefaultDevice) {
+               char tmp[MAX_DPATH];
+               sprintf (tmp, "Default [%s]", devname);
+               sd->alname = my_strdup (ppDefaultDevice);
+               sd->name = my_strdup (tmp);
+           } else {
+               sd->alname = my_strdup (pDeviceNames);
+               sd->name = my_strdup (pDeviceNames);
+           }
+       }
+       if (ppDefaultDevice)
+           ppDefaultDevice = NULL;
+       else
+           pDeviceNames += strlen (pDeviceNames) + 1;
+   }
+}
+
+static int isdllversion (const char *name, int version, int revision)
+{
+    DWORD  dwVersionHandle, dwFileVersionInfoSize;
+    LPVOID lpFileVersionData = NULL;
+    int ok = 0;
+
+    dwFileVersionInfoSize = GetFileVersionInfoSize (name, &dwVersionHandle);
+    if (dwFileVersionInfoSize) {
+       if (lpFileVersionData = xcalloc (1, dwFileVersionInfoSize)) {
+           if (GetFileVersionInfo (name, dwVersionHandle, dwFileVersionInfoSize, lpFileVersionData)) {
+               VS_FIXEDFILEINFO *vsFileInfo = NULL;
+               UINT uLen;
+               if (VerQueryValue (lpFileVersionData, TEXT("\\"), (void **)&vsFileInfo, &uLen)) {
+                   if (vsFileInfo) {
+                       write_log ("%s %d.%d.%d.%d\n", name,
+                           HIWORD (vsFileInfo->dwProductVersionMS), LOWORD (vsFileInfo->dwProductVersionMS),
+                           HIWORD (vsFileInfo->dwProductVersionLS), LOWORD (vsFileInfo->dwProductVersionLS));
+                       if (vsFileInfo->dwProductVersionMS >= version * 65536 + revision)
+                           ok = 1;
+                   }
+               }
+           }
+           xfree (lpFileVersionData);
+       }
+    }
+    return ok;
+}
+
+
 int enumerate_sound_devices (void)
 {
     if (!num_sound_devices) {
        HMODULE l = NULL;
        DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, sound_devices);
        DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK)DSEnumProc, record_devices);
-       l = LoadLibrary ("openal32.dll");
-       if (l != NULL) {
-           FreeLibrary (l);
+       if (isdllversion ("openal32.dll", 6, 14)) {
            if (alcIsExtensionPresent (NULL, "ALC_ENUMERATION_EXT")) {
-               const ALchar* pDeviceNames = alcGetString (NULL, ALC_DEVICE_SPECIFIER);
                const ALchar* ppDefaultDevice = alcGetString (NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
-               while (pDeviceNames && *pDeviceNames) {
-                   struct sound_device *sd;
-                   ALCdevice *pDevice;
-                   int i;
-                   for (i = 0; i < MAX_SOUND_DEVICES; i++) {
-                       sd = &sound_devices[i];
-                       if (sd->name == NULL)
-                           break;
-                   }
-                   if (i >= MAX_SOUND_DEVICES)
-                       break;
-                   pDevice = alcOpenDevice (pDeviceNames);
-                   if (pDevice) {
-                       ALCcontext *context = alcCreateContext (pDevice, NULL);
-                       if (context) {
-                           ALint iMajorVersion = 0, iMinorVersion = 0;
-                           alcMakeContextCurrent (context);
-                           alcGetIntegerv (pDevice, ALC_MAJOR_VERSION, sizeof (ALint), &iMajorVersion);
-                           alcGetIntegerv (pDevice, ALC_MINOR_VERSION, sizeof (ALint), &iMinorVersion);
-                           if (iMajorVersion > 1 || (iMajorVersion == 1 && iMinorVersion > 0)) {
-                               sd->type = SOUND_DEVICE_AL;
-                               sd->name = my_strdup (pDeviceNames);
-                           }
-                           alcMakeContextCurrent (NULL);
-                           alcDestroyContext (context);
-                       }
-                       alcCloseDevice (pDevice);
-                   }
-                   pDeviceNames += strlen (pDeviceNames) + 1;
-               }
+               const ALchar* pDeviceNames = alcGetString (NULL, ALC_DEVICE_SPECIFIER);
+               if (alcIsExtensionPresent (NULL, "ALC_ENUMERATE_ALL_EXT"))
+                   pDeviceNames = alcGetString (NULL, ALC_ALL_DEVICES_SPECIFIER);
+               OpenALEnumerate (sound_devices, pDeviceNames, ppDefaultDevice, FALSE);
+               ppDefaultDevice = alcGetString (NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
+               pDeviceNames = alcGetString (NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
+               OpenALEnumerate (record_devices, pDeviceNames, ppDefaultDevice, TRUE);
            }
        }
        for (num_sound_devices = 0; num_sound_devices < MAX_SOUND_DEVICES; num_sound_devices++) {
index 73752297526b0aad5288921c988380e3eb4b2d2c..97f4df8da0b93678e7609ab4d1bb6d40d2c3a745 100755 (executable)
@@ -320,10 +320,14 @@ static void setcursor (int oldx, int oldy)
     int y = (amigawin_rect.bottom - amigawin_rect.top) / 2;
     mouseposx = oldx - x;
     mouseposy = oldy - y;
-    if (abs (mouseposx) < 50 && abs (mouseposy) < 50)
-       return;
-    mouseposx = 0;
-    mouseposy = 0;
+    if (oldx >= 30000 || oldy >= 30000 || oldx <= -30000 || oldy <= -30000) {
+       mouseposx = mouseposy = 0;
+       oldx = oldy = 0;
+    } else {
+       if (abs (mouseposx) < 50 && abs (mouseposy) < 50)
+           return;
+    }
+    mouseposx = mouseposy = 0;
 //    if (oldx < amigawin_rect.left || oldy < amigawin_rect.top || oldx > amigawin_rect.right || oldy > amigawin_rect.bottom) {
     if (oldx < 0 || oldy < 0 || oldx > amigawin_rect.right - amigawin_rect.left || oldy > amigawin_rect.bottom - amigawin_rect.top) {
        write_log ("Mouse out of range: %dx%d (%dx%d %dx%d)\n", oldx, oldy,
@@ -487,7 +491,7 @@ void setmouseactive (int active)
        if (rp_isactive ())
            w3 = rp_getparent ();
 #endif
-       if (!(fw == w1 || fw == w2)) {
+       if (isfullscreen () > 0 || (!(fw == w1 || fw == w2))) {
            if (SetForegroundWindow (w2) == FALSE) {
                if (SetForegroundWindow (w1) == FALSE) {
                    if (w3 == NULL || SetForegroundWindow (w3) == FALSE) {
@@ -514,7 +518,7 @@ void setmouseactive (int active)
                ClipCursor (&amigawin_rect);
            }
            showcursor = 1;
-           setcursor (-1, -1);
+           setcursor (-30000, -30000);
        }
        inputdevice_acquire (TRUE);
     } else {
@@ -676,9 +680,6 @@ static LRESULT CALLBACK AmigaWindowProc (HWND hWnd, UINT message, WPARAM wParam,
     if (ignore_messages_all)
        return DefWindowProc (hWnd, message, wParam, lParam);
 
-    if (hMainWnd == 0)
-       hMainWnd = hWnd;
-
     switch (message)
     {
 
@@ -768,6 +769,7 @@ static LRESULT CALLBACK AmigaWindowProc (HWND hWnd, UINT message, WPARAM wParam,
     case WM_MOUSEWHEEL:
        if (dinput_winmouse () >= 0) {
            int val = ((short)HIWORD (wParam));
+           write_log ("dinput_winmouse=%d dinput_wheelbuttonstart=%d wheel=%d\n", dinput_winmouse(), dinput_wheelbuttonstart(), val);
            setmousestate (dinput_winmouse (), 2, val, 0);
            if (val < 0)
                setmousebuttonstate (dinput_winmouse (), dinput_wheelbuttonstart () + 0, -1);
@@ -775,6 +777,7 @@ static LRESULT CALLBACK AmigaWindowProc (HWND hWnd, UINT message, WPARAM wParam,
                setmousebuttonstate (dinput_winmouse (), dinput_wheelbuttonstart () + 1, -1);
            return TRUE;
        }
+       //write_log ("dinput_winmouse() = %d\n", dinput_winmouse());
     return 0;
     case WM_MOUSEHWHEEL:
        if (dinput_winmouse () >= 0) {
@@ -1609,7 +1612,7 @@ HMODULE language_load (WORD language)
                            if (vsFileInfo &&
                                HIWORD(vsFileInfo->dwProductVersionMS) == UAEMAJOR
                                && LOWORD(vsFileInfo->dwProductVersionMS) == UAEMINOR
-                               && (HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV)) {
+                               && (HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV || HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV - 1)) {
                                success = TRUE;
                                write_log ("Translation DLL '%s' loaded and enabled\n", dllbuf);
                            } else {
@@ -3226,9 +3229,14 @@ static int PASCAL WinMain2 (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR
        sortdisplays ();
        write_log ("Display buffer mode = %d\n", ddforceram);
        write_log ("Enumerating sound devices:\n");
-       for (i = 0; i < enumerate_sound_devices (); i++) {
+       enumerate_sound_devices ();
+       for (i = 0; sound_devices[i].name; i++) {
            write_log ("%d:%s: %s\n", i, sound_devices[i].type == SOUND_DEVICE_DS ? "DS" : "AL", sound_devices[i].name);
        }
+       write_log ("Enumerating recording devices:\n");
+       for (i = 0; record_devices[i].name; i++) {
+           write_log ("%d:%s: %s\n", i, record_devices[i].type == SOUND_DEVICE_DS ? "DS" : "AL", record_devices[i].name);
+       }
        write_log ("done\n");
        memset (&devmode, 0, sizeof(devmode));
        devmode.dmSize = sizeof (DEVMODE);
index 5e202e32da9e9a54390e8d89a8073796edf7d7af..121300dee319b9ad57dc69b09c18baace0ed6bd4 100755 (executable)
@@ -15,9 +15,9 @@
 #define GETBDM(x) (((x) - ((x / 10000) * 10000)) / 100)
 #define GETBDD(x) ((x) % 100)
 
-#define WINUAEBETA 3
+#define WINUAEBETA 4
 #define WINUAEPUBLICBETA 1
-#define WINUAEDATE MAKEBD(2008, 8, 24)
+#define WINUAEDATE MAKEBD(2008, 8, 30)
 #define WINUAEEXTRA ""
 #define WINUAEREV ""
 
@@ -146,6 +146,7 @@ struct sound_device
 {
     GUID guid;
     char *name;
+    char *alname;
     int type;
 };
 extern struct sound_device sound_devices[MAX_SOUND_DEVICES];
index 0fd09e0e676ff5d9db476f76e8e12c06aca23052..b90ae47327f2d2f62496b8c714e7ebbeda6ea1e6 100755 (executable)
@@ -819,6 +819,7 @@ static void close_hwnds (void)
     if (hStatusWnd) {
        ShowWindow (hStatusWnd, SW_HIDE);
        DestroyWindow (hStatusWnd);
+       hStatusWnd = 0;
     }
     if (hAmigaWnd) {
        addnotifications (hAmigaWnd, TRUE);
@@ -837,9 +838,8 @@ static void close_hwnds (void)
     if (hMainWnd) {
        ShowWindow (hMainWnd, SW_HIDE);
        DestroyWindow (hMainWnd);
+       hMainWnd = 0;
     }
-    hMainWnd = 0;
-    hStatusWnd = 0;
 }
 
 
@@ -1860,8 +1860,15 @@ static int create_windows_2 (void)
            if (hStatusWnd)
                createstatuswindow ();
            in_sizemove--;
+       } else {
+           w = nw;
+           h = nh;
+           x = nx;
+           y = ny;
        }
        GetWindowRect (hAmigaWnd, &amigawin_rect);
+       if (d3dfs || dxfs)
+           SetCursorPos (x + w / 2, y + h / 2);
        write_log ("window already open\n");
        return 1;
     }
@@ -1989,7 +1996,11 @@ static int create_windows_2 (void)
        close_hwnds();
        return 0;
     }
+    if (hMainWnd == NULL)
+       hMainWnd = hAmigaWnd;
     GetWindowRect (hAmigaWnd, &amigawin_rect);
+    if (dxfs || d3dfs)
+       SetCursorPos (x + w / 2, y + h / 2);
     addnotifications (hAmigaWnd, FALSE);
     if (hMainWnd != hAmigaWnd) {
        ShowWindow (hMainWnd, SW_SHOWNORMAL);
index 389fa510feb67828e509429c88642e785ed16f12..7832c7ab54d5ce6c8e4c290c2f1855eedb417f1d 100755 (executable)
@@ -1,11 +1,23 @@
 
+Beta 4: (final beta)
+
+- check openal32.dll version before using
+- accept 1.5.1 language DLL files (no GUI changes)
+- Catweasel: do not use direct access to read joyports if driver is
+  installed, caused conflicts with driver provided joystick/mouse
+  (note that I still don't care about CW until 64-bit compatible
+  drivers are released, if ever. Do not ask stupid questions.)
+- fixed D3D 8876086C error if display number in configuration file was
+  bigger than current number of displays
+
 Beta 3:
 
 - bsdsocket initialization rewritten, should be more reliable now
   if uae rom is moved and/or other extra residents enabled
+  (I don't understand how it was supposed to work previously..)
 - OpenAL sound mode problems fixed ("I hope")
-- Raw mouse/"name of mouse" mouse wheel support fixed (always been
-  broken)
+- Raw mouse/"name of mouse" mouse wheel support fixed (has always
+  been broken)
 
 Beta 2: