]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
4300b1
authorToni Wilen <twilen@winuae.net>
Sat, 19 Oct 2019 17:07:56 +0000 (20:07 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 19 Oct 2019 17:21:26 +0000 (20:21 +0300)
12 files changed:
debug.cpp
include/drawing.h
include/options.h
main.cpp
od-win32/direct3d11.cpp
od-win32/gencpu_msvc/gencpu_msvc.vcxproj
od-win32/resources/winuae.rc
od-win32/win32.cpp
od-win32/win32.h
od-win32/win32gfx.cpp
od-win32/winuae_msvc15/winuae_msvc.sln
sndboard.cpp

index 8a50b7daad9adb642d50e69480e9ed9609c0f520..6c3ba026f737c5854bbb244c158cc18de00b63eb 100644 (file)
--- a/debug.cpp
+++ b/debug.cpp
@@ -49,6 +49,7 @@
 #include "blitter.h"
 #include "ini.h"
 #include "readcpu.h"
+#include "cputbl.h"
 
 #define TRACE_SKIP_INS 1
 #define TRACE_MATCH_PC 2
@@ -65,6 +66,7 @@ static uae_u32 trace_param2;
 int debugger_active;
 static int debug_rewind;
 static int memwatch_triggered;
+static int inside_debugger;
 int memwatch_access_validator;
 int memwatch_enabled;
 int debugging;
@@ -103,6 +105,7 @@ static void debug_cycles(void)
 
 void deactivate_debugger (void)
 {
+       inside_debugger = 0;
        debugger_active = 0;
        debugging = 0;
        exception_debugging = 0;
@@ -120,6 +123,7 @@ void activate_debugger (void)
 
        debugger_load_libraries();
 
+       inside_debugger = 1;
        debug_pc = 0xffffffff;
        trace_mode = 0;
        if (debugger_active) {
@@ -2959,7 +2963,7 @@ static int memwatch_func (uaecptr addr, int rwi, int size, uae_u32 *valp, uae_u3
 {
        uae_u32 val = *valp;
 
-       if (debugging > 0)
+       if (inside_debugger)
                return 1;
 
        if (mungwall)
index 1f9961d2cc4cf18f23ae779a70bc9c74f9e503e4..94a79925f84a55705248ea4a80213bd95c8abe37 100644 (file)
@@ -226,9 +226,9 @@ struct color_change {
 
 struct sprite_entry
 {
-       unsigned short pos;
-       unsigned short max;
-       unsigned int first_pixel;
+       uae_u16 pos;
+       uae_u16 max;
+       uae_u32 first_pixel;
        bool has_attached;
 };
 
index 4d483a2abf31153f449c8fe10e0af8ddc9178a77..288e8372c45f9da2dd795d7df37e9bbc9754b54c 100644 (file)
@@ -15,8 +15,8 @@
 #include "traps.h"
 
 #define UAEMAJOR 4
-#define UAEMINOR 2
-#define UAESUBREV 1
+#define UAEMINOR 3
+#define UAESUBREV 0
 
 #define MAX_AMIGADISPLAYS 4
 
index 7ee074cbd8ff7f98f4c2bf2348ceca7228507c36..55971c5fcb6b85f1eeaf81de983dcc3f045ad8a0 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -193,7 +193,7 @@ void fixup_prefs_dimensions (struct uae_prefs *prefs)
                                        ap->gfx_strobo = prefs->lightboost_strobo;
                        }
                } else {
-                       if (ap->gfx_backbuffers > 0 && prefs->gfx_api > 1)
+                       if (ap->gfx_backbuffers > 0 && (prefs->gfx_api > 1 || prefs->gfx_variable_sync))
                                ap->gfx_strobo = prefs->lightboost_strobo;
                        // no vsync: wait if triple bufferirng
                        if (ap->gfx_backbuffers >= 2)
index 9087a7c7fcdb5321bf0f7bc1f94b92b952cccfb6..2d349e59ebf63b6dd6cf6190caf7af050c403408 100644 (file)
@@ -3215,8 +3215,11 @@ static void do_black(struct d3d11struct *d3d)
        color[1] = 0;
        color[2] = 0;
        color[3] = 0;
+       // Bind the render target view and depth stencil buffer to the output render pipeline.
+       d3d->m_deviceContext->OMSetRenderTargets(1, &d3d->m_renderTargetView, NULL);
        // Clear the back buffer.
        d3d->m_deviceContext->ClearRenderTargetView(d3d->m_renderTargetView, color);
+       d3d->m_deviceContext->Flush();
 }
 
 static void do_present(struct d3d11struct *d3d)
@@ -3230,7 +3233,7 @@ static void do_present(struct d3d11struct *d3d)
        UINT syncinterval = d3d->vblankintervals;
        // only if no vsync or low latency vsync
        if (d3d->m_tearingSupport && (d3d->swapChainDesc.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) && (!vsync || apm->gfx_vsyncmode)) {
-               if (apm->gfx_vsyncmode || d3d - d3d11data > 0 || currprefs.turbo_emulation) {
+               if (apm->gfx_vsyncmode || d3d - d3d11data > 0 || currprefs.turbo_emulation || currprefs.gfx_variable_sync) {
                        presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
                        syncinterval = 0;
                }
index 695aed4566d8f334c13dc39346ba00cf0538b0e7..4a1d9a8a1b29d817fb1c1002ea5da3937dc4cfaa 100644 (file)
     <IntDir Condition="'$(Configuration)|$(Platform)'=='FullRelease|Win32'">$(Configuration)\</IntDir>
     <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='FullRelease|Win32'">false</LinkIncremental>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='FullRelease|Win32'">
+    <PreLinkEventUseInBuild>false</PreLinkEventUseInBuild>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <PreLinkEventUseInBuild>false</PreLinkEventUseInBuild>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseXP|Win32'">
+    <PreLinkEventUseInBuild>false</PreLinkEventUseInBuild>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Test|Win32'">
+    <PreLinkEventUseInBuild>false</PreLinkEventUseInBuild>
+  </PropertyGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
     <Midl>
       <TypeLibraryName>.\Release/gencpu_msvc.tlb</TypeLibraryName>
       <Culture>0x0409</Culture>
     </ResourceCompile>
     <PreLinkEvent>
-      <Message>deleting gencpu files</Message>
-      <Command>del ..\..\cputbl.h
-del ..\..\cpustbl.cpp
-del ..\..\cpuemu.cpp
-
-</Command>
+      <Message>
+      </Message>
+      <Command>
+      </Command>
     </PreLinkEvent>
     <Link>
       <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
@@ -131,10 +141,8 @@ del ..\..\cpuemu.cpp
     </Link>
     <PostBuildEvent>
       <Message>generating gencpu files</Message>
-      <Command>cd ..\..
-od-win32\gencpu_msvc\gencpu.exe
-del od-win32\gencpu_msvc\gencpu.exe
-</Command>
+      <Command>cd ..\..\
+.\od-win32\gencpu_msvc\gencpu.exe</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseXP|Win32'">
@@ -163,12 +171,10 @@ del od-win32\gencpu_msvc\gencpu.exe
       <Culture>0x0409</Culture>
     </ResourceCompile>
     <PreLinkEvent>
-      <Message>deleting gencpu files</Message>
-      <Command>del ..\..\cputbl.h
-del ..\..\cpustbl.cpp
-del ..\..\cpuemu.cpp
-
-</Command>
+      <Message>
+      </Message>
+      <Command>
+      </Command>
     </PreLinkEvent>
     <Link>
       <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
@@ -182,10 +188,8 @@ del ..\..\cpuemu.cpp
     </Link>
     <PostBuildEvent>
       <Message>generating gencpu files</Message>
-      <Command>cd ..\..
-od-win32\gencpu_msvc\gencpu.exe
-del od-win32\gencpu_msvc\gencpu.exe
-</Command>
+      <Command>cd ..\..\
+.\od-win32\gencpu_msvc\gencpu.exe</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Test|Win32'">
@@ -214,12 +218,10 @@ del od-win32\gencpu_msvc\gencpu.exe
       <Culture>0x0409</Culture>
     </ResourceCompile>
     <PreLinkEvent>
-      <Message>deleting gencpu files</Message>
-      <Command>del ..\..\cputbl.h
-del ..\..\cpustbl.cpp
-
-
-</Command>
+      <Message>
+      </Message>
+      <Command>
+      </Command>
     </PreLinkEvent>
     <Link>
       <AdditionalOptions>/MACHINE:I386 %(AdditionalOptions)</AdditionalOptions>
@@ -233,10 +235,8 @@ del ..\..\cpustbl.cpp
     </Link>
     <PostBuildEvent>
       <Message>generating gencpu files</Message>
-      <Command>cd ..\..
-od-win32\gencpu_msvc\gencpu.exe
-
-</Command>
+      <Command>cd ..\..\
+.\od-win32\gencpu_msvc\gencpu.exe</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='FullRelease|Win32'">
@@ -264,7 +264,8 @@ od-win32\gencpu_msvc\gencpu.exe
       <Culture>0x0409</Culture>
     </ResourceCompile>
     <PreLinkEvent>
-      <Message>deleting gencpu files</Message>
+      <Message>
+      </Message>
       <Command>
       </Command>
     </PreLinkEvent>
@@ -280,9 +281,8 @@ od-win32\gencpu_msvc\gencpu.exe
     </Link>
     <PostBuildEvent>
       <Message>generating gencpu files</Message>
-      <Command>cd ..\..
-od-win32\gencpu_msvc\gencpu.exe
-</Command>
+      <Command>cd ..\..\
+.\od-win32\gencpu_msvc\gencpu.exe</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemGroup>
index 724969d309f1aa4b0bcbe9994a3d380b8f00890e..248fe87668bcbced55672ff824619a9390025691 100644 (file)
@@ -1396,8 +1396,8 @@ END
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 4,2,2,0
- PRODUCTVERSION 4,2,2,0
+ FILEVERSION 4,3,0,0
+ PRODUCTVERSION 4,3,0,0
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -1413,12 +1413,12 @@ BEGIN
         BLOCK "040904b0"
         BEGIN
             VALUE "FileDescription", "WinUAE"
-            VALUE "FileVersion", "4.2.2.0"
+            VALUE "FileVersion", "4.3.0.0"
             VALUE "InternalName", "WinUAE"
             VALUE "LegalCopyright", "© 1996-2019 under the GNU Public License (GPL)"
             VALUE "OriginalFilename", "WinUAE.exe"
             VALUE "ProductName", "WinUAE"
-            VALUE "ProductVersion", "4.2.2.0"
+            VALUE "ProductVersion", "4.3.0.0"
         END
     END
     BLOCK "VarFileInfo"
index 4398e3e44d869371f23ecd3f59c77fcbc839e668..ee3f76f94917023b90c3f3d1063d334b5c29ded1 100644 (file)
@@ -771,9 +771,12 @@ void releasecapture(struct AmigaMonitor *mon)
 #endif
        if (!mon_cursorclipped)
                return;
-       ClipCursor(NULL);
-       ReleaseCapture();
-       ShowCursor(TRUE);
+       if (!ClipCursor(NULL))
+               write_log(_T("ClipCursor %08x\n"), GetLastError());
+       if (!ReleaseCapture())
+               write_log(_T("ReleaseCapture %08x\n"), GetLastError());
+       int c = ShowCursor(TRUE);
+       write_log(_T("ShowCursor %d\n"), c);
        mon_cursorclipped = 0;
 }
 
@@ -5098,7 +5101,7 @@ static int parseversion (TCHAR **vs)
        return _tstol (tmp);
 }
 
-static int checkversion (TCHAR *vs)
+static int checkversion (TCHAR *vs, int *verp)
 {
        int ver;
        if (_tcslen (vs) < 10)
@@ -5109,6 +5112,8 @@ static int checkversion (TCHAR *vs)
        ver = parseversion (&vs) << 16;
        ver |= parseversion (&vs) << 8;
        ver |= parseversion (&vs);
+       if (verp)
+               *verp = ver;
        if (ver >= ((UAEMAJOR << 16) | (UAEMINOR << 8) | UAESUBREV))
                return 0;
        return 1;
@@ -5479,14 +5484,24 @@ static void WIN32_HandleRegistryStuff (void)
        }
        size = sizeof (version) / sizeof (TCHAR);
        if (regquerystr (NULL, _T("Version"), version, &size)) {
-               if (checkversion (version))
+               int ver = 0;
+               if (checkversion (version, &ver))
                        regsetstr (NULL, _T("Version"), VersionStr);
+               // Reset GUI setting if pre-4.3.0
+               if (ver > 0x030000 && ver < 0x040300) {
+                       regdelete(NULL, _T("GUISizeX"));
+                       regdelete(NULL, _T("GUISizeY"));
+                       regdelete(NULL, _T("GUISizeFWX"));
+                       regdelete(NULL, _T("GUISizeFWY"));
+                       regdelete(NULL, _T("GUISizeFSX"));
+                       regdelete(NULL, _T("GUISizeFSY"));
+               }
        } else {
                regsetstr (NULL, _T("Version"), VersionStr);
        }
        size = sizeof (version) / sizeof (TCHAR);
        if (regquerystr (NULL, _T("ROMCheckVersion"), version, &size)) {
-               if (checkversion (version)) {
+               if (checkversion (version, NULL)) {
                        if (regsetstr (NULL, _T("ROMCheckVersion"), VersionStr))
                                forceroms = 1;
                }
@@ -7372,7 +7387,7 @@ void registertouch(HWND hwnd)
 
 void systray (HWND hwnd, int remove)
 {
-       static const GUID iconguid = { 0xdac2e99b, 0xe8f6, 0x4150, { 0x98, 0x46, 0xd, 0x4a, 0x61, 0xfb, 0xdd, 0x03 } };
+       static const GUID iconguid = { 0x6974bfc1, 0x898b, 0x4157, { 0xa4, 0x30, 0x43, 0x6b, 0xa0, 0xdd, 0x5d, 0xf2 } };
        NOTIFYICONDATA nid;
        BOOL v;
        static bool noguid;
@@ -7413,7 +7428,7 @@ void systray (HWND hwnd, int remove)
                if (!remove) {
                        // if guid identifier: always remove first.
                        // old icon may not have been removed due to crash etc
-                       Shell_NotifyIcon(NIM_DELETE, &nid);
+                       v = Shell_NotifyIcon(NIM_DELETE, &nid);
                }
        }
        v = Shell_NotifyIcon (remove ? NIM_DELETE : NIM_ADD, &nid);
index 62cb7292babe176f5f7445d578160a0dc7a6d9e1..d984708d03c2eb0905d122a0f714b82b9deb2315 100644 (file)
 #define GETBDM(x) (((x) - ((x / 10000) * 10000)) / 100)
 #define GETBDD(x) ((x) % 100)
 
-#define WINUAEPUBLICBETA 0
+#define WINUAEPUBLICBETA 1
 #define LANG_DLL 1
 #define LANG_DLL_FULL_VERSION_MATCH 0
 
 #if WINUAEPUBLICBETA
-#define WINUAEBETA _T("")
+#define WINUAEBETA _T("1")
 #else
 #define WINUAEBETA _T("")
 #endif
 
-#define WINUAEDATE MAKEBD(2019, 5, 16)
+#define WINUAEDATE MAKEBD(2019, 10, 19)
 
 //#define WINUAEEXTRA _T("AmiKit Preview")
 //#define WINUAEEXTRA _T("Amiga Forever Edition")
index f4131d749aa3ab46956f375b09b6ffee143891e9..9083907639fa3ffbd4699e9a5c5c71a888de12ab 100644 (file)
@@ -1407,7 +1407,7 @@ void show_screen_special (void)
        }
 }
 static frame_time_t strobo_time;
-static volatile bool strobo_active;
+static volatile int strobo_active;
 static volatile bool strobo_active2;
 
 static void CALLBACK blackinsertion_cb(
@@ -1420,6 +1420,9 @@ static void CALLBACK blackinsertion_cb(
 {
        struct AmigaMonitor *mon = &AMonitors[0];
        if (mon->screen_is_initialized)  {
+               if (strobo_active) {
+               }
+
                while (strobo_active) {
                        frame_time_t ct = read_processor_time();
                        int diff = (int)strobo_time - (int)ct;
@@ -1427,8 +1430,11 @@ static void CALLBACK blackinsertion_cb(
                                break;
                        }
                        if (diff <= 0) {
-                               if (strobo_active2)
-                                       show_screen_special();
+                               if (strobo_active) {
+                                       gfx_lock();
+                                       D3D_showframe_special(0, 1);
+                                       gfx_unlock();
+                               }
                                break;
                        }
                        if (diff > vsynctimebase / 4) {
@@ -1436,7 +1442,7 @@ static void CALLBACK blackinsertion_cb(
                        }
                }
        }
-       strobo_active = false;
+       strobo_active = 0;
 }
 
 float target_adjust_vblank_hz(int monid, float hz)
@@ -1484,6 +1490,15 @@ void show_screen(int monid, int mode)
                return;
        }
        if (mon->currentmode.flags & DM_D3D) {
+               if (ap->gfx_strobo && currprefs.gfx_variable_sync) {
+                       float vblank = vblank_hz;
+                       int ratio = currprefs.lightboost_strobo_ratio;
+                       int ms = (int)(1000 / vblank);
+                       int waitms = ms * ratio / 100 - 1;
+                       strobo_active = -1;
+                       strobo_time = read_processor_time() + vsynctimebase * ratio / 100;
+                       timeSetEvent(waitms, 0, blackinsertion_cb, NULL, TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
+               }
 #if 0
                if (ap->gfx_vsync < 0 && ap->gfx_strobo && currprefs.gfx_api < 2) {
                        float vblank = vblank_hz;
@@ -1515,8 +1530,12 @@ void show_screen(int monid, int mode)
                }
 #endif
                D3D_showframe(monid);
-               if (monid == 0)
+               if (monid == 0) {
                        strobo_active2 = true;
+                       if (strobo_active < 0) {
+                               D3D_showframe_special(0, 2);
+                       }
+               }
 #ifdef GFXFILTER
        } else if (mon->currentmode.flags & DM_SWSCALE) {
                if (!dx_islost () && !ad->picasso_on)
@@ -1578,6 +1597,7 @@ int lockscr(struct vidbuffer *vb, bool fullupdate, bool first)
        flushymin = mon->currentmode.amiga_height;
        flushymax = 0;
 #endif
+       gfx_lock();
        ret = 1;
        if (mon->currentmode.flags & DM_D3D) {
 #ifdef D3D
@@ -1598,12 +1618,14 @@ int lockscr(struct vidbuffer *vb, bool fullupdate, bool first)
        } else if (mon->currentmode.flags & DM_DDRAW) {
                ret = ddraw_dolock() != 0;
        }
+       gfx_unlock();
        return ret;
 }
 
 void unlockscr(struct vidbuffer *vb, int y_start, int y_end)
 {
        struct AmigaMonitor *mon = &AMonitors[vb->monitor_id];
+       gfx_lock();
        if (mon->currentmode.flags & DM_D3D) {
                if (mon->currentmode.flags & DM_SWSCALE) {
                        S2X_render(vb->monitor_id, y_start, y_end);
@@ -1617,6 +1639,7 @@ void unlockscr(struct vidbuffer *vb, int y_start, int y_end)
                DirectDraw_SurfaceUnlock();
                vb->bufmem = NULL;
        }
+       gfx_unlock();
 }
 
 void flush_clear_screen (struct vidbuffer *vb)
index 65de335b6b8067abde43b04d64bb1eaeaa14ca62..da76a8673956ee40fa4c4f7fdf12e515d19c29c2 100644 (file)
@@ -468,7 +468,6 @@ Global
                {07609D0D-FE6B-4A84-8C87-F914A4566F6F}.Test|Mixed Platforms.ActiveCfg = Release|Win32
                {07609D0D-FE6B-4A84-8C87-F914A4566F6F}.Test|Mixed Platforms.Build.0 = Release|Win32
                {07609D0D-FE6B-4A84-8C87-F914A4566F6F}.Test|Win32.ActiveCfg = Release|Win32
-               {07609D0D-FE6B-4A84-8C87-F914A4566F6F}.Test|Win32.Build.0 = Release|Win32
                {07609D0D-FE6B-4A84-8C87-F914A4566F6F}.Test|x64.ActiveCfg = Release|x64
                {07609D0D-FE6B-4A84-8C87-F914A4566F6F}.Test|x64.Build.0 = Release|x64
        EndGlobalSection
index f2ef57decf6ca5a44607124f5e1ba298592a6322..2753a605d0b9982918e2787d49a745e37ded67e1 100644 (file)
@@ -77,6 +77,9 @@ struct uaesndboard_stream
        int framesize;
        uae_u8 io[256];
        uae_u16 wordlatch;
+       int timer_cnt;
+       int timer_event_time;
+       int timer_active;
        int sample[MAX_UAE_CHANNELS];
 };
 struct uaesndboard_data
@@ -125,7 +128,7 @@ static struct uaesndboard_data uaesndboard[MAX_DUPLICATE_SOUND_BOARDS];
        24.W volume (0 to 32768)
        26.L next sample set address (0=end, this was last set)
        32.B number of channels. (interleaved samples if 2 or more channels)
-       33.B sample type (bit 0: bits per sample, 0=8,1=16, bit 6=signed, bit 7=little-endian)
+       33.B sample type (bit 0: bits per sample, 0=8,1=16,2=24,3=32 bit 6=signed, bit 7=little-endian)
        34.B bit 0: interrupt when set starts, bit 1: interrupt when set ends (last sample played), bit 2: interrupt when repeat starts, bit 3: after each sample.
        35.B if mono stream, bit mask that selects output channels. (0=default, redirect to left and right channels)
        (Can be used for example when playing tracker modules by using 4 single channel streams)
@@ -179,13 +182,16 @@ static struct uaesndboard_data uaesndboard[MAX_DUPLICATE_SOUND_BOARDS];
        $0184.B Reserved
        $0185.B Reserved
        $0186.B Reserved
-       $0187.B Interrupt status. 7: set when interrupt active. 0,1,2,3: same as 30.B bit, always set when condition matches,
-               even if 30.B bit is not set. If also 30.B bit is set: bit 7 set and interrupt is activated.
+       $0187.B Interrupt status. 7: set when interrupt active. 0,1,2,3: same as 34.B bit, always set when condition matches,
+               even if 34.B bit is not set. If also 34.B bit is set: bit 7 set and interrupt is activated.
+               bit 4 = timer interrupt.
                Reading clears interrupt. RO.
        $0188.B Reserved
        $0189.B Reserved
        $018A.B Reserved
        $018B.B Alternate interrupt status. Same as $187.B but reading does not clear interrupt. RO.
+       $0190.B Stream master interrupt enable (same bits as $0187.B)
+       $0190.L Timer frequency (same format as 12.L), sets interrupt bit 4. Zero = disabled. WO.
 
        $0200 stream 2
 
@@ -202,7 +208,7 @@ static struct uaesndboard_data uaesndboard[MAX_DUPLICATE_SOUND_BOARDS];
        68020+ aligned long accesses are always guaranteed safe.
 
        Set structure is copied to emulator side internal address space when set starts.
-       This data can be always read and written in real time by accessing $0100-$011f space.
+       This data can be always read and written in real time by accessing $0100-$013f space.
        Writes are nearly immediate, values are updated during next sample period.
        (It probably is not a good idea to do on the fly change number of channels or bits per sample values..)
 
@@ -224,6 +230,8 @@ static struct uaesndboard_data uaesndboard[MAX_DUPLICATE_SOUND_BOARDS];
 
        Hardware word and long accesses must be aligned (unaligned write is ignored, unaligned read will return 0xffff or 0xffffffff)
 
+       Timer is usable when stream is allocated. Active audio play is not required.
+
 */
 
 #define STREAM_STRUCT_SIZE 40
@@ -495,8 +503,10 @@ static void uaesnd_stream_start(struct uaesndboard_data *data, struct uaesndboar
 
 static void uaesnd_irq(struct uaesndboard_stream *s, uae_u8 mask)
 {
+       uae_u8 enablemask = get_long_host(s->io + 0x90);
+       uae_u8 intenamask = s->intenamask | 0x10 | 0x20 | 0x40;
        s->intreqmask |= mask;
-       if ((s->intenamask & mask)) {
+       if ((intenamask & mask) && (enablemask & mask)) {
                s->intreqmask |= 0x80;
                devices_rethink_all(sndboard_rethink);
        }
@@ -545,7 +555,7 @@ static bool audio_state_sndboard_uae(int streamid, void *params)
                        len = s->repeating ? s->replen : s->len;
                        addr = s->repeating ? s->repeat : s->address;
                }
-               bool bit16 = (s->bitmode & 1) != 0;
+               int st = (s->bitmode & 7);
                bool le = (s->bitmode & 0x80) != 0;
                bool sign = (s->bitmode & 0x40) != 0;
                bool len_nonzero = len != 0;
@@ -554,16 +564,28 @@ static bool audio_state_sndboard_uae(int streamid, void *params)
                                addr -= s->framesize;
                        for (int i = 0; i < s->ch; i++) {
                                uae_u16 sample = 0;
-                               if (bit16) {
+                               switch (st)
+                               {
+                               case 3: // 32-bit (last 2 bytes ignored)
+                                       sample = get_word(le ? (addr + 2) : (addr + 0));
+                                       addr += 4;
+                                       break;
+                               case 2: // 24-bit (last byte ignored)
+                                       sample = get_word(le ? (addr + 1) : (addr + 0));
+                                       addr += 3;
+                                       break;
+                               case 1: // 16-bit
                                        sample = get_word(addr);
-                                       if (le)
-                                               sample = (sample >> 8) | (sample << 8);
                                        addr += 2;
-                               } else {
+                                       break;
+                               case 0: // 8-bit
                                        sample = get_byte(addr);
                                        sample = (sample << 8) | sample;
                                        addr += 1;
+                                       break;
                                }
+                               if (le)
+                                       sample = (sample >> 8) | (sample << 8);
                                if (sign)
                                        sample -= 0x8000;
                                uae_s16 samples = (uae_s16)sample;
@@ -700,12 +722,47 @@ static void uaesnd_unlatch_mask(struct uaesndboard_data *data, uae_u32 mask)
        }
 }
 
+static int uaesnd_timer_period(uae_u32 v)
+{
+       if ((v >> 16) == 0xffff) {
+               return v & 65535;
+       } else {
+               return (uae_s64)base_event_clock * CYCLE_UNIT * 256 / v;
+       }
+}
+
+static void uaesnd_timer(uae_u32 v)
+{
+       struct uaesndboard_data *data = &uaesndboard[v >> 16];
+       struct uaesndboard_stream *s = &data->stream[v & 65535];
+       s->timer_cnt = get_long_host(s->io + 0x90);
+       if (s->timer_cnt > 0 && data->enabled) {
+               s->timer_event_time = uaesnd_timer_period(s->timer_cnt);
+               if (s->timer_event_time > 0) {
+                       event2_newevent_xx(-1, s->timer_event_time, s - &data->stream[0], uaesnd_timer);
+                       uaesnd_irq(s, 0x10);
+                       s->timer_active = 1;
+               }
+       } else {
+               s->timer_active = 0;
+       }
+}
+
 static void uaesnd_put(struct uaesndboard_data *data, struct uaesndboard_stream *s, int reg)
 {
        if (reg == 0x80) { // set pointer write?
                uaecptr setaddr = get_long_host(s->io + 0x80);
                s->next = setaddr;
                uaesnd_stream_start(data, s);
+       } else if (reg == 0x90) { // timer
+               s->timer_cnt = get_long_host(s->io + 0x90);
+               if (s->timer_cnt > 0 && !s->timer_active) {
+                       s->timer_event_time = uaesnd_timer_period(s->timer_cnt);
+                       if (s->timer_event_time > 0) {
+                               s->timer_active = 1;
+                               event2_newevent_xx(-1, s->timer_event_time, ((data - &uaesndboard[0]) << 16) | (s - &data->stream[0]), uaesnd_timer);
+                       }
+               }
        } else {
                if (!uaesnd_directload(s, reg)) {
                        uaesndboard_stop(data, s);