From a0479b886b7fa8fa040ca6f8027101bdba17b1cc Mon Sep 17 00:00:00 2001 From: Lord-Nightmare Date: Mon, 5 Apr 2021 14:09:19 -0400 Subject: Mac 128/512/Plus/SE: Emulate the lowpass audio filter, and fix the volume control so it correctly gets louder when the slider is raised in control panel instead of quieter. [Lord Nightmare] --- src/devices/sound/flt_biquad.cpp | 39 +++++++++----- src/devices/sound/flt_biquad.h | 9 +++- src/mame/drivers/mac128.cpp | 110 +++++++++++++++++++++++++++++++++++---- 3 files changed, 136 insertions(+), 22 deletions(-) diff --git a/src/devices/sound/flt_biquad.cpp b/src/devices/sound/flt_biquad.cpp index 8daa78e07ae..659c8a5cd29 100644 --- a/src/devices/sound/flt_biquad.cpp +++ b/src/devices/sound/flt_biquad.cpp @@ -115,13 +115,13 @@ void filter_biquad_device::modify(filter_biquad_device::biquad_params p) * * .----------------------------. * | | - * --- c2 | + * --- c1 | * --- | * | | * r1 | r2 |\ | * In >----ZZZZ----+--ZZZZ---+--------+ | \ | * | '--|+ \ | - * --- c1 | >--+------> out + * --- c2 | >--+------> out * --- .--|- / | * | | | / | * gnd | |/ | @@ -137,19 +137,34 @@ void filter_biquad_device::modify(filter_biquad_device::biquad_params p) */ filter_biquad_device& filter_biquad_device::opamp_sk_lowpass_setup(double r1, double r2, double r3, double r4, double c1, double c2) { + filter_biquad_device::biquad_params p = opamp_sk_lowpass_calc(r1, r2, r3, r4, c1, c2); + return setup(p); +} + +void filter_biquad_device::opamp_sk_lowpass_modify(double r1, double r2, double r3, double r4, double c1, double c2) +{ + filter_biquad_device::biquad_params p = opamp_sk_lowpass_calc(r1, r2, r3, r4, c1, c2); + modify(p); +} + +filter_biquad_device::biquad_params filter_biquad_device::opamp_sk_lowpass_calc(double r1, double r2, double r3, double r4, double c1, double c2) +{ + filter_biquad_device::biquad_params r; if ((r1 == 0) || (r2 == 0) || (r3 == 0) || (r4 == 0) || (c1 == 0) || (c2 == 0)) { - fatalerror("filter_biquad_device::opamp_sk_lowpass_setup() - no parameters can be 0; parameters were: r1: %f, r2: %f, r3: %f, r4: %f, c1: %f, c2: %f", r1, r2, r3, r4, c1, c2); /* Filter can not be setup. Undefined results. */ + fatalerror("filter_biquad_device::opamp_sk_lowpass_calc() - no parameters can be 0; parameters were: r1: %f, r2: %f, r3: %f, r4: %f, c1: %f, c2: %f", r1, r2, r3, r4, c1, c2); /* Filter can not be setup. Undefined results. */ } - - // note: if R3 doesn't exist (no link to ground), pass a value of RES_M(999.99) or the like, i.e. an 'infinite resistor' - double const gain = (r3 + r4) / r3; - double const fc = 1.0 / (2 * M_PI * sqrt(r1 * r2 * c1 * c2)); - double const q = sqrt(r1 * r2 * c1 * c2) / ((r1 * c1) + (r2 * c1) + ((r2 * c2) * (1.0 - gain))); + // NOTE: if R3 doesn't exist (no link to ground), pass a value of RES_M(999.99) or the like, i.e. an 'infinite resistor' + // NOTE: if R4 is a direct short, set its resistance to RES_R(0.001) + // NOTE: if R3 doesn't exist AND R4 is a direct short, follow both rules above. + r.type = biquad_type::LOWPASS; + r.gain = 1.0 + (r4 / r3); // == (r3 + r4) / r3 + r.fc = 1.0 / (2 * M_PI * sqrt(r1 * r2 * c1 * c2)); + r.q = sqrt(r1 * r2 * c1 * c2) / ((r1 * c2) + (r2 * c2) + ((r2 * c1) * (1.0 - r.gain))); #ifdef FLT_BIQUAD_DEBUG_SETUP - logerror("filter_biquad_device::opamp_sk_lowpass_setup() yields: fc = %f, Q = %f, gain = %f\n", fc, q, gain); + logerror("filter_biquad_device::opamp_sk_lowpass_calc(%f, %f, %f, %f, %f, %f) yields: fc = %f, Q = %f, gain = %f\n", r1, r2, r3, r4, c1*1000000, c2*1000000, r.fc, r.q, r.gain); #endif - return setup(biquad_type::LOWPASS, fc, q, gain); + return r; } // Multiple-Feedback filters @@ -211,7 +226,7 @@ filter_biquad_device::biquad_params filter_biquad_device::opamp_mfb_lowpass_calc r.type = biquad_type::LOWPASS; } #ifdef FLT_BIQUAD_DEBUG_SETUP - logerror("filter_biquad_device::opamp_mfb_lowpass_setup(%f, %f, %f, %f, %f) yields:\n\ttype = %d, fc = %f, Q = %f, gain = %f\n", r1, r2, r3, c1*1000000, c2*1000000, static_cast(r.type), r.fc, r.q, r.gain); + logerror("filter_biquad_device::opamp_mfb_lowpass_calc(%f, %f, %f, %f, %f) yields:\n\ttype = %d, fc = %f, Q = %f, gain = %f\n", r1, r2, r3, c1*1000000, c2*1000000, static_cast(r.type), r.fc, r.q, r.gain); #endif return r; } @@ -489,7 +504,7 @@ void filter_biquad_device::recalc() logerror("a2: %f\n", m_a2); #endif // peak and shelf filters do not use gain for the entire signal, only for the peak/shelf portions - // side note: the first order lowpass and highpass filter analogues technically don't have gain either, + // side note: the first order lowpass and highpass filter analogs technically don't have gain either, // but this can be 'faked' by adjusting the bx factors, so we support that anyway, even if it isn't realistic. if ( (m_type != biquad_type::PEAK) && (m_type != biquad_type::LOWSHELF) diff --git a/src/devices/sound/flt_biquad.h b/src/devices/sound/flt_biquad.h index 97c434d9f79..ed4192ce44f 100644 --- a/src/devices/sound/flt_biquad.h +++ b/src/devices/sound/flt_biquad.h @@ -44,10 +44,17 @@ public: void modify(biquad_type type, double fc, double q, double gain); void modify(biquad_params p); - // helper setup functions to create common filters representable by biquad filters + // helper setup functions to create common filters representable by biquad filters: + // Sallen-Key low-pass filter_biquad_device& opamp_sk_lowpass_setup(double r1, double r2, double r3, double r4, double c1, double c2); + void opamp_sk_lowpass_modify(double r1, double r2, double r3, double r4, double c1, double c2); + biquad_params opamp_sk_lowpass_calc(double r1, double r2, double r3, double r4, double c1, double c2); + // TODO when needed: Sallen-Key band-pass + + // TODO when needed: Sallen-Key band-reject + // TODO when needed: Sallen-Key high-pass // Multiple-Feedback low-pass diff --git a/src/mame/drivers/mac128.cpp b/src/mame/drivers/mac128.cpp index f937efb280d..7aef5e0479c 100644 --- a/src/mame/drivers/mac128.cpp +++ b/src/mame/drivers/mac128.cpp @@ -91,6 +91,7 @@ part number 338-6523 (later Macs use a PLCC version which Apple numbered #include "machine/swim1.h" #include "machine/ncr5380n.h" #include "machine/nscsi_bus.h" +#include "machine/rescap.h" #include "bus/nscsi/hd.h" #include "bus/nscsi/cd.h" #include "machine/ncr5380.h" @@ -100,6 +101,7 @@ part number 338-6523 (later Macs use a PLCC version which Apple numbered #include "machine/z80scc.h" #include "machine/macadb.h" #include "sound/dac.h" +#include "sound/flt_biquad.h" #include "bus/macpds/pds_tpdfpd.h" #include "formats/ap_dsk35.h" @@ -119,8 +121,8 @@ static constexpr int MAC_H_TOTAL = 704; // (512+192) static constexpr int MAC_V_TOTAL = 370; // (342+28) // sound buffer locations -static constexpr int MAC_MAIN_SND_BUF_OFFSET = (0x0300>>1); -static constexpr int MAC_ALT_SND_BUF_OFFSET = (0x5F00>>1); +static constexpr int MAC_MAIN_SND_BUF_OFFSET = (0x0300>>1); // (end of memory minus 0x0300; for the typical macplus case, this is 0x3ffd00-0x3fffe3 in 16 bit blocks) +static constexpr int MAC_ALT_SND_BUF_OFFSET = (0x5F00>>1); // (end of memory minus 0x5F00) class mac128_state : public driver_device { @@ -140,6 +142,8 @@ public: m_rtc(*this,"rtc"), m_screen(*this, "screen"), m_dac(*this, "macdac"), + m_filter(*this, "dacfilter"), + m_volfilter(*this, "volfilter"), m_scc(*this, "scc"), m_mouse0(*this, "MOUSE0"), m_mouse1(*this, "MOUSE1"), @@ -174,6 +178,8 @@ private: optional_device m_rtc; required_device m_screen; required_device m_dac; + required_device m_filter; + required_device m_volfilter; required_device m_scc; optional_ioport m_mouse0, m_mouse1, m_mouse2; @@ -425,16 +431,38 @@ void mac128_state::update_volume() if (!m_snd_enable) { // ls161 clear input - m_dac->set_output_gain(ALL_OUTPUTS, 0); + m_dac->set_output_gain(ALL_OUTPUTS, 0.0); } else { - // sound -> r13 (470k) - // sound -> r12 (470k) -> 4016 (pa0 != 0) - // sound -> r17 (150k) -> 4016 (pa1 != 0) - // sound -> r16 (68k) -> 4016 (pa2 != 0) - m_dac->set_output_gain(ALL_OUTPUTS, 8.0 / (m_snd_vol + 1)); + m_dac->set_output_gain(ALL_OUTPUTS, 1.0); } + + /* LS161 audio PWM counters TC (SND) -> LS04 inverter (/SND) -> + * -> CD4016 gate A pulling a 5.1V zener-regulated signal to ground if input is high -> + * -> Sallen-key low-pass filter (R1 = 47K, R2 = 47K, C1 = 0.001uF, C2 = 470pF + * FC of 4939.3903Hz, Q of 0.7293, Gain of 1.0) -> + * ->\-> r13 (470k) ------------------------>| + * |-> r12 (470k) -> CD4016 D (pa0 != 0) ->| + * |-> r17 (150k) -> CD4016 C (pa1 != 0) ->| + * |-> r16 (68k) -> CD4016 B (pa2 != 0) ->\-> DC blocking caps -> + * -> Push-Pull +12v/-12vb amplifier w/feedback (technically a 1st order multifeedback lowpass filter?) -> + * -> Audio Jack -> Speaker + */ + const double res_ohm_tbl[8] = + { + // R13 R16 R17 R12 + (1.0 / ( (1.0 / RES_K(470)) ) ), + (1.0 / ( (1.0 / RES_K(470)) + (1.0 / RES_K(470)) ) ), + (1.0 / ( (1.0 / RES_K(470)) + (1.0 / RES_K(150)) ) ), + (1.0 / ( (1.0 / RES_K(470)) + (1.0 / RES_K(150)) + (1.0 / RES_K(470)) ) ), + (1.0 / ( (1.0 / RES_K(470)) + (1.0 / RES_K(68)) ) ), + (1.0 / ( (1.0 / RES_K(470)) + (1.0 / RES_K(68)) + (1.0 / RES_K(470)) ) ), + (1.0 / ( (1.0 / RES_K(470)) + (1.0 / RES_K(68)) + (1.0 / RES_K(150)) ) ), + (1.0 / ( (1.0 / RES_K(470)) + (1.0 / RES_K(68)) + (1.0 / RES_K(150)) + (1.0 / RES_K(470)) ) ) + }; + + m_volfilter->opamp_mfb_lowpass_modify(res_ohm_tbl[m_snd_vol&7], RES_K(0), RES_K(200), CAP_U(0), CAP_P(220)); // variable based on cd4016, short, R15, absent, C10 } WRITE_LINE_MEMBER(mac128_state::vblank_w) @@ -1097,7 +1125,11 @@ void mac128_state::mac512ke(machine_config &config) /* sound hardware */ SPEAKER(config, "speaker").front_center(); - DAC_8BIT_PWM(config, m_dac, 0).add_route(ALL_OUTPUTS, "speaker", 0.25); // 2 x ls161 + FILTER_BIQUAD(config, m_volfilter).opamp_mfb_lowpass_setup(RES_K(39.020), RES_K(0), RES_K(200), CAP_U(0), CAP_P(220)); // variable based on cd4016, short, R15, absent, C10 + m_volfilter->add_route(ALL_OUTPUTS, "speaker", 0.195); // this filter has a max gain of ~5.126, so we diminish it by the inverse of that (0.195) + FILTER_BIQUAD(config, m_filter).opamp_sk_lowpass_setup(RES_K(47), RES_K(47), RES_M(999.99), RES_R(0.001), CAP_U(0.001), CAP_P(470)); // R18, R14, absent, short, C18, C19 + m_filter->add_route(ALL_OUTPUTS, m_volfilter, 1.0); + DAC_8BIT_PWM(config, m_dac, 0).add_route(ALL_OUTPUTS, m_filter, 1.0); // 2 x ls161 /* devices */ RTC3430042(config, m_rtc, 32.768_kHz_XTAL); @@ -1278,6 +1310,28 @@ ROM_START( mactw ) ROM_REGION16_BE(0x100000, "bootrom", 0) ROM_LOAD( "rom4.3t_07-04-83.bin", 0x0000, 0x10000, CRC(d2c42f18) SHA1(f868c09ca70383a69751c37a5a3110a9597462a4) ) ROM_END + + // one twiggy mac (SN 1042) has the following sum16s on the 4x 16k eproms on the "512 EPROM ADAPTER" daughterboard: + // U3 EPROM // 1 HI: "H1 // A04A" + // U4 EPROM // 0 HI: "H0 // B6ED" + // U5 EPROM // 1 LOW: "Lo1 // 6C8C" + // U6 EPROM // 0 LOW: "Lo0 // F332" + // This one was publicly dumped by Adam Goolevitch, but one of the SUM16s (B5ED) does not match the ROM label (B6ED). + // The ROM has been marked as bad pending a redump or other verification of correctness. + ROMX_LOAD("h0__b6ed.u4", 0x00000, 0x04000, BAD_DUMP CRC(87136a61) SHA1(a33fc3b7908783a5742f06884fe44260447e5d55), ROM_SKIP(1) ) // SUM16: B5ED does not match written label + ROMX_LOAD("lo0__f332.u6", 0x00001, 0x04000, CRC(3d04b1c5) SHA1(11fe22e8ce415edf4133d7cee559dce4ab0f7974), ROM_SKIP(1) ) // SUM16: F332 + ROMX_LOAD("h1__a04a.u3", 0x08000, 0x04000, CRC(fa9ae0d1) SHA1(e89826325caf053aad2c09d134c8c7483d442821), ROM_SKIP(1) ) // SUM16: A04A + ROMX_LOAD("lo1__6c8c.u5", 0x08001, 0x04000, CRC(ca78a04e) SHA1(724d7d7b585c375cd5797e4334d6ab6267e798dc), ROM_SKIP(1) ) // SUM16: 6C8C + + + // one twiggy mac (SN 1072, upc MA1M830241240) has the following sum16s on the 4x 16k EPROMs on the "512 EPROM ADAPTER" daughterboard: + // U3 EPROM // 1 HI: "Rom 2.45 // H 1 // 1D79" + // U4 EPROM // 0 HI: "ROM 2.45 // High0 // D4DF" + // U5 EPROM // 1 LOW: "ROM 2.45 // LOW1 // 977F" + // U6 EPROM // 0 LOW: "ROM 2.45 // LOW0 // C813" + // This Twiggy mac has a prototype IWM labeled " 8248 // XXX-X299 (C) // APPLE 82" + // The ROM of this twiggy mac has been tentatively dated between March and April 1983, possibly March 11, 1983. + // See https://macgui.com/news/article.php?t=517 */ ROM_START( mac128k ) @@ -1303,6 +1357,15 @@ ROM_START( mac128k ) https://68kmla.org/forums/uploads/monthly_12_2014/post-2597-0-46269000-1419299800.jpg http://cdn.cultofmac.com/wp-content/uploads/2014/01/12A-128k-Motherboard.jpg */ + + //ROM_REGION(0x3000, "pals", 0) + // @U14E 342-0186-A PAL16R8 ASG + // @U2D 342-0187-A PAL16L8 BMU1 + // @U3D 342-0189-A PAL16R6 TSG + // @U2E 342-0191-A PAL16R4 BMU0 + // @U1E 342-0251-A PAL16R8 LAG + // @U1D 342-0254-A PAL16R4A TSM + ROM_END ROM_START( mac512k ) @@ -1310,11 +1373,20 @@ ROM_START( mac512k ) ROMX_LOAD("342-0220-b.u6d", 0x00000, 0x08000, CRC(0dce9a3f) SHA1(101ca6570f5a273e400d1a8bc63e15ee0e94153e), ROM_SKIP(1) ) // " 512 VH 6434 // 23256-1104 // 342-0220-B // (C) APPLE 84 // KOREA-A" ROMX_LOAD("342-0221-b.u8d", 0x00001, 0x08000, CRC(d51f376e) SHA1(575586109e876cffa4a4d472cb38771aa21b70cb), ROM_SKIP(1) ) // " 512 VH 6709 // 23256-1105 // 342-0221-B // (C) APPLE 84 // KOREA-A" // reference: http://i.ebayimg.com/images/g/Uj8AAOSwvzRXy2tW/s-l1600.jpg + + //ROM_REGION(0x3000, "pals", 0) + // @U14E 342-0186-A PAL16R8 ASG + // @U2D 342-0187-A PAL16L8 BMU1 + // @U3D 342-0189-A PAL16R6 TSG + // @U2E 342-0191-A PAL16R4 BMU0 + // @U1E 342-0251-A PAL16R8 LAG + // @U1D 342-0254-A PAL16R4A TSM ROM_END ROM_START( unitron ) ROM_REGION16_BE(0x100000, "bootrom", 0) ROM_LOAD16_WORD( "unitron_512.rom", 0x00000, 0x10000, CRC(1eabd37f) SHA1(a3d3696c08feac6805effb7ee07b68c2bf1a8dd7) ) + // pals are different from mac 128/512/512ke ROM_END ROM_START( utrn1024 ) @@ -1322,6 +1394,7 @@ ROM_START( utrn1024 ) // CRCs match the original "Lonely Hearts" version 1 Mac Plus ROM: 4d1eeee1 ROMX_LOAD( "342-0341-a.u6d", 0x000000, 0x010000, CRC(5095fe39) SHA1(be780580033d914b5035d60b5ebbd66bd1d28a9b), ROM_SKIP(1) ) // not correct label ROMX_LOAD( "342-0342-a.u8d", 0x000001, 0x010000, CRC(fb766270) SHA1(679f529fbfc05f9cc98924c53457d2996dfcb1a7), ROM_SKIP(1) ) // not correct label + // unknown pals ROM_END ROM_START( mac512ke ) // 512ke has been observed with any of the v3, v2 or v1 macplus romsets installed, and v1 romsets are more common here than in the plus, since the 512ke lacks scsi, which is the cause of the major bug fixed between v1 and v2, hence 512ke is unaffected and was a good way for apple to use up the buggy roms rather than destroying them. @@ -1372,6 +1445,14 @@ ROM_START( mac512ke ) // 512ke has been observed with any of the v3, v2 or v1 ma GUESSED, since this ROM is very rare: "VTI // 62? V0 86?? // 23512-1008 // 342-0341-A // (C)APPLE '83-'85 // KOREA A" 'ROM-LO' @ U8D is same as v2/4d1eeae1 'ROM-LO' @ U8D */ + + //ROM_REGION(0x3000, "pals", 0) + // @U14E 342-0186-A PAL16R8 ASG + // @U2D 342-0187-A PAL16L8 BMU1 + // @U3D 342-0189-A PAL16R6 TSG + // @U2E 342-0191-A PAL16R4 BMU0 + // @U1E 342-0251-A PAL16R8 LAG + // @U1D 342-0254-A PAL16R4A TSM ROM_END ROM_START( macplus ) // same notes as above apply here as well @@ -1396,16 +1477,27 @@ ROM_START( macplus ) // same notes as above apply here as well ROM_SYSTEM_BIOS(4, "romdisk2", "bigmessofwires.com ROMinator (2/25/2015)") ROMX_LOAD( "rominator-20150225-lo.bin", 0x000001, 0x080000, CRC(62cf2a0b) SHA1(f78ebb0919dd9e094bef7952b853b70e66d05e01), ROM_SKIP(1) | ROM_BIOS(4) ) ROMX_LOAD( "rominator-20150225-hi.bin", 0x000000, 0x080000, CRC(a28ba8ec) SHA1(9ddcf500727955c60db0ff24b5ca2458f53fd89a), ROM_SKIP(1) | ROM_BIOS(4) ) + + //ROM_REGION(0x3000, "pals", 0) + // @U11E 342-0517-A PAL16?? ASG + // @U2D 341-0514-A PAL16L8 BMU1 + // @U3D 342-0516-A PAL16R6 TSG + // @U3E 342-0519-A PAL20?? CAS + // @U2E 342-0520-A PAL20R4A BMU2 + // @U1E 342-0515-A PAL16R8 LAG + // @U1D 342-0522-A VP16RP8MPC (PAL16R4A on schem) TSM ROM_END ROM_START( macse ) ROM_REGION16_BE(0x100000, "bootrom", 0) ROM_LOAD16_WORD( "macse.rom", 0x00000, 0x40000, CRC(0f7ff80c) SHA1(58532b7d0d49659fd5228ac334a1b094f0241968)) + // GLU HAL (mask PAL) ROM_END ROM_START( macsefd ) ROM_REGION16_BE(0x100000, "bootrom", 0) ROM_LOAD( "be06e171.rom", 0x000000, 0x040000, CRC(f530cb10) SHA1(d3670a90273d12e53d86d1228c068cb660b8c9d1) ) + // GLU HAL (mask PAL) ROM_END ROM_START( macclasc ) -- cgit v1.2.3