#include "zfile.h"
#include "uae.h"
#include "gui.h"
+#include "xwin.h"
#ifdef AVIOUTPUT
#include "avioutput.h"
#endif
samplexx_sinc_handler (datas);
data1 = datas[0] + datas[3] + datas[1] + datas[2];
data1 = FINISH_DATA (data1, 16, 2);
+ set_sound_buffers ();
PUT_SOUND_WORD_MONO (data1);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
void sample16_handler (void)
data0 += data3;
data = SBASEVAL16(2) + data0;
data = FINISH_DATA (data, 16, 2);
+ set_sound_buffers ();
PUT_SOUND_WORD_MONO (data);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
/* This interpolator examines sample points when Paula switches the output
samplexx_anti_handler (datas);
data1 = datas[0] + datas[3] + datas[1] + datas[2];
data1 = FINISH_DATA (data1, 16, 2);
+ set_sound_buffers ();
PUT_SOUND_WORD_MONO (data1);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
static void sample16i_rh_handler (void)
data0 += (data3 * (256 - ratio) + data3p * ratio) >> 8;
data = SBASEVAL16(2) + data0;
data = FINISH_DATA (data, 16, 2);
+ set_sound_buffers ();
PUT_SOUND_WORD_MONO (data);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
static void sample16i_crux_handler (void)
data0 += data1;
data = SBASEVAL16(2) + data0;
data = FINISH_DATA (data, 16, 2);
+ set_sound_buffers ();
PUT_SOUND_WORD_MONO (data);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
#ifdef HAVE_STEREO_SUPPORT
data1 = FINISH_DATA (data1, 16, 0);
data2 = FINISH_DATA (data2, 16, 0);
data3 = FINISH_DATA (data3, 16, 0);
+ set_sound_buffers ();
put_sound_word_left (data0);
put_sound_word_right (data1);
if (currprefs.sound_stereo == SND_6CH)
make6ch (data0, data1, data2, data3);
put_sound_word_left2 (data3);
put_sound_word_right2 (data2);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
/* This interpolator examines sample points when Paula switches the output
data1 = FINISH_DATA (datas[1], 16, 0);
data2 = FINISH_DATA (datas[2], 16, 0);
data3 = FINISH_DATA (datas[3], 16, 0);
+ set_sound_buffers ();
put_sound_word_left (data0);
put_sound_word_right (data1);
if (currprefs.sound_stereo == SND_6CH)
make6ch (data0, data1, data2, data3);
put_sound_word_left2 (data3);
put_sound_word_right2 (data2);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
static void sample16si_anti_handler (void)
data2 = datas[1] + datas[2];
data1 = FINISH_DATA (data1, 16, 1);
data2 = FINISH_DATA (data2, 16, 1);
+ set_sound_buffers ();
put_sound_word_left (data1);
put_sound_word_right (data2);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
void sample16ss_sinc_handler (void)
data1 = FINISH_DATA (datas[1], 16, 0);
data2 = FINISH_DATA (datas[2], 16, 0);
data3 = FINISH_DATA (datas[3], 16, 0);
+ set_sound_buffers ();
put_sound_word_left (data0);
put_sound_word_right (data1);
if (currprefs.sound_stereo == SND_6CH)
make6ch (data0, data1, data2, data3);
put_sound_word_left2 (data3);
put_sound_word_right2 (data2);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
static void sample16si_sinc_handler (void)
data2 = datas[1] + datas[2];
data1 = FINISH_DATA (data1, 16, 1);
data2 = FINISH_DATA (data2, 16, 1);
+ set_sound_buffers ();
put_sound_word_left (data1);
put_sound_word_right (data2);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
void sample16s_handler (void)
data2 = FINISH_DATA (data2, 16, 1);
data3 = SBASEVAL16(1) + data1;
data3 = FINISH_DATA (data3, 16, 1);
+ set_sound_buffers ();
put_sound_word_left (data2);
put_sound_word_right (data3);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
static void sample16si_crux_handler (void)
data2 = FINISH_DATA (data2, 16, 1);
data3 = SBASEVAL16(1) + data1;
data3 = FINISH_DATA (data3, 16, 1);
+ set_sound_buffers ();
put_sound_word_left (data2);
put_sound_word_right (data3);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
static void sample16si_rh_handler (void)
data2 = FINISH_DATA (data2, 16, 1);
data3 = SBASEVAL16(1) + data1;
data3 = FINISH_DATA (data3, 16, 1);
+ set_sound_buffers ();
put_sound_word_left (data2);
put_sound_word_right (data3);
- check_sound_buffers (outputsample, doublesample);
+ check_sound_buffers ();
}
#else
{
if (changed_prefs.produce_sound != currprefs.produce_sound
|| changed_prefs.win32_soundcard != currprefs.win32_soundcard
+ || changed_prefs.win32_soundexclusive != currprefs.win32_soundexclusive
|| changed_prefs.sound_stereo != currprefs.sound_stereo
|| changed_prefs.sound_maxbsiz != currprefs.sound_maxbsiz
|| changed_prefs.sound_freq != currprefs.sound_freq
currprefs.produce_sound = changed_prefs.produce_sound;
currprefs.win32_soundcard = changed_prefs.win32_soundcard;
+ currprefs.win32_soundexclusive = changed_prefs.win32_soundexclusive;
currprefs.sound_stereo = changed_prefs.sound_stereo;
currprefs.sound_auto = changed_prefs.sound_auto;
currprefs.sound_freq = changed_prefs.sound_freq;
next_sample_evtime += scaled_sample_evtime;
doublesample = 0;
if (--samplecounter <= 0) {
- samplecounter = currprefs.sound_freq / 100;
+ samplecounter = currprefs.sound_freq / 1000;
if (extrasamples > 0) {
outputsample = 1;
doublesample = 1;
void audio_vsync (void)
{
+#if 0
int i, max, min;
static int lastdir;
- min = -5 * 10;
- max = 5 * 10;
+ min = -10 * 10;
+ max = (isfullscreen () > 0 && currprefs.gfx_avsync) ? 10 * 10 : 20 * 10;
extrasamples = 0;
if (gui_data.sndbuf < min) {
// add extra sample
extrasamples = 10;
if (extrasamples < -10)
extrasamples = -10;
+#endif
}
#define SPRITE_DEBUG 0
#define SPRITE_DEBUG_MINY 0xb0
#define SPRITE_DEBUG_MAXY 0xf8
-#ifdef NEWHSYNC
-#define SPR0_HPOS 0x19
-#else
#define SPR0_HPOS 0x15
-#endif
#define MAX_SPRITES 8
#define SPRITE_COLLISIONS
#define SPEEDUP
#define AUTOSCALE_SPRITES 1
#define NEW_BPL 1
+#define NEW_BPLX 0
#define SPRBORDER 0
#endif
static uae_u16 bplxdat[8];
+static int bpl1dat_written;
static uae_s16 bpl1mod, bpl2mod;
static uaecptr prevbpl[2][MAXVPOS][8];
static uaecptr bplpt[8], bplptx[8], f_bplpt[8];
static struct color_entry current_colors;
static unsigned int bplcon0, bplcon1, bplcon2, bplcon3, bplcon4;
-static unsigned int ta_bplcon0_res, td_bplcon0_res, t_bplcon0_planes, t_bplcon0_planes_limit;
+static unsigned int bplcon0d, bplcon0_res, bplcon0_planes, bplcon0_planes_limit;
static unsigned int diwstrt, diwstop, diwhigh;
static int diwhigh_written;
static unsigned int ddfstrt, ddfstop, ddfstrt_old_hpos, ddfstrt_old_vpos;
static int ddf_change, badmode;
+static int fmode;
/* The display and data fetch windows */
static struct copper cop_state;
static int copper_enabled_thisline;
static int cop_min_waittime;
-
-static uae_u16 f_bplcon0, f_fmode;
-static int fa_bplcon0_res, fd_bplcon0_res, f_bplcon0_planes, f_bplcon0_planes_limit;
-static int f_fetchunit, f_fetchunit_mask;
-static int f_fetchstart, f_fetchstart_mask, f_fetchstart_shift;
-static int f_fm_maxplane_shift, f_fm_maxplane;
-static int f_fetch_modulo_cycle, f_fetchmode;
-
/*
* Statistics
*/
#endif
static struct decision thisline_decision;
-static int fetch_cycle;
+static int fetch_cycle, fetch_modulo_cycle;
enum plfstate
{
STATIC_INLINE int ecsshres(void)
{
- return fd_bplcon0_res == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA);
+ return bplcon0_res == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA);
}
STATIC_INLINE int nodraw (void)
{
int res = GET_RES_AGNUS (bc0);
int planes = GET_PLANES (bc0);
- return real_bitplane_number[f_fetchmode][res][planes];
+ return real_bitplane_number[fetchmode][res][planes];
}
-#ifdef NEWHSYNC
-#define HARD_DDF_STOP 0xd8
-#define HARD_DDF_START 0x18
-#else
/* The HRM says 0xD8, but that can't work... */
#define HARD_DDF_STOP 0xd4
#define HARD_DDF_START 0x18
-#endif
static void add_modulos (void)
{
int m1, m2;
- if (f_fmode & 0x4000) {
+ if (fmode & 0x4000) {
if (((diwstrt >> 8) ^ vpos) & 1)
m1 = m2 = bpl2mod;
else
m2 = bpl2mod;
}
- switch (f_bplcon0_planes_limit) {
+ switch (bplcon0_planes_limit) {
#ifdef AGA
case 8: bplpt[7] += m2; bplptx[7] += m2;
case 7: bplpt[6] += m1; bplptx[6] += m1;
are contained in an indivisible block during which ddf is active. E.g.
if DDF starts at 0x30, and fetchunit is 8, then possible DDF stops are
0x30 + n * 8. */
-static int t_fetchunit, t_fetchunit_mask;
+static int fetchunit, fetchunit_mask;
/* The delay before fetching the same bitplane again. Can be larger than
the number of bitplanes; in that case there are additional empty cycles
with no data fetch (this happens for high fetchmodes and low
resolutions). */
-static int t_fetchstart, t_fetchstart_shift, t_fetchstart_mask;
+static int fetchstart, fetchstart_shift, fetchstart_mask;
/* fm_maxplane holds the maximum number of planes possible with the current
fetch mode. This selects the cycle diagram:
8 planes: 73516240
4 planes: 3120
2 planes: 10. */
-static int f_fm_maxplane, f_fm_maxplane_shift;
+static int fm_maxplane, fm_maxplane_shift;
/* The corresponding values, by fetchmode and display resolution. */
static const int fetchunits[] = { 8,8,8,0, 16,8,8,0, 32,16,8,0 };
static int cycle_diagram_table[3][3][9][32];
static int cycle_diagram_free_cycles[3][3][9];
static int cycle_diagram_total_cycles[3][3][9];
-static int *curr_diagram, curr_diagram_change;
+static int *curr_diagram;
static const int cycle_sequences[3 * 8] = { 2,1,2,1,2,1,2,1, 4,2,3,1,4,2,3,1, 8,4,6,2,7,3,5,1 };
static void debug_cycle_diagram (void)
static void estimate_last_fetch_cycle (int hpos)
{
- int fetchunit = fetchunits[f_fetchmode * 4 + fa_bplcon0_res];
+ int fetchunit = fetchunits[fetchmode * 4 + bplcon0_res];
if (plfstate < plf_passed_stop) {
int stop = plfstop < hpos || plfstop > HARD_DDF_STOP ? HARD_DDF_STOP : plfstop;
/* We know that fetching is up-to-date up until hpos, so we can use fetch_cycle. */
int fetch_cycle_at_stop = fetch_cycle + (stop - hpos);
- int starting_last_block_at = (fetch_cycle_at_stop + f_fetchunit - 1) & ~(f_fetchunit - 1);
+ int starting_last_block_at = (fetch_cycle_at_stop + fetchunit - 1) & ~(fetchunit - 1);
- estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + f_fetchunit;
+ estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
} else {
- int starting_last_block_at = (fetch_cycle + f_fetchunit - 1) & ~(f_fetchunit - 1);
+ int starting_last_block_at = (fetch_cycle + fetchunit - 1) & ~(fetchunit - 1);
if (plfstate == plf_passed_stop2)
starting_last_block_at -= fetchunit;
- estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + f_fetchunit;
+ estimated_last_fetch_cycle = hpos + (starting_last_block_at - fetch_cycle) + fetchunit;
}
}
STATIC_INLINE void compute_delay_offset (void)
{
-#ifdef NEWHSYNC
- int v = 4;
-#else
- int v = 0;
-#endif
- delayoffset = (16 << f_fetchmode) - (((plfstrt - v - HARD_DDF_START) & f_fetchstart_mask) << 1);
+ delayoffset = (16 << fetchmode) - (((plfstrt - HARD_DDF_START) & fetchstart_mask) << 1);
#if 0
/* maybe we can finally get rid of this stupid table.. */
if (tmp == 4)
curr_color_changes[next_color_change].regno = -1;
}
-// OCS/ECS, lores, 7 planes = 4 "real" planes + BPL5DAT and BPL6DAT as 5th and 6th plane
-STATIC_INLINE int isocs7planes (void)
+static int isehb (uae_u16 bplcon0, uae_u16 bplcon2)
{
- return !(currprefs.chipset_mask & CSMASK_AGA) && fa_bplcon0_res == 0 && f_bplcon0_planes == 7;
+ int bplehb;
+ if (currprefs.chipset_mask & CSMASK_AGA)
+ bplehb = (bplcon0 & 0x7010) == 0x6000;
+ else if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
+ bplehb = ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000);
+ else
+ bplehb = ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000) && !currprefs.cs_denisenoehb;
+ return bplehb;
}
-static uae_u16 tmp_bplcon0, tmp_fmode;
-STATIC_INLINE fetch_bpl_params (void)
+// OCS/ECS, lores, 7 planes = 4 "real" planes + BPL5DAT and BPL6DAT as 5th and 6th plane
+STATIC_INLINE int isocs7planes (void)
{
- tmp_bplcon0 = bplcon0;
- tmp_fmode = fmode;
+ return !(currprefs.chipset_mask & CSMASK_AGA) && bplcon0_res == 0 && bplcon0_planes == 7;
}
-static void copy_bpl_params (int pos)
-{
- int changed = 0;
- int fm;
-
- if (f_bplcon0 != tmp_bplcon0)
- changed = 1;
- if (f_fmode != tmp_fmode)
- changed = 1;
-
- if (changed)
- record_color_change2 (pos + 4, 0x100 + 0x1000, tmp_bplcon0);
- f_bplcon0 = tmp_bplcon0;
- f_fmode = tmp_fmode;
- fm = fmode & 3;
- if (fm == 0)
- f_fetchmode = 0;
- else if (fm == 1 || fm == 2)
- f_fetchmode = 1;
- else
- f_fetchmode = 2;
- fa_bplcon0_res = GET_RES_AGNUS (f_bplcon0);
- fd_bplcon0_res = GET_RES_DENISE (f_bplcon0);
- f_bplcon0_planes = GET_PLANES (f_bplcon0);
- f_bplcon0_planes_limit = GET_PLANES_LIMIT (f_bplcon0);
- f_fetchunit = fetchunits[fetchmode * 4 + fa_bplcon0_res];
- f_fetchunit_mask = t_fetchunit - 1;
- f_fetchstart_shift = fetchstarts[f_fetchmode * 4 + fa_bplcon0_res];
- f_fetchstart = 1 << t_fetchstart_shift;
- f_fetchstart_mask = t_fetchstart - 1;
- f_fm_maxplane_shift = fm_maxplanes[f_fetchmode * 4 + fa_bplcon0_res];
- f_fm_maxplane = 1 << f_fm_maxplane_shift;
- curr_diagram = cycle_diagram_table[f_fetchmode][fa_bplcon0_res][f_bplcon0_planes_limit];
- f_fetch_modulo_cycle = t_fetchunit - f_fetchstart;
- if (toscr_nr_planes < f_bplcon0_planes_limit)
- toscr_nr_planes = f_bplcon0_planes_limit;
+static void update_denise (int hpos)
+{
+ toscr_res = GET_RES_DENISE (bplcon0d);
+ record_color_change2 (hpos, 0x100 + 0x1000, bplcon0d);
+ toscr_nr_planes = GET_PLANES (bplcon0d);
if (isocs7planes ()) {
if (toscr_nr_planes2 < 6)
toscr_nr_planes2 = 6;
} else {
toscr_nr_planes2 = toscr_nr_planes;
}
- toscr_res = fd_bplcon0_res;
}
static void expand_fmodes (void)
{
- ta_bplcon0_res = GET_RES_AGNUS (bplcon0);
- td_bplcon0_res = GET_RES_DENISE (bplcon0);
- t_bplcon0_planes = GET_PLANES (bplcon0);
- t_bplcon0_planes_limit = GET_PLANES_LIMIT (bplcon0);
- t_fetchunit = fetchunits[fetchmode * 4 + ta_bplcon0_res];
- t_fetchunit_mask = t_fetchunit - 1;
- t_fetchstart_shift = fetchstarts[fetchmode * 4 + ta_bplcon0_res];
- t_fetchstart = 1 << t_fetchstart_shift;
- t_fetchstart_mask = t_fetchstart - 1;
+ bplcon0_res = GET_RES_AGNUS (bplcon0);
+ bplcon0_planes = GET_PLANES (bplcon0);
+ bplcon0_planes_limit = GET_PLANES_LIMIT (bplcon0);
+ fetchunit = fetchunits[fetchmode * 4 + bplcon0_res];
+ fetchunit_mask = fetchunit - 1;
+ fetchstart_shift = fetchstarts[fetchmode * 4 + bplcon0_res];
+ fetchstart = 1 << fetchstart_shift;
+ fetchstart_mask = fetchstart - 1;
+ fm_maxplane_shift = fm_maxplanes[fetchmode * 4 + bplcon0_res];
+ fm_maxplane = 1 << fm_maxplane_shift;
+ fetch_modulo_cycle = fetchunit - fetchstart;
+ curr_diagram = cycle_diagram_table[fetchmode][bplcon0_res][bplcon0_planes_limit];
}
/* Expand bplcon0/bplcon1 into the toscr_xxx variables. */
int shdelay1 = (bplcon1 >> 12) & 3;
int shdelay2 = (bplcon1 >> 8) & 3;
int delaymask;
- int fetchwidth = 16 << f_fetchmode;
+ int fetchwidth = 16 << fetchmode;
delay1 += delayoffset;
delay2 += delayoffset;
static void compute_toscr_delay (int hpos)
{
- toscr_res = fd_bplcon0_res;
- toscr_nr_planes = f_bplcon0_planes_limit;
- toscr_nr_planes2 = f_bplcon0_planes;
+ update_denise (hpos);
compute_toscr_delay_1 ();
}
}
}
-STATIC_INLINE void fetch (int nr, int fm)
+STATIC_INLINE void fetch (int nr, int fm, int hpos)
{
- if (nr < toscr_nr_planes) {
-#if NEW_BPL
- uaecptr p = f_bplpt[nr] + bpl_off[nr];
-#else
- uaecptr p = bplpt[nr];
+ if (nr < bplcon0_planes_limit) {
+ uaecptr p = bplpt[nr] + bpl_off[nr];
bplpt[nr] += 2 << fm;
+ if (nr == 0)
+ bpl1dat_written = 1;
+#ifdef DEBUGGER
+ if (debug_copper)
+ record_copper_otherdma (0x110 + nr * 2, chipmem_agnus_wget (p), hpos, vpos);
#endif
switch (fm)
{
break;
#endif
}
- if (plfstate == plf_passed_stop2 && fetch_cycle >= (fetch_cycle & ~f_fetchunit_mask) + f_fetch_modulo_cycle) {
+ if (plfstate == plf_passed_stop2 && fetch_cycle >= (fetch_cycle & ~fetchunit_mask) + fetch_modulo_cycle) {
int mod;
- if (f_fmode & 0x4000) {
+ if (fmode & 0x4000) {
if (((diwstrt >> 8) ^ vpos) & 1)
mod = bpl2mod;
else
bplpt[nr] += mod;
bplptx[nr] += mod;
}
- } else if (isocs7planes ()) {
+ } else {
+ // use whatever left in BPLxDAT if no DMA
+ // normally useless but "7-planes" feature won't work without this
fetched[nr] = bplxdat[nr];
}
- if (nr == 0)
- fetch_state = fetch_was_plane0;
-#if NEW_BPL
- else if (nr == 1 && ta_bplcon0_res > fa_bplcon0_res)
- fetch_state = fetch_was_plane0;
-#endif
}
static void clear_fetchbuffer (uae_u32 *ptr, int nwords)
int j;
for (j = thisline_decision.nr_planes; j < toscr_nr_planes2; j++)
clear_fetchbuffer ((uae_u32 *)(line_data[next_lineno] + 2 * MAX_WORDS_PER_LINE * j), out_offs);
-#if 0
- if (thisline_decision.nr_planes > 0)
- printf ("Planes from %d to %d\n", thisline_decision.nr_planes, toscr_nr_planes2);
-#endif
thisline_decision.nr_planes = toscr_nr_planes2;
}
}
toscr_nbits = 0;
}
-STATIC_INLINE void fetch_start (int hpoa)
+STATIC_INLINE void fetch_start (int hpos)
{
fetch_state = fetch_started;
}
/* Called when all planes have been fetched, i.e. when a new block
of data is available to be displayed. The data in fetched[] is
moved into todisplay[]. */
-STATIC_INLINE void beginning_of_plane_block (int pos, int fm)
+STATIC_INLINE void beginning_of_plane_block (int hpos, int fm)
{
int i;
flush_display (fm);
if (fm == 0)
- for (i = 0; i < MAX_PLANES; i++)
+ for (i = 0; i < MAX_PLANES; i++) {
todisplay[i][0] |= fetched[i];
+ }
#ifdef AGA
else
for (i = 0; i < MAX_PLANES; i++) {
todisplay[i][0] = fetched_aga0[i];
}
#endif
- maybe_first_bpl1dat (pos);
+ update_denise (hpos);
+ maybe_first_bpl1dat (hpos);
toscr_delay1 = toscr_delay1x;
toscr_delay2 = toscr_delay2x;
+ compute_toscr_delay (hpos);
}
#ifdef SPEEDUP
finish_playfield_line ();
}
-/* current theory: bitplane operation is pipelined, bitplane pointer is copied
- * to backup registers -4 to -1 cycles before fetch is done and pointer is
- * increased during this time, not when real DMA fetch is done, this makes some
- * sense to demos that change bitplane pointers during display
- * (this code is not really emulating above behavior yet..)
- */
-STATIC_INLINE void inc_bpl (int fm, int oe)
-{
-#if NEW_BPL
- int i;
- for (i = 0; i < f_bplcon0_planes; i++) {
- if ((oe == 0) || (oe < 0 && (i & 1)) || (oe > 0 && !(i & 1))) {
- f_bplpt[i] = bplpt[i];
- bplpt[i] += 2 << fm;
- bplptx[i] += 2 << fm;
- }
- }
-#endif
-}
-
STATIC_INLINE int one_fetch_cycle_0 (int pos, int ddfstop_to_test, int dma, int fm)
{
if (plfstate < plf_passed_stop && pos == ddfstop_to_test)
plfstate = plf_passed_stop;
- if ((fetch_cycle & f_fetchunit_mask) == 0) {
+ if ((fetch_cycle & fetchunit_mask) == 0) {
if (plfstate == plf_passed_stop2) {
finish_final_fetch (pos, fm);
return 1;
/* fetchstart_mask can be larger than fm_maxplane if FMODE > 0. This means
that the remaining cycles are idle; we'll fall through the whole switch
without doing anything. */
- int cycle_start = fetch_cycle & f_fetchstart_mask;
- switch (f_fm_maxplane) {
+ int cycle_start = fetch_cycle & fetchstart_mask;
+ switch (fm_maxplane) {
case 8:
switch (cycle_start) {
- case 0: inc_bpl (fm, -1); fetch (7, fm); break;
- case 1: fetch (3, fm); break;
- case 2: fetch (5, fm); break;
- case 3: fetch (1, fm); break;
- case 4: inc_bpl (fm, 1); fetch (6, fm); break;
- case 5: fetch (2, fm); break;
- case 6: fetch (4, fm); break;
- case 7: fetch (0, fm); break;
+ case 0: fetch (7, fm, pos); break;
+ case 1: fetch (3, fm, pos); break;
+ case 2: fetch (5, fm, pos); break;
+ case 3: fetch (1, fm, pos); break;
+ case 4: fetch (6, fm, pos); break;
+ case 5: fetch (2, fm, pos); break;
+ case 6: fetch (4, fm, pos); break;
+ case 7: fetch (0, fm, pos); break;
}
break;
case 4:
switch (cycle_start) {
- case 0: inc_bpl (fm, -1); fetch (3, fm); break;
- case 1: fetch (1, fm); break;
- case 2: inc_bpl (fm, 1); fetch (2, fm); break;
- case 3: fetch (0, fm); break;
+ case 0: fetch (3, fm, pos); break;
+ case 1: fetch (1, fm, pos); break;
+ case 2: fetch (2, fm, pos); break;
+ case 3: fetch (0, fm, pos); break;
}
break;
case 2:
switch (cycle_start) {
- case 0: inc_bpl (fm, 0); fetch (1, fm); break;
- case 1: fetch (0, fm); break;
+ case 0: fetch (1, fm, pos); break;
+ case 1: fetch (0, fm, pos); break;
}
break;
}
}
+
+ if (bpl1dat_written) {
+ // do this here because if program plays with BPLCON0 during scanline
+ // it is possible that one DMA BPL1DAT write is completely missed
+ // -> do not draw anything at all in next dma block
+ // (Disposable Hero titlescreen)
+ fetch_state = fetch_was_plane0;
+ bpl1dat_written = 0;
+ }
+
fetch_cycle++;
toscr_nbits += 2 << toscr_res;
if (ddfstop >= last_fetch_hpos && plfstop < ddfstop_to_test)
ddfstop_to_test = plfstop;
- compute_toscr_delay (last_fetch_hpos);
update_toscr_planes ();
pos = last_fetch_hpos;
/* Unrolled version of the for loop below. */
if (plfstate < plf_passed_stop && ddf_change != vpos && ddf_change + 1 != vpos
&& dma
- && (fetch_cycle & f_fetchstart_mask) == (f_fm_maxplane & f_fetchstart_mask)
+ && (fetch_cycle & fetchstart_mask) == (fm_maxplane & fetchstart_mask)
&& toscr_delay1 == toscr_delay1x && toscr_delay2 == toscr_delay2x && !badmode
# if 0
/* @@@ We handle this case, but the code would be simpler if we
# endif
&& toscr_nr_planes == thisline_decision.nr_planes)
{
- int offs = (pos - fetch_cycle) & f_fetchunit_mask;
- int ddf2 = ((ddfstop_to_test - offs + f_fetchunit - 1) & ~f_fetchunit_mask) + offs;
- int ddf3 = ddf2 + f_fetchunit;
+ int offs = (pos - fetch_cycle) & fetchunit_mask;
+ int ddf2 = ((ddfstop_to_test - offs + fetchunit - 1) & ~fetchunit_mask) + offs;
+ int ddf3 = ddf2 + fetchunit;
int stop = until < ddf2 ? until : until < ddf3 ? ddf2 : ddf3;
int count;
count = stop - pos;
- if (count >= f_fetchstart) {
- count &= ~f_fetchstart_mask;
+ if (count >= fetchstart) {
+ count &= ~fetchstart_mask;
if (thisline_decision.plfleft == -1) {
compute_delay_offset ();
plfstate = plf_passed_stop;
if (pos <= ddfstop_to_test && pos + count > ddf2)
plfstate = plf_passed_stop2;
- if (pos <= ddf2 && pos + count >= ddf2 + f_fm_maxplane)
+ if (pos <= ddf2 && pos + count >= ddf2 + fm_maxplane)
add_modulos ();
pos += count;
fetch_cycle += count;
#endif
for (; pos < until; pos++) {
if (fetch_state == fetch_was_plane0) {
- fetch_bpl_params ();
- copy_bpl_params (pos);
beginning_of_plane_block (pos, fm);
estimate_last_fetch_cycle (pos);
}
STATIC_INLINE void decide_fetch (int hpos)
{
if (fetch_state != fetch_not_started && hpos > last_fetch_hpos) {
- switch (f_fetchmode) {
+ switch (fetchmode) {
case 0: update_fetch_0 (hpos); break;
#ifdef AGA
case 1: update_fetch_1 (hpos); break;
}
}
- fetch_bpl_params ();
- copy_bpl_params (hpos);
fetch_start (hpos);
fetch_cycle = 0;
last_fetch_hpos = hstart;
out_nbits = 0;
out_offs = 0;
toscr_nbits = 0;
- thisline_decision.bplres = fd_bplcon0_res;
+ thisline_decision.bplres = bplcon0_res;
ddfstate = DIW_waiting_stop;
compute_toscr_delay (last_fetch_hpos);
return;
if (hpos <= plfstrt)
return;
- if (hpos > plfstop - t_fetchunit)
+ if (hpos > plfstop - fetchunit)
return;
if (ddfstate != DIW_waiting_start)
plfstate = plf_passed_stop;
static void record_register_change (int hpos, int regno, unsigned long value)
{
- if (regno == 0x100) {
- if (plfstate >= plf_end)
- return;
+ if (regno == 0x100) { // BPLCON0
if (value & 0x800)
thisline_decision.ham_seen = 1;
- if (hpos < HARD_DDF_START || hpos < plfstrt + 0x20) {
- thisline_decision.bplcon0 = value;
- thisline_decision.bplres = GET_RES_DENISE (value);
- }
+ thisline_decision.ehb_seen = !! isehb (value, bplcon2);
+ } else if (regno == 0x104) { // BPLCON2
+ thisline_decision.ehb_seen = !! isehb (value, bplcon2);
}
record_color_change (hpos, regno + 0x1000, value);
}
/* handle very rarely needed playfield collision (CLXDAT bit 0) */
static void do_playfield_collisions (void)
{
- int bplres = td_bplcon0_res;
+ int bplres = bplcon0_res;
hwres_t ddf_left = thisline_decision.plfleft * 2 << bplres;
hwres_t hw_diwlast = coord_window_to_diw_x (thisline_decision.diwlastword);
hwres_t hw_diwfirst = coord_window_to_diw_x (thisline_decision.diwfirstword);
int first = curr_drawinfo[next_lineno].first_sprite_entry;
int i;
unsigned int collision_mask = clxmask[clxcon >> 12];
- int bplres = td_bplcon0_res;
+ int bplres = bplcon0_res;
hwres_t ddf_left = thisline_decision.plfleft * 2 << bplres;
hwres_t hw_diwlast = coord_window_to_diw_x (thisline_decision.diwlastword);
hwres_t hw_diwfirst = coord_window_to_diw_x (thisline_decision.diwfirstword);
if (nodraw ())
return;
- curr_diagram_change = -1;
toscr_nr_planes = toscr_nr_planes2 = 0;
- thisline_decision.bplres = td_bplcon0_res;
+ thisline_decision.bplres = bplcon0_res;
thisline_decision.nr_planes = 0;
+ bpl1dat_written = 0;
thisline_decision.plfleft = -1;
thisline_decision.plflinelen = -1;
thisline_decision.ham_seen = !! (bplcon0 & 0x800);
+ thisline_decision.ehb_seen = !! isehb (bplcon0, bplcon2);
thisline_decision.ham_at_start = !! (bplcon0 & 0x800);
/* decided_res shouldn't be touched before it's initialized by decide_line(). */
plfstrt = ddfstrt;
plfstop = ddfstop;
-#ifdef NEWHSYNC
- plfstrt += 4;
- plfstop += 4;
-#endif
/* probably not the correct place.. should use plfstate instead */
if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) {
/* ECS/AGA and ddfstop > maxhpos == always-on display */
if ((plfstate == plf_end && hpos >= thisline_decision.plfright)
|| hpos >= estimated_last_fetch_cycle)
return 0;
- if (curr_diagram_change >= 0 && hpos >= curr_diagram_change) {
- curr_diagram = cycle_diagram_table[fetchmode][ta_bplcon0_res][t_bplcon0_planes_limit];
- curr_diagram_change = -1;
- }
- return curr_diagram[(hpos - cycle_diagram_shift) & f_fetchstart_mask];
+ return curr_diagram[(hpos - cycle_diagram_shift) & fetchstart_mask];
}
STATIC_INLINE int is_bitplane_dma_inline (int hpos)
if ((plfstate == plf_end && hpos >= thisline_decision.plfright)
|| hpos >= estimated_last_fetch_cycle)
return 0;
- if (curr_diagram_change >= 0 && hpos >= curr_diagram_change) {
- curr_diagram = cycle_diagram_table[fetchmode][ta_bplcon0_res][t_bplcon0_planes_limit];
- curr_diagram_change = -1;
- }
- return curr_diagram[(hpos - cycle_diagram_shift) & f_fetchstart_mask];
+ return curr_diagram[(hpos - cycle_diagram_shift) & fetchstart_mask];
}
static void BPLxPTH (int hpos, uae_u16 v, int num)
}
static void BPLxPTL (int hpos, uae_u16 v, int num)
{
- int delta = 0;
decide_line (hpos);
decide_fetch (hpos);
- /* fix for "bitplane dma fetch at the same time while updating BPLxPTL" */
- /* fixes "3v Demo" by Cave and "New Year Demo" by Phoenix */
- if (is_bitplane_dma (hpos) == num + 1 || is_bitplane_dma (hpos - 1) == num + 1) {
- delta = 2 << f_fetchmode;
- }
-
- // hack until bitplane pipelin is properly emulated
- if (fetchmode == 0 && fetch_state != fetch_not_started && diwstate == DIW_waiting_stop && f_fm_maxplane == 8 && t_bplcon0_planes > 1 && td_bplcon0_res == 0) {
- if (hpos > plfstrt && hpos <= plfstrt + 7) {
- if (num == 1 && hpos <= plfstrt + 2)
- delta = 2;
- }
- }
-
- f_bplpt[num] = bplpt[num] = (bplpt[num] & 0xffff0000) | ((v + delta) & 0x0000fffe);
- bplptx[num] = (bplptx[num] & 0xffff0000) | ((v + delta) & 0x0000fffe);
+ f_bplpt[num] = bplpt[num] = (bplpt[num] & 0xffff0000) | (v & 0x0000fffe);
+ bplptx[num] = (bplptx[num] & 0xffff0000) | (v & 0x0000fffe);
//write_log (L"%d:%d:BPL%dPTL %08X COP=%08x\n", hpos, vpos, num, bplpt[num], cop_state.ip);
}
-static int isehb (uae_u16 bplcon0, uae_u16 bplcon2)
+static void BPLCON0_Denise (int hpos, uae_u16 v)
{
- int bplehb;
- if (currprefs.chipset_mask & CSMASK_AGA)
- bplehb = (bplcon0 & 0x7010) == 0x6000;
- else if (currprefs.chipset_mask & CSMASK_ECS_DENISE)
- bplehb = ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000);
- else
- bplehb = ((bplcon0 & 0xFC00) == 0x6000 || (bplcon0 & 0xFC00) == 0x7000) && !currprefs.cs_denisenoehb;
- return bplehb;
+ if (! (currprefs.chipset_mask & CSMASK_ECS_DENISE))
+ v &= ~0x00F1;
+ else if (! (currprefs.chipset_mask & CSMASK_AGA))
+ v &= ~0x00B1;
+ v &= ~(0x0200 | 0x0100 | 0x0080 | 0x0020);
+#if SPRBORDER
+ v |= 1;
+#endif
+
+ if (bplcon0d == v)
+ return;
+
+ // fake unused 0x0080 bit as an EHB bit (see below)
+ if (isehb (bplcon0d, bplcon2))
+ v |= 0x80;
+
+ // Denise reacts to HAM/EHB/DPF changes instantly
+ if ((bplcon0d & (0x800 | 0x400 | 0x80)) != (v & (0x800 | 0x400 | 0x80)))
+ record_register_change (hpos, 0x100, (bplcon0d & ~(0x800 | 0x400 | 0x80)) | (v & (0x0800 | 0x400 | 0x80)));
+
+ bplcon0d = v & ~0x80;
+
+#ifdef ECS_DENISE
+ if (currprefs.chipset_mask & CSMASK_ECS_DENISE) {
+ decide_sprites (hpos);
+ sprres = expand_sprres (v, bplcon3);
+ }
+#endif
+ if (thisline_decision.plfleft == -1)
+ update_denise (hpos);
}
static void BPLCON0 (int hpos, uae_u16 v)
decide_fetch (hpos);
decide_blitter (hpos);
- badmode = GET_RES_AGNUS (v) != GET_RES_DENISE (v);
+ bplcon0 = v;
- // fake unused 0x0080 bit as an EHB bit (see below)
- if (isehb (v, bplcon2))
+ badmode = GET_RES_AGNUS (bplcon0) != GET_RES_DENISE (bplcon0);
+
+ // fake unused 0x0080 bit as an EHB bit (see above)
+ if (isehb (bplcon0, bplcon2))
v |= 0x80;
- if ((bplcon0 & (0x800 | 0x400 | 0x80)) != (v & (0x800 | 0x400 | 0x80))) // HAM/EBH/DPF change is instant
- record_register_change (hpos, 0x100, (bplcon0 & ~(0x800 | 0x400 | 0x80)) | (v & (0x0800 | 0x400 | 0x80)));
+ BPLCON0_Denise (hpos, v);
- // don't ask..
- if (GET_PLANES (v) > GET_PLANES (bplcon0) && GET_RES_AGNUS (v) >= GET_RES_AGNUS (bplcon0) && fetch_state != fetch_not_started)
- fetch_state = fetch_was_plane0;
+ expand_fmodes ();
- bplcon0 = v;
+ record_register_change (hpos, 0x100, v | 0x80);
-#ifdef ECS_DENISE
- if (currprefs.chipset_mask & CSMASK_ECS_DENISE) {
- decide_sprites (hpos);
- sprres = expand_sprres (bplcon0, bplcon3);
- }
-#endif
- expand_fmodes ();
-#if NEW_BPL
- if (fetch_state == fetch_not_started || diwstate != DIW_waiting_stop) {
- record_register_change (hpos, 0x100, v);
- fetch_bpl_params ();
- copy_bpl_params (hpos);
- } else if (fetch_state != fetch_not_started && diwstate == DIW_waiting_stop && (hpos >= plfstrt && hpos <= plfstrt + 1)) {
- fetch_bpl_params ();
- copy_bpl_params (hpos);
- }
-#else
- fetch_bpl_params ();
- copy_bpl_params (hpos);
-#endif
calcdiw ();
estimate_last_fetch_cycle (hpos);
- curr_diagram_change = -1;
- if (fetch_state == fetch_started && diwstate == DIW_waiting_stop) {
- curr_diagram_change = hpos - 2 + f_fm_maxplane - (fetch_cycle & f_fetchstart_mask);
- } else {
- curr_diagram = cycle_diagram_table[fetchmode][ta_bplcon0_res][t_bplcon0_planes_limit];
- }
-
}
STATIC_INLINE void BPLCON1 (int hpos, uae_u16 v)
static void BPL5DAT (int hpos, uae_u16 v)
{
decide_line (hpos);
+ decide_fetch (hpos);
bplxdat[4] = v;
}
static void BPL6DAT (int hpos, uae_u16 v)
{
decide_line (hpos);
+ decide_fetch (hpos);
bplxdat[5] = v;
}
STATIC_INLINE void BPL1DAT (int hpos, uae_u16 v)
{
decide_line (hpos);
+ decide_fetch (hpos);
+ bpl1dat_written = 1;
bplxdat[0] = v;
-
maybe_first_bpl1dat (hpos);
}
v &= 0xfe;
if (!(currprefs.chipset_mask & CSMASK_ECS_AGNUS))
v &= 0xfc;
- if (ddfstrt == v && hpos != plfstrt - 2)
- return;
ddf_change = vpos;
decide_line (hpos);
ddfstrt_old_hpos = hpos;
STATIC_INLINE int copper_cant_read (int hpos)
{
-#ifdef NEWHSYNC
- if (hpos == 0)
- return 1;
-#else
if (hpos + 1 >= maxhpos)
return 1;
-#endif
return is_bitplane_dma_inline (hpos);
}
return custom_wput_1 (hpos, addr, value, noget);
}
-static void perform_copper_write (int old_hpos, int address, int data)
+static void perform_copper_write (int hpos, int address, int data)
{
-#ifdef DEBUGGER
- if (debug_copper)
- record_copper (cop_state.saved_ip - 4, old_hpos, vpos);
-#endif
-
if (test_copper_dangerous (address))
return;
if (address == 0x88) {
cop_state.ip = cop2lc;
cop_state.state = COP_strobe_delay1;
} else {
- custom_wput_copper (old_hpos, address, data, 0);
+ custom_wput_copper (hpos, address, data, 0);
cop_state.last_write = address;
- cop_state.last_write_hpos = old_hpos;
- old_hpos++;
- if (!nocustom () && address >= 0x140 && address < 0x180 && old_hpos >= SPR0_HPOS && old_hpos < SPR0_HPOS + 4 * MAX_SPRITES) {
- //write_log (L"%d:%d %04X:%04X\n", vpos, old_hpos, cop_state.saved_i1, cop_state.saved_i2);
- do_sprites (old_hpos);
+ cop_state.last_write_hpos = hpos;
+ hpos++;
+ if (!nocustom () && address >= 0x140 && address < 0x180 && hpos >= SPR0_HPOS && hpos < SPR0_HPOS + 4 * MAX_SPRITES) {
+ //write_log (L"%d:%d %04X:%04X\n", vpos, hpos, cop_state.saved_i1, cop_state.saved_i2);
+ do_sprites (hpos);
}
}
}
-static int isagnus[]= {
+static void dump_copper (TCHAR *error, int until_hpos)
+{
+ write_log (L"%s: vpos=%d until_hpos=%d\n",
+ error, vpos, until_hpos);
+ write_log (L"cvcmp=%d chcmp=%d chpos=%d cvpos=%d ci1=%04X ci2=%04X\n",
+ cop_state.vcmp,cop_state.hcmp,cop_state.hpos,cop_state.vpos,cop_state.saved_i1,cop_state.saved_i2);
+ write_log (L"cstate=%d ip=%x SPCFLAGS=%x\n",
+ cop_state.state, cop_state.ip, regs.spcflags);
+}
+
+static int customdelay[]= {
1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0, /* 32 0x00 - 0x3e */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 27 0x40 - 0x74 */
0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0, /* 21 */
1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0, /* 32 0xa0 - 0xde */
/* BPLxPTH/BPLxPTL */
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */
/* BPLCON0-3,BPLMOD1-2 */
- 0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, /* 16 */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 16 */
/* SPRxPTH/SPRxPTL */
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 16 */
/* SPRxPOS/SPRxCTL/SPRxDATA/SPRxDATB */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
-static void dump_copper (TCHAR *error, int until_hpos)
-{
- write_log (L"%s: vpos=%d until_hpos=%d\n",
- error, vpos, until_hpos);
- write_log (L"cvcmp=%d chcmp=%d chpos=%d cvpos=%d ci1=%04X ci2=%04X\n",
- cop_state.vcmp,cop_state.hcmp,cop_state.hpos,cop_state.vpos,cop_state.saved_i1,cop_state.saved_i2);
- write_log (L"cstate=%d ip=%x SPCFLAGS=%x\n",
- cop_state.state, cop_state.ip, regs.spcflags);
-}
-
static void update_copper (int until_hpos)
{
int vp = vpos & (((cop_state.saved_i2 >> 8) & 0x7F) | 0x80);
/* So we know about the fetch state. */
decide_line (c_hpos);
+ decide_fetch (c_hpos);
if (cop_state.movedelay > 0) {
cop_state.movedelay--;
+ if (cop_state.movedelay == 1 && cop_state.moveaddr == 0x100) {
+ // Denise reacts to BPLCON0 change a bit earlier than Agnus
+ BPLCON0_Denise (old_hpos, cop_state.movedata);
+ }
if (cop_state.movedelay == 0) {
perform_copper_write (old_hpos, cop_state.moveaddr, cop_state.movedata);
if (! copper_enabled_thisline)
cop_state.ip = cop2lc;
cop_state.state = COP_strobe_delay1;
} else {
- cop_state.movedelay = isagnus[reg >> 1] ? 1 : 2;
+ if (cop_state.moveaddr == 0x100) {
+ // special case BPLCON0 BPL DMA sequency delay
+ cop_state.movedelay = 2;
+ } else if (customdelay[cop_state.moveaddr / 2]) {
+ cop_state.movedelay = customdelay[cop_state.moveaddr / 2];
+ } else {
+ perform_copper_write (old_hpos, cop_state.moveaddr, cop_state.movedata);
+ }
}
- }
#ifdef DEBUGGER
- if (debug_copper)
- record_copper (cop_state.ip - 4, old_hpos, vpos);
+ if (debug_copper)
+ record_copper (cop_state.ip - 4, old_hpos, vpos);
#endif
+ }
break;
case COP_wait1:
}
if (debug_copper)
- record_copper_reset();
+ record_copper_reset ();
vsync_handle_redraw (lof, lof_changed);
if (currprefs.cpu_cycle_exact || currprefs.blitter_cycle_exact) {
decide_blitter (hpos);
memset (cycle_line, 0, sizeof cycle_line);
-#ifdef NEWHSYNC
- alloc_cycle (3, CYCLE_REFRESH); /* strobe */
+#if 1
+ alloc_cycle (1, CYCLE_REFRESH); /* strobe */
+ alloc_cycle (3, CYCLE_REFRESH);
alloc_cycle (5, CYCLE_REFRESH);
alloc_cycle (7, CYCLE_REFRESH);
- alloc_cycle (9, CYCLE_REFRESH);
#else
- alloc_cycle (1, CYCLE_REFRESH); /* strobe */
+ alloc_cycle (maxhpos - 1, CYCLE_REFRESH); /* strobe */
+ alloc_cycle (1, CYCLE_REFRESH);
alloc_cycle (3, CYCLE_REFRESH);
alloc_cycle (5, CYCLE_REFRESH);
- alloc_cycle (7, CYCLE_REFRESH);
#endif
}
#endif
if (!nocustom()) {
if (!currprefs.blitter_cycle_exact && bltstate != BLT_done && dmaen (DMA_BITPLANE) && diwstate == DIW_waiting_stop) {
- blitter_slowdown (thisline_decision.plfleft, thisline_decision.plfright - (16 << f_fetchmode),
- cycle_diagram_total_cycles[f_fetchmode][GET_RES_AGNUS (f_bplcon0)][GET_PLANES_LIMIT (f_bplcon0)],
- cycle_diagram_free_cycles[f_fetchmode][GET_RES_AGNUS (f_bplcon0)][GET_PLANES_LIMIT (f_bplcon0)]);
+ blitter_slowdown (thisline_decision.plfleft, thisline_decision.plfright - (16 << fetchmode),
+ cycle_diagram_total_cycles[fetchmode][GET_RES_AGNUS (bplcon0)][GET_PLANES_LIMIT (bplcon0)],
+ cycle_diagram_free_cycles[fetchmode][GET_RES_AGNUS (bplcon0)][GET_PLANES_LIMIT (bplcon0)]);
}
hardware_line_completed (next_lineno);
if (doflickerfix () && interlace_seen)
static uae_u16 sr_bpmask, sr_bpvalue;
int debugging;
int exception_debugging;
-int debug_copper;
+int debug_copper = 0;
int debug_sprite_mask = 0xff;
static uaecptr processptr;
console_out (L", ignore horizontal");
}
- console_out_f (L".\n \t; VP %02x, VE %02x; HP %02x, HE %02x; BFD %d\n",
+ console_out_f (L"\n \t; VP %02x, VE %02x; HP %02x, HE %02x; BFD %d\n",
vp, ve, hp, he, bfd);
}
-#define NR_COPPER_RECORDS 100000
+#define NR_COPPER_RECORDS 1000000
/* Record copper activity for the debugger. */
-struct cop_record
+struct cop_rec
{
int hpos, vpos;
+ uae_u16 reg, dat;
uaecptr addr;
};
-static struct cop_record *cop_record[2];
+static struct cop_rec *cop_record[2];
static int nr_cop_records[2], curr_cop_set;
-void record_copper_reset(void)
+void record_copper_reset (void)
{
/* Start a new set of copper records. */
curr_cop_set ^= 1;
nr_cop_records[curr_cop_set] = 0;
}
+void record_copper_otherdma (uae_u16 bpl, uae_u16 dat, int hpos, int vpos)
+{
+ int t = nr_cop_records[curr_cop_set];
+ if (!cop_record[0])
+ return;
+ if (t >= NR_COPPER_RECORDS)
+ return;
+ cop_record[curr_cop_set][t].addr = 0xffffffff;
+ cop_record[curr_cop_set][t].hpos = hpos;
+ cop_record[curr_cop_set][t].vpos = vpos;
+ cop_record[curr_cop_set][t].reg = bpl;
+ cop_record[curr_cop_set][t].dat = dat;
+ nr_cop_records[curr_cop_set] = t + 1;
+}
+
void record_copper (uaecptr addr, int hpos, int vpos)
{
int t = nr_cop_records[curr_cop_set];
if (!cop_record[0]) {
- cop_record[0] = xmalloc (NR_COPPER_RECORDS * sizeof (struct cop_record));
- cop_record[1] = xmalloc (NR_COPPER_RECORDS * sizeof (struct cop_record));
+ cop_record[0] = xmalloc (NR_COPPER_RECORDS * sizeof (struct cop_rec));
+ cop_record[1] = xmalloc (NR_COPPER_RECORDS * sizeof (struct cop_rec));
}
if (t < NR_COPPER_RECORDS) {
cop_record[curr_cop_set][t].addr = addr;
cop_record[curr_cop_set][t].hpos = hpos;
cop_record[curr_cop_set][t].vpos = vpos;
+ cop_record[curr_cop_set][t].reg = 0xffff;
+ cop_record[curr_cop_set][t].dat = 0xffff;
nr_cop_records[curr_cop_set] = t + 1;
}
if (debug_copper & 2) { /* trace */
}
}
-static int find_copper_record (uaecptr addr, int *phpos, int *pvpos)
+static struct cop_rec *find_copper_records (uaecptr addr)
{
int s = curr_cop_set ^ 1;
int t = nr_cop_records[s];
int i;
for (i = 0; i < t; i++) {
- if (cop_record[s][i].addr == addr) {
- *phpos = cop_record[s][i].hpos;
- *pvpos = cop_record[s][i].vpos;
- return 1;
- }
+ if (cop_record[s][i].addr == addr)
+ return &cop_record[s][i];
}
return 0;
}
/* simple decode copper by Mark Cox */
static void decode_copper_insn (FILE* file, unsigned long insn, unsigned long addr)
{
+ struct cop_rec *cr = NULL;
uae_u32 insn_type = insn & 0x00010001;
- int hpos, vpos;
TCHAR here = ' ';
TCHAR record[] = L" ";
- if (find_copper_record (addr, &hpos, &vpos)) {
- _stprintf (record, L" [%03x %03x]", vpos, hpos);
+ int cnt;
+
+ if ((cr = find_copper_records (addr))) {
+ _stprintf (record, L" [%03x %03x]", cr->vpos, cr->hpos);
}
if (get_copper_address (-1) >= addr && get_copper_address(-1) <= addr + 3)
abort ();
}
+ if (!cr)
+ return;
+ cr++;
+ cnt = 0;
+ while (cr->addr == 0xffffffff) {
+ int addr = cr->reg;
+ int i = 0;
+ while (custd[i].name) {
+ if (custd[i].adr == addr + 0xdff000)
+ break;
+ i++;
+ }
+ _stprintf (record, L" [%03x %03x]", cr->vpos, cr->hpos);
+ console_out_f (L" %04lx %04lx%s\t; ", addr, cr->dat, record);
+ if (custd[i].name)
+ console_out_f (L"%s := 0x%04lx\n", custd[i].name, cr->dat);
+ else
+ console_out_f (L"%04x := 0x%04lx\n", addr, cr->dat);
+ cr++;
+ if (cnt++ >= 10) {
+ console_out_f (L" ...\n");
+ break;
+ }
+
+ }
+
}
static uaecptr decode_copperlist (FILE* file, uaecptr address, int nolines)
int lines;
if (**c == 'd') {
- next_char(c);
+ next_char (c);
if (debug_copper)
debug_copper = 0;
else
debug_copper = 1;
console_out_f (L"Copper debugger %s.\n", debug_copper ? L"enabled" : L"disabled");
- } else if(**c == 't') {
+ } else if (**c == 't') {
debug_copper = 1|2;
return 1;
- } else if(**c == 'b') {
+ } else if (**c == 'b') {
(*c)++;
debug_copper = 1|4;
- if (more_params(c)) {
- debug_copper_pc = readhex(c);
+ if (more_params (c)) {
+ debug_copper_pc = readhex (c);
console_out_f (L"Copper breakpoint @0x%08x\n", debug_copper_pc);
} else {
debug_copper &= ~4;
}
} else {
- if (more_params(c)) {
- maddr = readhex(c);
+ if (more_params (c)) {
+ maddr = readhex (c);
if (maddr == 1 || maddr == 2)
maddr = get_copper_address (maddr);
else if (maddr == 0)
break;
case 'o':
{
- if (copper_debugger(&inptr)) {
+ if (copper_debugger (&inptr)) {
debugger_active = 0;
debugging = 0;
return;
*pdy = dy;
write_log (L"Display Size: %dx%d Offset: %dx%d\n", w, h, dx, dy);
- write_log (L"first: %d last: %d minv: %d maxv: %d min: %d\n",
+ write_log (L"First: %d Last: %d MinV: %d MaxV: %d Min: %d\n",
plffirstline_total, plflastline_total,
first_planes_vpos, last_planes_vpos, minfirstline);
return 1;
bplres = dp_for_drawing->bplres;
bplplanecnt = dp_for_drawing->nr_planes;
bplham = dp_for_drawing->ham_seen;
+ bplehb = dp_for_drawing->ehb_seen;
+ if ((currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon2 & 0x0200))
+ bplehb = 0;
issprites = dip_for_drawing->nr_sprites;
#ifdef ECS_DENISE
ecsshres = bplres == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA);
if (bplres > 0)
can_use_lores = 0;
- bplehb = (dp_for_drawing->bplcon0 & 0x80) == 0x80;
- if ((currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon2 & 0x0200))
- bplehb = 0;
plf1pri = dp_for_drawing->bplcon2 & 7;
plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7;
plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri);
extern int notinrom (void);
extern const TCHAR *debuginfo (int);
extern void record_copper (uaecptr addr, int hpos, int vpos);
+extern void record_copper_otherdma (uae_u16 bpl, uae_u16 dat, int hpos, int vpos);
extern void record_copper_reset(void);
extern int mmu_init(int,uaecptr,uaecptr);
extern void mmu_do_hit(void);
#else
/* According to the HRM, pixel data spends a couple of cycles somewhere in the chips
before it appears on-screen. */
-#define DIW_DDF_OFFSET 9
+#define DIW_DDF_OFFSET 1
/* this many cycles starting from hpos=0 are visible on right border */
#define HBLANK_OFFSET 9
/* We ignore that many lores pixels at the start of the display. These are
#endif
uae_u8 nr_planes;
uae_u8 bplres;
+ unsigned int ehb_seen;
unsigned int ham_seen;
unsigned int ham_at_start;
};
int win32_midiindev;
int win32_uaescsimode;
int win32_soundcard;
+ int win32_soundexclusive;
int win32_norecyclebin;
int win32_specialkey;
int win32_guikey;
int win32_kbledmode;
int win32_fscodepage;
+ TCHAR win32_commandpath[MAX_DPATH];
int curses_reverse_video;
D3DCAPS9 d3dCaps;
int adapter;
DWORD flags;
- HINSTANCE d3dDLL;
+ HINSTANCE d3dDLL, d3dx;
D3D_free ();
D3D_canshaders ();
_tcscpy (errmsg, L"D3D: not enabled");
return errmsg;
}
+ d3dx = LoadLibrary (L"d3dx9_41.dll");
+ if (d3dx == NULL) {
+ _tcscpy (errmsg, L"Direct3D: March 2009 or newer DirectX Runtime required.\n\nhttp://go.microsoft.com/fwlink/?linkid=56513");
+ if (isfullscreen () <= 0)
+ ShellExecute(NULL, L"open", L"http://go.microsoft.com/fwlink/?linkid=56513", NULL, NULL, SW_SHOWNORMAL);
+ return errmsg;
+ }
+ FreeLibrary (d3dx);
d3d_ex = FALSE;
d3dDLL = LoadLibrary (L"D3D9.DLL");
#define IDC_SOUND_AUTO 1709
#define IDC_FILTERKEEPASPECT 1709
#define IDC_CS_RTC 1710
+#define IDC_SOUND_AUTO2 1710
+#define IDC_SOUND_EXCLUSIVE 1710
#define IDC_CS_CIAA_TOD1 1711
#define IDC_CS_CIAA_TOD2 1712
#define IDC_CS_EXT 1712
FONT 8, "MS Sans Serif", 0, 0, 0x1\r
BEGIN\r
COMBOBOX IDC_SOUNDCARDLIST,5,9,291,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\r
- GROUPBOX "Sound Emulation",IDC_SOUNDSETTINGS,5,30,120,81\r
- CONTROL "Disabled",IDC_SOUND0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,45,101,10\r
- CONTROL "Disabled, but emulated",IDC_SOUND1,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,57,102,10\r
- CONTROL "Enabled",IDC_SOUND2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,69,102,10\r
- CONTROL "Enabled, 100% accurate",IDC_SOUND3,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,81,101,10\r
- GROUPBOX "Volume",IDC_STATIC,132,36,164,31\r
- CONTROL "",IDC_SOUNDVOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,137,44,105,20\r
- EDITTEXT IDC_SOUNDVOLUME2,247,47,40,12,ES_CENTER | ES_READONLY\r
- GROUPBOX "Sound Buffer Size",IDC_STATIC,132,73,164,31\r
- CONTROL "Slider1",IDC_SOUNDBUFFERRAM,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,137,81,105,19\r
- EDITTEXT IDC_SOUNDBUFFERMEM,247,84,40,12,ES_CENTER | ES_READONLY\r
+ GROUPBOX "Sound Emulation",IDC_SOUNDSETTINGS,5,26,120,85\r
+ CONTROL "Disabled",IDC_SOUND0,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,13,41,101,10\r
+ CONTROL "Disabled, but emulated",IDC_SOUND1,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,54,102,10\r
+ CONTROL "Enabled",IDC_SOUND2,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,67,102,10\r
+ CONTROL "Enabled, 100% accurate",IDC_SOUND3,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,13,80,101,10\r
+ GROUPBOX "Volume",IDC_STATIC,132,42,164,31\r
+ CONTROL "",IDC_SOUNDVOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,137,50,105,20\r
+ EDITTEXT IDC_SOUNDVOLUME2,247,53,40,12,ES_CENTER | ES_READONLY\r
+ GROUPBOX "Sound Buffer Size",IDC_STATIC,132,79,164,31\r
+ CONTROL "Slider1",IDC_SOUNDBUFFERRAM,"msctls_trackbar32",TBS_AUTOTICKS | TBS_TOP | WS_TABSTOP,137,87,105,19\r
+ EDITTEXT IDC_SOUNDBUFFERMEM,247,90,40,12,ES_CENTER | ES_READONLY\r
GROUPBOX "Settings",IDC_SOUNDINTERPOLATION2,6,114,290,60\r
LTEXT "Frequency:",IDC_SOUNDFREQTXT,11,148,53,8,SS_CENTERIMAGE\r
COMBOBOX IDC_SOUNDFREQ,13,157,51,75,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP\r
COMBOBOX IDC_SOUNDSWAP,73,157,62,75,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\r
LTEXT "Swap channels:",IDC_SOUNDSWAPTXT,74,148,61,8,SS_CENTERIMAGE\r
CONTROL "Automatic switching",IDC_SOUND_AUTO,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,14,95,103,10\r
+ CONTROL "Exclusive mode",IDC_SOUND_EXCLUSIVE,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,137,31,154,10\r
END\r
\r
IDD_LOADSAVE DIALOGEX 0, 0, 302, 241\r
#include <dsound.h>
#include <ks.h>
#include <ksmedia.h>
+#include <Audioclient.h>
+#include <Mmdeviceapi.h>
+#include <Functiondiscoverykeys_devpkey.h>
#include <al.h>
#include <alc.h>
HANDLE paevent;
int opacounter;
int pablocking;
+
+// wasapi
+
+ IMMDevice *pDevice;
+ IAudioClient *pAudioClient;
+ IAudioRenderClient *pRenderClient;
+ IMMDeviceEnumerator *pEnumerator;
+ IAudioClock *pAudioClock;
+ REFERENCE_TIME hnsRequestedDuration;
+ HANDLE wasapihandle;
+ int bufferFrameCount;
+ UINT64 wasapiclock;
+ UINT64 wasapiframes;
+ int wasapiexclusive;
+ int framecounter;
+ int sndbuf;
+ int wasapigoodsize;
+ int sndbufframes;
};
#define ADJUST_SIZE 30
int sound_mode_skip = 0;
static int have_sound;
+static int statuscnt;
#define SND_MAX_BUFFER2 524288
#define SND_MAX_BUFFER 8192
clearbuffer_ds (sd);
}
+static void pause_audio_wasapi (struct sound_data *sd)
+{
+ struct sound_dp *s = sd->data;
+ HRESULT hr;
+
+ hr = s->pAudioClient->lpVtbl->Stop (s->pAudioClient);
+ if (FAILED (hr))
+ write_log (L"WASAPI: Stop() %08X\n", hr);
+}
+static void resume_audio_wasapi (struct sound_data *sd)
+{
+ struct sound_dp *s = sd->data;
+ HRESULT hr;
+ BYTE *pData;
+ int framecnt;
+
+ ResetEvent (s->wasapihandle);
+ hr = s->pAudioClient->lpVtbl->Reset (s->pAudioClient);
+ if (FAILED (hr))
+ write_log (L"WASAPI: Reset() %08X\n", hr);
+ if (s->wasapiexclusive)
+ framecnt = s->bufferFrameCount;
+ else
+ framecnt = s->wasapigoodsize;
+ hr = s->pRenderClient->lpVtbl->GetBuffer (s->pRenderClient, framecnt, &pData);
+ if (FAILED (hr))
+ return;
+ hr = s->pRenderClient->lpVtbl->ReleaseBuffer (s->pRenderClient, framecnt, AUDCLNT_BUFFERFLAGS_SILENT);
+ hr = s->pAudioClient->lpVtbl->Start (s->pAudioClient);
+ if (FAILED (hr))
+ write_log (L"WASAPI: Start() %08X\n", hr);
+ if (s->wasapiexclusive) {
+ WaitForSingleObject (s->wasapihandle, 5 * 1000);
+ hr = s->pRenderClient->lpVtbl->GetBuffer (s->pRenderClient, framecnt, &pData);
+ if (SUCCEEDED (hr))
+ hr = s->pRenderClient->lpVtbl->ReleaseBuffer (s->pRenderClient, framecnt, AUDCLNT_BUFFERFLAGS_SILENT);
+ }
+ s->wasapiframes = 0;
+ s->framecounter = 0;
+ s->sndbuf = 0;
+}
+
static void pause_audio_ds (struct sound_data *sd)
{
struct sound_dp *s = sd->data;
return 0;
}
+static void close_audio_wasapi (struct sound_data *sd)
+{
+ struct sound_dp *s = sd->data;
+
+ if (s->pRenderClient)
+ s->pRenderClient->lpVtbl->Release (s->pRenderClient);
+ if (s->pAudioClock)
+ s->pAudioClock->lpVtbl->Release (s->pAudioClock);
+ if (s->pAudioClient)
+ s->pAudioClient->lpVtbl->Release (s->pAudioClient);
+ if (s->pDevice)
+ s->pDevice->lpVtbl->Release (s->pDevice);
+ if (s->pEnumerator)
+ s->pEnumerator->lpVtbl->Release (s->pEnumerator);
+ if (s->wasapihandle)
+ CloseHandle (s->wasapihandle);
+}
+
+const static GUID XIID_IAudioClient = {0x1CB9AD4C,0xDBFA,0x4c32,{0xB1,0x78,0xC2,0xF5,0x68,0xA7,0x03,0xB2}};
+const static GUID XIID_IAudioRenderClient = {0xF294ACFC,0x3146,0x4483,{0xA7,0xBF,0xAD,0xDC,0xA7,0xC2,0x60,0xE2}};
+const static GUID XIID_IMMDeviceEnumerator = {0xA95664D2,0x9614,0x4F35,{0xA7,0x46,0xDE,0x8D,0xB6,0x36,0x17,0xE6}};
+const static GUID XCLSID_MMDeviceEnumerator = {0xBCDE0395,0xE52F,0x467C,{0x8E,0x3D,0xC4,0x57,0x92,0x91,0x69,0x2E}};
+const static GUID XIID_IAudioClock = {0xCD63314F,0x3FBA,0x4a1b,{0x81,0x2C,0xEF,0x96,0x35,0x87,0x28,0xE7}};
+
+static int open_audio_wasapi (struct sound_data *sd, int index, int exclusive)
+{
+ HRESULT hr;
+ struct sound_dp *s = sd->data;
+ WAVEFORMATEX *pwfx;
+ WAVEFORMATEXTENSIBLE wavfmt;
+ int final;
+ LPWSTR name = NULL;
+ int rn[4], rncnt;
+ AUDCLNT_SHAREMODE sharemode;
+ int size;
+
+ sd->devicetype = SOUND_DEVICE_WASAPI;
+ s->wasapiexclusive = exclusive;
+
+ if (s->wasapiexclusive)
+ sharemode = AUDCLNT_SHAREMODE_EXCLUSIVE;
+ else
+ sharemode = AUDCLNT_SHAREMODE_SHARED;
+
+ hr = CoCreateInstance (&XCLSID_MMDeviceEnumerator, NULL,
+ CLSCTX_ALL, &XIID_IMMDeviceEnumerator,
+ (void**)&s->pEnumerator);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: %d\n", hr);
+ goto error;
+ }
+
+ if (sound_devices[index].alname == NULL)
+ hr = s->pEnumerator->lpVtbl->GetDefaultAudioEndpoint (s->pEnumerator, eRender, eMultimedia, &s->pDevice);
+ else
+ hr = s->pEnumerator->lpVtbl->GetDevice (s->pEnumerator, sound_devices[index].alname, &s->pDevice);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetDevice(%s) %08X\n", sound_devices[index].alname ? sound_devices[index].alname : L"NULL", hr);
+ goto error;
+ }
+
+ hr = s->pDevice->lpVtbl->GetId (s->pDevice, &name);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetId() %08X\n", hr);
+ goto error;
+ }
+
+ hr = s->pDevice->lpVtbl->Activate (s->pDevice, &XIID_IAudioClient, CLSCTX_ALL, NULL, (void**)&s->pAudioClient);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: Activate() %d\n", hr);
+ goto error;
+ }
+
+ hr = s->pAudioClient->lpVtbl->GetMixFormat (s->pAudioClient, &pwfx);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetMixFormat() %08X\n", hr);
+ goto error;
+ }
+
+ hr = s->pAudioClient->lpVtbl->GetDevicePeriod (s->pAudioClient, NULL, &s->hnsRequestedDuration);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetDevicePeriod() %08X\n", hr);
+ goto error;
+ }
+
+ final = 0;
+ rncnt = 0;
+ for (;;) {
+
+ if (sd->channels == 6) {
+ rn[0] = KSAUDIO_SPEAKER_5POINT1;
+ rn[1] = KSAUDIO_SPEAKER_5POINT1_SURROUND;
+ rn[2] = 0;
+ } else if (sd->channels == 4) {
+ rn[0] = KSAUDIO_SPEAKER_QUAD;
+ rn[1] = KSAUDIO_SPEAKER_QUAD_SURROUND;
+ rn[2] = KSAUDIO_SPEAKER_SURROUND;
+ rn[3] = 0;
+ } else if (sd->channels == 2) {
+ rn[0] = KSAUDIO_SPEAKER_STEREO;
+ rn[1] = 0;
+ } else {
+ rn[0] = KSAUDIO_SPEAKER_MONO;
+ rn[1] = 0;
+ }
+
+ memset (&wavfmt, 0, sizeof wavfmt);
+ wavfmt.Format.nChannels = sd->channels;
+ wavfmt.Format.nSamplesPerSec = sd->freq;
+ wavfmt.Format.wBitsPerSample = 16;
+ wavfmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
+ wavfmt.Format.cbSize = sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX);
+ wavfmt.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ wavfmt.Samples.wValidBitsPerSample = 16;
+ wavfmt.dwChannelMask = rn[rncnt];
+ wavfmt.Format.nBlockAlign = wavfmt.Format.wBitsPerSample / 8 * wavfmt.Format.nChannels;
+ wavfmt.Format.nAvgBytesPerSec = wavfmt.Format.nBlockAlign * wavfmt.Format.nSamplesPerSec;
+ CoTaskMemFree (pwfx);
+ pwfx = NULL;
+ hr = s->pAudioClient->lpVtbl->IsFormatSupported (s->pAudioClient, sharemode, &wavfmt.Format, &pwfx);
+ if (SUCCEEDED (hr) && hr != S_FALSE)
+ break;
+ write_log (L"WASAPI: IsFormatSupported(%d,%08X,%d) %08X\n", sd->channels, rn[rncnt], sd->freq, hr);
+ if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
+ goto error;
+ rncnt++;
+ if (rn[rncnt])
+ continue;
+ if (final)
+ goto error;
+ rncnt = 0;
+ if (sd->freq < 44100) {
+ sd->freq = 44100;
+ continue;
+ }
+ if (sd->freq < 48000) {
+ sd->freq = 48000;
+ continue;
+ }
+ if (sd->channels != 2) {
+ sd->channels = 2;
+ continue;
+ }
+ final = 1;
+ if (pwfx == NULL)
+ goto error;
+ sd->channels = pwfx->nChannels;
+ sd->freq = pwfx->nSamplesPerSec;
+ }
+
+ if (!s->wasapiexclusive) {
+ size = sd->sndbufsize * sd->channels * 16 / 8;
+ s->snd_configsize = size;
+ sd->sndbufsize = size / 32;
+ size /= (sd->channels * 16 / 8);
+ } else {
+ s->hnsRequestedDuration *= sd->sndbufsize / 512;
+ }
+
+ s->bufferFrameCount = (UINT32)( // frames =
+ 1.0 * s->hnsRequestedDuration * // hns *
+ wavfmt.Format.nSamplesPerSec / // (frames / s) /
+ 1000 / // (ms / s) /
+ 10000 // (hns / s) /
+ + 0.5); // rounding
+
+ if (!s->wasapiexclusive) {
+ if (s->bufferFrameCount < size) {
+ s->bufferFrameCount = size;
+ s->hnsRequestedDuration = // hns =
+ (REFERENCE_TIME)(
+ 10000.0 * // (hns / ms) *
+ 1000 * // (ms / s) *
+ s->bufferFrameCount / // frames /
+ wavfmt.Format.nSamplesPerSec // (frames / s)
+ + 0.5 // rounding
+ );
+ }
+ }
+
+ hr = s->pAudioClient->lpVtbl->Initialize (s->pAudioClient,
+ sharemode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ s->hnsRequestedDuration, s->wasapiexclusive ? s->hnsRequestedDuration : 0, &wavfmt.Format, NULL);
+ if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
+ hr = s->pAudioClient->lpVtbl->GetBufferSize (s->pAudioClient, &s->bufferFrameCount);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetBufferSize() %08X\n", hr);
+ goto error;
+ }
+ s->pAudioClient->lpVtbl->Release (s->pAudioClient);
+ s->hnsRequestedDuration = // hns =
+ (REFERENCE_TIME)(
+ 10000.0 * // (hns / ms) *
+ 1000 * // (ms / s) *
+ s->bufferFrameCount / // frames /
+ wavfmt.Format.nSamplesPerSec // (frames / s)
+ + 0.5 // rounding
+ );
+ s->hnsRequestedDuration *= sd->sndbufsize / 512;
+ hr = s->pDevice->lpVtbl->Activate (s->pDevice, &XIID_IAudioClient, CLSCTX_ALL, NULL, (void**)&s->pAudioClient);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: Activate() %08X\n", hr);
+ goto error;
+ }
+ hr = s->pAudioClient->lpVtbl->Initialize (s->pAudioClient,
+ sharemode, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ s->hnsRequestedDuration, s->wasapiexclusive ? s->hnsRequestedDuration : 0, &wavfmt.Format, NULL);
+ }
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: Initialize() %08X\n", hr);
+ goto error;
+ }
+
+ s->wasapihandle = CreateEvent(NULL, FALSE, FALSE, NULL);
+ hr = s->pAudioClient->lpVtbl->SetEventHandle (s->pAudioClient, s->wasapihandle);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: SetEventHandle() %08X\n", hr);
+ goto error;
+ }
+
+ hr = s->pAudioClient->lpVtbl->GetBufferSize (s->pAudioClient, &s->bufferFrameCount);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetBufferSize() %08X\n", hr);
+ goto error;
+ }
+
+ s->hnsRequestedDuration = // hns =
+ (REFERENCE_TIME)(
+ 10000.0 * // (hns / ms) *
+ 1000 * // (ms / s) *
+ s->bufferFrameCount / // frames /
+ wavfmt.Format.nSamplesPerSec // (frames / s)
+ + 0.5 // rounding
+ );
+
+ hr = s->pAudioClient->lpVtbl->GetService (s->pAudioClient, &XIID_IAudioRenderClient, (void**)&s->pRenderClient);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetService(IID_IAudioRenderClient) %08X\n", hr);
+ goto error;
+ }
+
+ hr = s->pAudioClient->lpVtbl->GetService (s->pAudioClient, &XIID_IAudioClock, (void**)&s->pAudioClock);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetService(IID_IAudioClock) %08X\n", hr);
+ } else {
+ hr = s->pAudioClock->lpVtbl->GetFrequency (s->pAudioClock, &s->wasapiclock);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetFrequency() %08X\n", hr);
+ }
+ }
+
+ if (s->wasapiexclusive) {
+ sd->sndbufsize = s->bufferFrameCount * sd->channels * 16 / 8;
+ } else {
+ int v = s->bufferFrameCount * sd->channels * 16 / 8;
+ v /= 2;
+ if (sd->sndbufsize > v)
+ sd->sndbufsize = v;
+ s->wasapigoodsize =s->bufferFrameCount / 2;
+ }
+ s->sndbufframes = sd->sndbufsize / (sd->channels * 16 / 8);
+
+ write_log(L"WASAPI: '%s'\nWASAPI: EX=%d CH=%d FREQ=%d BUF=%d (%d)\n",
+ name, s->wasapiexclusive, sd->channels, sd->freq, sd->sndbufsize, s->bufferFrameCount);
+
+ CoTaskMemFree (pwfx);
+ CoTaskMemFree (name);
+
+ return 1;
+
+error:
+ CoTaskMemFree (pwfx);
+ CoTaskMemFree (name);
+ close_audio_wasapi (sd);
+ return 0;
+}
+
static int open_audio_ds (struct sound_data *sd, int index)
{
struct sound_dp *s = sd->data;
return 0;
}
-int open_sound_device (struct sound_data *sd, int index, int bufsize, int freq, int channels)
+int open_sound_device (struct sound_data *sd, int index, int exclusive, int bufsize, int freq, int channels)
{
int ret = 0;
struct sound_dp *sdp = xcalloc (sizeof (struct sound_dp), 1);
ret = open_audio_ds (sd, index);
else if (sound_devices[index].type == SOUND_DEVICE_PA)
ret = open_audio_pa (sd, index);
+ else if (sound_devices[index].type == SOUND_DEVICE_WASAPI)
+ ret = open_audio_wasapi (sd, index, exclusive);
sd->samplesize = sd->channels * 2;
return ret;
}
close_audio_ds (sd);
else if (sd->devicetype == SOUND_DEVICE_PA)
close_audio_pa (sd);
+ else if (sd->devicetype == SOUND_DEVICE_WASAPI)
+ close_audio_wasapi (sd);
xfree (sd->data);
sd->data = NULL;
}
pause_audio_ds (sd);
else if (sd->devicetype == SOUND_DEVICE_PA)
pause_audio_pa (sd);
+ else if (sd->devicetype == SOUND_DEVICE_WASAPI)
+ pause_audio_wasapi (sd);
}
void resume_sound_device (struct sound_data *sd)
{
resume_audio_ds (sd);
else if (sd->devicetype == SOUND_DEVICE_PA)
resume_audio_pa (sd);
+ else if (sd->devicetype == SOUND_DEVICE_WASAPI)
+ resume_audio_wasapi (sd);
sd->paused = 0;
}
if (currprefs.win32_soundcard >= num)
currprefs.win32_soundcard = changed_prefs.win32_soundcard = 0;
ch = get_audio_nativechannels (currprefs.sound_stereo);
- ret = open_sound_device (sdp, currprefs.win32_soundcard, size, currprefs.sound_freq, ch);
+ ret = open_sound_device (sdp, currprefs.win32_soundcard, currprefs.win32_soundexclusive, size, currprefs.sound_freq, ch);
if (!ret)
return 0;
currprefs.sound_freq = changed_prefs.sound_freq = sdp->freq;
v = 0;
mult = (1000.0 + v);
+ if (avioutput_audio)
+ mult = 1000.0;
if (isvsync () || (avioutput_audio && !compiled_code)) {
vsynctime = vsynctime_orig;
scaled_sample_evtime = scaled_sample_evtime_orig * mult / 1000.0;
if ((0 || sound_debug) && !(tfprev % 10))
write_log (L"s=%+02.1f\n", skipmode);
tfprev = timeframes;
- if (!avioutput_audio)
- sound_setadjust (skipmode);
+ sound_setadjust (skipmode);
}
}
struct sound_dp *s = sd->data;
if (sd->devicetype == SOUND_DEVICE_DS) {
+
HRESULT hr;
DWORD playpos, safepos;
int diff;
return 0;
} else if (sd->devicetype == SOUND_DEVICE_AL) {
+
int v = 0;
alGetError ();
alGetSourcei (s->al_Source, AL_BUFFERS_QUEUED, &v);
if (v < AL_BUFFERS)
return 0;
return 1;
+
+ } else if (sd->devicetype == SOUND_DEVICE_WASAPI) {
+
+ if (WaitForSingleObject (s->wasapihandle, 0) == WAIT_TIMEOUT)
+ return 0;
+ return 1;
+
}
return -1;
}
return -1;
}
+static double sync_sound (double m)
+{
+ double skipmode;
+ if (isvsync ()) {
+
+ skipmode = pow (m < 0 ? -m : m, EXP) / 8;
+ if (m < 0)
+ skipmode = -skipmode;
+ if (skipmode < -ADJUST_VSSIZE)
+ skipmode = -ADJUST_VSSIZE;
+ if (skipmode > ADJUST_VSSIZE)
+ skipmode = ADJUST_VSSIZE;
+
+ } else if (1) {
+
+ skipmode = pow (m < 0 ? -m : m, EXP) / 2;
+ if (m < 0)
+ skipmode = -skipmode;
+ if (skipmode < -ADJUST_SIZE)
+ skipmode = -ADJUST_SIZE;
+ if (skipmode > ADJUST_SIZE)
+ skipmode = ADJUST_SIZE;
+ }
+
+ return skipmode;
+}
+
+static void finish_sound_buffer_wasapi (struct sound_data *sd, uae_u16 *sndbuffer)
+{
+ struct sound_dp *s = sd->data;
+ HRESULT hr;
+ BYTE *pData;
+ DWORD v;
+ double skipmode;
+
+ if (sd->paused)
+ return;
+
+ s->framecounter++;
+ if (s->framecounter > 50) {
+ s->sndbuf = s->sndbuf / s->framecounter;
+ s->framecounter = 2;
+ }
+ if (s->wasapiexclusive) {
+
+ v = WaitForSingleObject (s->wasapihandle, 0);
+ if (v == WAIT_OBJECT_0) {
+ gui_data.sndbuf_status = -1;
+ statuscnt = SND_STATUSCNT;
+ pause_audio_wasapi (sd);
+ resume_audio_wasapi (sd);
+ return;
+ } else if (v == WAIT_TIMEOUT) {
+ if (WaitForSingleObject (s->wasapihandle, 2000) != WAIT_OBJECT_0) {
+ write_log (L"WASAPI: event timed out\n");
+ return;
+ }
+ } else {
+ return;
+ }
+
+ if (s->wasapiclock) {
+
+ double v, v2;
+ UINT64 pos;
+ hr = s->pAudioClock->lpVtbl->GetPosition (s->pAudioClock, &pos, NULL);
+ if (FAILED (hr))
+ return;
+ v = (double)pos;
+ v /= s->wasapiclock;
+ v2 = s->wasapiframes / (double)sd->freq;
+ v = v2 - v;
+ v2 = v * 10000.0 / ((double)s->bufferFrameCount / (double)sd->freq);
+ s->sndbuf += v2 + 10000.0;
+ gui_data.sndbuf = s->sndbuf / s->framecounter;
+ if ((s->framecounter & 7) == 7) {
+ skipmode = sync_sound (gui_data.sndbuf / 70.0);
+ sound_setadjust (skipmode);
+ }
+
+ }
+
+ hr = s->pRenderClient->lpVtbl->GetBuffer (s->pRenderClient, s->bufferFrameCount, &pData);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetBuffer() %08X\n", hr);
+ return;
+ }
+ memcpy (pData, sndbuffer, s->bufferFrameCount * sd->channels * 16 / 8);
+ hr = s->pRenderClient->lpVtbl->ReleaseBuffer (s->pRenderClient, s->bufferFrameCount, 0);
+ s->wasapiframes += s->bufferFrameCount;
+
+ } else {
+
+ int numFramesPadding, avail;
+
+ for (;;) {
+ hr = s->pAudioClient->lpVtbl->GetCurrentPadding (s->pAudioClient, &numFramesPadding);
+ if (FAILED (hr)) {
+ write_log (L"WASAPI: GetCurrentPadding() %08X\n", hr);
+ return;
+ }
+ avail = s->bufferFrameCount - numFramesPadding;
+ if (avail >= s->sndbufframes)
+ break;
+ gui_data.sndbuf_status = 1;
+ statuscnt = SND_STATUSCNT;
+ sleep_millis (1);
+ }
+ s->sndbuf += (s->wasapigoodsize - avail) * 1000 / s->wasapigoodsize;
+ gui_data.sndbuf = s->sndbuf / s->framecounter;
+ if (s->framecounter == 2) {
+ skipmode = sync_sound (gui_data.sndbuf / 70.0);
+ sound_setadjust (skipmode);
+ }
+ hr = s->pRenderClient->lpVtbl->GetBuffer (s->pRenderClient, s->sndbufframes, &pData);
+ if (SUCCEEDED (hr)) {
+ memcpy (pData, sndbuffer, sd->sndbufsize);
+ s->pRenderClient->lpVtbl->ReleaseBuffer (s->pRenderClient, s->sndbufframes, 0);
+ }
+
+ }
+
+}
+
static void finish_sound_buffer_ds (struct sound_data *sd, uae_u16 *sndbuffer)
{
struct sound_dp *s = sd->data;
DWORD s1, s2;
int diff;
int counter;
- static int statuscnt;
-
- if (sd == sdp) {
- if (statuscnt > 0) {
- statuscnt--;
- if (statuscnt == 0)
- gui_data.sndbuf_status = 0;
- }
- if (gui_data.sndbuf_status == 3)
- gui_data.sndbuf_status = 0;
- }
if (!sd->waiting_for_buffer)
return;
- if (savestate_state)
- return;
if (sd->waiting_for_buffer == 1) {
hr = IDirectSoundBuffer_Play (s->lpDSBsecondary, 0, 0, DSBPLAY_LOOPING);
vdiff = diff - s->snd_writeoffset;
m = 100.0 * vdiff / s->max_sndbufsize;
-
- if (isvsync ()) {
-
- skipmode = pow (m < 0 ? -m : m, EXP) / 8;
- if (m < 0)
- skipmode = -skipmode;
- if (skipmode < -ADJUST_VSSIZE)
- skipmode = -ADJUST_VSSIZE;
- if (skipmode > ADJUST_VSSIZE)
- skipmode = ADJUST_VSSIZE;
-
- } else {
-
- skipmode = pow (m < 0 ? -m : m, EXP) / 2;
- if (m < 0)
- skipmode = -skipmode;
- if (skipmode < -ADJUST_SIZE)
- skipmode = -ADJUST_SIZE;
- if (skipmode > ADJUST_SIZE)
- skipmode = ADJUST_SIZE;
-
- }
+ skipmode = sync_sound (m);
if (tfprev != timeframes) {
+ gui_data.sndbuf = vdiff * 1000 / (s->snd_maxoffset - s->snd_writeoffset);
if ((0 || sound_debug) && !(tfprev % 10))
write_log (L"b=%4d,%5d,%5d,%5d d=%5d vd=%5.0f s=%+02.1f\n",
sd->sndbufsize / sd->samplesize, s->snd_configsize / sd->samplesize, s->max_sndbufsize / sd->samplesize,
s->dsoundbuf / sd->samplesize, diff / sd->samplesize, vdiff, skipmode);
tfprev = timeframes;
- if (!avioutput_audio)
- sound_setadjust (skipmode);
- gui_data.sndbuf = vdiff * 1000 / (s->snd_maxoffset - s->snd_writeoffset);
+ sound_setadjust (skipmode);
}
}
void send_sound (struct sound_data *sd, uae_u16 *sndbuffer)
{
+ if (savestate_state)
+ return;
if (sd->devicetype == SOUND_DEVICE_AL)
finish_sound_buffer_al (sd, sndbuffer);
else if (sd->devicetype == SOUND_DEVICE_DS)
finish_sound_buffer_ds (sd, sndbuffer);
else if (sd->devicetype == SOUND_DEVICE_PA)
finish_sound_buffer_pa (sd, sndbuffer);
+ else if (sd->devicetype == SOUND_DEVICE_WASAPI)
+ finish_sound_buffer_wasapi (sd, sndbuffer);
}
void finish_sound_buffer (void)
#endif
if (!have_sound)
return;
+ if (statuscnt > 0) {
+ statuscnt--;
+ if (statuscnt == 0)
+ gui_data.sndbuf_status = 0;
+ }
+ if (gui_data.sndbuf_status == 3)
+ gui_data.sndbuf_status = 0;
send_sound (sdp, paula_sndbuffer);
}
return TRUE;
}
+static void wasapi_enum (struct sound_device *sd)
+{
+ HRESULT hr;
+ IMMDeviceEnumerator *enumerator;
+ IMMDeviceCollection *col;
+ int i, cnt;
+
+ write_log (L"Enumerating WASAPI devices...\n");
+ for (cnt = 0; cnt < MAX_SOUND_DEVICES; cnt++) {
+ if (sd->name == NULL)
+ break;
+ sd++;
+ }
+ if (cnt >= MAX_SOUND_DEVICES)
+ return;
+
+ hr = CoCreateInstance (&XCLSID_MMDeviceEnumerator, NULL,
+ CLSCTX_ALL, &XIID_IMMDeviceEnumerator,
+ (void**)&enumerator);
+ if (SUCCEEDED (hr)) {
+ hr = enumerator->lpVtbl->EnumAudioEndpoints (enumerator, eRender, DEVICE_STATE_ACTIVE, &col);
+ if (SUCCEEDED (hr)) {
+ UINT num;
+ hr = col->lpVtbl->GetCount (col, &num);
+ if (SUCCEEDED (hr)) {
+ for (i = 0; i < num && cnt < MAX_SOUND_DEVICES; i++) {
+ IMMDevice *dev;
+ LPWSTR devid = NULL;
+ LPWSTR devname = NULL;
+ hr = col->lpVtbl->Item (col, i, &dev);
+ if (SUCCEEDED (hr)) {
+ IPropertyStore *prop;
+ dev->lpVtbl->GetId (dev, &devid);
+ hr = dev->lpVtbl->OpenPropertyStore (dev, STGM_READ, &prop);
+ if (SUCCEEDED (hr)) {
+ PROPVARIANT pv;
+ PropVariantInit (&pv);
+ hr = prop->lpVtbl->GetValue (prop, &PKEY_Device_FriendlyName, &pv);
+ if (SUCCEEDED (hr)) {
+ devname = my_strdup (pv.pwszVal);
+ }
+ PropVariantClear (&pv);
+ prop->lpVtbl->Release (prop);
+ }
+ dev->lpVtbl->Release (dev);
+ }
+ if (devid && devname) {
+ TCHAR tmp[MAX_DPATH];
+ if (i == 0) {
+ sd->cfgname = my_strdup (L"WASAPI:Default Audio Device");
+ sd->type = SOUND_DEVICE_WASAPI;
+ sd->name = my_strdup (L"Default Audio Device");
+ sd->alname = NULL;
+ sd++;
+ cnt++;
+ }
+ if (cnt < MAX_SOUND_DEVICES) {
+ _stprintf (tmp, L"WASAPI:%s", devname);
+ sd->cfgname = my_strdup (tmp);
+ sd->type = SOUND_DEVICE_WASAPI;
+ sd->name = my_strdup (devname);
+ sd->alname = my_strdup (devid);
+ sd++;
+ cnt++;
+ }
+ }
+ xfree (devname);
+ CoTaskMemFree (devid);
+ }
+ }
+ col->lpVtbl->Release (col);
+ }
+ enumerator->lpVtbl->Release (enumerator);
+ }
+}
+
static void OpenALEnumerate (struct sound_device *sds, const char *pDeviceNames, const char *ppDefaultDevice, int skipdetect)
{
struct sound_device *sd;
ok = 1;
}
if (ok) {
+ TCHAR tmp[MAX_DPATH];
sd->type = SOUND_DEVICE_AL;
if (ppDefaultDevice) {
- TCHAR tmp[MAX_DPATH];
TCHAR *tdevname = au (devname);
_stprintf (tmp, L"Default [%s]", tdevname);
xfree (tdevname);
sd->alname = my_strdup_ansi (pDeviceNames);
sd->name = my_strdup_ansi (pDeviceNames);
}
- sd->cfgname = my_strdup (sd->alname);
+ _stprintf (tmp, L"OPENAL:%s", sd->alname);
+ sd->cfgname = my_strdup (tmp);
}
if (ppDefaultDevice)
ppDefaultDevice = NULL;
struct sound_device *sd;
int num;
int i, j;
- TCHAR tmp[MAX_DPATH], *s1, *s2;
+ TCHAR tmp[MAX_DPATH], tmp2[MAX_DPATH], *s1, *s2;
num = Pa_GetDeviceCount ();
if (num < 0) {
xfree (s1);
sd->type = SOUND_DEVICE_PA;
sd->name = my_strdup (tmp);
- sd->cfgname = my_strdup (tmp);
+ _stprintf (tmp2, L"PORTAUDIO:%s", tmp);
+ sd->cfgname = my_strdup (tmp2);
sd->panum = j;
}
}
return EXCEPTION_EXECUTE_HANDLER;
}
+int force_directsound;
int enumerate_sound_devices (void)
{
if (!num_sound_devices) {
HMODULE l = NULL;
write_log (L"Enumerating DirectSound devices..\n");
- DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, sound_devices);
- DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK)DSEnumProc, record_devices);
+ if (os_vista)
+ wasapi_enum (sound_devices);
+ if (1 || force_directsound || !os_vista) {
+ DirectSoundEnumerate ((LPDSENUMCALLBACK)DSEnumProc, sound_devices);
+ //DirectSoundCaptureEnumerate ((LPDSENUMCALLBACK)DSEnumProc, record_devices);
+ }
__try {
if (isdllversion (L"openal32.dll", 6, 14, 357, 22)) {
write_log (L"Enumerating OpenAL devices..\n");
*/
const static GUID XIID_MMDeviceEnumerator = {0xBCDE0395,0xE52F,0x467C,
{0x8E,0x3D,0xC4,0x57,0x92,0x91,0x69,0x2E}};
-const static GUID XIID_IMMDeviceEnumerator = {0xA95664D2,0x9614,0x4F35,
- {0xA7,0x46,0xDE,0x8D,0xB6,0x36,0x17,0xE6}};
const static GUID XIID_IAudioEndpointVolume = {0x5CDF2C82, 0x841E,0x4546,
{0x97,0x22,0x0C,0xF7,0x40,0x78,0x22,0x9A}};
void send_sound (struct sound_data *sd, uae_u16 *sndbuffer);
-int open_sound_device (struct sound_data *sd, int index, int bufsize, int freq, int channels);
+int open_sound_device (struct sound_data *sd, int index, int exclusive, int bufsize, int freq, int channels);
void close_sound_device (struct sound_data *sd);
void pause_sound_device (struct sound_data *sd);
void resume_sound_device (struct sound_data *sd);
int get_offset_sound_device (struct sound_data *sd);
int blocking_sound_device (struct sound_data *sd);
+static uae_u16 *paula_sndbufpt_prev, *paula_sndbufpt_start;
-STATIC_INLINE void check_sound_buffers (int outputsample, int doublesample)
+STATIC_INLINE void set_sound_buffers (void)
{
- static uae_u16 *paula_sndbufpt_prev;
- uae_u16 *start;
+#if 0
+ paula_sndbufpt_prev = paula_sndbufpt_start;
+ paula_sndbufpt_start = paula_sndbufpt;
+#endif
+}
+
+STATIC_INLINE void check_sound_buffers (void)
+{
+#if 0
int len;
+#endif
- start = paula_sndbufpt;
if (currprefs.sound_stereo == SND_4CH_CLONEDSTEREO) {
((uae_u16*)paula_sndbufpt)[0] = ((uae_u16*)paula_sndbufpt)[-2];
((uae_u16*)paula_sndbufpt)[1] = ((uae_u16*)paula_sndbufpt)[-1];
p[1] = sum >> 3;
paula_sndbufpt = (uae_u16 *)(((uae_u8 *)paula_sndbufpt) + 4 * 2);
}
- if (outputsample == 0) {
- paula_sndbufpt_prev = start;
+#if 0
+ if (outputsample == 0)
return;
- }
- len = paula_sndbufpt - start;
+ len = paula_sndbufpt - paula_sndbufpt_start;
if (outputsample < 0) {
int i;
uae_s16 *p1 = (uae_s16*)paula_sndbufpt_prev;
- uae_s16 *p2 = (uae_s16*)start;
- for (i = 0; i < len; i++)
- p1[i] = (p1[i] + p2[i]) / 2;
- paula_sndbufpt -= len;
+ uae_s16 *p2 = (uae_s16*)paula_sndbufpt_start;
+ for (i = 0; i < len; i++) {
+ *p1 = (*p1 + *p2) / 2;
+ }
+ paula_sndbufpt = paula_sndbufpt_start;
}
+#endif
if ((uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer >= paula_sndbufsize) {
finish_sound_buffer ();
paula_sndbufpt = paula_sndbuffer;
}
- if (doublesample) {
- memcpy (paula_sndbufpt, start, len * 2);
+#if 0
+ while (doublesample-- > 0) {
+ memcpy (paula_sndbufpt, paula_sndbufpt_start, len * 2);
+ paula_sndbufpt += len;
if ((uae_u8*)paula_sndbufpt - (uae_u8*)paula_sndbuffer >= paula_sndbufsize) {
finish_sound_buffer ();
paula_sndbufpt = paula_sndbuffer;
}
}
+#endif
}
STATIC_INLINE void clear_sound_buffers (void)
#include <dbghelp.h>
#include <float.h>
#include <WtsApi32.h>
+#include <Avrt.h>
#include "resource"
#endif
extern int harddrive_dangerous, do_rdbdump, aspi_allow_all, no_rawinput, rawkeyboard;
+extern int force_directsound;
int log_scsi, log_net, uaelib_debug;
int pissoff_value = 25000;
unsigned int fpucontrol;
static void *tablet;
HCURSOR normalcursor;
static HWND hwndNextViewer;
+static HANDLE AVTask;
TCHAR VersionStr[256];
TCHAR BetaStr[64];
lcd_priority (1);
#endif
clipboard_active (hAmigaWnd, 1);
+ if (os_vista && AVTask == NULL) {
+ DWORD taskIndex = 0;
+ AVTask = AvSetMmThreadCharacteristics (TEXT("Pro Audio"), &taskIndex);
+ }
}
static void winuae_inactive (HWND hWnd, int minimized)
int wasfocus = focus;
write_log (L"winuae_inactive(%d)\n", minimized);
+ if (AVTask)
+ AvRevertMmThreadCharacteristics (AVTask);
+ AVTask = NULL;
if (minimized)
exit_gui (0);
focus = 0;
if (vsFileInfo &&
HIWORD(vsFileInfo->dwProductVersionMS) == UAEMAJOR
&& LOWORD(vsFileInfo->dwProductVersionMS) == UAEMINOR
- && (HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV || HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV - 1)) {
+ && (HIWORD(vsFileInfo->dwProductVersionLS) == UAESUBREV)) {
success = TRUE;
write_log (L"Translation DLL '%s' loaded and enabled\n", dllbuf);
} else {
p->win32_inactive_pause = 0;
p->win32_ctrl_F11_is_quit = 0;
p->win32_soundcard = 0;
+ p->win32_soundexclusive = 0;
p->win32_active_priority = 1;
p->win32_inactive_priority = 2;
p->win32_iconified_priority = 3;
p->win32_rtgscaleaspectratio = -1;
p->win32_rtgvblankrate = 0;
p->win32_fscodepage = 0;
+ p->win32_commandpath[0] = 0;
}
if (type == 1 || type == 0) {
p->win32_uaescsimode = get_aspi (p->win32_uaescsimode);
cfgfile_target_dwrite (f, L"soundcard", L"%d", p->win32_soundcard);
if (sound_devices[p->win32_soundcard].cfgname)
cfgfile_target_dwrite_str (f, L"soundcardname", sound_devices[p->win32_soundcard].cfgname);
+ cfgfile_target_dwrite_bool (f, L"soundcard_exclusive", p->win32_soundexclusive);
cfgfile_target_dwrite (f, L"cpu_idle", L"%d", p->cpu_idle);
cfgfile_target_dwrite_bool (f, L"notaskbarbutton", p->win32_notaskbarbutton);
cfgfile_target_dwrite_bool (f, L"always_on_top", p->win32_alwaysontop);
cfgfile_target_dwrite (f, L"kbledmode", L"%d", p->win32_kbledmode);
cfgfile_target_dwrite_bool (f, L"powersavedisabled", p->win32_powersavedisabled);
cfgfile_target_dwrite (f, L"filesystem_codepage", L"%d", p->win32_fscodepage);
+ cfgfile_target_dwrite_str (f, L"exec", p->win32_commandpath);
}
|| cfgfile_intval (option, value, L"midiout_device", &p->win32_midioutdev, 1)
|| cfgfile_intval (option, value, L"midiin_device", &p->win32_midiindev, 1)
|| cfgfile_intval (option, value, L"soundcard", &p->win32_soundcard, 1)
+ || cfgfile_yesno (option, value, L"soundcard_exclusive", &p->win32_soundexclusive)
|| cfgfile_yesno (option, value, L"notaskbarbutton", &p->win32_notaskbarbutton)
|| cfgfile_yesno (option, value, L"always_on_top", &p->win32_alwaysontop)
|| cfgfile_yesno (option, value, L"powersavedisabled", &p->win32_powersavedisabled)
+ || cfgfile_string (option, value, L"exec", p->win32_commandpath, sizeof p->win32_commandpath / sizeof (TCHAR))
|| cfgfile_intval (option, value, L"specialkey", &p->win32_specialkey, 1)
|| cfgfile_intval (option, value, L"guikey", &p->win32_guikey, 1)
|| cfgfile_intval (option, value, L"kbledmode", &p->win32_kbledmode, 1)
rawkeyboard = 1;
return 1;
}
+ if (!_tcscmp (arg, L"-directsound")) {
+ force_directsound = 1;
+ return 1;
+ }
if (!_tcscmp (arg, L"-scsilog")) {
log_scsi = 1;
return 1;
static TCHAR **parseargstring (TCHAR *s)
{
- int cnt;
+ int cnt, i;
TCHAR **args;
if (_tcslen (s) == 0)
cnt = 0;
for (;;) {
TCHAR *p = s;
+ TCHAR *d, prev;
int skip = 0;
while (*p && _istspace (*p))
p++;
while (*p && !_istspace (*p))
p++;
}
- args[cnt] = xcalloc (p - s + 1, sizeof (TCHAR));
- memcpy (args[cnt++], s, (p - s) * sizeof (TCHAR));
+ args[cnt] = d = xcalloc (p - s + 1, sizeof (TCHAR));
+ memcpy (d, s, (p - s) * sizeof (TCHAR));
+ prev = 0;
+ for (i = 0; d[i]; i++) {
+ TCHAR c = d[i];
+ if (c == '\"' || c == '\'') {
+ memmove (&d[i], &d[i + 1], (_tcslen (&d[i + 1]) + 1) * sizeof (TCHAR));
+ i--;
+ continue;
+ }
+ prev = c;
+ }
+ cnt++;
p += skip;
while (*p && _istspace (*p))
p++;
#define WINUAEPUBLICBETA 1
-#define WINUAEBETA L"Beta 0"
-#define WINUAEDATE MAKEBD(2009, 7, 9)
+#define WINUAEBETA L"Beta 1"
+#define WINUAEDATE MAKEBD(2009, 7, 16)
#define WINUAEEXTRA L""
#define WINUAEREV L""
#define SOUND_DEVICE_DS 1
#define SOUND_DEVICE_AL 2
#define SOUND_DEVICE_PA 3
+#define SOUND_DEVICE_WASAPI 4
struct sound_device
{
OffsetRect (zr, w / 2, h / 2);
}
-static void xymult (int *x, int *y)
-{
- int mult = currprefs.gfx_resolution - (currprefs.gfx_linedbl ? 1 : 0);
- if (mult < 0)
- *x *= 1 << (-mult);
- else
- *y *= 1 << mult;
-}
-
-static int ppp = 320;
-
void getfilterrect2 (RECT *sr, RECT *dr, RECT *zr, int dst_width, int dst_height, int aw, int ah, int scale, int temp_width, int temp_height)
{
float srcratio, dstratio;
static INT_PTR CALLBACK MemoryDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
- int v;
static int recursive = 0;
switch (msg)
static void update_soundgui (HWND hDlg)
{
- int bufsize;
+ int bufsize, canexc;
TCHAR txt[20];
bufsize = exact_log2 (workprefs.sound_maxbsiz / 1024);
_stprintf (txt, L"%d", bufsize);
SetDlgItemText (hDlg, IDC_SOUNDBUFFERMEM, txt);
- SendDlgItemMessage( hDlg, IDC_SOUNDVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.sound_volume);
+ SendDlgItemMessage (hDlg, IDC_SOUNDVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.sound_volume);
_stprintf (txt, L"%d%%", 100 - workprefs.sound_volume);
SetDlgItemText (hDlg, IDC_SOUNDVOLUME2, txt);
- SendDlgItemMessage( hDlg, IDC_SOUNDDRIVEVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.dfxclickvolume);
+ SendDlgItemMessage (hDlg, IDC_SOUNDDRIVEVOLUME, TBM_SETPOS, TRUE, 100 - workprefs.dfxclickvolume);
_stprintf (txt, L"%d%%", 100 - workprefs.dfxclickvolume);
SetDlgItemText (hDlg, IDC_SOUNDDRIVEVOLUME2, txt);
+
+ canexc = sound_devices[workprefs.win32_soundcard].type == SOUND_DEVICE_WASAPI;
+ ew (hDlg, IDC_SOUND_EXCLUSIVE, canexc);
+ if (!canexc)
+ workprefs.win32_soundexclusive = 0;
+ CheckDlgButton (hDlg, IDC_SOUND_EXCLUSIVE, workprefs.win32_soundexclusive);
+
}
static int soundfreqs[] = { 11025, 15000, 22050, 32000, 44100, 48000, 0 };
{
TCHAR txt[10];
LRESULT idx;
+ int soundcard;
idx = SendDlgItemMessage (hDlg, IDC_SOUNDFREQ, CB_GETCURSEL, 0, 0);
if (idx >= 0) {
}
workprefs.sound_interpol = SendDlgItemMessage (hDlg, IDC_SOUNDINTERPOLATION, CB_GETCURSEL, 0, 0);
- workprefs.win32_soundcard = SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_GETCURSEL, 0, 0L);
+ workprefs.win32_soundexclusive = IsDlgButtonChecked (hDlg, IDC_SOUND_EXCLUSIVE) ? 1 : 0;
+ soundcard = SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_GETCURSEL, 0, 0L);
+ if (soundcard != workprefs.win32_soundcard && soundcard != CB_ERR) {
+ workprefs.win32_soundcard = soundcard;
+ update_soundgui (hDlg);
+ }
+
switch (SendDlgItemMessage (hDlg, IDC_SOUNDFILTER, CB_GETCURSEL, 0, 0))
{
case 0:
switch (msg) {
case WM_INITDIALOG:
{
- int gotnonds = 0;
+ recursive++;
sound_loaddrivesamples ();
SendDlgItemMessage (hDlg, IDC_SOUNDBUFFERRAM, TBM_SETRANGE, TRUE, MAKELONG (MIN_SOUND_MEM, MAX_SOUND_MEM));
SendDlgItemMessage (hDlg, IDC_SOUNDBUFFERRAM, TBM_SETPAGESIZE, 0, 1);
SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_RESETCONTENT, 0, 0L);
numdevs = enumerate_sound_devices ();
- for (card = 0; card < numdevs; card++) {
- if (sound_devices[card].type != SOUND_DEVICE_DS)
- gotnonds = 1;
- }
for (card = 0; card < numdevs; card++) {
TCHAR tmp[MAX_DPATH];
int type = sound_devices[card].type;
- if (gotnonds)
- _stprintf (tmp, L"%s: %s", type == SOUND_DEVICE_DS ? L"DS" : (type == SOUND_DEVICE_AL ? L"AL" : L"PA"),
- sound_devices[card].name);
- else
- _tcscpy (tmp, sound_devices[card].name);
+ _stprintf (tmp, L"%s: %s",
+ type == SOUND_DEVICE_DS ? L"DSOUND" : (type == SOUND_DEVICE_AL ? L"OpenAL" : (type == SOUND_DEVICE_PA ? L"PortAudio" : L"WASAPI")),
+ sound_devices[card].name);
SendDlgItemMessage (hDlg, IDC_SOUNDCARDLIST, CB_ADDSTRING, 0, (LPARAM)tmp);
}
if (numdevs == 0)
pages[SOUND_ID] = hDlg;
currentpage = SOUND_ID;
+ update_soundgui (hDlg);
+ recursive--;
}
case WM_USER:
recursive++;
<Tool
Name="VCLinkerTool"
AdditionalOptions="/MACHINE:I386"
- AdditionalDependencies="opengl32.lib ws2_32.lib ddraw.lib dxguid.lib winmm.lib comctl32.lib version.lib msacm32.lib dsound.lib dinput8.lib d3d9.lib d3dx9.lib winio.lib setupapi.lib wininet.lib dxerr9.lib shlwapi.lib zlibstat.lib libpng.lib lglcd.lib wpcap.lib packet.lib openal32.lib wintab32.lib portaudio_x86.lib freetype.lib vfw32.lib wtsapi32.lib"
+ AdditionalDependencies="ws2_32.lib ddraw.lib dxguid.lib winmm.lib comctl32.lib version.lib msacm32.lib dsound.lib dinput8.lib d3d9.lib d3dx9.lib winio.lib setupapi.lib wininet.lib dxerr9.lib shlwapi.lib zlibstat.lib libpng.lib lglcd.lib wpcap.lib packet.lib openal32.lib wintab32.lib portaudio_x86.lib freetype.lib vfw32.lib wtsapi32.lib avrt.lib"
ShowProgress="0"
OutputFile="d:\amiga\winuae.exe"
LinkIncremental="2"
SuppressStartupBanner="true"
GenerateManifest="false"
- DelayLoadDLLs="wpcap.dll;packet.dll;d3dx9_41.dll;openal32.dll;wintab32.dll;portaudio_x86.dll;freetype6.dll;ws2_32.dll;msacm32.dll;wtsapi32.dll"
+ DelayLoadDLLs="wpcap.dll;packet.dll;d3dx9_41.dll;openal32.dll;wintab32.dll;portaudio_x86.dll;freetype6.dll;ws2_32.dll;msacm32.dll;wtsapi32.dll;dsound.dll;avrt.dll"
GenerateDebugInformation="true"
ProgramDatabaseFile=".\Debug/winuae.pdb"
SubSystem="2"
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="opengl32.lib ws2_32.lib ddraw.lib dxguid.lib winmm.lib comctl32.lib version.lib msacm32.lib dsound.lib dinput8.lib d3d9.lib d3dx9.lib winio.lib setupapi.lib wininet.lib dxerr9.lib shlwapi.lib zlibstat.lib libpng.lib lglcd.lib wpcap.lib packet.lib openal32.lib wintab32.lib portaudio_x86.lib freetype.lib vfw32.lib wtsapi32.lib"
+ AdditionalDependencies="ws2_32.lib ddraw.lib dxguid.lib winmm.lib comctl32.lib version.lib msacm32.lib dsound.lib dinput8.lib d3d9.lib d3dx9.lib winio.lib setupapi.lib wininet.lib dxerr9.lib shlwapi.lib zlibstat.lib libpng.lib lglcd.lib wpcap.lib packet.lib openal32.lib wintab32.lib portaudio_x86.lib freetype.lib vfw32.lib wtsapi32.lib avrt.lib"
OutputFile="d:\amiga\winuae.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories=""
GenerateManifest="true"
AdditionalManifestDependencies=""
- DelayLoadDLLs="wpcap.dll;packet.dll;d3dx9_41.dll;openal32.dll;wintab32.dll;portaudio_x86.dll;freetype6.dlll;ws2_32.dll;msacm32.dll;wtsapi32.dll"
+ DelayLoadDLLs="wpcap.dll;packet.dll;d3dx9_41.dll;openal32.dll;wintab32.dll;portaudio_x86.dll;freetype6.dll;ws2_32.dll;msacm32.dll;wtsapi32.dll;dsound.dll;avrt.dll"
GenerateDebugInformation="true"
ProgramDatabaseFile=".\Release/winuae.pdb"
SubSystem="2"
/>
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="opengl32.lib ws2_32.lib ddraw.lib dxguid.lib winmm.lib comctl32.lib version.lib msacm32.lib dsound.lib dinput8.lib d3d9.lib d3dx9.lib winio.lib setupapi.lib wininet.lib dxerr9.lib shlwapi.lib zlibstat.lib libpng.lib lglcd.lib wpcap.lib packet.lib openal32.lib wintab32.lib portaudio_x86.lib freetype.lib vfw32.lib wtsapi32.lib"
+ AdditionalDependencies="ws2_32.lib ddraw.lib dxguid.lib winmm.lib comctl32.lib version.lib msacm32.lib dsound.lib dinput8.lib d3d9.lib d3dx9.lib winio.lib setupapi.lib wininet.lib dxerr9.lib shlwapi.lib zlibstat.lib libpng.lib lglcd.lib wpcap.lib packet.lib openal32.lib wintab32.lib portaudio_x86.lib freetype.lib vfw32.lib wtsapi32.lib avrt.lib"
OutputFile="d:\amiga\winuae.exe"
LinkIncremental="1"
SuppressStartupBanner="true"
AdditionalLibraryDirectories=""
GenerateManifest="true"
AdditionalManifestDependencies=""
- DelayLoadDLLs="wpcap.dll;packet.dll;d3dx9_41.dll;openal32.dll;wintab32.dll;portaudio_x86.dll;freetype6.dll;opengl32.dll;ws2_32.dll;msacm32.dll;wtsapi32.dll"
+ DelayLoadDLLs="wpcap.dll;packet.dll;d3dx9_41.dll;openal32.dll;wintab32.dll;portaudio_x86.dll;freetype6.dll;ws2_32.dll;msacm32.dll;wtsapi32.dll;dsound.dll;avrt.dll"
GenerateDebugInformation="true"
ProgramDatabaseFile=".\FullRelease/winuae.pdb"
SubSystem="2"
latency (in worst case it may increase power requirements..)
- marked DLLs that are rarely used/only in specific configurations
as delay loaded, may make startup slightly faster
-- programmed display modes had bad sound (161b4 sound update was not
- fully complete.. most stupid 1.6.1 bug so far)
-- "Add PC drives at startup" does not anymore mount drives that are
- also configured as real harddrives
- inserting/ejecting USB input devices on the fly replaced all "<none>"
and all keyboard layouts with keyboard layout A (old bug)
-- portaudio fallback code added, unsupported samplerate = try 44000,
- 48000 and default reported before disabling sound. Same with number
- of channels, unsupported channels = fall back to stereo
+- "Add PC drives at startup" does not anymore mount drives that are
+ also configured as real harddrives
- real harddrive safetycheck modified, now all drives can be mounted as
long as drive does not have any Windows mounted partitions. Any drive
with one or more Windows mounted partitions are only available in read
read-write mode.
- SCSI (RDB hdf emulation) write commands return proper write protected
sense status if hdf is read-only
+- A590/A2091 SCSI ROM 7.0 was not accepted (debugging code..)
+- RDB filesystem loader still had fse_PatchFlags hack instead of
+ handling it 100% correctly (no functional change, at least with any
+ popular filesystem)
+- accept also partition type 0x30 (another Amithlon like RDB drive
+ inside real PC partition)
+- added new RTG configuration panel, more space for future options, also
+ old RTG setting panel was not really in correct place anymore
+- command line parsing didn't handle quotes inside strings as Windows
+ does when running from command line
+
+- added bitplane DMA fetches to copper debugger (there will be separate
+ DMA sequence "disassembler" in future)
+- Agnus bitplane DMA behavior correctly emulated when number of planes
+ or resolution changes mid screen. Old code was totally wrong and too
+ complex.. Now all my test statefiles work 100% correctly:
+ Disposable Hero, Bass-O-Matic/Crusaders, Innovation Part 2/Axxis
+ Brian The Lion "dialog" screen is corrupted again but this seems to be
+ AGA specific feature (SMD chips = no logic analyzer)
+
- CD32 CD controller emulation improved, CDXL animations should run more
smoothly now, previously emulation couldn't load more than few sectors
- before cd driver decided to read some previously loaded sectors again
+ before cd driver detected error condition and retried
- added seek delays to CD32 emulation (CD32 drive has really slow seeks)
-- CD32 Lotus Trilogy's Lotus 3 finally loads (stupid loader overwriting
- already loaded data if CD DMA sequence is not identical to real
- hardware)
+- CD32 Lotus Trilogy's Lotus 3 finally loads (stupid loader partially
+ overwriting already loaded data if CD DMA "slot" sequencing is not
+ exactly correct)
- CD32 CD audio moved to separate thread, no more emulator pausing when
CD audio starts or track changes (possibly introduces other issues..)
-- distortion in sound was possible with short square wave samples (160)
-- final 16-bit sound samples always had lowest bit (or two lowest bits)
- zero, now lowest bit(s) are duplicated from real lowest significant
- bit(s)
-- A590/A2091 SCSI ROM 7.0 was not accepted (debugging code..)
-- added new RTG configuration panel, more space for future options, also
- old RTG setting panel was not really in correct place anymore
-- RDB filesystem loader still had fse_PatchFlags hack instead of
- handling it 100% correctly (no functional change, at least with any
- popular filesystem)
-- D3D 2D sprites (ID3DXSPrite) used in D3D filter onscreen leds, correct
+
+- D3D 2D sprites (ID3DXSprite) used in D3D filter onscreen leds, correct
positioning, no scaling and free transparency. Scanline texture also
converted to 2D sprite, now works correctly with D3D filters (future
plan: convert all DirectDraw code to D3D 2D sprites)
-- accept also partition type 0x30 (another Amithlon like RDB drive
- inside real PC partition)
- OpenGL filter removed, totally obsolete now. Gone forever unless
someone updates it. (includes correct positioning and scaling)
+- built-in WASAPI sound driver implemented. Replaces DirectSound if
+ running on Vista or newer. WASAPI has two modes, shared and
+ exclusive. Shared roughly equals old DirectSound, exclusive means
+ sound card is exclusively used by WinUAE. Exclusive mode has lowest
+ possibly latency but note that there may be only one or two
+ supported sample rates (for example 48000). NOTE: buffer sizes
+ can not be directly compared between different modes. PortAudio
+ is now considered very unsupported (that didn't last long..)
+ Needs tuning, not good enough yet (especially exclusive mode)
+- distortion in sound was possible with short square wave samples (160)
+- final 16-bit sound samples always had lowest bit (or two lowest bits)
+ zero, now lowest bit(s) are duplicated from real lowest significant
+ bit(s)
+- programmed display modes had bad sound (161b4 sound update was not
+ fully complete.. most stupid 1.6.1 bug so far)
+- portaudio fallback code added, unsupported samplerate = try 44000,
+ 48000 and default reported before disabling sound. Same with number
+ of channels, unsupported channels = fall back to stereo
+
+- Vista or newer: AvSetMmThreadCharacteristics() is used to enable
+ task scheduling better suited for multimedia applications = more
+ CPU time given without slowing down lower priority tasks (which
+ can happen with normal priority settings)
+
+
1.6.1
Beta 5: (1.6.1 RC)