[PATCH variant 1] dsound: use a low-quality FIR for games

Alexander E. Patrakov patrakov at gmail.com
Sat May 19 10:09:35 CDT 2012


There is a bug (#30639) caused by the fact that the new high-quality
resampler reportedly wants to eat more than 100% CPU for some games.
Something is needed to reduce the CPU usage in games, while preserving
high quality in music players. We can tell whether the program is a
game (and thus needs a high-performance resampler) or a music player
(that needs high quality) by the number of its secondary buffers.

There are two ways to implement a high-performance resampler, and I
have prepared (conflicting, pick no more than one) patches for both:

1 (this patch): Use a shorter FIR with the existing code. This has the
advantage of higher quality (unwanted frequencies are at least
attempted to be rejected) and almost no new code.
2 (the other patch): Write new code. E.g., linear interpolation. This
is what Windows XP does at its lowest quality setting, and it eats
less CPU than variant 1.

Zero-order hold is IMHO not an option even for games because of
too-bad quality (worse than linear interpolation). SSE has been
mentioned before, but something has changed in my system and I cannot
reproduce the speedup anymore, even though GCC properly autovectorizes
the FIR-based resampler given -O3 -ffast-math -msse2.

Here are some preformance numbers from my system. They are from
Darwinia Demo. It is not affected by the bug, but it is rather close.
Darwinia Demo creates 32 secondary buffers with various weird rates
ranging from 30 to 70 kHz and mixes them to 22050 Hz. The benchmark
is: let it run, enable thread display in htop, watch the numbers. In
both cases, there are two processes (or threads?) eating the CPU.

Wine with a high-quality resampler: the process with the lower number
eats 95-110% CPU (depending on the graphical complexity), the one with
the higher number eats 46%.
Wine with a debugging patch that forces the primary buffer to 48 kHz:
100% and 60%, respectively.
Wine with variant 1 (this patch): the process with the lower number
eats 75% CPU, the one with the higher number eats 14%.
Wine with variant 2 (the other patch): the process with the lower
number eats 56% CPU, the one with the higher number eats 6%.

Note that for some yet-unknown reason CPU consumption of BOTH
processes changes due to a sound-related patch.

Also note that, as evicenced by the debugging patch, a Core 2 Duo
E6420 @ 2.13 GHz _can_ resample more than 32 streams simultaneously
from various weird rates to 48000 Hz. As GTA:SA reportedly creates
only 16 secondary buffers, it _should_ have more than enough CPU time
to mix them. IMHO, this makes bug #30639 look somewhat strange: on
GyB's computer, GTA:SA stutters, while Darwinia (which looks more
demanding about sound) doesn't. It may well be that in fact none of my
patches are needed, and that the real bug is that the CPU-intensive
cp_fields() function is called from a wrong thread or process. I don't
have the expertise needed to debug this.

-- 
Alexander E. Patrakov
-------------- next part --------------
From 612133d414fd6a6f4d5ee6c61fed3673248d3ecb Mon Sep 17 00:00:00 2001
From: "Alexander E. Patrakov" <patrakov at gmail.com>
Date: Sat, 19 May 2012 19:11:51 +0600
Subject: [PATCH] dsound: use a low-quality FIR for games

---
 dlls/dsound/dsound_main.c    |    5 +
 dlls/dsound/dsound_private.h |    1 +
 dlls/dsound/fir.h            |  248 +++++++++++++++++++++++++++++++++++++++++-
 dlls/dsound/mixer.c          |   25 ++++-
 tools/make_fir               |  175 ++++++++++++++----------------
 5 files changed, 357 insertions(+), 97 deletions(-)

diff --git a/dlls/dsound/dsound_main.c b/dlls/dsound/dsound_main.c
index 76b71c9..7c7cfcf 100644
--- a/dlls/dsound/dsound_main.c
+++ b/dlls/dsound/dsound_main.c
@@ -95,6 +95,7 @@ int ds_hel_buflen = 32768 * 2;
 int ds_snd_queue_max = 10;
 int ds_default_sample_rate = 44100;
 int ds_default_bits_per_sample = 16;
+int ds_hq_buffers_max = 4;
 static HINSTANCE instance;
 
 /*
@@ -157,6 +158,9 @@ void setup_dsound_options(void)
     if (!get_config_key( hkey, appkey, "DefaultBitsPerSample", buffer, MAX_PATH ))
         ds_default_bits_per_sample = atoi(buffer);
 
+    if (!get_config_key( hkey, appkey, "HQBuffersMax", buffer, MAX_PATH ))
+        ds_hq_buffers_max = atoi(buffer);
+
     if (appkey) RegCloseKey( appkey );
     if (hkey) RegCloseKey( hkey );
 
@@ -164,6 +168,7 @@ void setup_dsound_options(void)
     TRACE("ds_snd_queue_max = %d\n", ds_snd_queue_max);
     TRACE("ds_default_sample_rate = %d\n", ds_default_sample_rate);
     TRACE("ds_default_bits_per_sample = %d\n", ds_default_bits_per_sample);
+    TRACE("ds_hq_buffers_max = %d\n", ds_hq_buffers_max);
 }
 
 static const char * get_device_id(LPCGUID pGuid)
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 45c8c5d..7204376 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -35,6 +35,7 @@ extern int ds_snd_queue_max DECLSPEC_HIDDEN;
 extern int ds_snd_shadow_maxsize DECLSPEC_HIDDEN;
 extern int ds_default_sample_rate DECLSPEC_HIDDEN;
 extern int ds_default_bits_per_sample DECLSPEC_HIDDEN;
+extern int ds_hq_buffers_max DECLSPEC_HIDDEN;
 
 /*****************************************************************************
  * Predeclare the interface implementation structures
diff --git a/dlls/dsound/fir.h b/dlls/dsound/fir.h
index 0b54c16..013d4f9 100644
--- a/dlls/dsound/fir.h
+++ b/dlls/dsound/fir.h
@@ -1,7 +1,7 @@
 /* generated by tools/make_fir; DO NOT EDIT! */
