From 7200229af33e3063156d3ba104e5f580dadf5386 Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Wed, 18 May 2016 20:27:05 -0700 Subject: [PATCH] Fix potential threading issues with resid and residfp. --- .../builders/resid-builder/resid/envelope.cc | 24 +- .../builders/resid-builder/resid/filter.cc | 408 +++++++++--------- .../src/builders/resid-builder/resid/wave.cc | 50 ++- .../residfp/WaveformCalculator.cpp | 2 + .../residfp/WaveformCalculator.h | 2 + 5 files changed, 254 insertions(+), 232 deletions(-) diff --git a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/envelope.cc b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/envelope.cc index 45afa8294..dbc23bd3f 100644 --- a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/envelope.cc +++ b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/envelope.cc @@ -17,6 +17,8 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // --------------------------------------------------------------------------- +#include + #define RESID_ENVELOPE_CC #include "envelope.h" @@ -156,18 +158,22 @@ unsigned short EnvelopeGenerator::model_dac[2][1 << 8] = { // ---------------------------------------------------------------------------- // Constructor. // ---------------------------------------------------------------------------- +static std::mutex g_class_init_mutex; +static bool g_class_init = false; + EnvelopeGenerator::EnvelopeGenerator() { - static bool class_init; + { + std::lock_guard guard(g_class_init_mutex); + if (!g_class_init) { + // Build DAC lookup tables for 8-bit DACs. + // MOS 6581: 2R/R ~ 2.20, missing termination resistor. + build_dac_table(model_dac[0], 8, 2.20, false); + // MOS 8580: 2R/R ~ 2.00, correct termination. + build_dac_table(model_dac[1], 8, 2.00, true); - if (!class_init) { - // Build DAC lookup tables for 8-bit DACs. - // MOS 6581: 2R/R ~ 2.20, missing termination resistor. - build_dac_table(model_dac[0], 8, 2.20, false); - // MOS 8580: 2R/R ~ 2.00, correct termination. - build_dac_table(model_dac[1], 8, 2.00, true); - - class_init = true; + g_class_init = true; + } } set_chip_model(MOS6581); diff --git a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/filter.cc b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/filter.cc index 8aca2c25e..733aa8767 100644 --- a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/filter.cc +++ b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/filter.cc @@ -17,6 +17,8 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // --------------------------------------------------------------------------- +#include + #define RESID_FILTER_CC #ifdef _M_ARM @@ -191,231 +193,235 @@ Filter::model_filter_t Filter::model_filter[2]; // ---------------------------------------------------------------------------- // Constructor. // ---------------------------------------------------------------------------- +static std::mutex g_class_init_mutex; +static bool g_class_init = false; + Filter::Filter() { - static bool class_init; + { + std::lock_guard guard(g_class_init_mutex); + if (!g_class_init) { + // Temporary table for op-amp transfer function. + int* opamp = new int[1 << 16]; - if (!class_init) { - // Temporary table for op-amp transfer function. - int* opamp = new int[1 << 16]; + for (int m = 0; m < 2; m++) { + model_filter_init_t& fi = model_filter_init[m]; + model_filter_t& mf = model_filter[m]; - for (int m = 0; m < 2; m++) { - model_filter_init_t& fi = model_filter_init[m]; - model_filter_t& mf = model_filter[m]; + // Convert op-amp voltage transfer to 16 bit values. + double vmin = fi.opamp_voltage[0][0]; + double opamp_max = fi.opamp_voltage[0][1]; + double kVddt = fi.k*(fi.Vdd - fi.Vth); + double vmax = kVddt < opamp_max ? opamp_max : kVddt; + double denorm = vmax - vmin; + double norm = 1.0/denorm; - // Convert op-amp voltage transfer to 16 bit values. - double vmin = fi.opamp_voltage[0][0]; - double opamp_max = fi.opamp_voltage[0][1]; - double kVddt = fi.k*(fi.Vdd - fi.Vth); - double vmax = kVddt < opamp_max ? opamp_max : kVddt; - double denorm = vmax - vmin; - double norm = 1.0/denorm; + // Scaling and translation constants. + double N16 = norm*((1u << 16) - 1); + double N30 = norm*((1u << 30) - 1); + double N31 = norm*((1u << 31) - 1); + mf.vo_N16 = (int)(N16); // FIXME: Remove? - // Scaling and translation constants. - double N16 = norm*((1u << 16) - 1); - double N30 = norm*((1u << 30) - 1); - double N31 = norm*((1u << 31) - 1); - mf.vo_N16 = (int)(N16); // FIXME: Remove? + // The "zero" output level of the voices. + // The digital range of one voice is 20 bits; create a scaling term + // for multiplication which fits in 11 bits. + double N14 = norm*(1u << 14); + mf.voice_scale_s14 = (int)(N14*fi.voice_voltage_range); + mf.voice_DC = (int)(N16*(fi.voice_DC_voltage - vmin)); - // The "zero" output level of the voices. - // The digital range of one voice is 20 bits; create a scaling term - // for multiplication which fits in 11 bits. - double N14 = norm*(1u << 14); - mf.voice_scale_s14 = (int)(N14*fi.voice_voltage_range); - mf.voice_DC = (int)(N16*(fi.voice_DC_voltage - vmin)); + // Vdd - Vth, normalized so that translated values can be subtracted: + // k*Vddt - x = (k*Vddt - t) - (x - t) + mf.kVddt = (int)(N16*(kVddt - vmin) + 0.5); - // Vdd - Vth, normalized so that translated values can be subtracted: - // k*Vddt - x = (k*Vddt - t) - (x - t) - mf.kVddt = (int)(N16*(kVddt - vmin) + 0.5); + // Normalized snake current factor, 1 cycle at 1MHz. + // Fit in 5 bits. + mf.n_snake = (int)(denorm*(1 << 13)*(fi.uCox/(2*fi.k)*fi.WL_snake*1.0e-6/fi.C) + 0.5); - // Normalized snake current factor, 1 cycle at 1MHz. - // Fit in 5 bits. - mf.n_snake = (int)(denorm*(1 << 13)*(fi.uCox/(2*fi.k)*fi.WL_snake*1.0e-6/fi.C) + 0.5); + // Create lookup table mapping op-amp voltage across output and input + // to input voltage: vo - vx -> vx + // FIXME: No variable length arrays in ISO C++, hardcoding to max 50 + // points. + // double_point scaled_voltage[fi.opamp_voltage_size]; + double_point scaled_voltage[50]; - // Create lookup table mapping op-amp voltage across output and input - // to input voltage: vo - vx -> vx - // FIXME: No variable length arrays in ISO C++, hardcoding to max 50 - // points. - // double_point scaled_voltage[fi.opamp_voltage_size]; - double_point scaled_voltage[50]; + for (int i = 0; i < fi.opamp_voltage_size; i++) { + // The target output range is 16 bits, in order to fit in an unsigned + // short. + // + // The y axis is temporarily scaled to 31 bits for maximum accuracy in + // the calculated derivative. + // + // Values are normalized using + // + // x_n = m*2^N*(x - xmin) + // + // and are translated back later (for fixed point math) using + // + // m*2^N*x = x_n - m*2^N*xmin + // + scaled_voltage[fi.opamp_voltage_size - 1 - i][0] = int((N16*(fi.opamp_voltage[i][1] - fi.opamp_voltage[i][0]) + (1 << 16))/2 + 0.5); + scaled_voltage[fi.opamp_voltage_size - 1 - i][1] = N31*(fi.opamp_voltage[i][0] - vmin); + } - for (int i = 0; i < fi.opamp_voltage_size; i++) { - // The target output range is 16 bits, in order to fit in an unsigned - // short. + // Clamp x to 16 bits (rounding may cause overflow). + if (scaled_voltage[fi.opamp_voltage_size - 1][0] >= (1 << 16)) { + // The last point is repeated. + scaled_voltage[fi.opamp_voltage_size - 1][0] = + scaled_voltage[fi.opamp_voltage_size - 2][0] = (1 << 16) - 1; + } + + interpolate(scaled_voltage, scaled_voltage + fi.opamp_voltage_size - 1, + PointPlotter(opamp), 1.0); + + // Store both fn and dfn in the same table. + mf.ak = (int)scaled_voltage[0][0]; + mf.bk = (int)scaled_voltage[fi.opamp_voltage_size - 1][0]; + int j; + for (j = 0; j < mf.ak; j++) { + opamp[j] = 0; + } + int f = opamp[j] - (opamp[j + 1] - opamp[j]); + for (; j <= mf.bk; j++) { + int fp = f; + f = opamp[j]; // Scaled by m*2^31 + // m*2^31*dy/1 = (m*2^31*dy)/(m*2^16*dx) = 2^15*dy/dx + int df = f - fp; // Scaled by 2^15 + + // High 16 bits (15 bits + sign bit): 2^11*dfn + // Low 16 bits (unsigned): m*2^16*(fn - xmin) + opamp[j] = ((df << (16 + 11 - 15)) & ~0xffff) | (f >> 15); + } + for (; j < (1 << 16); j++) { + opamp[j] = 0; + } + + // Create lookup tables for gains / summers. + + // 4 bit "resistor" ladders in the bandpass resonance gain and the audio + // output gain necessitate 16 gain tables. + // From die photographs of the bandpass and volume "resistor" ladders + // it follows that gain ~ vol/8 and 1/Q ~ ~res/8 (assuming ideal + // op-amps and ideal "resistors"). + for (int n8 = 0; n8 < 16; n8++) { + int n = n8 << 4; // Scaled by 2^7 + int x = mf.ak; + for (int vi = 0; vi < (1 << 16); vi++) { + mf.gain[n8][vi] = solve_gain(opamp, n, vi, x, mf); + } + } + + // The filter summer operates at n ~ 1, and has 5 fundamentally different + // input configurations (2 - 6 input "resistors"). // - // The y axis is temporarily scaled to 31 bits for maximum accuracy in - // the calculated derivative. + // Note that all "on" transistors are modeled as one. This is not + // entirely accurate, since the input for each transistor is different, + // and transistors are not linear components. However modeling all + // transistors separately would be extremely costly. + int offset = 0; + int size; + for (int k = 0; k < 5; k++) { + int idiv = 2 + k; // 2 - 6 input "resistors". + int n_idiv = idiv << 7; // n*idiv, scaled by 2^7 + size = idiv << 16; + int x = mf.ak; + for (int vi = 0; vi < size; vi++) { + mf.summer[offset + vi] = + solve_gain(opamp, n_idiv, vi/idiv, x, mf); + } + offset += size; + } + + // The audio mixer operates at n ~ 8/6, and has 8 fundamentally different + // input configurations (0 - 7 input "resistors"). // - // Values are normalized using - // - // x_n = m*2^N*(x - xmin) - // - // and are translated back later (for fixed point math) using - // - // m*2^N*x = x_n - m*2^N*xmin - // - scaled_voltage[fi.opamp_voltage_size - 1 - i][0] = int((N16*(fi.opamp_voltage[i][1] - fi.opamp_voltage[i][0]) + (1 << 16))/2 + 0.5); - scaled_voltage[fi.opamp_voltage_size - 1 - i][1] = N31*(fi.opamp_voltage[i][0] - vmin); - } + // All "on", transistors are modeled as one - see comments above for + // the filter summer. + offset = 0; + size = 1; // Only one lookup element for 0 input "resistors". + for (int l = 0; l < 8; l++) { + int idiv = l; // 0 - 7 input "resistors". + int n_idiv = (idiv << 7)*8/6; // n*idiv, scaled by 2^7 + if (idiv == 0) { + // Avoid division by zero; the result will be correct since + // n_idiv = 0. + idiv = 1; + } + int x = mf.ak; + for (int vi = 0; vi < size; vi++) { + mf.mixer[offset + vi] = + solve_gain(opamp, n_idiv, vi/idiv, x, mf); + } + offset += size; + size = (l + 1) << 16; + } - // Clamp x to 16 bits (rounding may cause overflow). - if (scaled_voltage[fi.opamp_voltage_size - 1][0] >= (1 << 16)) { - // The last point is repeated. - scaled_voltage[fi.opamp_voltage_size - 1][0] = - scaled_voltage[fi.opamp_voltage_size - 2][0] = (1 << 16) - 1; - } + // Create lookup table mapping capacitor voltage to op-amp input voltage: + // vc -> vx + for (int m = 0; m < (1 << 16); m++) { + mf.opamp_rev[m] = opamp[m] & 0xffff; + } - interpolate(scaled_voltage, scaled_voltage + fi.opamp_voltage_size - 1, - PointPlotter(opamp), 1.0); + mf.vc_max = (int)(N30*(fi.opamp_voltage[0][1] - fi.opamp_voltage[0][0])); + mf.vc_min = (int)(N30*(fi.opamp_voltage[fi.opamp_voltage_size - 1][1] - fi.opamp_voltage[fi.opamp_voltage_size - 1][0])); - // Store both fn and dfn in the same table. - mf.ak = (int)scaled_voltage[0][0]; - mf.bk = (int)scaled_voltage[fi.opamp_voltage_size - 1][0]; - int j; - for (j = 0; j < mf.ak; j++) { - opamp[j] = 0; - } - int f = opamp[j] - (opamp[j + 1] - opamp[j]); - for (; j <= mf.bk; j++) { - int fp = f; - f = opamp[j]; // Scaled by m*2^31 - // m*2^31*dy/1 = (m*2^31*dy)/(m*2^16*dx) = 2^15*dy/dx - int df = f - fp; // Scaled by 2^15 - - // High 16 bits (15 bits + sign bit): 2^11*dfn - // Low 16 bits (unsigned): m*2^16*(fn - xmin) - opamp[j] = ((df << (16 + 11 - 15)) & ~0xffff) | (f >> 15); - } - for (; j < (1 << 16); j++) { - opamp[j] = 0; - } - - // Create lookup tables for gains / summers. - - // 4 bit "resistor" ladders in the bandpass resonance gain and the audio - // output gain necessitate 16 gain tables. - // From die photographs of the bandpass and volume "resistor" ladders - // it follows that gain ~ vol/8 and 1/Q ~ ~res/8 (assuming ideal - // op-amps and ideal "resistors"). - for (int n8 = 0; n8 < 16; n8++) { - int n = n8 << 4; // Scaled by 2^7 - int x = mf.ak; - for (int vi = 0; vi < (1 << 16); vi++) { - mf.gain[n8][vi] = solve_gain(opamp, n, vi, x, mf); + // DAC table. + int bits = 11; + build_dac_table(mf.f0_dac, bits, fi.dac_2R_div_R, fi.dac_term); + for (int n = 0; n < (1 << bits); n++) { + mf.f0_dac[n] = (unsigned short)(N16*(fi.dac_zero + mf.f0_dac[n]*fi.dac_scale/(1 << bits) - vmin) + 0.5); } } - // The filter summer operates at n ~ 1, and has 5 fundamentally different - // input configurations (2 - 6 input "resistors"). - // - // Note that all "on" transistors are modeled as one. This is not - // entirely accurate, since the input for each transistor is different, - // and transistors are not linear components. However modeling all - // transistors separately would be extremely costly. - int offset = 0; - int size; - for (int k = 0; k < 5; k++) { - int idiv = 2 + k; // 2 - 6 input "resistors". - int n_idiv = idiv << 7; // n*idiv, scaled by 2^7 - size = idiv << 16; - int x = mf.ak; - for (int vi = 0; vi < size; vi++) { - mf.summer[offset + vi] = - solve_gain(opamp, n_idiv, vi/idiv, x, mf); - } - offset += size; + // Free temporary table. + delete[] opamp; + + // VCR - 6581 only. + model_filter_init_t& fi = model_filter_init[0]; + + double N16 = model_filter[0].vo_N16; + double vmin = N16*fi.opamp_voltage[0][0]; + double k = fi.k; + double kVddt = N16*(k*(fi.Vdd - fi.Vth)); + + for (int i = 0; i < (1 << 16); i++) { + // The table index is right-shifted 16 times in order to fit in + // 16 bits; the argument to sqrt is thus multiplied by (1 << 16). + // + // The returned value must be corrected for translation. Vg always + // takes part in a subtraction as follows: + // + // k*Vg - Vx = (k*Vg - t) - (Vx - t) + // + // I.e. k*Vg - t must be returned. + double Vg = kVddt - sqrt((double)i*(1 << 16)); + vcr_kVg[i] = (unsigned short)(k*Vg - vmin + 0.5); } - // The audio mixer operates at n ~ 8/6, and has 8 fundamentally different - // input configurations (0 - 7 input "resistors"). - // - // All "on", transistors are modeled as one - see comments above for - // the filter summer. - offset = 0; - size = 1; // Only one lookup element for 0 input "resistors". - for (int l = 0; l < 8; l++) { - int idiv = l; // 0 - 7 input "resistors". - int n_idiv = (idiv << 7)*8/6; // n*idiv, scaled by 2^7 - if (idiv == 0) { - // Avoid division by zero; the result will be correct since - // n_idiv = 0. - idiv = 1; - } - int x = mf.ak; - for (int vi = 0; vi < size; vi++) { - mf.mixer[offset + vi] = - solve_gain(opamp, n_idiv, vi/idiv, x, mf); - } - offset += size; - size = (l + 1) << 16; + /* + EKV model: + + Ids = Is*(if - ir) + Is = 2*u*Cox*Ut^2/k*W/L + if = ln^2(1 + e^((k*(Vg - Vt) - Vs)/(2*Ut)) + ir = ln^2(1 + e^((k*(Vg - Vt) - Vd)/(2*Ut)) + */ + double kVt = fi.k*fi.Vth; + double Ut = fi.Ut; + double Is = 2*fi.uCox*Ut*Ut/fi.k*fi.WL_vcr; + // Normalized current factor for 1 cycle at 1MHz. + double N15 = N16/2; + double n_Is = N15*1.0e-6/fi.C*Is; + + // kVg_Vx = k*Vg - Vx + // I.e. if k != 1.0, Vg must be scaled accordingly. + for (int kVg_Vx = 0; kVg_Vx < (1 << 16); kVg_Vx++) { + double log_term = log1p(exp((kVg_Vx/N16 - kVt)/(2*Ut))); + // Scaled by m*2^15 + vcr_n_Ids_term[kVg_Vx] = (unsigned short)(n_Is*log_term*log_term); } - // Create lookup table mapping capacitor voltage to op-amp input voltage: - // vc -> vx - for (int m = 0; m < (1 << 16); m++) { - mf.opamp_rev[m] = opamp[m] & 0xffff; - } - - mf.vc_max = (int)(N30*(fi.opamp_voltage[0][1] - fi.opamp_voltage[0][0])); - mf.vc_min = (int)(N30*(fi.opamp_voltage[fi.opamp_voltage_size - 1][1] - fi.opamp_voltage[fi.opamp_voltage_size - 1][0])); - - // DAC table. - int bits = 11; - build_dac_table(mf.f0_dac, bits, fi.dac_2R_div_R, fi.dac_term); - for (int n = 0; n < (1 << bits); n++) { - mf.f0_dac[n] = (unsigned short)(N16*(fi.dac_zero + mf.f0_dac[n]*fi.dac_scale/(1 << bits) - vmin) + 0.5); - } + g_class_init = true; } - - // Free temporary table. - delete[] opamp; - - // VCR - 6581 only. - model_filter_init_t& fi = model_filter_init[0]; - - double N16 = model_filter[0].vo_N16; - double vmin = N16*fi.opamp_voltage[0][0]; - double k = fi.k; - double kVddt = N16*(k*(fi.Vdd - fi.Vth)); - - for (int i = 0; i < (1 << 16); i++) { - // The table index is right-shifted 16 times in order to fit in - // 16 bits; the argument to sqrt is thus multiplied by (1 << 16). - // - // The returned value must be corrected for translation. Vg always - // takes part in a subtraction as follows: - // - // k*Vg - Vx = (k*Vg - t) - (Vx - t) - // - // I.e. k*Vg - t must be returned. - double Vg = kVddt - sqrt((double)i*(1 << 16)); - vcr_kVg[i] = (unsigned short)(k*Vg - vmin + 0.5); - } - - /* - EKV model: - - Ids = Is*(if - ir) - Is = 2*u*Cox*Ut^2/k*W/L - if = ln^2(1 + e^((k*(Vg - Vt) - Vs)/(2*Ut)) - ir = ln^2(1 + e^((k*(Vg - Vt) - Vd)/(2*Ut)) - */ - double kVt = fi.k*fi.Vth; - double Ut = fi.Ut; - double Is = 2*fi.uCox*Ut*Ut/fi.k*fi.WL_vcr; - // Normalized current factor for 1 cycle at 1MHz. - double N15 = N16/2; - double n_Is = N15*1.0e-6/fi.C*Is; - - // kVg_Vx = k*Vg - Vx - // I.e. if k != 1.0, Vg must be scaled accordingly. - for (int kVg_Vx = 0; kVg_Vx < (1 << 16); kVg_Vx++) { - double log_term = log1p(exp((kVg_Vx/N16 - kVt)/(2*Ut))); - // Scaled by m*2^15 - vcr_n_Ids_term[kVg_Vx] = (unsigned short)(n_Is*log_term*log_term); - } - - class_init = true; } enable_filter(true); diff --git a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/wave.cc b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/wave.cc index 25bc6724a..bdfb4d857 100644 --- a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/wave.cc +++ b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/resid-builder/resid/wave.cc @@ -17,6 +17,8 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // --------------------------------------------------------------------------- +#include + #define RESID_WAVE_CC #include "wave.h" @@ -60,34 +62,38 @@ unsigned short WaveformGenerator::model_dac[2][1 << 12] = { // ---------------------------------------------------------------------------- // Constructor. // ---------------------------------------------------------------------------- +static std::mutex g_class_init_mutex; +static bool g_class_init = false; + WaveformGenerator::WaveformGenerator() { - static bool class_init; + { + std::lock_guard guard(g_class_init_mutex); + if (!g_class_init) { + // Calculate tables for normal waveforms. + accumulator = 0; + for (int i = 0; i < (1 << 12); i++) { + reg24 msb = accumulator & 0x800000; - if (!class_init) { - // Calculate tables for normal waveforms. - accumulator = 0; - for (int i = 0; i < (1 << 12); i++) { - reg24 msb = accumulator & 0x800000; + // Noise mask, triangle, sawtooth, pulse mask. + // The triangle calculation is made branch-free, just for the hell of it. + model_wave[0][0][i] = model_wave[1][0][i] = 0xfff; + model_wave[0][1][i] = model_wave[1][1][i] = + ((accumulator ^ -!!msb) >> 11) & 0xffe; + model_wave[0][2][i] = model_wave[1][2][i] = accumulator >> 12; + model_wave[0][4][i] = model_wave[1][4][i] = 0xfff; - // Noise mask, triangle, sawtooth, pulse mask. - // The triangle calculation is made branch-free, just for the hell of it. - model_wave[0][0][i] = model_wave[1][0][i] = 0xfff; - model_wave[0][1][i] = model_wave[1][1][i] = - ((accumulator ^ -!!msb) >> 11) & 0xffe; - model_wave[0][2][i] = model_wave[1][2][i] = accumulator >> 12; - model_wave[0][4][i] = model_wave[1][4][i] = 0xfff; + accumulator += 0x1000; + } - accumulator += 0x1000; + // Build DAC lookup tables for 12-bit DACs. + // MOS 6581: 2R/R ~ 2.20, missing termination resistor. + build_dac_table(model_dac[0], 12, 2.20, false); + // MOS 8580: 2R/R ~ 2.00, correct termination. + build_dac_table(model_dac[1], 12, 2.00, true); + + class_init = true; } - - // Build DAC lookup tables for 12-bit DACs. - // MOS 6581: 2R/R ~ 2.20, missing termination resistor. - build_dac_table(model_dac[0], 12, 2.20, false); - // MOS 8580: 2R/R ~ 2.00, correct termination. - build_dac_table(model_dac[1], 12, 2.00, true); - - class_init = true; } sync_source = this; diff --git a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/residfp-builder/residfp/WaveformCalculator.cpp b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/residfp-builder/residfp/WaveformCalculator.cpp index 0619090b7..00ab27aed 100644 --- a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/residfp-builder/residfp/WaveformCalculator.cpp +++ b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/residfp-builder/residfp/WaveformCalculator.cpp @@ -172,6 +172,8 @@ short calculateCombinedWaveform(CombinedWaveformConfig config, int waveform, int matrix_t* WaveformCalculator::buildTable(ChipModel model) { + std::lock_guard guard(CACHE_LOCK); + const CombinedWaveformConfig* cfgArray = config[model == MOS6581 ? 0 : 1]; cw_cache_t::iterator lb = CACHE.lower_bound(cfgArray); diff --git a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/residfp-builder/residfp/WaveformCalculator.h b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/residfp-builder/residfp/WaveformCalculator.h index 7ed0e81d0..01b6d46b0 100644 --- a/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/residfp-builder/residfp/WaveformCalculator.h +++ b/Frameworks/libsidplay/sidplay-residfp-code/libsidplayfp/src/builders/residfp-builder/residfp/WaveformCalculator.h @@ -23,6 +23,7 @@ #define WAVEFORMCALCULATOR_h #include +#include #include "siddefs-fp.h" #include "array.h" @@ -95,6 +96,7 @@ private: typedef std::map cw_cache_t; private: + std::mutex CACHE_LOCK; cw_cache_t CACHE; WaveformCalculator() {}