-static const int fir_len = 7907;
 static const int fir_step = 120;
-static const float fir[] = {
+static const int fir_len_hq = 7907;
+static const float fir_hq[] = {
 -0.0000000000, -0.0000021601, -0.0000043304, -0.0000065096, -0.0000086969,
 -0.0000108911, -0.0000130912, -0.0000152960, -0.0000175046, -0.0000197157,
 -0.0000219284, -0.0000241414, -0.0000263537, -0.0000285642, -0.0000307717,
@@ -1585,3 +1585,247 @@ static const float fir[] = {
 -0.0000130912, -0.0000108911, -0.0000086969, -0.0000065096, -0.0000043304,
 -0.0000021601, -0.0000000000
 };
+static const int fir_len_lq = 1203;
+static const float fir_lq[] = {
+0.0000000000, -0.0000168070, -0.0000341564, -0.0000520528, -0.0000705003,
+-0.0000895027, -0.0001090636, -0.0001291862, -0.0001498735, -0.0001711280,
+-0.0001929520, -0.0002153473, -0.0002383155, -0.0002618577, -0.0002859746,
+-0.0003106664, -0.0003359332, -0.0003617742, -0.0003881887, -0.0004151750,
+-0.0004427313, -0.0004708551, -0.0004995437, -0.0005287934, -0.0005586004,
+-0.0005889603, -0.0006198680, -0.0006513179, -0.0006833039, -0.0007158193,
+-0.0007488567, -0.0007824083, -0.0008164654, -0.0008510189, -0.0008860590,
+-0.0009215752, -0.0009575564, -0.0009939908, -0.0010308659, -0.0010681685,
+-0.0011058848, -0.0011440002, -0.0011824994, -0.0012213662, -0.0012605840,
+-0.0013001352, -0.0013400015, -0.0013801638, -0.0014206024, -0.0014612966,
+-0.0015022250, -0.0015433654, -0.0015846950, -0.0016261897, -0.0016678252,
+-0.0017095760, -0.0017514158, -0.0017933176, -0.0018352536, -0.0018771950,
+-0.0019191124, -0.0019609755, -0.0020027529, -0.0020444128, -0.0020859224,
+-0.0021272479, -0.0021683549, -0.0022092081, -0.0022497715, -0.0022900080,
+-0.0023298799, -0.0023693487, -0.0024083751, -0.0024469190, -0.0024849394,
+-0.0025223946, -0.0025592422, -0.0025954391, -0.0026309413, -0.0026657040,
+-0.0026996820, -0.0027328291, -0.0027650986, -0.0027964430, -0.0028268142,
+-0.0028561634, -0.0028844413, -0.0029115979, -0.0029375827, -0.0029623445,
+-0.0029858317, -0.0030079920, -0.0030287730, -0.0030481213, -0.0030659834,
+-0.0030823055, -0.0030970330, -0.0031101112, -0.0031214852, -0.0031310995,
+-0.0031388985, -0.0031448265, -0.0031488272, -0.0031508447, -0.0031508224,
+-0.0031487040, -0.0031444330, -0.0031379530, -0.0031292075, -0.0031181400,
+-0.0031046944, -0.0030888146, -0.0030704445, -0.0030495285, -0.0030260112,
+-0.0029998376, -0.0029709531, -0.0029393033, -0.0029048345, -0.0028674935,
+-0.0028272277, -0.0027839851, -0.0027377142, -0.0026883647, -0.0026358866,
+-0.0025802311, -0.0025213502, -0.0024591967, -0.0023937247, -0.0023248892,
+-0.0022526464, -0.0021769537, -0.0020977697, -0.0020150543, -0.0019287690,
+-0.0018388764, -0.0017453409, -0.0016481283, -0.0015472060, -0.0014425433,
+-0.0013341110, -0.0012218819, -0.0011058305, -0.0009859334, -0.0008621692,
+-0.0007345185, -0.0006029640, -0.0004674907, -0.0003280859, -0.0001847390,
+-0.0000374421, 0.0001138104, 0.0002690217, 0.0004281923, 0.0005913199,
+0.0007583998, 0.0009294242, 0.0011043829, 0.0012832624, 0.0014660464,
+0.0016527156, 0.0018432477, 0.0020376171, 0.0022357952, 0.0024377500,
+0.0026434463, 0.0028528456, 0.0030659059, 0.0032825817, 0.0035028241,
+0.0037265807, 0.0039537952, 0.0041844081, 0.0044183558, 0.0046555712,
+0.0048959834, 0.0051395175, 0.0053860950, 0.0056356333, 0.0058880459,
+0.0061432425, 0.0064011287, 0.0066616059, 0.0069245718, 0.0071899198,
+0.0074575392, 0.0077273153, 0.0079991292, 0.0082728579, 0.0085483741,
+0.0088255465, 0.0091042395, 0.0093843134, 0.0096656244, 0.0099480242,
+0.0102313607, 0.0105154774, 0.0108002136, 0.0110854048, 0.0113708819,
+0.0116564720, 0.0119419980, 0.0122272787, 0.0125121290, 0.0127963596,
+0.0130797775, 0.0133621856, 0.0136433827, 0.0139231643, 0.0142013216,
+0.0144776424, 0.0147519105, 0.0150239065, 0.0152934071, 0.0155601855,
+0.0158240119, 0.0160846527, 0.0163418712, 0.0165954276, 0.0168450790,
+0.0170905794, 0.0173316800, 0.0175681291, 0.0177996724, 0.0180260530,
+0.0182470115, 0.0184622861, 0.0186716127, 0.0188747253, 0.0190713556,
+0.0192612337, 0.0194440878, 0.0196196446, 0.0197876293, 0.0199477657,
+0.0200997766, 0.0202433838, 0.0203783081, 0.0205042698, 0.0206209885,
+0.0207281836, 0.0208255742, 0.0209128795, 0.0209898188, 0.0210561117,
+0.0211114786, 0.0211556404, 0.0211883190, 0.0212092373, 0.0212181198,
+0.0212146922, 0.0211986822, 0.0211698193, 0.0211278351, 0.0210724637,
+0.0210034417, 0.0209205085, 0.0208234065, 0.0207118814, 0.0205856823,
+0.0204445620, 0.0202882774, 0.0201165892, 0.0199292628, 0.0197260681,
+0.0195067799, 0.0192711782, 0.0190190481, 0.0187501804, 0.0184643719,
+0.0181614252, 0.0178411494, 0.0175033601, 0.0171478795, 0.0167745373,
+0.0163831701, 0.0159736222, 0.0155457456, 0.0150994004, 0.0146344551,
+0.0141507864, 0.0136482800, 0.0131268306, 0.0125863420, 0.0120267277,
+0.0114479106, 0.0108498239, 0.0102324109, 0.0095956252, 0.0089394311,
+0.0082638039, 0.0075687299, 0.0068542068, 0.0061202438, 0.0053668620,
+0.0045940943, 0.0038019859, 0.0029905945, 0.0021599902, 0.0013102560,
+0.0004414881, -0.0004462045, -0.0013526992, -0.0022778597, -0.0032215362,
+-0.0041835650, -0.0051637681, -0.0061619535, -0.0071779147, -0.0082114308,
+-0.0092622659, -0.0103301697, -0.0114148768, -0.0125161065, -0.0136335633,
+-0.0147669361, -0.0159158987, -0.0170801092, -0.0182592102, -0.0194528286,
+-0.0206605756, -0.0218820467, -0.0231168215, -0.0243644636, -0.0256245208,
+-0.0268965249, -0.0281799917, -0.0294744212, -0.0307792970, -0.0320940870,
+-0.0334182432, -0.0347512013, -0.0360923814, -0.0374411877, -0.0387970082,
+-0.0401592157, -0.0415271669, -0.0429002030, -0.0442776498, -0.0456588174,
+-0.0470430010, -0.0484294802, -0.0498175200, -0.0512063701, -0.0525952656,
+-0.0539834271, -0.0553700607, -0.0567543584, -0.0581354980, -0.0595126436,
+-0.0608849457, -0.0622515413, -0.0636115545, -0.0649640963, -0.0663082653,
+-0.0676431476, -0.0689678173, -0.0702813366, -0.0715827564, -0.0728711164,
+-0.0741454454, -0.0754047618, -0.0766480738, -0.0778743799, -0.0790826690,
+-0.0802719210, -0.0814411073, -0.0825891908, -0.0837151266, -0.0848178625,
+-0.0858963390, -0.0869494904, -0.0879762443, -0.0889755232, -0.0899462439,
+-0.0908873186, -0.0917976554, -0.0926761582, -0.0935217280, -0.0943332627,
+-0.0951096580, -0.0958498079, -0.0965526050, -0.0972169414, -0.0978417089,
+-0.0984257996, -0.0989681065, -0.0994675244, -0.0999229498, -0.1003332820,
+-0.1006974233, -0.1010142801, -0.1012827629, -0.1015017873, -0.1016702743,
+-0.1017871512, -0.1018513520, -0.1018618180, -0.1018174985, -0.1017173514,
+-0.1015603439, -0.1013454527, -0.1010716653, -0.1007379799, -0.1003434068,
+-0.0998869680, -0.0993676990, -0.0987846484, -0.0981368792, -0.0974234691,
+-0.0966435111, -0.0957961143, -0.0948804046, -0.0938955247, -0.0928406356,
+-0.0917149165, -0.0905175656, -0.0892478011, -0.0879048612, -0.0864880049,
+-0.0849965128, -0.0834296875, -0.0817868542, -0.0800673611, -0.0782705803,
+-0.0763959083, -0.0744427662, -0.0724106005, -0.0702988839, -0.0681071152,
+-0.0658348203, -0.0634815527, -0.0610468937, -0.0585304530, -0.0559318695,
+-0.0532508113, -0.0504869764, -0.0476400932, -0.0447099206, -0.0416962491,
+-0.0385989003, -0.0354177281, -0.0321526187, -0.0288034909, -0.0253702968,
+-0.0218530218, -0.0182516850, -0.0145663399, -0.0107970740, -0.0069440096,
+-0.0030073042, 0.0010128500, 0.0051162249, 0.0093025570, 0.0135715469,
+0.0179228591, 0.0223561219, 0.0268709272, 0.0314668305, 0.0361433504,
+0.0408999690, 0.0457361316, 0.0506512463, 0.0556446847, 0.0607157809,
+0.0658638326, 0.0710881001, 0.0763878069, 0.0817621396, 0.0872102479,
+0.0927312449, 0.0983242068, 0.1039881735, 0.1097221485, 0.1155250988,
+0.1213959558, 0.1273336146, 0.1333369350, 0.1394047412, 0.1455358225,
+0.1517289331, 0.1579827929, 0.1642960873, 0.1706674680, 0.1770955531,
+0.1835789275, 0.1901161435, 0.1967057207, 0.2033461471, 0.2100358791,
+0.2167733421, 0.2235569310, 0.2303850107, 0.2372559165, 0.2441679550,
+0.2511194042, 0.2581085145, 0.2651335088, 0.2721925837, 0.2792839097,
+0.2864056320, 0.2935558713, 0.3007327240, 0.3079342635, 0.3151585406,
+0.3224035841, 0.3296674019, 0.3369479813, 0.3442432904, 0.3515512781,
+0.3588698755, 0.3661969966, 0.3735305389, 0.3808683842, 0.3882084001,
+0.3955484398, 0.4028863439, 0.4102199409, 0.4175470479, 0.4248654719,
+0.4321730104, 0.4394674526, 0.4467465799, 0.4540081672, 0.4612499838,
+0.4684697943, 0.4756653594, 0.4828344370, 0.4899747833, 0.4970841535,
+0.5041603030, 0.5112009881, 0.5182039673, 0.5251670023, 0.5320878584,
+0.5389643065, 0.5457941230, 0.5525750916, 0.5593050038, 0.5659816604,
+0.5726028718, 0.5791664596, 0.5856702573, 0.5921121113, 0.5984898819,
+0.6048014444, 0.6110446900, 0.6172175264, 0.6233178794, 0.6293436935,
+0.6352929329, 0.6411635824, 0.6469536483, 0.6526611597, 0.6582841687,
+0.6638207521, 0.6692690118, 0.6746270759, 0.6798930993, 0.6850652650,
+0.6901417846, 0.6951208995, 0.7000008811, 0.7047800325, 0.7094566885,
+0.7140292170, 0.7184960191, 0.7228555308, 0.7271062228, 0.7312466018,
+0.7352752112, 0.7391906314, 0.7429914809, 0.7466764168, 0.7502441354,
+0.7536933731, 0.7570229064, 0.7602315532, 0.7633181730, 0.7662816675,
+0.7691209809, 0.7718351012, 0.7744230595, 0.7768839316, 0.7792168377,
+0.7814209432, 0.7834954589, 0.7854396417, 0.7872527944, 0.7889342667,
+0.7904834550, 0.7918998030, 0.7931828018, 0.7943319901, 0.7953469549,
+0.7962273310, 0.7969728016, 0.7975830985, 0.7980580018, 0.7983973407,
+0.7986009930, 0.7986688852, 0.7986009930, 0.7983973407, 0.7980580018,
+0.7975830985, 0.7969728016, 0.7962273310, 0.7953469549, 0.7943319901,
+0.7931828018, 0.7918998030, 0.7904834550, 0.7889342667, 0.7872527944,
+0.7854396417, 0.7834954589, 0.7814209432, 0.7792168377, 0.7768839316,
+0.7744230595, 0.7718351012, 0.7691209809, 0.7662816675, 0.7633181730,
+0.7602315532, 0.7570229064, 0.7536933731, 0.7502441354, 0.7466764168,
+0.7429914809, 0.7391906314, 0.7352752112, 0.7312466018, 0.7271062228,
+0.7228555308, 0.7184960191, 0.7140292170, 0.7094566885, 0.7047800325,
+0.7000008811, 0.6951208995, 0.6901417846, 0.6850652650, 0.6798930993,
+0.6746270759, 0.6692690118, 0.6638207521, 0.6582841687, 0.6526611597,
+0.6469536483, 0.6411635824, 0.6352929329, 0.6293436935, 0.6233178794,
+0.6172175264, 0.6110446900, 0.6048014444, 0.5984898819, 0.5921121113,
+0.5856702573, 0.5791664596, 0.5726028718, 0.5659816604, 0.5593050038,
+0.5525750916, 0.5457941230, 0.5389643065, 0.5320878584, 0.5251670023,
+0.5182039673, 0.5112009881, 0.5041603030, 0.4970841535, 0.4899747833,
+0.4828344370, 0.4756653594, 0.4684697943, 0.4612499838, 0.4540081672,
+0.4467465799, 0.4394674526, 0.4321730104, 0.4248654719, 0.4175470479,
+0.4102199409, 0.4028863439, 0.3955484398, 0.3882084001, 0.3808683842,
+0.3735305389, 0.3661969966, 0.3588698755, 0.3515512781, 0.3442432904,
+0.3369479813, 0.3296674019, 0.3224035841, 0.3151585406, 0.3079342635,
+0.3007327240, 0.2935558713, 0.2864056320, 0.2792839097, 0.2721925837,
+0.2651335088, 0.2581085145, 0.2511194042, 0.2441679550, 0.2372559165,
+0.2303850107, 0.2235569310, 0.2167733421, 0.2100358791, 0.2033461471,
+0.1967057207, 0.1901161435, 0.1835789275, 0.1770955531, 0.1706674680,
+0.1642960873, 0.1579827929, 0.1517289331, 0.1455358225, 0.1394047412,
+0.1333369350, 0.1273336146, 0.1213959558, 0.1155250988, 0.1097221485,
+0.1039881735, 0.0983242068, 0.0927312449, 0.0872102479, 0.0817621396,
+0.0763878069, 0.0710881001, 0.0658638326, 0.0607157809, 0.0556446847,
+0.0506512463, 0.0457361316, 0.0408999690, 0.0361433504, 0.0314668305,
+0.0268709272, 0.0223561219, 0.0179228591, 0.0135715469, 0.0093025570,
+0.0051162249, 0.0010128500, -0.0030073042, -0.0069440096, -0.0107970740,
+-0.0145663399, -0.0182516850, -0.0218530218, -0.0253702968, -0.0288034909,
+-0.0321526187, -0.0354177281, -0.0385989003, -0.0416962491, -0.0447099206,
+-0.0476400932, -0.0504869764, -0.0532508113, -0.0559318695, -0.0585304530,
+-0.0610468937, -0.0634815527, -0.0658348203, -0.0681071152, -0.0702988839,
+-0.0724106005, -0.0744427662, -0.0763959083, -0.0782705803, -0.0800673611,
+-0.0817868542, -0.0834296875, -0.0849965128, -0.0864880049, -0.0879048612,
+-0.0892478011, -0.0905175656, -0.0917149165, -0.0928406356, -0.0938955247,
+-0.0948804046, -0.0957961143, -0.0966435111, -0.0974234691, -0.0981368792,
+-0.0987846484, -0.0993676990, -0.0998869680, -0.1003434068, -0.1007379799,
+-0.1010716653, -0.1013454527, -0.1015603439, -0.1017173514, -0.1018174985,
+-0.1018618180, -0.1018513520, -0.1017871512, -0.1016702743, -0.1015017873,
+-0.1012827629, -0.1010142801, -0.1006974233, -0.1003332820, -0.0999229498,
+-0.0994675244, -0.0989681065, -0.0984257996, -0.0978417089, -0.0972169414,
+-0.0965526050, -0.0958498079, -0.0951096580, -0.0943332627, -0.0935217280,
+-0.0926761582, -0.0917976554, -0.0908873186, -0.0899462439, -0.0889755232,
+-0.0879762443, -0.0869494904, -0.0858963390, -0.0848178625, -0.0837151266,
+-0.0825891908, -0.0814411073, -0.0802719210, -0.0790826690, -0.0778743799,
+-0.0766480738, -0.0754047618, -0.0741454454, -0.0728711164, -0.0715827564,
+-0.0702813366, -0.0689678173, -0.0676431476, -0.0663082653, -0.0649640963,
+-0.0636115545, -0.0622515413, -0.0608849457, -0.0595126436, -0.0581354980,
+-0.0567543584, -0.0553700607, -0.0539834271, -0.0525952656, -0.0512063701,
+-0.0498175200, -0.0484294802, -0.0470430010, -0.0456588174, -0.0442776498,
+-0.0429002030, -0.0415271669, -0.0401592157, -0.0387970082, -0.0374411877,
+-0.0360923814, -0.0347512013, -0.0334182432, -0.0320940870, -0.0307792970,
+-0.0294744212, -0.0281799917, -0.0268965249, -0.0256245208, -0.0243644636,
+-0.0231168215, -0.0218820467, -0.0206605756, -0.0194528286, -0.0182592102,
+-0.0170801092, -0.0159158987, -0.0147669361, -0.0136335633, -0.0125161065,
+-0.0114148768, -0.0103301697, -0.0092622659, -0.0082114308, -0.0071779147,
+-0.0061619535, -0.0051637681, -0.0041835650, -0.0032215362, -0.0022778597,
+-0.0013526992, -0.0004462045, 0.0004414881, 0.0013102560, 0.0021599902,
+0.0029905945, 0.0038019859, 0.0045940943, 0.0053668620, 0.0061202438,
+0.0068542068, 0.0075687299, 0.0082638039, 0.0089394311, 0.0095956252,
+0.0102324109, 0.0108498239, 0.0114479106, 0.0120267277, 0.0125863420,
+0.0131268306, 0.0136482800, 0.0141507864, 0.0146344551, 0.0150994004,
+0.0155457456, 0.0159736222, 0.0163831701, 0.0167745373, 0.0171478795,
+0.0175033601, 0.0178411494, 0.0181614252, 0.0184643719, 0.0187501804,
+0.0190190481, 0.0192711782, 0.0195067799, 0.0197260681, 0.0199292628,
+0.0201165892, 0.0202882774, 0.0204445620, 0.0205856823, 0.0207118814,
+0.0208234065, 0.0209205085, 0.0210034417, 0.0210724637, 0.0211278351,
+0.0211698193, 0.0211986822, 0.0212146922, 0.0212181198, 0.0212092373,
+0.0211883190, 0.0211556404, 0.0211114786, 0.0210561117, 0.0209898188,
+0.0209128795, 0.0208255742, 0.0207281836, 0.0206209885, 0.0205042698,
+0.0203783081, 0.0202433838, 0.0200997766, 0.0199477657, 0.0197876293,
+0.0196196446, 0.0194440878, 0.0192612337, 0.0190713556, 0.0188747253,
+0.0186716127, 0.0184622861, 0.0182470115, 0.0180260530, 0.0177996724,
+0.0175681291, 0.0173316800, 0.0170905794, 0.0168450790, 0.0165954276,
+0.0163418712, 0.0160846527, 0.0158240119, 0.0155601855, 0.0152934071,
+0.0150239065, 0.0147519105, 0.0144776424, 0.0142013216, 0.0139231643,
+0.0136433827, 0.0133621856, 0.0130797775, 0.0127963596, 0.0125121290,
+0.0122272787, 0.0119419980, 0.0116564720, 0.0113708819, 0.0110854048,
+0.0108002136, 0.0105154774, 0.0102313607, 0.0099480242, 0.0096656244,
+0.0093843134, 0.0091042395, 0.0088255465, 0.0085483741, 0.0082728579,
+0.0079991292, 0.0077273153, 0.0074575392, 0.0071899198, 0.0069245718,
+0.0066616059, 0.0064011287, 0.0061432425, 0.0058880459, 0.0056356333,
+0.0053860950, 0.0051395175, 0.0048959834, 0.0046555712, 0.0044183558,
+0.0041844081, 0.0039537952, 0.0037265807, 0.0035028241, 0.0032825817,
+0.0030659059, 0.0028528456, 0.0026434463, 0.0024377500, 0.0022357952,
+0.0020376171, 0.0018432477, 0.0016527156, 0.0014660464, 0.0012832624,
+0.0011043829, 0.0009294242, 0.0007583998, 0.0005913199, 0.0004281923,
+0.0002690217, 0.0001138104, -0.0000374421, -0.0001847390, -0.0003280859,
+-0.0004674907, -0.0006029640, -0.0007345185, -0.0008621692, -0.0009859334,
+-0.0011058305, -0.0012218819, -0.0013341110, -0.0014425433, -0.0015472060,
+-0.0016481283, -0.0017453409, -0.0018388764, -0.0019287690, -0.0020150543,
+-0.0020977697, -0.0021769537, -0.0022526464, -0.0023248892, -0.0023937247,
+-0.0024591967, -0.0025213502, -0.0025802311, -0.0026358866, -0.0026883647,
+-0.0027377142, -0.0027839851, -0.0028272277, -0.0028674935, -0.0029048345,
+-0.0029393033, -0.0029709531, -0.0029998376, -0.0030260112, -0.0030495285,
+-0.0030704445, -0.0030888146, -0.0031046944, -0.0031181400, -0.0031292075,
+-0.0031379530, -0.0031444330, -0.0031487040, -0.0031508224, -0.0031508447,
+-0.0031488272, -0.0031448265, -0.0031388985, -0.0031310995, -0.0031214852,
+-0.0031101112, -0.0030970330, -0.0030823055, -0.0030659834, -0.0030481213,
+-0.0030287730, -0.0030079920, -0.0029858317, -0.0029623445, -0.0029375827,
+-0.0029115979, -0.0028844413, -0.0028561634, -0.0028268142, -0.0027964430,
+-0.0027650986, -0.0027328291, -0.0026996820, -0.0026657040, -0.0026309413,
+-0.0025954391, -0.0025592422, -0.0025223946, -0.0024849394, -0.0024469190,
+-0.0024083751, -0.0023693487, -0.0023298799, -0.0022900080, -0.0022497715,
+-0.0022092081, -0.0021683549, -0.0021272479, -0.0020859224, -0.0020444128,
+-0.0020027529, -0.0019609755, -0.0019191124, -0.0018771950, -0.0018352536,
+-0.0017933176, -0.0017514158, -0.0017095760, -0.0016678252, -0.0016261897,
+-0.0015846950, -0.0015433654, -0.0015022250, -0.0014612966, -0.0014206024,
+-0.0013801638, -0.0013400015, -0.0013001352, -0.0012605840, -0.0012213662,
+-0.0011824994, -0.0011440002, -0.0011058848, -0.0010681685, -0.0010308659,
+-0.0009939908, -0.0009575564, -0.0009215752, -0.0008860590, -0.0008510189,
+-0.0008164654, -0.0007824083, -0.0007488567, -0.0007158193, -0.0006833039,
+-0.0006513179, -0.0006198680, -0.0005889603, -0.0005586004, -0.0005287934,
+-0.0004995437, -0.0004708551, -0.0004427313, -0.0004151750, -0.0003881887,
+-0.0003617742, -0.0003359332, -0.0003106664, -0.0002859746, -0.0002618577,
+-0.0002383155, -0.0002153473, -0.0001929520, -0.0001711280, -0.0001498735,
+-0.0001291862, -0.0001090636, -0.0000895027, -0.0000705003, -0.0000520528,
+-0.0000341564, -0.0000168070, 0.0000000000
+};
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 09b69b4..14f0d6c 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -246,7 +246,7 @@ static UINT cp_fields_noresample(IDirectSoundBufferImpl *dsb, UINT count)
     return count;
 }
 
-static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *freqAcc)
+static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, const float *fir, int fir_len, float *freqAcc)
 {
     UINT i, channel;
     UINT istride = dsb->pwfx->nBlockAlign;
@@ -256,11 +256,18 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f
     float freqAcc_start = *freqAcc;
     float freqAcc_end = freqAcc_start + count * freqAdjust;
     UINT dsbfirstep = dsb->firstep;
+
+    /* Add some padding so that centers of high-quality and low-quality
+     * FIRs align properly. Failure to do this can lead to audible clicks
+     * when dsound switches between these two FIRs.
+     */
+    float freqAcc_pad = (fir_len_hq - fir_len) / (2 * dsbfirstep);
+
     UINT channels = dsb->mix_channels;
     UINT max_ipos = freqAcc_end;
 
     UINT fir_cachesize = (fir_len + dsbfirstep - 2) / dsbfirstep;
-    UINT required_input = max_ipos + fir_cachesize;
+    UINT required_input = freqAcc_end + freqAcc_pad + fir_cachesize;
 
     float* intermediate = HeapAlloc(GetProcessHeap(), 0,
             sizeof(float) * required_input * channels);
@@ -278,6 +285,8 @@ static UINT cp_fields_resample(IDirectSoundBufferImpl *dsb, UINT count, float *f
             *(itmp++) = get_current_sample(dsb,
                     dsb->sec_mixpos + i * istride, channel);
 
+    freqAcc_start += freqAcc_pad;
+
     for(i = 0; i < count; ++i) {
         float total_fir_steps = (freqAcc_start + i * freqAdjust) * dsbfirstep;
         UINT int_fir_steps = total_fir_steps;
@@ -320,8 +329,18 @@ static void cp_fields(IDirectSoundBufferImpl *dsb, UINT count, float *freqAcc)
 
     if (dsb->freqAdjust == 1.0)
         adv = cp_fields_noresample(dsb, count); /* *freqAcc is unmodified */
+    /**
+     * HACK: distinguish music players from games by the number of
+     * secondary buffers. Music players usually have only one buffer,
+     * (or maybe two if crossfading, give them four by default just to
+     * be sure) while games have many. Sound quality is important for
+     * players (bug 14717), but the high-quality resampler is too slow
+     * for some games (bug 30639).
+     */
+    else if (dsb->device->nrofbuffers > ds_hq_buffers_max)
+        adv = cp_fields_resample(dsb, count, fir_lq, fir_len_lq, freqAcc);
     else
-        adv = cp_fields_resample(dsb, count, freqAcc);
+        adv = cp_fields_resample(dsb, count, fir_hq, fir_len_hq, freqAcc);
 
     ipos = dsb->sec_mixpos + adv * dsb->pwfx->nBlockAlign;
     if (ipos >= dsb->buflen) {
diff --git a/tools/make_fir b/tools/make_fir
index 97c5583..836a027 100755
--- a/tools/make_fir
+++ b/tools/make_fir
@@ -23,46 +23,15 @@ use Math::Trig;
 
 # This program generates an array of Finite Impulse Response (FIR) filter
 # values for use in resampling audio.
-#
-# Values are based on the resampler from Windows XP at the default (best)
-# quality, reverse engineered by saving kvm output to a wav file.
-
-# Controls how sharp the transition between passband and stopband is.
-# The transition bandwidth is approximately (1 / exp_width) of the
-# Nyquist frequency.
-
-my $exp_width = 41.0;
-
-# Controls the stopband attenuation. It is related but not proportional
-# to exp(-(PI * lobes_per_wing / exp_width) ^2) / lobes_per_wing
-
-my $lobes_per_wing = 28;
-
-# Controls the position of the transition band and thus attenuation at the
-# Nyquist frequency and above. Amended below so that the length of the FIR is
-# an integer. Essentially, this controls the trade-off between good rejection
-# of unrepresentable frequencies (those above half of the lower of the sample
-# rates) and not rejecting the wanted ones. Windows XP errs on the side of
-# letting artifacts through, which somewhat makes sense if they are above
-# 20 kHz anyway, or in the case of upsampling, where we can assume that the
-# problematic frequencies are not in the input. This, however, doesn't match
-# what linux resamplers do - so set this to 0.85 to match them. 0.98 would
-# give Windows XP behaviour.
-
-my $approx_bandwidth = 0.85;
-
-# The amended value will be stored here
-my $bandwidth;
 
 # The number of points per time unit equal to one period of the original
 # Nyquist frequency. The more points, the less interpolation error is.
 my $fir_step = 120;
 
-
 # Here x is measured in half-periods of the lower sample rate
-sub fir_val($)
+sub fir_val($$$)
 {
-    my ($x) = @_;
+    my ($x, $bandwidth, $exp_width) = @_;
     $x *= pi * $bandwidth;
     my $s = $x / $exp_width;
     my $sinc = $x ? (sin($x) / $x) : 1.0;
@@ -83,76 +52,98 @@ sub to_db($) {
     return 20.0 * log(abs($x))/log(10.0);
 }
 
-my $wing_len = int($lobes_per_wing / $approx_bandwidth * $fir_step + 1);
-$bandwidth = 1.0 * $lobes_per_wing / $wing_len;
-
-my $amended_bandwidth = $bandwidth * $fir_step;
-my $fir_len = 2 * $wing_len + 1;
-my @fir;
-
-# Constructing the FIR is easy
-for (my $i = 0; $i < $fir_len; $i++) {
-    push @fir, fir_val($i - $wing_len);
-}
-
-# Now we have to test it and print some statistics to stderr.
-# Test 0: FIR size
-print STDERR "size: $fir_len\n";
-
-# Test 1: Interpolation noise. It should be less than -90 dB.
+# $exp_width controls how sharp the transition between passband and stopband
+# is. The transition bandwidth is approximately (1 / exp_width) of the
+# Nyquist frequency.
+#
+# $lobes_per_wing Controls the stopband attenuation. It is related but not
+# proportional to exp(-(PI * lobes_per_wing / exp_width) ^2) / lobes_per_wing
+#
+# $approx_bandwidth Controls the position of the transition band and thus
+# attenuation at the Nyquist frequency and above. Amended below so that the
+# length of the FIR is an integer. Essentially, this controls the trade-off
+# between good rejection of unrepresentable frequencies (those above half of
+# the lower of the sample rates) and not rejecting the wanted ones. Windows
+# XP errs on the side of letting artifacts through, which somewhat makes
+# sense if they are above 20 kHz anyway, or in the case of upsampling, where
+# we can assume that the problematic frequencies are not in the input. This,
+# however, doesn't match what linux resamplers do - so set this to 0.85 to
+# match them. 0.98 would give Windows XP behaviour.
+sub make_fir($$$$) {
+    my ($name, $lobes_per_wing, $exp_width, $approx_bandwidth) = @_;
+    my $wing_len = int($lobes_per_wing / $approx_bandwidth * $fir_step + 1);
+    my $bandwidth = 1.0 * $lobes_per_wing / $wing_len;
+    my $amended_bandwidth = $bandwidth * $fir_step;
+    my $fir_len = 2 * $wing_len + 1;
+    my @fir;
+
+    # Constructing the FIR is easy
+    for (my $i = 0; $i < $fir_len; $i++) {
+        push @fir, fir_val($i - $wing_len, $bandwidth, $exp_width);
+    }
 
-# If you suspect that 0.5 is special due to some symmetry and thus yields
-# an abnormally low noise figure, change it. But really, it isn't special.
-my $testpoint = 0.5;
+    # Now we have to test it and print some statistics to stderr.
+    # Test 0: FIR size
+    print STDERR "Filter $name has size $fir_len\n";
 
-my $exact_val = fir_val($testpoint);
-my $lin_approx_val = mlinear($fir[$wing_len], $fir[$wing_len + 1],
+    # Test 1: Interpolation noise. It should be less than -90 dB
+    # for the best-quality FIR.
+    my $testpoint = 0.5;
+    my $exact_val = fir_val($testpoint, $bandwidth, $exp_width);
+    my $lin_approx_val = mlinear($fir[$wing_len], $fir[$wing_len + 1],
         $testpoint);
+    my $lin_error_db = to_db($exact_val - $lin_approx_val);
+
+    printf STDERR "interpolation noise: %1.2f dB\n", $lin_error_db;
+
+    # Test 2: Passband and stopband.
+    # The filter gain, ideally, should be 0.00 dB below the Nyquist
+    # frequency and -inf dB above it. But it is impossible. So
+    # let's settle for -80 dB above 1.08 * f_Nyquist.
+
+    my $sum = 0.0;
+    $sum += $_ for @fir;
+
+    # Frequencies in this list are expressed as fractions
+    # of the Nyquist frequency.
+    my @testfreqs = (0.5, 0.8, 1.0, 1.08, 1.18, 1.33, 1.38);
+    foreach my $testfreq(@testfreqs) {
+        my $dct_coeff = 0.0;
+        for (my $i = 0; $i < $fir_len; $i++) {
+            my $x = 1.0 * ($i - $wing_len) / $fir_step;
+            $dct_coeff += $fir[$i] * cos($x * $testfreq * pi);
+        }
+        printf STDERR "DCT: %1.2f -> %1.2f dB\n",
+            $testfreq, to_db($dct_coeff / $sum);
+    }
+    # Now actually print the FIR to a C header file
+    print "static const int fir_len_${name} = $fir_len;\n";
+    print "static const float fir_${name}[] = {\n";
 
-my $lin_error_db = to_db($exact_val - $lin_approx_val);
-
-printf STDERR "interpolation noise: %1.2f dB\n", $lin_error_db;
-
-# Test 2: Passband and stopband.
-# The filter gain, ideally, should be 0.00 dB below the Nyquist
-# frequency and -inf dB above it. But it is impossible. So
-# let's settle for -80 dB above 1.08 * f_Nyquist.
-
-my $sum = 0.0;
-$sum += $_ for @fir;
-
-# Frequencies in this list are expressed as fractions
-# of the Nyquist frequency.
-my @testfreqs = (0.5, 0.8, 1.0, 1.08, 1.18, 1.33, 1.38);
-foreach my $testfreq(@testfreqs) {
-    my $dct_coeff = 0.0;
     for (my $i = 0; $i < $fir_len; $i++) {
-        my $x = 1.0 * ($i - $wing_len) / $fir_step;
-        $dct_coeff += $fir[$i] * cos($x * $testfreq * pi);
+        printf "%10.10f", $amended_bandwidth * $fir[$i];
+        if ($i == $fir_len - 1) {
+            print "\n";
+        } elsif (($i + 1) % 5 == 0) {
+            print ",\n";
+        } else {
+            print ", ";
+        }
     }
-    printf STDERR "DCT: %1.2f -> %1.2f dB\n",
-        $testfreq, to_db($dct_coeff / $sum);
+    print "};\n";
 }
 
-# Now actually print the FIR to a C header file
-
 chdir ".." if -f "./make_fir";
 open FILE, ">dlls/dsound/fir.h";
 select FILE;
 
 print "/* generated by tools/make_fir; DO NOT EDIT! */\n";
-print "static const int fir_len = $fir_len;\n";
 print "static const int fir_step = $fir_step;\n";
-print "static const float fir[] = {\n";
-
-for (my $i = 0; $i < $fir_len; $i++) {
-    printf "%10.10f", $amended_bandwidth * $fir[$i];
-    if ($i == $fir_len - 1) {
-        print "\n";
-    } elsif (($i + 1) % 5 == 0) {
-        print ",\n";
-    } else {
-        print ", ";
-    }
-}
-print "};\n";
+
+# Values for the high-quality FIR are based on the resampler from Windows
+# XP at the default (best) quality, reverse engineered by saving kvm output
+# to a wav file. Values for the low-quality FIR are made up without any
+# particular reference.
+
+make_fir("hq", 28, 41.0, 0.85);
+make_fir("lq", 4, 6.0, 0.8);
-- 
1.7.8.6


More information about the wine-patches mailing list