nonogamer9

OC-SID : A Sid Player for Computronics OpenComputers!

Sep 25th, 2026 (edited)
90
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 82.10 KB | Source Code | 0 0
  1. local component = require("component")
  2. local event = require("event")
  3. local computer = require("computer")
  4. local bit = require("bit32")
  5.  
  6. if not component.isAvailable("sound") then
  7.     error("A Computronics Sound Card is required.")
  8. end
  9.  
  10. local sound = component.sound
  11.  
  12. local RAM_SIZE = 65536
  13.  
  14. local SID_BASE = 0xD400
  15. local SID_END = 0xD41F
  16.  
  17. local MAX_SIDS = 3
  18. local VOICES_PER_SID = 3
  19. local TOTAL_VOICES = MAX_SIDS * VOICES_PER_SID
  20.  
  21. local SOUND_CHANNELS = 8
  22. local AUDIO_BATCH_SINGLE = 2
  23. local AUDIO_BATCH_MULTI = 4
  24.  
  25. local PWM_MODE = "blend"
  26.  
  27. local SAW_BLEND_GAIN = 1.6
  28. local SAW_BLEND_MAX = 1.5
  29.  
  30. local PWM_DETUNE = 0.006
  31. local PWM_BALANCE = 0.65
  32. local PWM_NARROW = 0.15
  33.  
  34. local FILTER_ENABLED = true
  35. local FILTER_MIN_HZ = 30
  36. local FILTER_MAX_HZ = 12000
  37. local FILTER_HARMONIC_RATIO = 3
  38. local FILTER_MAX_GAIN = 1.6
  39.  
  40. local ENVELOPE_SHAPING = true
  41. local DECAY_SCALE = 0.6
  42. local RELEASE_SCALE = 0.6
  43.  
  44. local PULSE_LEVEL_STRENGTH = 1.0
  45. local PULSE_LEVEL_FLOOR = 0.15
  46.  
  47. local HF_SOFTEN_START = 4000
  48. local HF_SOFTEN_END = 10000
  49. local HF_SOFTEN_STRENGTH = 0.6
  50. local HF_SOFTEN_MIX = 0.8
  51.  
  52. local COMBINED_LEVEL = 0.7
  53.  
  54. local SYNC_APPROX = true
  55. local RING_APPROX = true
  56.  
  57. local SAW_BLEND_EXP = 0.35
  58.  
  59. local PULSE_LEVEL_CURVE = 0.6
  60.  
  61. local ANALOG_DRIFT_ENABLED = true
  62. local ANALOG_DRIFT_STRENGTH = 0.0015
  63. local ANALOG_DRIFT_SMOOTH = 0.05
  64.  
  65. local FILTER_MODEL_AWARE = true
  66. local FILTER_6581_EXPONENT = 1.7
  67.  
  68. local FILTER_SELF_OSC_RESONANCE = 14
  69. local FILTER_SELF_OSC_GAIN = 3.0
  70.  
  71. local ENV_ACCURATE = true
  72. local ENV_SUBSTEPS = 4
  73.  
  74. local ENV_ADSR_DELAY_BUG = true
  75. local ENV_VOLUME_STEP = 0.006
  76.  
  77. local NOISE_RATE_SCALE = 16
  78.  
  79. local NOISE_LOCKUP = true
  80.  
  81. local DEFAULT_SID_MODEL = "6581"
  82.  
  83. local BUS_READBACK = true
  84. local BUS_TTL_CYCLES = 8192
  85.  
  86. local CIA_TRACKING = true
  87.  
  88. local PAL_HZ = 50
  89. local NTSC_HZ = 60
  90.  
  91. local PAL_CLOCK = 985248
  92. local NTSC_CLOCK = 1022727
  93. local SID_FREQ_DIV = 16777216
  94.  
  95. local DEFAULT_VOLUME = 0.55
  96. local MIN_VOLUME = 0.0
  97. local MAX_VOLUME = 1.0
  98.  
  99. local MAX_INSTRUCTIONS_PER_CALL = 200000
  100. local MAX_INSTRUCTIONS_PER_IRQ = 200000
  101. local MAX_CYCLES_PER_CALL = 1000000
  102. local MAX_CYCLES_PER_IRQ = 1000000
  103.  
  104. local KERNAL_IRQ_EXIT = 0xEA31
  105.  
  106. local WAVE_NOISE = sound.modes.noise
  107. local WAVE_SQUARE = sound.modes.square
  108. local WAVE_SAW = sound.modes.sawtooth
  109. local WAVE_TRIANGLE = sound.modes.triangle
  110.  
  111. local function u8(x)
  112.     x = x % 256
  113.     if x < 0 then
  114.         x = x + 256
  115.     end
  116.     return x
  117. end
  118.  
  119. local function u16(x)
  120.     x = x % 65536
  121.     if x < 0 then
  122.         x = x + 65536
  123.     end
  124.     return x
  125. end
  126.  
  127. local function lo(x)
  128.     return bit.band(x, 0xFF)
  129. end
  130.  
  131. local function hi(x)
  132.     return bit.band(bit.rshift(x, 8), 0xFF)
  133. end
  134.  
  135. local function signed8(x)
  136.     if x >= 128 then
  137.         return x - 256
  138.     end
  139.     return x
  140. end
  141.  
  142. local function clamp(x, a, b)
  143.     if x < a then
  144.         return a
  145.     end
  146.  
  147.     if x > b then
  148.         return b
  149.     end
  150.  
  151.     return x
  152. end
  153.  
  154. local SID = {}
  155.  
  156. function SID.readBE16(data, p)
  157.     local a, b = string.byte(data, p, p + 1)
  158.  
  159.     if not a or not b then
  160.         error("Unexpected end of SID header.")
  161.     end
  162.  
  163.     return a * 256 + b
  164. end
  165.  
  166. function SID.readBE32(data, p)
  167.     local a, b, c, d = string.byte(data, p, p + 3)
  168.  
  169.     if not a or not b or not c or not d then
  170.         error("Unexpected end of SID header.")
  171.     end
  172.  
  173.     return ((a * 256 + b) * 256 + c) * 256 + d
  174. end
  175.  
  176. function SID.text(data, p, length)
  177.     local s = data:sub(p, p + length - 1)
  178.  
  179.     s = s:gsub("%z.*$", "")
  180.     s = s:gsub("[%c]", "")
  181.  
  182.     return s
  183. end
  184.  
  185. function SID.decodeClock(flags)
  186.     if flags == 0 then
  187.         return "unknown"
  188.     end
  189.  
  190.     local clockBits = bit.band(bit.rshift(flags, 2), 0x03)
  191.  
  192.     if clockBits == 1 then
  193.         return "PAL"
  194.     end
  195.  
  196.     if clockBits == 2 then
  197.         return "NTSC"
  198.     end
  199.  
  200.     if clockBits == 3 then
  201.         return "PAL+NTSC"
  202.     end
  203.  
  204.     return "unknown"
  205. end
  206.  
  207. function SID.decodeModel(flags, shift)
  208.     local modelBits = bit.band(bit.rshift(flags, shift), 0x03)
  209.  
  210.     if modelBits == 1 then
  211.         return "6581"
  212.     end
  213.  
  214.     if modelBits == 2 then
  215.         return "8580"
  216.     end
  217.  
  218.     if modelBits == 3 then
  219.         return "6581/8580"
  220.     end
  221.  
  222.     return "unknown"
  223. end
  224.  
  225. function SID.decodeSIDAddress(selector)
  226.     if not selector or selector == 0 then
  227.         return 0
  228.     end
  229.  
  230.     selector = bit.band(selector, 0xFF)
  231.  
  232.     if bit.band(selector, 1) ~= 0 then
  233.         return 0
  234.     end
  235.  
  236.     if selector < 0x42 then
  237.         return 0
  238.     end
  239.  
  240.     if selector > 0x7F and selector < 0xE0 then
  241.         return 0
  242.     end
  243.  
  244.     if selector > 0xFE then
  245.         return 0
  246.     end
  247.  
  248.     return 0xD000 + bit.lshift(selector, 4)
  249. end
  250.  
  251. function SID.loadFile(path)
  252.     local f, err = io.open(path, "rb")
  253.  
  254.     if not f then
  255.         error("Cannot open SID file: " .. tostring(err))
  256.     end
  257.  
  258.     local data = f:read("*a")
  259.     f:close()
  260.  
  261.     if not data or #data < 0x76 then
  262.         error("File is too small to be a valid SID file.")
  263.     end
  264.  
  265.     local magic = data:sub(1, 4)
  266.  
  267.     if magic ~= "PSID" and magic ~= "RSID" then
  268.         error("Not a PSID/RSID file.")
  269.     end
  270.  
  271.     local version = SID.readBE16(data, 5)
  272.     local dataOffset = SID.readBE16(data, 7)
  273.     local loadAddress = SID.readBE16(data, 9)
  274.     local initAddress = SID.readBE16(data, 11)
  275.     local playAddress = SID.readBE16(data, 13)
  276.     local songs = SID.readBE16(data, 15)
  277.     local startSong = SID.readBE16(data, 17)
  278.     local speed = SID.readBE32(data, 19)
  279.  
  280.     if songs < 1 then
  281.         songs = 1
  282.     end
  283.  
  284.     if startSong < 1 or startSong > songs then
  285.         startSong = 1
  286.     end
  287.  
  288.     if dataOffset < 0x76 or dataOffset > #data then
  289.         error("Invalid SID data offset.")
  290.     end
  291.  
  292.     local flags = 0
  293.  
  294.     if version >= 2 and #data >= 0x7C then
  295.         flags = SID.readBE16(data, 0x77)
  296.     end
  297.  
  298.     local secondSID = 0
  299.     local thirdSID = 0
  300.  
  301.     if version >= 3 and #data >= 0x7C then
  302.         secondSID = SID.decodeSIDAddress(string.byte(data, 0x7B))
  303.     end
  304.  
  305.     if version >= 4 and #data >= 0x7C then
  306.         thirdSID = SID.decodeSIDAddress(string.byte(data, 0x7C))
  307.     end
  308.  
  309.     if secondSID == SID_BASE then
  310.         secondSID = 0
  311.     end
  312.  
  313.     if thirdSID == SID_BASE or thirdSID == secondSID then
  314.         thirdSID = 0
  315.     end
  316.  
  317.     local name = SID.text(data, 0x17, 32)
  318.     local author = SID.text(data, 0x37, 32)
  319.     local released = SID.text(data, 0x57, 32)
  320.  
  321.     local binary = data:sub(dataOffset + 1)
  322.  
  323.     if loadAddress == 0 then
  324.         if #binary < 2 then
  325.             error("SID data has no embedded load address.")
  326.         end
  327.  
  328.         local a = string.byte(binary, 1)
  329.         local b = string.byte(binary, 2)
  330.  
  331.         loadAddress = a + b * 256
  332.         binary = binary:sub(3)
  333.     end
  334.  
  335.     if loadAddress < 0 or loadAddress + #binary > RAM_SIZE then
  336.         error("SID program does not fit into C64 memory.")
  337.     end
  338.  
  339.     local effectiveInitAddress = initAddress
  340.  
  341.     if effectiveInitAddress == 0 then
  342.         effectiveInitAddress = loadAddress
  343.     end
  344.  
  345.     local sidBases = { SID_BASE }
  346.  
  347.     if secondSID ~= 0 then
  348.         sidBases[2] = secondSID
  349.     end
  350.  
  351.     if thirdSID ~= 0 then
  352.         sidBases[3] = thirdSID
  353.     end
  354.  
  355.     return {
  356.         magic = magic,
  357.         version = version,
  358.         dataOffset = dataOffset,
  359.  
  360.         loadAddress = loadAddress,
  361.         initAddress = initAddress,
  362.         effectiveInitAddress = effectiveInitAddress,
  363.         playAddress = playAddress,
  364.  
  365.         songs = songs,
  366.         startSong = startSong,
  367.         speed = speed,
  368.  
  369.         flags = flags,
  370.  
  371.         clock = SID.decodeClock(flags),
  372.  
  373.         sidModel1 = SID.decodeModel(flags, 4),
  374.         sidModel2 = SID.decodeModel(flags, 6),
  375.         sidModel3 = SID.decodeModel(flags, 8),
  376.  
  377.         secondSID = secondSID,
  378.         thirdSID = thirdSID,
  379.  
  380.         sidBases = sidBases,
  381.  
  382.         name = name,
  383.         author = author,
  384.         released = released,
  385.  
  386.         data = binary
  387.     }
  388. end
  389.  
  390. local function lfsrStep(l)
  391.     local b = bit.bxor(bit.rshift(l, 22), bit.rshift(l, 17))
  392.  
  393.     return bit.band(bit.bor(bit.lshift(l, 1), bit.band(b, 1)), 0x7FFFFF)
  394. end
  395.  
  396. local function lfsrByte(l)
  397.     local function b(n)
  398.         return bit.band(bit.rshift(l, n), 1)
  399.     end
  400.  
  401.     return b(22) * 128 + b(20) * 64 + b(16) * 32 + b(13) * 16 +
  402.            b(11) * 8 + b(7) * 4 + b(4) * 2 + b(2)
  403. end
  404.  
  405. local ENV_PERIODS = {
  406.     9, 32, 63, 95, 149, 220, 267, 313,
  407.     392, 977, 1954, 3126, 3907, 11720, 19532, 31251
  408. }
  409.  
  410. local EnvGen = {}
  411. EnvGen.__index = EnvGen
  412.  
  413. function EnvGen.new()
  414.     local self = setmetatable({}, EnvGen)
  415.  
  416.     self.level = 0
  417.     self.state = "release"
  418.     self.gate = false
  419.     self.holdZero = true
  420.  
  421.     self.rateCounter = 0
  422.     self.ratePeriod = ENV_PERIODS[1]
  423.     self.expCounter = 0
  424.     self.expPeriod = 1
  425.  
  426.     self.attack = 0
  427.     self.decay = 0
  428.     self.release = 0
  429.     self.sustainLevel = 0
  430.  
  431.     self.t = 0
  432.  
  433.     return self
  434. end
  435.  
  436. function EnvGen:refreshPeriod()
  437.     if self.state == "attack" then
  438.         self.ratePeriod = ENV_PERIODS[self.attack + 1]
  439.     elseif self.state == "decay" then
  440.         self.ratePeriod = ENV_PERIODS[self.decay + 1]
  441.     else
  442.         self.ratePeriod = ENV_PERIODS[self.release + 1]
  443.     end
  444.  
  445.     if not ENV_ADSR_DELAY_BUG and self.rateCounter >= self.ratePeriod then
  446.         self.rateCounter = 0
  447.     end
  448. end
  449.  
  450. function EnvGen:setGate(gate)
  451.     if gate == self.gate then
  452.         return
  453.     end
  454.  
  455.     self.gate = gate
  456.  
  457.     if gate then
  458.         self.state = "attack"
  459.         self.holdZero = false
  460.     else
  461.         self.state = "release"
  462.     end
  463.  
  464.     self:refreshPeriod()
  465. end
  466.  
  467. function EnvGen:setAD(value)
  468.     self.attack = math.floor(value / 16) % 16
  469.     self.decay = value % 16
  470.  
  471.     if self.state ~= "release" then
  472.         self:refreshPeriod()
  473.     end
  474. end
  475.  
  476. function EnvGen:setSR(value)
  477.     self.sustainLevel = (math.floor(value / 16) % 16) * 17
  478.     self.release = value % 16
  479.  
  480.     if self.state == "release" then
  481.         self:refreshPeriod()
  482.     end
  483. end
  484.  
  485. function EnvGen:tick()
  486.     if self.state ~= "attack" then
  487.         self.expCounter = self.expCounter + 1
  488.  
  489.         if self.expCounter ~= self.expPeriod then
  490.             return
  491.         end
  492.     end
  493.  
  494.     self.expCounter = 0
  495.  
  496.     if self.holdZero then
  497.         return
  498.     end
  499.  
  500.     local level = self.level
  501.  
  502.     if self.state == "attack" then
  503.         level = (level + 1) % 256
  504.  
  505.         if level == 255 then
  506.             self.state = "decay"
  507.             self.ratePeriod = ENV_PERIODS[self.decay + 1]
  508.         end
  509.  
  510.     elseif self.state == "decay" then
  511.         if level ~= self.sustainLevel then
  512.             level = (level - 1) % 256
  513.         end
  514.  
  515.     else
  516.         level = (level - 1) % 256
  517.     end
  518.  
  519.     self.level = level
  520.  
  521.     if level == 255 then
  522.         self.expPeriod = 1
  523.     elseif level == 93 then
  524.         self.expPeriod = 2
  525.     elseif level == 54 then
  526.         self.expPeriod = 4
  527.     elseif level == 26 then
  528.         self.expPeriod = 8
  529.     elseif level == 14 then
  530.         self.expPeriod = 16
  531.     elseif level == 6 then
  532.         self.expPeriod = 30
  533.     elseif level == 0 then
  534.         self.expPeriod = 1
  535.         self.holdZero = true
  536.     end
  537. end
  538.  
  539. function EnvGen:isIdle()
  540.     if self.state == "decay" then
  541.         return self.holdZero or self.level == self.sustainLevel
  542.     end
  543.  
  544.     if self.state == "release" then
  545.         return self.holdZero
  546.     end
  547.  
  548.     return false
  549. end
  550.  
  551. function EnvGen:advance(cycles)
  552.     while cycles > 0 do
  553.         local period = self.ratePeriod
  554.         local rc = self.rateCounter
  555.         local need
  556.  
  557.         if rc < period then
  558.             need = period - rc
  559.         else
  560.             need = 0x7FFF - rc + period
  561.         end
  562.  
  563.         if cycles < need then
  564.             rc = rc + cycles
  565.  
  566.             if rc >= 0x8000 then
  567.                 rc = rc - 0x7FFF
  568.             end
  569.  
  570.             self.rateCounter = rc
  571.             return
  572.         end
  573.  
  574.         cycles = cycles - need
  575.         self.rateCounter = 0
  576.  
  577.         self:tick()
  578.  
  579.         if self:isIdle() then
  580.             period = self.ratePeriod
  581.  
  582.             local events = math.floor(cycles / period)
  583.  
  584.             self.rateCounter = cycles - events * period
  585.             self.expCounter = (self.expCounter + events) % self.expPeriod
  586.  
  587.             return
  588.         end
  589.     end
  590. end
  591.  
  592. function EnvGen:advanceTo(now)
  593.     local n = now - self.t
  594.  
  595.     if n > 0 then
  596.         self.t = now
  597.         self:advance(n)
  598.     end
  599. end
  600.  
  601. local ENV_CONTROL_VOICE = { [0x04] = 1, [0x0B] = 2, [0x12] = 3 }
  602. local ENV_AD_VOICE = { [0x05] = 1, [0x0C] = 2, [0x13] = 3 }
  603. local ENV_SR_VOICE = { [0x06] = 1, [0x0D] = 2, [0x14] = 3 }
  604.  
  605. local SIDChip = {}
  606. SIDChip.__index = SIDChip
  607.  
  608. function SIDChip.new()
  609.     local self = setmetatable({}, SIDChip)
  610.  
  611.     self.reg = {}
  612.  
  613.     for i = 0, 0x1F do
  614.         self.reg[i] = 0
  615.     end
  616.  
  617.     self.voices = { {}, {}, {} }
  618.  
  619.     self.gateOn = { false, false, false }
  620.  
  621.     self.filter = {}
  622.  
  623.     self.cpu = nil
  624.  
  625.     self.osc = { phase = 0, last = 0, lfsr = 0x7FFFF8 }
  626.  
  627.     self.envs = { EnvGen.new(), EnvGen.new(), EnvGen.new() }
  628.  
  629.     self.noiseLocked = { false, false, false }
  630.  
  631.     self.bus = 0
  632.     self.busTime = 0
  633.  
  634.     return self
  635. end
  636.  
  637. function SIDChip:now()
  638.     if self.cpu then
  639.         return self.cpu.cycles
  640.     end
  641.  
  642.     return 0
  643. end
  644.  
  645. function SIDChip:advanceOsc(now)
  646.     local o = self.osc
  647.     local elapsed = now - o.last
  648.  
  649.     o.last = now
  650.  
  651.     if elapsed <= 0 then
  652.         return
  653.     end
  654.  
  655.     if bit.band(self.reg[0x12] or 0, 0x08) ~= 0 then
  656.         o.phase = 0
  657.         return
  658.     end
  659.  
  660.     local freq = (self.reg[0x0E] or 0) + (self.reg[0x0F] or 0) * 256
  661.  
  662.     local prev = o.phase
  663.     local total = prev + freq * elapsed
  664.  
  665.     o.phase = total % 16777216
  666.  
  667.     local rises =
  668.         math.floor((total - 524288) / 1048576) -
  669.         math.floor((prev - 524288) / 1048576)
  670.  
  671.     if rises > 32 then
  672.         rises = 32
  673.     end
  674.  
  675.     for _ = 1, rises do
  676.         o.lfsr = lfsrStep(o.lfsr)
  677.     end
  678. end
  679.  
  680. function SIDChip:osc3Output()
  681.     self:advanceOsc(self:now())
  682.  
  683.     local control = self.reg[0x12] or 0
  684.     local phase = self.osc.phase
  685.  
  686.     if bit.band(control, 0xF0) == 0 then
  687.         return 0
  688.     end
  689.  
  690.     local value = 0xFF
  691.  
  692.     if bit.band(control, 0x10) ~= 0 then
  693.         local t = bit.band(bit.rshift(phase, 15), 0xFF)
  694.  
  695.         if bit.band(bit.rshift(phase, 23), 1) == 1 then
  696.             t = bit.bxor(t, 0xFF)
  697.         end
  698.  
  699.         value = bit.band(value, t)
  700.     end
  701.  
  702.     if bit.band(control, 0x20) ~= 0 then
  703.         value = bit.band(value, bit.band(bit.rshift(phase, 16), 0xFF))
  704.     end
  705.  
  706.     if bit.band(control, 0x40) ~= 0 then
  707.         local pw = (self.reg[0x10] or 0) +
  708.             bit.band(self.reg[0x11] or 0, 0x0F) * 256
  709.  
  710.         local acc12 = math.floor(phase / 4096)
  711.  
  712.         value = bit.band(value, acc12 >= pw and 0xFF or 0)
  713.     end
  714.  
  715.     if bit.band(control, 0x80) ~= 0 then
  716.         value = bit.band(value, lfsrByte(self.osc.lfsr))
  717.     end
  718.  
  719.     return value
  720. end
  721.  
  722. function SIDChip:env3Output()
  723.     local e = self.envs[3]
  724.  
  725.     e:advanceTo(self:now())
  726.  
  727.     return e.level
  728. end
  729.  
  730. function SIDChip:read(reg)
  731.     reg = bit.band(reg, 0x1F)
  732.  
  733.     if reg == 0x1B then
  734.         return self:osc3Output()
  735.     end
  736.  
  737.     if reg == 0x1C then
  738.         return self:env3Output()
  739.     end
  740.  
  741.     if reg == 0x19 or reg == 0x1A then
  742.         return 0
  743.     end
  744.  
  745.     if BUS_READBACK then
  746.         if self:now() - self.busTime > BUS_TTL_CYCLES then
  747.             return 0
  748.         end
  749.  
  750.         return self.bus
  751.     end
  752.  
  753.     return self.reg[reg] or 0
  754. end
  755.  
  756. function SIDChip:write(reg, value)
  757.     reg = bit.band(reg, 0x1F)
  758.     value = u8(value)
  759.  
  760.     if reg == 0x03 or reg == 0x0A or reg == 0x11 then
  761.         value = bit.band(value, 0x0F)
  762.     end
  763.  
  764.     if reg == 0x15 then
  765.         value = bit.band(value, 0x07)
  766.     end
  767.  
  768.     local now = self:now()
  769.  
  770.     self.bus = value
  771.     self.busTime = now
  772.  
  773.     if reg == 0x0E or reg == 0x0F or reg == 0x12 then
  774.         self:advanceOsc(now)
  775.     end
  776.  
  777.     local envVoice = ENV_CONTROL_VOICE[reg]
  778.  
  779.     if envVoice then
  780.         local env = self.envs[envVoice]
  781.  
  782.         env:advanceTo(now)
  783.         env:setGate(bit.band(value, 0x01) ~= 0)
  784.  
  785.         if bit.band(value, 0x08) ~= 0 then
  786.             self.noiseLocked[envVoice] = false
  787.         end
  788.     end
  789.  
  790.     envVoice = ENV_AD_VOICE[reg]
  791.  
  792.     if envVoice then
  793.         local env = self.envs[envVoice]
  794.  
  795.         env:advanceTo(now)
  796.         env:setAD(value)
  797.     end
  798.  
  799.     envVoice = ENV_SR_VOICE[reg]
  800.  
  801.     if envVoice then
  802.         local env = self.envs[envVoice]
  803.  
  804.         env:advanceTo(now)
  805.         env:setSR(value)
  806.     end
  807.  
  808.     if reg == 0x04 or reg == 0x0B or reg == 0x12 then
  809.         local voiceIndex = (reg == 0x04) and 1 or ((reg == 0x0B) and 2 or 3)
  810.  
  811.         local oldGate = bit.band(self.reg[reg] or 0, 1)
  812.         local newGate = bit.band(value, 1)
  813.  
  814.         if newGate == 1 and oldGate == 0 then
  815.             self.gateOn[voiceIndex] = true
  816.         end
  817.     end
  818.  
  819.     if reg >= 0x19 and reg <= 0x1C then
  820.         return
  821.     end
  822.  
  823.     self.reg[reg] = value
  824. end
  825.  
  826. function SIDChip:masterVolume()
  827.     return bit.band(self.reg[0x18] or 0, 0x0F)
  828. end
  829.  
  830. function SIDChip:voice3Off()
  831.     return bit.band(self.reg[0x18] or 0, 0x80) ~= 0
  832. end
  833.  
  834. function SIDChip:voice(v)
  835.     local base = (v - 1) * 7
  836.     local out = self.voices[v]
  837.  
  838.     local freqLo = self.reg[base] or 0
  839.     local freqHi = self.reg[base + 1] or 0
  840.     local pwLo = self.reg[base + 2] or 0
  841.     local pwHi = self.reg[base + 3] or 0
  842.     local control = self.reg[base + 4] or 0
  843.     local attackDecay = self.reg[base + 5] or 0
  844.     local sustainRelease = self.reg[base + 6] or 0
  845.  
  846.     out.frequency = freqLo + bit.lshift(freqHi, 8)
  847.     out.pulse = pwLo + bit.lshift(bit.band(pwHi, 0x0F), 8)
  848.     out.control = control
  849.  
  850.     out.attack = bit.rshift(attackDecay, 4)
  851.     out.decay = bit.band(attackDecay, 0x0F)
  852.     out.sustain = bit.rshift(sustainRelease, 4)
  853.     out.release = bit.band(sustainRelease, 0x0F)
  854.  
  855.     out.gate = bit.band(control, 0x01) ~= 0
  856.     out.sync = bit.band(control, 0x02) ~= 0
  857.     out.ring = bit.band(control, 0x04) ~= 0
  858.     out.test = bit.band(control, 0x08) ~= 0
  859.     out.triangle = bit.band(control, 0x10) ~= 0
  860.     out.saw = bit.band(control, 0x20) ~= 0
  861.     out.square = bit.band(control, 0x40) ~= 0
  862.     out.noise = bit.band(control, 0x80) ~= 0
  863.  
  864.     if NOISE_LOCKUP and out.noise and
  865.        (out.triangle or out.saw or out.square) then
  866.         self.noiseLocked[v] = true
  867.     end
  868.  
  869.     out.noiseLocked = self.noiseLocked[v]
  870.  
  871.     out.retrigger = self.gateOn[v]
  872.     self.gateOn[v] = false
  873.  
  874.     return out
  875. end
  876.  
  877. function SIDChip:filterState()
  878.     local r15 = self.reg[0x15] or 0
  879.     local r16 = self.reg[0x16] or 0
  880.     local r17 = self.reg[0x17] or 0
  881.     local r18 = self.reg[0x18] or 0
  882.  
  883.     local st = self.filter
  884.  
  885.     st.cutoff = bit.band(r15, 0x07) + bit.lshift(r16, 3)
  886.     st.resonance = bit.rshift(r17, 4)
  887.     st.route = bit.band(r17, 0x07)
  888.  
  889.     st.lp = bit.band(r18, 0x10) ~= 0
  890.     st.bp = bit.band(r18, 0x20) ~= 0
  891.     st.hp = bit.band(r18, 0x40) ~= 0
  892.  
  893.     return st
  894. end
  895.  
  896. local OPCODE
  897.  
  898. local CPU = {}
  899. CPU.__index = CPU
  900.  
  901. function CPU.new(memory, sids, sidBases)
  902.     local self = setmetatable({}, CPU)
  903.  
  904.     self.mem = memory
  905.  
  906.     self.sids = sids
  907.     self.sidBases = sidBases
  908.  
  909.     self.sidCount = #sids
  910.  
  911.     self.A = 0
  912.     self.X = 0
  913.     self.Y = 0
  914.  
  915.     self.P = 0x24
  916.     self.SP = 0xFD
  917.     self.PC = 0
  918.  
  919.     self.running = true
  920.  
  921.     self.cycles = 0
  922.     self.lastCallCycles = 0
  923.     self.lastIRQCycles = 0
  924.  
  925.     for i = 1, #sids do
  926.         sids[i].cpu = self
  927.     end
  928.  
  929.     return self
  930. end
  931.  
  932. local RMW_OPS = {
  933.     ASL = true, LSR = true, ROL = true, ROR = true,
  934.     INC = true, DEC = true, SLO = true, RLA = true,
  935.     SRE = true, RRA = true, DCP = true, ISC = true
  936. }
  937.  
  938. function CPU:estimateCycles(opcode)
  939.     local entry = OPCODE[opcode]
  940.  
  941.     if not entry then
  942.         return 2
  943.     end
  944.  
  945.     local op = entry.op
  946.     local mode = entry.mode
  947.  
  948.     if op == "BRK" then return 7 end
  949.     if op == "JSR" then return 6 end
  950.     if op == "RTI" or op == "RTS" then return 6 end
  951.     if op == "JMP" then
  952.         return mode == "ind" and 5 or 3
  953.     end
  954.     if mode == "rel" then return 2 end
  955.     if mode == "imp" or mode == "acc" then
  956.         if op == "PHA" or op == "PHP" or op == "PLA" or op == "PLP" then
  957.             return 3
  958.         end
  959.         return 2
  960.     end
  961.     if mode == "imm" then return 2 end
  962.     if mode == "zp" then
  963.         return RMW_OPS[op] and 5 or 3
  964.     end
  965.     if mode == "zpx" or mode == "zpy" then
  966.         return RMW_OPS[op] and 6 or 4
  967.     end
  968.     if mode == "izx" then
  969.         return 6
  970.     end
  971.     if mode == "izy" then
  972.         return (op == "STA" or op == "SAX" or op == "SHA" or op == "AHX") and 6 or 5
  973.     end
  974.     if mode == "abs" then
  975.         return RMW_OPS[op] and 6 or 4
  976.     end
  977.     if mode == "abx" or mode == "aby" then
  978.         if op == "STA" or op == "SHX" or op == "SHY" or op == "TAS" or op == "AHX" then
  979.             return 5
  980.         end
  981.         if RMW_OPS[op] then
  982.             return 7
  983.         end
  984.         return 4
  985.     end
  986.  
  987.     return 2
  988. end
  989.  
  990. function CPU:sidAt(addr)
  991.     if addr >= SID_BASE and addr <= SID_END then
  992.         return self.sids[1], addr - SID_BASE
  993.     end
  994.  
  995.     for i = 2, self.sidCount do
  996.         local base = self.sidBases[i]
  997.  
  998.         if base and base ~= 0 and
  999.            addr >= base and addr <= base + 0x1F then
  1000.             return self.sids[i], addr - base
  1001.         end
  1002.     end
  1003.  
  1004.     return nil
  1005. end
  1006.  
  1007. function CPU:read(addr)
  1008.     addr = bit.band(addr, 0xFFFF)
  1009.  
  1010.     local sid, reg = self:sidAt(addr)
  1011.  
  1012.     if sid then
  1013.         return sid:read(reg)
  1014.     end
  1015.  
  1016.     return self.mem[addr] or 0
  1017. end
  1018.  
  1019. function CPU:write(addr, value)
  1020.     addr = bit.band(addr, 0xFFFF)
  1021.     value = u8(value)
  1022.  
  1023.     local sid, reg = self:sidAt(addr)
  1024.  
  1025.     if sid then
  1026.         sid:write(reg, value)
  1027.         return
  1028.     end
  1029.  
  1030.     self.mem[addr] = value
  1031. end
  1032.  
  1033. function CPU:fetch()
  1034.     local pc = self.PC
  1035.     local value = self:read(pc)
  1036.  
  1037.     self.PC = bit.band(pc + 1, 0xFFFF)
  1038.  
  1039.     return value
  1040. end
  1041.  
  1042. function CPU:fetch16()
  1043.     local l = self:fetch()
  1044.     local h = self:fetch()
  1045.  
  1046.     return l + bit.lshift(h, 8)
  1047. end
  1048.  
  1049. function CPU:push(v)
  1050.     self:write(0x100 + self.SP, v)
  1051.     self.SP = u8(self.SP - 1)
  1052. end
  1053.  
  1054. function CPU:pull()
  1055.     self.SP = u8(self.SP + 1)
  1056.     return self:read(0x100 + self.SP)
  1057. end
  1058.  
  1059. function CPU:push16(v)
  1060.     self:push(hi(v))
  1061.     self:push(lo(v))
  1062. end
  1063.  
  1064. function CPU:pull16()
  1065.     local l = self:pull()
  1066.     local h = self:pull()
  1067.  
  1068.     return l + bit.lshift(h, 8)
  1069. end
  1070.  
  1071. function CPU:getFlag(mask)
  1072.     return bit.band(self.P, mask) ~= 0
  1073. end
  1074.  
  1075. function CPU:setFlag(mask, value)
  1076.     if value then
  1077.         self.P = bit.bor(self.P, mask)
  1078.     else
  1079.         self.P = bit.band(self.P, bit.bnot(mask))
  1080.     end
  1081.  
  1082.     self.P = bit.bor(self.P, 0x20)
  1083. end
  1084.  
  1085. function CPU:setZN(v)
  1086.     v = u8(v)
  1087.  
  1088.     self:setFlag(0x02, v == 0)
  1089.     self:setFlag(0x80, bit.band(v, 0x80) ~= 0)
  1090. end
  1091.  
  1092. function CPU:adc(v)
  1093.     v = u8(v)
  1094.  
  1095.     local carry = self:getFlag(0x01) and 1 or 0
  1096.  
  1097.     local a = self.A
  1098.     local result = a + v + carry
  1099.  
  1100.     self:setFlag(0x01, result > 255)
  1101.  
  1102.     local r = u8(result)
  1103.  
  1104.     local overflow =
  1105.         bit.band(
  1106.             bit.bnot(bit.bxor(a, v)),
  1107.             bit.bxor(a, r),
  1108.             0x80
  1109.         ) ~= 0
  1110.  
  1111.     self:setFlag(0x40, overflow)
  1112.  
  1113.     self.A = r
  1114.  
  1115.     self:setZN(self.A)
  1116. end
  1117.  
  1118. function CPU:sbc(v)
  1119.     self:adc(bit.bxor(v, 0xFF))
  1120. end
  1121.  
  1122. function CPU:cmp(reg, v)
  1123.     v = u8(v)
  1124.  
  1125.     local result = u8(reg - v)
  1126.  
  1127.     self:setFlag(0x01, reg >= v)
  1128.     self:setZN(result)
  1129. end
  1130.  
  1131. function CPU:asl(v)
  1132.     v = u8(v)
  1133.  
  1134.     local carry = bit.band(v, 0x80) ~= 0
  1135.  
  1136.     v = u8(bit.lshift(v, 1))
  1137.  
  1138.     self:setFlag(0x01, carry)
  1139.     self:setZN(v)
  1140.  
  1141.     return v
  1142. end
  1143.  
  1144. function CPU:lsr(v)
  1145.     v = u8(v)
  1146.  
  1147.     local carry = bit.band(v, 1) ~= 0
  1148.  
  1149.     v = bit.rshift(v, 1)
  1150.  
  1151.     self:setFlag(0x01, carry)
  1152.     self:setZN(v)
  1153.  
  1154.     return v
  1155. end
  1156.  
  1157. function CPU:rol(v)
  1158.     v = u8(v)
  1159.  
  1160.     local carryIn = self:getFlag(0x01) and 1 or 0
  1161.     local carryOut = bit.band(v, 0x80) ~= 0
  1162.  
  1163.     v = u8(bit.lshift(v, 1) + carryIn)
  1164.  
  1165.     self:setFlag(0x01, carryOut)
  1166.     self:setZN(v)
  1167.  
  1168.     return v
  1169. end
  1170.  
  1171. function CPU:ror(v)
  1172.     v = u8(v)
  1173.  
  1174.     local carryIn = self:getFlag(0x01) and 0x80 or 0
  1175.     local carryOut = bit.band(v, 1) ~= 0
  1176.  
  1177.     v = bit.bor(bit.rshift(v, 1), carryIn)
  1178.  
  1179.     self:setFlag(0x01, carryOut)
  1180.     self:setZN(v)
  1181.  
  1182.     return v
  1183. end
  1184.  
  1185. function CPU:addr(mode)
  1186.     if mode == "imp" or mode == "acc" then
  1187.         return nil
  1188.     end
  1189.  
  1190.     if mode == "imm" then
  1191.         local a = self.PC
  1192.  
  1193.         self.PC = u16(self.PC + 1)
  1194.  
  1195.         return a
  1196.     end
  1197.  
  1198.     if mode == "zp" then
  1199.         return self:fetch()
  1200.     end
  1201.  
  1202.     if mode == "zpx" then
  1203.         return bit.band(self:fetch() + self.X, 0xFF)
  1204.     end
  1205.  
  1206.     if mode == "zpy" then
  1207.         return bit.band(self:fetch() + self.Y, 0xFF)
  1208.     end
  1209.  
  1210.     if mode == "abs" then
  1211.         return self:fetch16()
  1212.     end
  1213.  
  1214.     if mode == "abx" then
  1215.         return u16(self:fetch16() + self.X)
  1216.     end
  1217.  
  1218.     if mode == "aby" then
  1219.         return u16(self:fetch16() + self.Y)
  1220.     end
  1221.  
  1222.     if mode == "izx" then
  1223.         local p = bit.band(self:fetch() + self.X, 0xFF)
  1224.  
  1225.         local l = self:read(p)
  1226.         local h = self:read(bit.band(p + 1, 0xFF))
  1227.  
  1228.         return l + bit.lshift(h, 8)
  1229.     end
  1230.  
  1231.     if mode == "izy" then
  1232.         local p = self:fetch()
  1233.  
  1234.         local l = self:read(p)
  1235.         local h = self:read(bit.band(p + 1, 0xFF))
  1236.  
  1237.         return u16(l + bit.lshift(h, 8) + self.Y)
  1238.     end
  1239.  
  1240.     if mode == "ind" then
  1241.         local p = self:fetch16()
  1242.  
  1243.         local l = self:read(p)
  1244.  
  1245.         local hp = bit.bor(bit.band(p, 0xFF00), bit.band(p + 1, 0xFF))
  1246.  
  1247.         local h = self:read(hp)
  1248.  
  1249.         return l + bit.lshift(h, 8)
  1250.     end
  1251.  
  1252.     if mode == "rel" then
  1253.         local r = signed8(self:fetch())
  1254.  
  1255.         return u16(self.PC + r)
  1256.     end
  1257.  
  1258.     error("Unknown addressing mode: " .. tostring(mode))
  1259. end
  1260.  
  1261. local opcodeRows = {
  1262.     "BRK/imp ORA/izx */imp */imp NOP/zp ORA/zp ASL/zp */imp PHP/imp ORA/imm ASL/acc */imp NOP/abs ORA/abs ASL/abs */imp",
  1263.     "BPL/rel ORA/izy */imp */imp NOP/zpx ORA/zpx ASL/zpx */imp CLC/imp ORA/aby NOP/imp */imp NOP/abx ORA/abx ASL/abx */imp",
  1264.     "JSR/abs AND/izx */imp */imp BIT/zp AND/zp ROL/zp */imp PLP/imp AND/imm ROL/acc */imp BIT/abs AND/abs ROL/abs */imp",
  1265.     "BMI/rel AND/izy */imp */imp NOP/zpx AND/zpx ROL/zpx */imp SEC/imp AND/aby NOP/imp */imp NOP/abx AND/abx ROL/abx */imp",
  1266.     "RTI/imp EOR/izx */imp */imp NOP/zp EOR/zp LSR/zp */imp PHA/imp EOR/imm LSR/acc */imp JMP/abs EOR/abs LSR/abs */imp",
  1267.     "BVC/rel EOR/izy */imp */imp NOP/zpx EOR/zpx LSR/zpx */imp CLI/imp EOR/aby NOP/imp */imp NOP/abx EOR/abx LSR/abx */imp",
  1268.     "RTS/imp ADC/izx */imp */imp NOP/zp ADC/zp ROR/zp */imp PLA/imp ADC/imm ROR/acc */imp JMP/ind ADC/abs ROR/abs */imp",
  1269.     "BVS/rel ADC/izy */imp */imp NOP/zpx ADC/zpx ROR/zpx */imp SEI/imp ADC/aby NOP/imp */imp NOP/abx ADC/abx ROR/abx */imp",
  1270.     "NOP/imm STA/izx NOP/imm */imp STY/zp STA/zp STX/zp */imp DEY/imp NOP/imm TXA/imp */imp STY/abs STA/abs STX/abs */imp",
  1271.     "BCC/rel STA/izy */imp */imp STY/zpx STA/zpx STX/zpy */imp TYA/imp STA/aby TXS/imp */imp */imp STA/abx */imp */imp",
  1272.     "LDY/imm LDA/izx LDX/imm */imp LDY/zp LDA/zp LDX/zp */imp TAY/imp LDA/imm TAX/imp */imp LDY/abs LDA/abs LDX/abs */imp",
  1273.     "BCS/rel LDA/izy */imp */imp LDY/zpx LDA/zpx LDX/zpy */imp CLV/imp LDA/aby TSX/imp */imp LDY/abx LDA/abx LDX/aby */imp",
  1274.     "CPY/imm CMP/izx NOP/imm */imp CPY/zp CMP/zp DEC/zp */imp INY/imp CMP/imm DEX/imp */imp CPY/abs CMP/abs DEC/abs */imp",
  1275.     "BNE/rel CMP/izy */imp */imp NOP/zpx CMP/zpx DEC/zpx */imp CLD/imp CMP/aby NOP/imp */imp NOP/abx CMP/abx DEC/abx */imp",
  1276.     "CPX/imm SBC/izx NOP/imm */imp CPX/zp SBC/zp INC/zp */imp INX/imp SBC/imm NOP/imp */imp CPX/abs SBC/abs INC/abs */imp",
  1277.     "BEQ/rel SBC/izy */imp */imp NOP/zpx SBC/zpx INC/zpx */imp SED/imp SBC/aby NOP/imp */imp NOP/abx SBC/abx INC/abx */imp"
  1278. }
  1279.  
  1280. OPCODE = {}
  1281.  
  1282. for rowIndex = 1, #opcodeRows do
  1283.     local col = 0
  1284.  
  1285.     for token in string.gmatch(opcodeRows[rowIndex], "%S+") do
  1286.         col = col + 1
  1287.  
  1288.         local slash = string.find(token, "/", 1, true)
  1289.  
  1290.         local mnemonic = token:sub(1, slash - 1)
  1291.         local mode = token:sub(slash + 1)
  1292.  
  1293.         local opcode = (rowIndex - 1) * 16 + (col - 1)
  1294.  
  1295.         OPCODE[opcode] = {
  1296.             op = mnemonic,
  1297.             mode = mode
  1298.         }
  1299.     end
  1300. end
  1301.  
  1302. local ILLEGAL = {
  1303.     [0x03] = {"SLO", "izx"}, [0x07] = {"SLO", "zp"}, [0x0F] = {"SLO", "abs"},
  1304.     [0x13] = {"SLO", "izy"}, [0x17] = {"SLO", "zpx"}, [0x1B] = {"SLO", "aby"},
  1305.     [0x1F] = {"SLO", "abx"},
  1306.  
  1307.     [0x23] = {"RLA", "izx"}, [0x27] = {"RLA", "zp"}, [0x2F] = {"RLA", "abs"},
  1308.     [0x33] = {"RLA", "izy"}, [0x37] = {"RLA", "zpx"}, [0x3B] = {"RLA", "aby"},
  1309.     [0x3F] = {"RLA", "abx"},
  1310.  
  1311.     [0x43] = {"SRE", "izx"}, [0x47] = {"SRE", "zp"}, [0x4F] = {"SRE", "abs"},
  1312.     [0x53] = {"SRE", "izy"}, [0x57] = {"SRE", "zpx"}, [0x5B] = {"SRE", "aby"},
  1313.     [0x5F] = {"SRE", "abx"},
  1314.  
  1315.     [0x63] = {"RRA", "izx"}, [0x67] = {"RRA", "zp"}, [0x6F] = {"RRA", "abs"},
  1316.     [0x73] = {"RRA", "izy"}, [0x77] = {"RRA", "zpx"}, [0x7B] = {"RRA", "aby"},
  1317.     [0x7F] = {"RRA", "abx"},
  1318.  
  1319.     [0x83] = {"SAX", "izx"}, [0x87] = {"SAX", "zp"}, [0x8F] = {"SAX", "abs"},
  1320.     [0x97] = {"SAX", "zpy"},
  1321.  
  1322.     [0xA3] = {"LAX", "izx"}, [0xA7] = {"LAX", "zp"}, [0xAB] = {"LAX", "imm"},
  1323.     [0xAF] = {"LAX", "abs"}, [0xB3] = {"LAX", "izy"}, [0xB7] = {"LAX", "zpy"},
  1324.     [0xBF] = {"LAX", "aby"},
  1325.  
  1326.     [0xC3] = {"DCP", "izx"}, [0xC7] = {"DCP", "zp"}, [0xCF] = {"DCP", "abs"},
  1327.     [0xD3] = {"DCP", "izy"}, [0xD7] = {"DCP", "zpx"}, [0xDB] = {"DCP", "aby"},
  1328.     [0xDF] = {"DCP", "abx"},
  1329.  
  1330.     [0xE3] = {"ISC", "izx"}, [0xE7] = {"ISC", "zp"}, [0xEF] = {"ISC", "abs"},
  1331.     [0xF3] = {"ISC", "izy"}, [0xF7] = {"ISC", "zpx"}, [0xFB] = {"ISC", "aby"},
  1332.     [0xFF] = {"ISC", "abx"},
  1333.  
  1334.     [0x1A] = {"NOP", "imp"}, [0x3A] = {"NOP", "imp"}, [0x5A] = {"NOP", "imp"},
  1335.     [0x7A] = {"NOP", "imp"}, [0xDA] = {"NOP", "imp"}, [0xFA] = {"NOP", "imp"},
  1336.  
  1337.     [0x80] = {"NOP", "imm"}, [0x82] = {"NOP", "imm"}, [0x89] = {"NOP", "imm"},
  1338.  
  1339.     [0x04] = {"NOP", "zp"}, [0x44] = {"NOP", "zp"}, [0x64] = {"NOP", "zp"},
  1340.  
  1341.     [0x14] = {"NOP", "zpx"}, [0x34] = {"NOP", "zpx"}, [0x54] = {"NOP", "zpx"},
  1342.     [0x74] = {"NOP", "zpx"}, [0xD4] = {"NOP", "zpx"}, [0xF4] = {"NOP", "zpx"},
  1343.  
  1344.     [0x0C] = {"NOP", "abs"},
  1345.  
  1346.     [0x1C] = {"NOP", "abx"}, [0x3C] = {"NOP", "abx"}, [0x5C] = {"NOP", "abx"},
  1347.     [0x7C] = {"NOP", "abx"}, [0xDC] = {"NOP", "abx"}, [0xFC] = {"NOP", "abx"},
  1348.  
  1349.     [0x0B] = {"ANC", "imm"}, [0x2B] = {"ANC", "imm"},
  1350.     [0x4B] = {"ALR", "imm"}, [0x6B] = {"ARR", "imm"},
  1351.     [0xCB] = {"AXS", "imm"},
  1352.  
  1353.     [0xBB] = {"LAS", "aby"},
  1354.  
  1355.     [0x9C] = {"SHY", "abx"}, [0x9E] = {"SHX", "aby"}, [0x9B] = {"TAS", "aby"},
  1356.     [0x93] = {"AHX", "izy"}, [0x9F] = {"AHX", "aby"}
  1357. }
  1358.  
  1359. for opcode, info in pairs(ILLEGAL) do
  1360.     OPCODE[opcode] = {
  1361.         op = info[1],
  1362.         mode = info[2]
  1363.     }
  1364. end
  1365.  
  1366. local KIL = {
  1367.     [0x02] = true, [0x12] = true, [0x22] = true, [0x32] = true,
  1368.     [0x42] = true, [0x52] = true, [0x62] = true, [0x72] = true,
  1369.     [0x92] = true, [0xB2] = true, [0xD2] = true, [0xF2] = true
  1370. }
  1371.  
  1372. for opcode in pairs(KIL) do
  1373.     OPCODE[opcode] = {
  1374.         op = "KIL",
  1375.         mode = "imp"
  1376.     }
  1377. end
  1378.  
  1379. local CYCLES = {}
  1380.  
  1381. for opcode = 0, 255 do
  1382.     CYCLES[opcode] = CPU.estimateCycles(nil, opcode)
  1383. end
  1384.  
  1385. local BRANCHES = {
  1386.     BPL = {0x80, false}, BMI = {0x80, true},
  1387.     BVC = {0x40, false}, BVS = {0x40, true},
  1388.     BCC = {0x01, false}, BCS = {0x01, true},
  1389.     BNE = {0x02, false}, BEQ = {0x02, true}
  1390. }
  1391.  
  1392. local FLAG_OPS = {
  1393.     CLC = {0x01, false}, SEC = {0x01, true},
  1394.     CLI = {0x04, false}, SEI = {0x04, true},
  1395.     CLV = {0x40, false},
  1396.     CLD = {0x08, false}, SED = {0x08, true}
  1397. }
  1398.  
  1399. function CPU:execute(opcode)
  1400.     local entry = OPCODE[opcode]
  1401.  
  1402.     if not entry then
  1403.         return
  1404.     end
  1405.  
  1406.     local op = entry.op
  1407.     local mode = entry.mode
  1408.  
  1409.     if op == "KIL" then
  1410.         self.running = false
  1411.         return
  1412.     end
  1413.  
  1414.     if op == "*" then
  1415.         if mode == "imm" or mode == "zp" or mode == "zpx" or
  1416.            mode == "zpy" or mode == "rel" then
  1417.             self.PC = u16(self.PC + 1)
  1418.         elseif mode == "abs" or mode == "abx" or mode == "aby" then
  1419.             self.PC = u16(self.PC + 2)
  1420.         elseif mode == "izx" or mode == "izy" or mode == "ind" then
  1421.             self.PC = u16(self.PC + 1)
  1422.         end
  1423.  
  1424.         return
  1425.     end
  1426.  
  1427.     local branch = BRANCHES[op]
  1428.  
  1429.     if branch then
  1430.         local a = self:addr("rel")
  1431.  
  1432.         if self:getFlag(branch[1]) == branch[2] then
  1433.             self.PC = a
  1434.         end
  1435.  
  1436.         return
  1437.     end
  1438.  
  1439.     local flagOp = FLAG_OPS[op]
  1440.  
  1441.     if flagOp then
  1442.         self:setFlag(flagOp[1], flagOp[2])
  1443.         return
  1444.     end
  1445.  
  1446.     if op == "JMP" then
  1447.         self.PC = self:addr(mode)
  1448.         return
  1449.     end
  1450.  
  1451.     if op == "JSR" then
  1452.         local target = self:addr("abs")
  1453.  
  1454.         self:push16(u16(self.PC - 1))
  1455.  
  1456.         self.PC = target
  1457.         return
  1458.     end
  1459.  
  1460.     if op == "RTS" then
  1461.         self.PC = u16(self:pull16() + 1)
  1462.         return
  1463.     end
  1464.  
  1465.     if op == "RTI" then
  1466.         self.P = self:pull()
  1467.         self.PC = self:pull16()
  1468.         self.P = bit.bor(self.P, 0x20)
  1469.         return
  1470.     end
  1471.  
  1472.     if op == "BRK" then
  1473.         self.PC = u16(self.PC + 1)
  1474.  
  1475.         self:push16(self.PC)
  1476.         self:push(bit.bor(self.P, 0x30))
  1477.  
  1478.         self:setFlag(0x04, true)
  1479.  
  1480.         local l = self:read(0xFFFE)
  1481.         local h = self:read(0xFFFF)
  1482.  
  1483.         self.PC = l + bit.lshift(h, 8)
  1484.  
  1485.         return
  1486.     end
  1487.  
  1488.     if op == "PHA" then
  1489.         self:push(self.A)
  1490.         return
  1491.     end
  1492.  
  1493.     if op == "PLA" then
  1494.         self.A = self:pull()
  1495.         self:setZN(self.A)
  1496.         return
  1497.     end
  1498.  
  1499.     if op == "PHP" then
  1500.         self:push(bit.bor(self.P, 0x30))
  1501.         return
  1502.     end
  1503.  
  1504.     if op == "PLP" then
  1505.         self.P = self:pull()
  1506.         self.P = bit.bor(self.P, 0x20)
  1507.         return
  1508.     end
  1509.  
  1510.     if op == "TAX" then
  1511.         self.X = self.A
  1512.         self:setZN(self.X)
  1513.         return
  1514.     end
  1515.  
  1516.     if op == "TAY" then
  1517.         self.Y = self.A
  1518.         self:setZN(self.Y)
  1519.         return
  1520.     end
  1521.  
  1522.     if op == "TXA" then
  1523.         self.A = self.X
  1524.         self:setZN(self.A)
  1525.         return
  1526.     end
  1527.  
  1528.     if op == "TYA" then
  1529.         self.A = self.Y
  1530.         self:setZN(self.A)
  1531.         return
  1532.     end
  1533.  
  1534.     if op == "TSX" then
  1535.         self.X = self.SP
  1536.         self:setZN(self.X)
  1537.         return
  1538.     end
  1539.  
  1540.     if op == "TXS" then
  1541.         self.SP = self.X
  1542.         return
  1543.     end
  1544.  
  1545.     if op == "INX" then
  1546.         self.X = u8(self.X + 1)
  1547.         self:setZN(self.X)
  1548.         return
  1549.     end
  1550.  
  1551.     if op == "DEX" then
  1552.         self.X = u8(self.X - 1)
  1553.         self:setZN(self.X)
  1554.         return
  1555.     end
  1556.  
  1557.     if op == "INY" then
  1558.         self.Y = u8(self.Y + 1)
  1559.         self:setZN(self.Y)
  1560.         return
  1561.     end
  1562.  
  1563.     if op == "DEY" then
  1564.         self.Y = u8(self.Y - 1)
  1565.         self:setZN(self.Y)
  1566.         return
  1567.     end
  1568.  
  1569.     if op == "ASL" or op == "LSR" or op == "ROL" or op == "ROR" then
  1570.         local fn
  1571.  
  1572.         if op == "ASL" then
  1573.             fn = self.asl
  1574.         elseif op == "LSR" then
  1575.             fn = self.lsr
  1576.         elseif op == "ROL" then
  1577.             fn = self.rol
  1578.         else
  1579.             fn = self.ror
  1580.         end
  1581.  
  1582.         if mode == "acc" then
  1583.             self.A = fn(self, self.A)
  1584.         else
  1585.             local a = self:addr(mode)
  1586.  
  1587.             self:write(a, fn(self, self:read(a)))
  1588.         end
  1589.  
  1590.         return
  1591.     end
  1592.  
  1593.     if op == "LDA" then
  1594.         local a = self:addr(mode)
  1595.         self.A = self:read(a)
  1596.         self:setZN(self.A)
  1597.         return
  1598.     end
  1599.  
  1600.     if op == "LDX" then
  1601.         local a = self:addr(mode)
  1602.         self.X = self:read(a)
  1603.         self:setZN(self.X)
  1604.         return
  1605.     end
  1606.  
  1607.     if op == "LDY" then
  1608.         local a = self:addr(mode)
  1609.         self.Y = self:read(a)
  1610.         self:setZN(self.Y)
  1611.         return
  1612.     end
  1613.  
  1614.     if op == "STA" then
  1615.         local a = self:addr(mode)
  1616.         self:write(a, self.A)
  1617.         return
  1618.     end
  1619.  
  1620.     if op == "STX" then
  1621.         local a = self:addr(mode)
  1622.         self:write(a, self.X)
  1623.         return
  1624.     end
  1625.  
  1626.     if op == "STY" then
  1627.         local a = self:addr(mode)
  1628.         self:write(a, self.Y)
  1629.         return
  1630.     end
  1631.  
  1632.     if op == "AND" then
  1633.         local a = self:addr(mode)
  1634.         self.A = bit.band(self.A, self:read(a))
  1635.         self:setZN(self.A)
  1636.         return
  1637.     end
  1638.  
  1639.     if op == "ORA" then
  1640.         local a = self:addr(mode)
  1641.         self.A = bit.bor(self.A, self:read(a))
  1642.         self:setZN(self.A)
  1643.         return
  1644.     end
  1645.  
  1646.     if op == "EOR" then
  1647.         local a = self:addr(mode)
  1648.         self.A = bit.bxor(self.A, self:read(a))
  1649.         self:setZN(self.A)
  1650.         return
  1651.     end
  1652.  
  1653.     if op == "BIT" then
  1654.         local a = self:addr(mode)
  1655.         local v = self:read(a)
  1656.  
  1657.         self:setFlag(0x02, bit.band(self.A, v) == 0)
  1658.         self:setFlag(0x80, bit.band(v, 0x80) ~= 0)
  1659.         self:setFlag(0x40, bit.band(v, 0x40) ~= 0)
  1660.  
  1661.         return
  1662.     end
  1663.  
  1664.     if op == "ADC" then
  1665.         local a = self:addr(mode)
  1666.         self:adc(self:read(a))
  1667.         return
  1668.     end
  1669.  
  1670.     if op == "SBC" then
  1671.         local a = self:addr(mode)
  1672.         self:sbc(self:read(a))
  1673.         return
  1674.     end
  1675.  
  1676.     if op == "CMP" then
  1677.         local a = self:addr(mode)
  1678.         self:cmp(self.A, self:read(a))
  1679.         return
  1680.     end
  1681.  
  1682.     if op == "CPX" then
  1683.         local a = self:addr(mode)
  1684.         self:cmp(self.X, self:read(a))
  1685.         return
  1686.     end
  1687.  
  1688.     if op == "CPY" then
  1689.         local a = self:addr(mode)
  1690.         self:cmp(self.Y, self:read(a))
  1691.         return
  1692.     end
  1693.  
  1694.     if op == "INC" then
  1695.         local a = self:addr(mode)
  1696.         local v = u8(self:read(a) + 1)
  1697.  
  1698.         self:write(a, v)
  1699.         self:setZN(v)
  1700.  
  1701.         return
  1702.     end
  1703.  
  1704.     if op == "DEC" then
  1705.         local a = self:addr(mode)
  1706.         local v = u8(self:read(a) - 1)
  1707.  
  1708.         self:write(a, v)
  1709.         self:setZN(v)
  1710.  
  1711.         return
  1712.     end
  1713.  
  1714.     if op == "NOP" then
  1715.         if mode ~= "imp" and mode ~= "acc" then
  1716.             self:addr(mode)
  1717.         end
  1718.  
  1719.         return
  1720.     end
  1721.  
  1722.     if op == "SLO" then
  1723.         local a = self:addr(mode)
  1724.         local v = self:asl(self:read(a))
  1725.  
  1726.         self:write(a, v)
  1727.  
  1728.         self.A = bit.bor(self.A, v)
  1729.         self:setZN(self.A)
  1730.         return
  1731.     end
  1732.  
  1733.     if op == "RLA" then
  1734.         local a = self:addr(mode)
  1735.         local v = self:rol(self:read(a))
  1736.  
  1737.         self:write(a, v)
  1738.  
  1739.         self.A = bit.band(self.A, v)
  1740.         self:setZN(self.A)
  1741.         return
  1742.     end
  1743.  
  1744.     if op == "SRE" then
  1745.         local a = self:addr(mode)
  1746.         local v = self:lsr(self:read(a))
  1747.  
  1748.         self:write(a, v)
  1749.  
  1750.         self.A = bit.bxor(self.A, v)
  1751.         self:setZN(self.A)
  1752.         return
  1753.     end
  1754.  
  1755.     if op == "RRA" then
  1756.         local a = self:addr(mode)
  1757.         local v = self:ror(self:read(a))
  1758.  
  1759.         self:write(a, v)
  1760.         self:adc(v)
  1761.  
  1762.         return
  1763.     end
  1764.  
  1765.     if op == "SAX" then
  1766.         local a = self:addr(mode)
  1767.  
  1768.         self:write(a, bit.band(self.A, self.X))
  1769.  
  1770.         return
  1771.     end
  1772.  
  1773.     if op == "LAX" then
  1774.         local a = self:addr(mode)
  1775.         local v = self:read(a)
  1776.  
  1777.         self.A = v
  1778.         self.X = v
  1779.  
  1780.         self:setZN(v)
  1781.  
  1782.         return
  1783.     end
  1784.  
  1785.     if op == "DCP" then
  1786.         local a = self:addr(mode)
  1787.         local v = u8(self:read(a) - 1)
  1788.  
  1789.         self:write(a, v)
  1790.         self:cmp(self.A, v)
  1791.  
  1792.         return
  1793.     end
  1794.  
  1795.     if op == "ISC" then
  1796.         local a = self:addr(mode)
  1797.         local v = u8(self:read(a) + 1)
  1798.  
  1799.         self:write(a, v)
  1800.         self:sbc(v)
  1801.  
  1802.         return
  1803.     end
  1804.  
  1805.     if op == "ANC" then
  1806.         local a = self:addr(mode)
  1807.  
  1808.         self.A = bit.band(self.A, self:read(a))
  1809.  
  1810.         self:setZN(self.A)
  1811.         self:setFlag(0x01, bit.band(self.A, 0x80) ~= 0)
  1812.  
  1813.         return
  1814.     end
  1815.  
  1816.     if op == "ALR" then
  1817.         local a = self:addr(mode)
  1818.  
  1819.         self.A = bit.band(self.A, self:read(a))
  1820.         self.A = self:lsr(self.A)
  1821.  
  1822.         return
  1823.     end
  1824.  
  1825.     if op == "ARR" then
  1826.         local a = self:addr(mode)
  1827.  
  1828.         local value = bit.band(self.A, self:read(a))
  1829.  
  1830.         local carryIn = self:getFlag(0x01) and 0x80 or 0
  1831.  
  1832.         value = bit.bor(bit.rshift(value, 1), carryIn)
  1833.  
  1834.         self.A = value
  1835.  
  1836.         self:setZN(value)
  1837.  
  1838.         self:setFlag(0x01, bit.band(value, 0x40) ~= 0)
  1839.  
  1840.         self:setFlag(
  1841.             0x40,
  1842.             bit.bxor(bit.band(value, 0x40), bit.band(value, 0x20)) ~= 0
  1843.         )
  1844.  
  1845.         return
  1846.     end
  1847.  
  1848.     if op == "AXS" then
  1849.         local a = self:addr(mode)
  1850.  
  1851.         local value = self:read(a)
  1852.  
  1853.         local result = bit.band(self.A, self.X) - value
  1854.  
  1855.         self:setFlag(0x01, result >= 0)
  1856.  
  1857.         self.X = u8(result)
  1858.  
  1859.         self:setZN(self.X)
  1860.  
  1861.         return
  1862.     end
  1863.  
  1864.     if op == "LAS" then
  1865.         local a = self:addr(mode)
  1866.  
  1867.         local v = bit.band(self:read(a), self.SP)
  1868.  
  1869.         self.A = v
  1870.         self.X = v
  1871.         self.SP = v
  1872.  
  1873.         self:setZN(v)
  1874.  
  1875.         return
  1876.     end
  1877.  
  1878.     if op == "SHY" then
  1879.         local base = self:fetch16()
  1880.         local address = u16(base + self.X)
  1881.  
  1882.         self:write(address, bit.band(self.Y, hi(address) + 1))
  1883.  
  1884.         return
  1885.     end
  1886.  
  1887.     if op == "SHX" then
  1888.         local base = self:fetch16()
  1889.         local address = u16(base + self.Y)
  1890.  
  1891.         self:write(address, bit.band(self.X, hi(address) + 1))
  1892.  
  1893.         return
  1894.     end
  1895.  
  1896.     if op == "TAS" then
  1897.         local base = self:fetch16()
  1898.         local address = u16(base + self.Y)
  1899.  
  1900.         self.SP = bit.band(self.A, self.X)
  1901.  
  1902.         self:write(address, bit.band(self.SP, hi(address) + 1))
  1903.  
  1904.         return
  1905.     end
  1906.  
  1907.     if op == "AHX" then
  1908.         local a = self:addr(mode)
  1909.  
  1910.         self:write(a, bit.band(self.A, self.X, hi(a) + 1))
  1911.  
  1912.         return
  1913.     end
  1914. end
  1915.  
  1916. function CPU:runUntilReturn(maxInstructions)
  1917.     maxInstructions = maxInstructions or MAX_INSTRUCTIONS_PER_CALL
  1918.  
  1919.     local count = 0
  1920.     local cycles = 0
  1921.     self.lastCallCycles = 0
  1922.  
  1923.     while self.running and
  1924.           count < maxInstructions and
  1925.           cycles < MAX_CYCLES_PER_CALL do
  1926.  
  1927.         if self.PC == 0xFFFF then
  1928.             self.running = false
  1929.             return true
  1930.         end
  1931.  
  1932.         local opcode = self:fetch()
  1933.  
  1934.         if not OPCODE[opcode] then
  1935.             self.running = false
  1936.             self.lastCallCycles = cycles
  1937.             return false,
  1938.                 string.format("Unknown 6502 opcode $%02X", opcode)
  1939.         end
  1940.  
  1941.         local instructionCycles = CYCLES[opcode] or 2
  1942.  
  1943.         self:execute(opcode)
  1944.  
  1945.         cycles = cycles + instructionCycles
  1946.         self.cycles = self.cycles + instructionCycles
  1947.         count = count + 1
  1948.     end
  1949.  
  1950.     self.lastCallCycles = cycles
  1951.  
  1952.     if not self.running then
  1953.         return false, "CPU stopped on KIL/JAM opcode"
  1954.     end
  1955.  
  1956.     self.running = false
  1957.  
  1958.     if cycles >= MAX_CYCLES_PER_CALL then
  1959.         return false, "CPU cycle watchdog triggered"
  1960.     end
  1961.  
  1962.     return false, "CPU instruction watchdog triggered"
  1963. end
  1964.  
  1965. function CPU:finishSyntheticIRQ()
  1966.     self.cycles = self.cycles + 6
  1967.     self.lastIRQCycles = self.lastIRQCycles + 6
  1968.  
  1969.     self.P = self:pull()
  1970.     self.PC = self:pull16()
  1971.     self.P = bit.bor(self.P, 0x20)
  1972.     self.PC = u16(self.PC)
  1973.  
  1974.     return true
  1975. end
  1976.  
  1977. function CPU:runUntilIRQReturn(maxInstructions)
  1978.     maxInstructions = maxInstructions or MAX_INSTRUCTIONS_PER_IRQ
  1979.  
  1980.     local count = 0
  1981.     local cycles = 0
  1982.     self.lastIRQCycles = 0
  1983.  
  1984.     while self.running and
  1985.           count < maxInstructions and
  1986.           cycles < MAX_CYCLES_PER_IRQ do
  1987.  
  1988.         if self.PC == KERNAL_IRQ_EXIT then
  1989.             return self:finishSyntheticIRQ()
  1990.         end
  1991.  
  1992.         local opcode = self:fetch()
  1993.  
  1994.         if not OPCODE[opcode] then
  1995.             self.running = false
  1996.             self.lastIRQCycles = cycles
  1997.             return false,
  1998.                 string.format("Unknown 6502 IRQ opcode $%02X", opcode)
  1999.         end
  2000.  
  2001.         local instructionCycles = CYCLES[opcode] or 2
  2002.  
  2003.         if opcode == 0x40 then
  2004.             self:execute(opcode)
  2005.             cycles = cycles + instructionCycles
  2006.             self.cycles = self.cycles + instructionCycles
  2007.             self.lastIRQCycles = cycles
  2008.             return true
  2009.         end
  2010.  
  2011.         self:execute(opcode)
  2012.  
  2013.         cycles = cycles + instructionCycles
  2014.         self.cycles = self.cycles + instructionCycles
  2015.         count = count + 1
  2016.     end
  2017.  
  2018.     self.lastIRQCycles = cycles
  2019.  
  2020.     if not self.running then
  2021.         return false, "IRQ CPU stopped on KIL/JAM opcode"
  2022.     end
  2023.  
  2024.     if cycles >= MAX_CYCLES_PER_IRQ then
  2025.         return false, "IRQ cycle watchdog triggered"
  2026.     end
  2027.  
  2028.     return false, "IRQ instruction watchdog triggered"
  2029. end
  2030.  
  2031. function CPU:interrupt(vector)
  2032.     local oldP = self.P
  2033.  
  2034.     self:push16(self.PC)
  2035.     self:push(bit.band(oldP, 0xEF))
  2036.  
  2037.     self.P = bit.bor(bit.band(oldP, 0xFB), 0x20)
  2038.  
  2039.     local low = self:read(vector)
  2040.     local high = self:read(bit.band(vector + 1, 0xFFFF))
  2041.  
  2042.     self.PC = low + bit.lshift(high, 8)
  2043.  
  2044.     self.running = true
  2045.  
  2046.     return self:runUntilIRQReturn()
  2047. end
  2048.  
  2049. function CPU:call(address, a, x, y)
  2050.     self.A = u8(a or 0)
  2051.     self.X = u8(x or 0)
  2052.     self.Y = u8(y or 0)
  2053.  
  2054.     self.P = 0x24
  2055.     self.SP = 0xFB
  2056.     self.running = true
  2057.  
  2058.     self:push16(0xFFFE)
  2059.  
  2060.     self.PC = u16(address)
  2061.  
  2062.     return self:runUntilReturn()
  2063. end
  2064.  
  2065. local AUDIO = {}
  2066. AUDIO.__index = AUDIO
  2067.  
  2068. local ATTACK_TIMES = {
  2069.     2, 8, 16, 24,
  2070.     38, 56, 68, 80,
  2071.     100, 250, 500, 800,
  2072.     1000, 3000, 5000, 8000
  2073. }
  2074.  
  2075. local DECAY_TIMES = {
  2076.     6, 24, 48, 72,
  2077.     114, 168, 204, 240,
  2078.     300, 750, 1500, 2400,
  2079.     3000, 9000, 15000, 24000
  2080. }
  2081.  
  2082. function AUDIO.new(sids, sidCount)
  2083.     local self = setmetatable({}, AUDIO)
  2084.  
  2085.     self.sids = sids
  2086.     self.sidCount = sidCount
  2087.  
  2088.     self.volume = DEFAULT_VOLUME
  2089.  
  2090.     self.channels = {}
  2091.     self.drift = {}
  2092.     self.sidModels = nil
  2093.  
  2094.     self.audioChannelCount = math.min(SOUND_CHANNELS, TOTAL_VOICES)
  2095.  
  2096.     self.pendingFrames = 0
  2097.     self.batchFrames =
  2098.         sidCount >= 2 and AUDIO_BATCH_MULTI or AUDIO_BATCH_SINGLE
  2099.  
  2100.     self.channelsSupported = self.audioChannelCount
  2101.  
  2102.     self.pwmMode = PWM_MODE
  2103.     self.pwmPair = ((PWM_MODE == "blend" or PWM_MODE == "pair") and sidCount == 1)
  2104.  
  2105.     self.filterEnabled = FILTER_ENABLED
  2106.  
  2107.     self.muteMask = {}
  2108.     self.curSamples = nil
  2109.     self.delayCarry = 0
  2110.  
  2111.     for i = 1, self.audioChannelCount do
  2112.         self.channels[i] = {
  2113.             opened = false,
  2114.             gate = false,
  2115.  
  2116.             waveform = nil,
  2117.             frequency = nil,
  2118.             pulse = nil,
  2119.             volume = nil,
  2120.  
  2121.             attack = nil,
  2122.             decay = nil,
  2123.             sustain = nil,
  2124.             release = nil,
  2125.  
  2126.             adsrSet = false,
  2127.             base = 0,
  2128.             envSamples = nil,
  2129.             touched = false,
  2130.  
  2131.             audible = false
  2132.         }
  2133.     end
  2134.  
  2135.     return self
  2136. end
  2137.  
  2138. function AUDIO:driftFactor(key)
  2139.     if not ANALOG_DRIFT_ENABLED then
  2140.         return 1
  2141.     end
  2142.  
  2143.     local d = self.drift[key]
  2144.  
  2145.     if not d then
  2146.         d = { value = 0, target = 0 }
  2147.         self.drift[key] = d
  2148.     end
  2149.  
  2150.     d.target = clamp(d.target + (math.random() * 2 - 1) * 0.15, -1, 1)
  2151.  
  2152.     d.value = d.value + (d.target - d.value) * ANALOG_DRIFT_SMOOTH
  2153.  
  2154.     return 1 + d.value * ANALOG_DRIFT_STRENGTH
  2155. end
  2156.  
  2157. function AUDIO:setDrift(enabled)
  2158.     ANALOG_DRIFT_ENABLED = enabled
  2159. end
  2160.  
  2161. function AUDIO:filterGain(f, voiceNumber, freq, model)
  2162.     if not self.filterEnabled then
  2163.         return 1, false
  2164.     end
  2165.  
  2166.     local routeBit = bit.lshift(1, voiceNumber - 1)
  2167.  
  2168.     if bit.band(f.route, routeBit) == 0 then
  2169.         return 1, false
  2170.     end
  2171.  
  2172.     if not (f.lp or f.bp or f.hp) then
  2173.         return 0, false
  2174.     end
  2175.  
  2176.     if freq <= 0 then
  2177.         return 1, false
  2178.     end
  2179.  
  2180.     if model ~= "6581" and model ~= "8580" then
  2181.         model = DEFAULT_SID_MODEL
  2182.     end
  2183.  
  2184.     local fc
  2185.  
  2186.     if FILTER_MODEL_AWARE and model == "6581" then
  2187.         local frac = f.cutoff / 2047
  2188.  
  2189.         fc = FILTER_MIN_HZ +
  2190.             (FILTER_MAX_HZ - FILTER_MIN_HZ) * (frac ^ FILTER_6581_EXPONENT)
  2191.     else
  2192.         fc = FILTER_MIN_HZ +
  2193.             f.cutoff * (FILTER_MAX_HZ - FILTER_MIN_HZ) / 2047
  2194.     end
  2195.  
  2196.     local r = freq / fc
  2197.     local r2 = r * r
  2198.     local q = 0.7 + f.resonance * 0.4
  2199.  
  2200.     local maxGain = FILTER_MAX_GAIN
  2201.  
  2202.     if f.resonance >= FILTER_SELF_OSC_RESONANCE then
  2203.         maxGain = FILTER_SELF_OSC_GAIN
  2204.     end
  2205.  
  2206.     local numRe = (f.lp and 1 or 0) - (f.hp and r2 or 0)
  2207.     local numIm = f.bp and (r / q) or 0
  2208.  
  2209.     local denRe = 1 - r2
  2210.     local denIm = r / q
  2211.  
  2212.     local den = math.sqrt(denRe * denRe + denIm * denIm)
  2213.  
  2214.     if den < 1e-6 then
  2215.         den = 1e-6
  2216.     end
  2217.  
  2218.     local gain = math.sqrt(numRe * numRe + numIm * numIm) / den
  2219.  
  2220.     gain = clamp(gain, 0, maxGain)
  2221.  
  2222.     local rich =
  2223.         (f.lp or f.bp) and
  2224.         (not f.hp) and
  2225.         fc < freq * FILTER_HARMONIC_RATIO
  2226.  
  2227.     return gain, rich
  2228. end
  2229.  
  2230. function AUDIO:setFilter(enabled)
  2231.     self.filterEnabled = enabled
  2232. end
  2233.  
  2234. function AUDIO:setPWMMode(mode)
  2235.     self.pwmMode = mode
  2236.     self.pwmPair = ((mode == "blend" or mode == "pair") and self.sidCount == 1)
  2237.  
  2238.     self:resetChannels()
  2239. end
  2240.  
  2241. function AUDIO:pwmDescription()
  2242.     if self.pwmPair and self.pwmMode == "blend" then
  2243.         return "square+saw blend (channels 4-6 used as partners)"
  2244.     end
  2245.  
  2246.     if self.pwmPair then
  2247.         return "detuned pair (channels 4-6 used as partners)"
  2248.     end
  2249.  
  2250.     if self.pwmMode == "morph" then
  2251.         return "timbre morph (square -> saw at narrow duty)"
  2252.     end
  2253.  
  2254.     if self.pwmMode ~= "off" then
  2255.         return "morph fallback (" .. self.pwmMode .. " mode needs a single-SID tune)"
  2256.     end
  2257.  
  2258.     return "off (plain 50% square)"
  2259. end
  2260.  
  2261. function AUDIO:frequencyFromSID(value, pal)
  2262.     value = bit.band(value or 0, 0xFFFF)
  2263.  
  2264.     if value == 0 then
  2265.         return 0
  2266.     end
  2267.  
  2268.     local clock = pal and PAL_CLOCK or NTSC_CLOCK
  2269.  
  2270.     local f = value * clock / SID_FREQ_DIV
  2271.  
  2272.     if f <= 0 then
  2273.         return 0
  2274.     end
  2275.  
  2276.     if f > 20000 then
  2277.         return 20000
  2278.     end
  2279.  
  2280.     return f
  2281. end
  2282.  
  2283. function AUDIO:waveform(v)
  2284.     if v.noise then
  2285.         return WAVE_NOISE
  2286.     end
  2287.  
  2288.     if v.square then
  2289.         if self.pwmMode ~= "off" and not self.pwmPair then
  2290.             local duty = v.pulse / 4096
  2291.  
  2292.             if duty < PWM_NARROW or duty > 1 - PWM_NARROW then
  2293.                 return WAVE_SAW
  2294.             end
  2295.         end
  2296.  
  2297.         return WAVE_SQUARE
  2298.     end
  2299.  
  2300.     if v.saw then
  2301.         return WAVE_SAW
  2302.     end
  2303.  
  2304.     if v.triangle then
  2305.         return WAVE_TRIANGLE
  2306.     end
  2307.  
  2308.     return WAVE_SQUARE
  2309. end
  2310.  
  2311. function AUDIO:adsr(v)
  2312.     local attack = ATTACK_TIMES[v.attack + 1] or 8
  2313.     local decay = DECAY_TIMES[v.decay + 1] or 24
  2314.     local sustain = v.sustain / 15
  2315.     local release = DECAY_TIMES[v.release + 1] or 24
  2316.  
  2317.     if ENVELOPE_SHAPING then
  2318.         decay = decay * (1 - sustain) * DECAY_SCALE
  2319.         release = release * math.max(sustain, 0.25) * RELEASE_SCALE
  2320.     end
  2321.  
  2322.     attack = math.max(1, math.floor(attack + 0.5))
  2323.     decay = math.max(1, math.floor(decay + 0.5))
  2324.     release = math.max(1, math.floor(release + 0.5))
  2325.  
  2326.     return attack, decay, sustain, release
  2327. end
  2328.  
  2329. function AUDIO:setVolume(v)
  2330.     self.volume = clamp(v, MIN_VOLUME, MAX_VOLUME)
  2331. end
  2332.  
  2333. function AUDIO:toggleMute(logical)
  2334.     self.muteMask[logical] = not self.muteMask[logical]
  2335.  
  2336.     return self.muteMask[logical]
  2337. end
  2338.  
  2339. function AUDIO:queueDelay(ms)
  2340.     local total = ms + self.delayCarry
  2341.     local whole = math.floor(total + 0.5)
  2342.  
  2343.     self.delayCarry = total - whole
  2344.  
  2345.     if whole > 0 then
  2346.         sound.delay(whole)
  2347.     end
  2348. end
  2349.  
  2350. function AUDIO:sampleEnvelope(env, startCycles, frameCycles, steps)
  2351.     local samples = {}
  2352.  
  2353.     for s = 1, steps do
  2354.         env:advanceTo(
  2355.             math.floor(startCycles + frameCycles * (s - 0.5) / steps)
  2356.         )
  2357.  
  2358.         samples[s] = env.level
  2359.     end
  2360.  
  2361.     env:advanceTo(startCycles + frameCycles)
  2362.  
  2363.     return samples
  2364. end
  2365.  
  2366. function AUDIO:setChannelVolume(ch, channel, volume)
  2367.     if ch.volume == nil or
  2368.        math.abs(ch.volume - volume) > ENV_VOLUME_STEP or
  2369.        (volume == 0 and ch.volume ~= 0) then
  2370.         sound.setVolume(channel, volume)
  2371.         ch.volume = volume
  2372.     end
  2373. end
  2374.  
  2375. function AUDIO:applyChannelEnvelope(ch, channel, volume)
  2376.     local samples = self.curSamples
  2377.  
  2378.     if not ch.adsrSet then
  2379.         sound.setADSR(channel, 1, 1, 1, 1)
  2380.  
  2381.         ch.adsrSet = true
  2382.  
  2383.         ch.attack = nil
  2384.         ch.decay = nil
  2385.         ch.sustain = nil
  2386.         ch.release = nil
  2387.     end
  2388.  
  2389.     local peak = 0
  2390.  
  2391.     for i = 1, #samples do
  2392.         if samples[i] > peak then
  2393.             peak = samples[i]
  2394.         end
  2395.     end
  2396.  
  2397.     ch.base = volume
  2398.     ch.envSamples = samples
  2399.     ch.touched = true
  2400.  
  2401.     if volume > 0 and peak > 0 then
  2402.         self:setChannelVolume(ch, channel, volume * samples[1] / 255)
  2403.  
  2404.         if not ch.opened then
  2405.             sound.open(channel)
  2406.             ch.opened = true
  2407.         end
  2408.  
  2409.     elseif ch.opened then
  2410.         sound.close(channel)
  2411.         ch.opened = false
  2412.     end
  2413. end
  2414.  
  2415. function AUDIO:channelFor(sidIndex, voiceNumber)
  2416.     local logical = (sidIndex - 1) * VOICES_PER_SID + voiceNumber
  2417.  
  2418.     if logical > self.audioChannelCount then
  2419.         return nil
  2420.     end
  2421.  
  2422.     return logical
  2423. end
  2424.  
  2425. function AUDIO:applyChannel(channel, wave, frequency, volume,
  2426.                             attack, decay, sustain, release, gate, retrigger)
  2427.     local ch = self.channels[channel]
  2428.  
  2429.     if ch.waveform ~= wave then
  2430.         sound.setWave(channel, wave)
  2431.         ch.waveform = wave
  2432.     end
  2433.  
  2434.     if ch.frequency == nil or math.abs(ch.frequency - frequency) > 0.25 then
  2435.         sound.setFrequency(channel, frequency)
  2436.         ch.frequency = frequency
  2437.     end
  2438.  
  2439.     if self.curSamples then
  2440.         self:applyChannelEnvelope(ch, channel, volume)
  2441.  
  2442.         ch.gate = gate
  2443.  
  2444.         return
  2445.     end
  2446.  
  2447.     if ch.attack ~= attack or ch.decay ~= decay or
  2448.        ch.sustain ~= sustain or ch.release ~= release then
  2449.         sound.setADSR(channel, attack, decay, sustain, release)
  2450.  
  2451.         ch.attack = attack
  2452.         ch.decay = decay
  2453.         ch.sustain = sustain
  2454.         ch.release = release
  2455.     end
  2456.  
  2457.     if ch.volume == nil or math.abs(ch.volume - volume) > 0.001 then
  2458.         sound.setVolume(channel, volume)
  2459.         ch.volume = volume
  2460.     end
  2461.  
  2462.     if gate then
  2463.         if ch.opened and retrigger then
  2464.             sound.close(channel)
  2465.             ch.opened = false
  2466.         end
  2467.  
  2468.         if not ch.opened then
  2469.             sound.open(channel)
  2470.             ch.opened = true
  2471.         end
  2472.     elseif ch.opened then
  2473.         sound.close(channel)
  2474.         ch.opened = false
  2475.     end
  2476.  
  2477.     ch.gate = gate
  2478. end
  2479.  
  2480. function AUDIO:updateVoice(channel, voiceNumber, v, pal, masterVolume, muted, fstate, modV, sidIndex)
  2481.     if not channel then
  2482.         return
  2483.     end
  2484.  
  2485.     local frequency = self:frequencyFromSID(v.frequency, pal)
  2486.     local modFrequency = 0
  2487.  
  2488.     if modV then
  2489.         modFrequency = self:frequencyFromSID(modV.frequency, pal)
  2490.     end
  2491.  
  2492.     if SYNC_APPROX and v.sync and modFrequency > 0 then
  2493.         frequency = modFrequency
  2494.     end
  2495.  
  2496.     if frequency > 0 then
  2497.         frequency = frequency * self:driftFactor(sidIndex * 10 + voiceNumber)
  2498.     end
  2499.  
  2500.     if v.noise and frequency > 0 then
  2501.         frequency = math.min(frequency * NOISE_RATE_SCALE, 20000)
  2502.     end
  2503.  
  2504.     local ringActive =
  2505.         RING_APPROX and
  2506.         v.ring and
  2507.         v.triangle and
  2508.         (not v.noise) and
  2509.         modFrequency > 0 and
  2510.         frequency > 0
  2511.  
  2512.     local ringSum = 0
  2513.     local ringDiff = 0
  2514.  
  2515.     if ringActive then
  2516.         ringSum = math.min(frequency + modFrequency, 20000)
  2517.         ringDiff = math.abs(frequency - modFrequency)
  2518.     end
  2519.  
  2520.     local wave = self:waveform(v)
  2521.     local attack, decay, sustain, release = self:adsr(v)
  2522.  
  2523.     local hasWave = v.noise or v.square or v.saw or v.triangle
  2524.     local noiseDead = NOISE_LOCKUP and v.noise and v.noiseLocked
  2525.  
  2526.     local audible =
  2527.         (not v.test) and hasWave and (not muted) and (not noiseDead)
  2528.  
  2529.     local levelScale = 1
  2530.  
  2531.     local waveBits =
  2532.         (v.triangle and 1 or 0) +
  2533.         (v.saw and 1 or 0) +
  2534.         (v.square and 1 or 0)
  2535.  
  2536.     if not v.noise then
  2537.         if waveBits >= 2 then
  2538.             levelScale = COMBINED_LEVEL
  2539.  
  2540.         elseif v.square then
  2541.             local d = v.pulse / 4096
  2542.  
  2543.             local pulseLevel =
  2544.                 math.max(PULSE_LEVEL_FLOOR, 2 * math.sqrt(d * (1 - d)))
  2545.  
  2546.             local perceivedLevel = pulseLevel ^ PULSE_LEVEL_CURVE
  2547.  
  2548.             levelScale = 1 + PULSE_LEVEL_STRENGTH * (perceivedLevel - 1)
  2549.         end
  2550.     end
  2551.  
  2552.     local targetVolume = 0
  2553.  
  2554.     if audible then
  2555.         local gain, rich = 1, false
  2556.  
  2557.         if fstate then
  2558.             gain, rich = self:filterGain(fstate, voiceNumber, frequency, self.sidModels and self.sidModels[sidIndex])
  2559.         end
  2560.  
  2561.         if rich and (wave == WAVE_SAW or wave == WAVE_SQUARE) then
  2562.             wave = WAVE_TRIANGLE
  2563.         end
  2564.  
  2565.         targetVolume = clamp(
  2566.             self.volume * masterVolume / 15 * gain * levelScale,
  2567.             MIN_VOLUME,
  2568.             MAX_VOLUME
  2569.         )
  2570.     end
  2571.  
  2572.     self.channels[channel].pulse = v.pulse
  2573.     self.channels[channel].audible = audible
  2574.  
  2575.     local pairChannel = nil
  2576.  
  2577.     if self.pwmPair then
  2578.         pairChannel = channel + VOICES_PER_SID
  2579.     end
  2580.  
  2581.     local partnerMode = nil
  2582.  
  2583.     if ringActive then
  2584.         wave = WAVE_TRIANGLE
  2585.  
  2586.         if pairChannel and ringDiff >= 20 then
  2587.             partnerMode = "ring"
  2588.         else
  2589.             frequency = ringSum
  2590.         end
  2591.  
  2592.     elseif pairChannel and not v.noise then
  2593.         if wave == WAVE_SQUARE and v.square then
  2594.             if v.triangle and not v.saw then
  2595.                 partnerMode = "square-tri"
  2596.             elseif self.pwmMode == "blend" then
  2597.                 partnerMode = "blend"
  2598.             elseif self.pwmMode == "pair" and
  2599.                    not v.saw and not v.triangle then
  2600.                 partnerMode = "pair"
  2601.             end
  2602.  
  2603.         elseif wave == WAVE_SAW and v.saw and v.triangle and
  2604.                not v.square then
  2605.             partnerMode = "saw-tri"
  2606.         end
  2607.     end
  2608.  
  2609.     if partnerMode == "blend" then
  2610.         local duty = v.pulse / 4096
  2611.         local e = math.abs(1 - 2 * duty)
  2612.  
  2613.         local w = math.min(SAW_BLEND_MAX, SAW_BLEND_GAIN * e ^ SAW_BLEND_EXP)
  2614.  
  2615.         if v.saw then
  2616.             w = SAW_BLEND_MAX
  2617.         end
  2618.  
  2619.         local hf = clamp(
  2620.             (frequency - HF_SOFTEN_START) /
  2621.             (HF_SOFTEN_END - HF_SOFTEN_START),
  2622.             0,
  2623.             1
  2624.         )
  2625.  
  2626.         local partnerWave = WAVE_SAW
  2627.  
  2628.         if hf > 0 then
  2629.             w = math.max(w, HF_SOFTEN_MIX * hf)
  2630.  
  2631.             if hf > 0.5 then
  2632.                 partnerWave = WAVE_TRIANGLE
  2633.             end
  2634.         end
  2635.  
  2636.         local squareShare = 1 - HF_SOFTEN_STRENGTH * hf
  2637.  
  2638.         local norm = math.sqrt(squareShare * squareShare + w * w / 3)
  2639.  
  2640.         local squareVolume = clamp(targetVolume * squareShare / norm, 0, 1)
  2641.         local partnerVolume = clamp(targetVolume * w / norm, 0, 1)
  2642.  
  2643.         self:applyChannel(
  2644.             channel, WAVE_SQUARE, frequency, squareVolume,
  2645.             attack, decay, sustain, release, v.gate, v.retrigger
  2646.         )
  2647.  
  2648.         self:applyChannel(
  2649.             pairChannel, partnerWave, frequency, partnerVolume,
  2650.             attack, decay, sustain, release, v.gate, v.retrigger
  2651.         )
  2652.  
  2653.     elseif partnerMode == "pair" then
  2654.         self:applyChannel(
  2655.             channel, WAVE_SQUARE, frequency,
  2656.             targetVolume * PWM_BALANCE,
  2657.             attack, decay, sustain, release, v.gate, v.retrigger
  2658.         )
  2659.  
  2660.         self:applyChannel(
  2661.             pairChannel, WAVE_SQUARE,
  2662.             math.min(frequency * (1 + PWM_DETUNE), 20000),
  2663.             targetVolume * (1 - PWM_BALANCE),
  2664.             attack, decay, sustain, release, v.gate, v.retrigger
  2665.         )
  2666.  
  2667.     elseif partnerMode == "ring" then
  2668.         self:applyChannel(
  2669.             channel, WAVE_TRIANGLE, ringSum, targetVolume * 0.6,
  2670.             attack, decay, sustain, release, v.gate, v.retrigger
  2671.         )
  2672.  
  2673.         self:applyChannel(
  2674.             pairChannel, WAVE_TRIANGLE, ringDiff, targetVolume * 0.6,
  2675.             attack, decay, sustain, release, v.gate, v.retrigger
  2676.         )
  2677.  
  2678.     elseif partnerMode == "square-tri" then
  2679.         self:applyChannel(
  2680.             channel, WAVE_SQUARE, frequency, targetVolume * 0.7,
  2681.             attack, decay, sustain, release, v.gate, v.retrigger
  2682.         )
  2683.  
  2684.         self:applyChannel(
  2685.             pairChannel, WAVE_TRIANGLE, frequency, targetVolume * 0.7,
  2686.             attack, decay, sustain, release, v.gate, v.retrigger
  2687.         )
  2688.  
  2689.     elseif partnerMode == "saw-tri" then
  2690.         self:applyChannel(
  2691.             channel, WAVE_SAW, frequency, targetVolume * 0.65,
  2692.             attack, decay, sustain, release, v.gate, v.retrigger
  2693.         )
  2694.  
  2695.         self:applyChannel(
  2696.             pairChannel, WAVE_TRIANGLE, frequency, targetVolume * 0.65,
  2697.             attack, decay, sustain, release, v.gate, v.retrigger
  2698.         )
  2699.  
  2700.     else
  2701.         self:applyChannel(
  2702.             channel, wave, frequency, targetVolume,
  2703.             attack, decay, sustain, release, v.gate, v.retrigger
  2704.         )
  2705.  
  2706.         if pairChannel then
  2707.             self:applyChannel(
  2708.                 pairChannel, WAVE_SQUARE, 0, 0,
  2709.                 attack, decay, sustain, release, false
  2710.             )
  2711.         end
  2712.     end
  2713. end
  2714.  
  2715. function AUDIO:render(pal, frameMilliseconds, startCycles, frameCycles)
  2716.     local envMode =
  2717.         ENV_ACCURATE and startCycles ~= nil and frameCycles ~= nil
  2718.  
  2719.     local steps = 1
  2720.     local samples = nil
  2721.  
  2722.     if envMode then
  2723.         steps = math.max(
  2724.             1,
  2725.             math.min(ENV_SUBSTEPS, math.floor(frameMilliseconds / 2))
  2726.         )
  2727.  
  2728.         samples = {}
  2729.  
  2730.         local changing = false
  2731.  
  2732.         for sidIndex = 1, self.sidCount do
  2733.             local chip = self.sids[sidIndex]
  2734.  
  2735.             samples[sidIndex] = {}
  2736.  
  2737.             for voiceNumber = 1, 3 do
  2738.                 local s = self:sampleEnvelope(
  2739.                     chip.envs[voiceNumber], startCycles, frameCycles, steps
  2740.                 )
  2741.  
  2742.                 samples[sidIndex][voiceNumber] = s
  2743.  
  2744.                 local low, high = s[1], s[1]
  2745.  
  2746.                 for i = 2, steps do
  2747.                     if s[i] < low then low = s[i] end
  2748.                     if s[i] > high then high = s[i] end
  2749.                 end
  2750.  
  2751.                 if high - low >= 2 then
  2752.                     changing = true
  2753.                 end
  2754.             end
  2755.         end
  2756.  
  2757.         if not changing then
  2758.             steps = 1
  2759.         end
  2760.  
  2761.         for i = 1, self.audioChannelCount do
  2762.             self.channels[i].touched = false
  2763.         end
  2764.     end
  2765.  
  2766.     for sidIndex = 1, self.sidCount do
  2767.         local chip = self.sids[sidIndex]
  2768.  
  2769.         local masterVolume = chip:masterVolume()
  2770.         local voice3Off = chip:voice3Off()
  2771.         local fstate = chip:filterState()
  2772.  
  2773.         local vs = { chip:voice(1), chip:voice(2), chip:voice(3) }
  2774.  
  2775.         for voiceNumber = 1, 3 do
  2776.             local channel = self:channelFor(sidIndex, voiceNumber)
  2777.  
  2778.             local v = vs[voiceNumber]
  2779.  
  2780.             local modV = vs[((voiceNumber - 2) % 3) + 1]
  2781.  
  2782.             local logical = (sidIndex - 1) * VOICES_PER_SID + voiceNumber
  2783.  
  2784.             local muted =
  2785.                 (voiceNumber == 3 and voice3Off and
  2786.                  bit.band(fstate.route, 0x04) == 0) or
  2787.                 self.muteMask[logical] == true
  2788.  
  2789.             self.curSamples = samples and samples[sidIndex][voiceNumber]
  2790.  
  2791.             self:updateVoice(
  2792.                 channel,
  2793.                 voiceNumber,
  2794.                 v,
  2795.                 pal,
  2796.                 masterVolume,
  2797.                 muted,
  2798.                 fstate,
  2799.                 modV,
  2800.                 sidIndex
  2801.             )
  2802.         end
  2803.     end
  2804.  
  2805.     self.curSamples = nil
  2806.  
  2807.     if envMode then
  2808.         local slice = frameMilliseconds / steps
  2809.  
  2810.         self:queueDelay(slice)
  2811.  
  2812.         for s = 2, steps do
  2813.             for i = 1, self.audioChannelCount do
  2814.                 local ch = self.channels[i]
  2815.  
  2816.                 if ch.touched and ch.opened and ch.envSamples then
  2817.                     self:setChannelVolume(
  2818.                         ch, i, ch.base * ch.envSamples[s] / 255
  2819.                     )
  2820.                 end
  2821.             end
  2822.  
  2823.             self:queueDelay(slice)
  2824.         end
  2825.     else
  2826.         sound.delay(frameMilliseconds)
  2827.     end
  2828.  
  2829.     self.pendingFrames = self.pendingFrames + 1
  2830.  
  2831.     if self.pendingFrames >= self.batchFrames then
  2832.         sound.process()
  2833.         self.pendingFrames = 0
  2834.     end
  2835. end
  2836.  
  2837. function AUDIO:resetChannels()
  2838.     local anyOpen = false
  2839.  
  2840.     for i = 1, self.audioChannelCount do
  2841.         local ch = self.channels[i]
  2842.  
  2843.         if ch.opened then
  2844.             sound.close(i)
  2845.             ch.opened = false
  2846.             anyOpen = true
  2847.         end
  2848.     end
  2849.  
  2850.     if anyOpen or self.pendingFrames > 0 then
  2851.         sound.process()
  2852.     end
  2853.  
  2854.     self.pendingFrames = 0
  2855.     self.delayCarry = 0
  2856.  
  2857.     for i = 1, self.audioChannelCount do
  2858.         local ch = self.channels[i]
  2859.  
  2860.         ch.gate = false
  2861.  
  2862.         ch.waveform = nil
  2863.         ch.frequency = nil
  2864.         ch.pulse = nil
  2865.         ch.volume = nil
  2866.  
  2867.         ch.attack = nil
  2868.         ch.decay = nil
  2869.         ch.sustain = nil
  2870.         ch.release = nil
  2871.  
  2872.         ch.adsrSet = false
  2873.         ch.base = 0
  2874.         ch.envSamples = nil
  2875.         ch.touched = false
  2876.  
  2877.         ch.audible = false
  2878.     end
  2879. end
  2880.  
  2881. function AUDIO:stop()
  2882.     local anyOpen = false
  2883.  
  2884.     for i = 1, self.audioChannelCount do
  2885.         local ch = self.channels[i]
  2886.  
  2887.         if ch.opened then
  2888.             sound.close(i)
  2889.  
  2890.             ch.opened = false
  2891.             anyOpen = true
  2892.         end
  2893.     end
  2894.  
  2895.     if anyOpen or self.pendingFrames > 0 then
  2896.         sound.process()
  2897.     end
  2898.  
  2899.     self.pendingFrames = 0
  2900. end
  2901.  
  2902. local Machine = {}
  2903. Machine.__index = Machine
  2904.  
  2905. function Machine.new(tune)
  2906.     local self = setmetatable({}, Machine)
  2907.  
  2908.     self.memory = {}
  2909.  
  2910.     self.tune = tune
  2911.  
  2912.     self.sids = { SIDChip.new() }
  2913.  
  2914.     if tune.secondSID and tune.secondSID ~= 0 then
  2915.         self.sids[2] = SIDChip.new()
  2916.     end
  2917.  
  2918.     if tune.thirdSID and tune.thirdSID ~= 0 then
  2919.         self.sids[3] = SIDChip.new()
  2920.     end
  2921.  
  2922.     self.sidBases = {
  2923.         SID_BASE,
  2924.         tune.secondSID or 0,
  2925.         tune.thirdSID or 0
  2926.     }
  2927.  
  2928.     self.sidCount = #self.sids
  2929.  
  2930.     self.cpu = CPU.new(self.memory, self.sids, self.sidBases)
  2931.  
  2932.     self.audio = AUDIO.new(self.sids, self.sidCount)
  2933.  
  2934.     self.audio.sidModels = {
  2935.         tune.sidModel1,
  2936.         tune.sidModel2,
  2937.         tune.sidModel3
  2938.     }
  2939.  
  2940.     self.song = tune.startSong
  2941.  
  2942.     if tune.clock == "NTSC" then
  2943.         self.pal = false
  2944.     else
  2945.         self.pal = true
  2946.     end
  2947.  
  2948.     self.frameRate = self.pal and PAL_HZ or NTSC_HZ
  2949.  
  2950.     self.irqMode = tune.playAddress == 0
  2951.  
  2952.     return self
  2953. end
  2954.  
  2955. function Machine:setFrameRate(rate)
  2956.     self.frameRate = rate
  2957. end
  2958.  
  2959. function Machine:ciaRate()
  2960.     local latch =
  2961.         (self.memory[0xDC04] or 0) +
  2962.         (self.memory[0xDC05] or 0) * 256
  2963.  
  2964.     if latch < 1000 then
  2965.         return nil
  2966.     end
  2967.  
  2968.     local clock = self.pal and PAL_CLOCK or NTSC_CLOCK
  2969.  
  2970.     local rate = clock / (latch + 1)
  2971.  
  2972.     if rate < 20 or rate > 200 then
  2973.         return nil
  2974.     end
  2975.  
  2976.     return rate
  2977. end
  2978.  
  2979. function Machine:setClock(pal)
  2980.     self.pal = pal
  2981.  
  2982.     self.frameRate = pal and PAL_HZ or NTSC_HZ
  2983.  
  2984.     self.memory[0x02A6] = pal and 0x01 or 0x00
  2985. end
  2986.  
  2987. function Machine:load()
  2988.     local address = self.tune.loadAddress
  2989.     local data = self.tune.data
  2990.     local memory = self.memory
  2991.  
  2992.     for i = 1, #data do
  2993.         memory[address + i - 1] = string.byte(data, i)
  2994.     end
  2995.  
  2996.     memory[0x02A6] = self.pal and 0x01 or 0x00
  2997.  
  2998.     memory[0xFFFA] = 0
  2999.     memory[0xFFFB] = 0
  3000.  
  3001.     memory[0xFFFC] = lo(self.tune.effectiveInitAddress)
  3002.     memory[0xFFFD] = hi(self.tune.effectiveInitAddress)
  3003.  
  3004. end
  3005.  
  3006. function Machine:init(song)
  3007.     song = clamp(song or self.song, 1, self.tune.songs)
  3008.  
  3009.     self.song = song
  3010.  
  3011.     local ok, reason =
  3012.         self.cpu:call(self.tune.effectiveInitAddress, song - 1, 0, 0)
  3013.  
  3014.     if not ok then
  3015.         print("Warning: init CPU: " .. tostring(reason))
  3016.     end
  3017.  
  3018.     self.audio:resetChannels()
  3019.  
  3020.     if self.irqMode then
  3021.         local irqLo = self.memory[0x0314]
  3022.         local irqHi = self.memory[0x0315]
  3023.  
  3024.         local irqVector = (irqLo or 0) + bit.lshift(irqHi or 0, 8)
  3025.  
  3026.         if irqVector == 0 then
  3027.             print(
  3028.                 "Warning: play address is $0000, " ..
  3029.                 "but the init routine did not install a non-zero IRQ vector at $0314/$0315."
  3030.             )
  3031.         else
  3032.             print(string.format("IRQ playback vector: $%04X", irqVector))
  3033.         end
  3034.     end
  3035. end
  3036.  
  3037. function Machine:playFrame(frameMilliseconds)
  3038.     local ok
  3039.     local reason
  3040.  
  3041.     local startCycles = self.cpu.cycles
  3042.  
  3043.     if self.tune.playAddress == 0 then
  3044.         ok, reason = self.cpu:interrupt(0x0314)
  3045.     else
  3046.         ok, reason = self.cpu:call(self.tune.playAddress, 0, 0, 0)
  3047.     end
  3048.  
  3049.     if not ok then
  3050.         return false, reason
  3051.     end
  3052.  
  3053.     local frameCycles = math.floor(
  3054.         (self.pal and PAL_CLOCK or NTSC_CLOCK) / self.frameRate
  3055.     )
  3056.  
  3057.     if self.cpu.cycles < startCycles + frameCycles then
  3058.         self.cpu.cycles = startCycles + frameCycles
  3059.     end
  3060.  
  3061.     self.audio:render(self.pal, frameMilliseconds, startCycles, frameCycles)
  3062.  
  3063.     return true
  3064. end
  3065.  
  3066. local function printInfo(tune)
  3067.     print("")
  3068.     print("========================================")
  3069.     print("OC-SID! A Sid Player for OpenComputers!")
  3070.     print("========================================")
  3071.     print("")
  3072.  
  3073.     if tune.name ~= "" then
  3074.         print("Title  : " .. tune.name)
  3075.     end
  3076.  
  3077.     if tune.author ~= "" then
  3078.         print("Author : " .. tune.author)
  3079.     end
  3080.  
  3081.     if tune.released ~= "" then
  3082.         print("Release: " .. tune.released)
  3083.     end
  3084.  
  3085.     print("----------------------------------------")
  3086.     print("Format : " .. tune.magic)
  3087.     print("Version: " .. tostring(tune.version))
  3088.     print("Songs  : " .. tostring(tune.songs))
  3089.     print("Start  : " .. tostring(tune.startSong))
  3090.  
  3091.     print(string.format("Load   : $%04X", tune.loadAddress))
  3092.     print(string.format("Init   : $%04X", tune.effectiveInitAddress))
  3093.  
  3094.     if tune.initAddress == 0 then
  3095.         print("         (effective load address)")
  3096.     end
  3097.  
  3098.     print(string.format("Play   : $%04X", tune.playAddress))
  3099.  
  3100.     print("----------------------------------------")
  3101.  
  3102.     print("Clock  : " .. tostring(tune.clock))
  3103.  
  3104.     print("SID #1 : " .. tostring(tune.sidModel1) .. " @ $D400")
  3105.  
  3106.     if tune.secondSID ~= 0 then
  3107.         print(
  3108.             string.format(
  3109.                 "SID #2 : %s @ $%04X",
  3110.                 tostring(tune.sidModel2),
  3111.                 tune.secondSID
  3112.             )
  3113.         )
  3114.     else
  3115.         print("SID #2 : none")
  3116.     end
  3117.  
  3118.     if tune.thirdSID ~= 0 then
  3119.         print(
  3120.             string.format(
  3121.                 "SID #3 : %s @ $%04X",
  3122.                 tostring(tune.sidModel3),
  3123.                 tune.thirdSID
  3124.             )
  3125.         )
  3126.  
  3127.         print("         emulated; audio voice 3 is unavailable on 8-channel cards")
  3128.     end
  3129.  
  3130.     print("----------------------------------------")
  3131.  
  3132.     if tune.playAddress == 0 then
  3133.         print("Playback: installed IRQ handler")
  3134.     else
  3135.         print("Playback: direct play routine")
  3136.     end
  3137.  
  3138.     print("")
  3139.     print("Space = pause/resume")
  3140.     print("N / P = next / previous song")
  3141.     print("+ / - = volume")
  3142.     print("D     = analog drift on/off")
  3143.     print("F     = filter approximation on/off")
  3144.     print("M     = pulse mode (blend/pair/morph/off)")
  3145.     print("1-9   = mute / unmute voice")
  3146.     print("V     = voice / envelope status")
  3147.     print("Q     = quit")
  3148.     print("========================================")
  3149.     print("")
  3150. end
  3151.  
  3152. math.randomseed(math.floor(computer.uptime() * 1000) % 2147483647)
  3153.  
  3154. local args = {...}
  3155.  
  3156. if not args[1] then
  3157.     print("Usage:")
  3158.     print("  sid.lua /path/to/file.sid [song]")
  3159.     print("")
  3160.     print("Keys: Space pause | N/P next/previous song | +/- volume")
  3161.     print("      F filter on/off | M pulse mode | Q quit")
  3162.     print("      1-9 mute voice | V voice status")
  3163.     return
  3164. end
  3165.  
  3166. local filename = args[1]
  3167. local requestedSong = tonumber(args[2])
  3168.  
  3169. local tune = SID.loadFile(filename)
  3170.  
  3171. if tune.magic == "RSID" then
  3172.     print("")
  3173.     print("WARNING: RSID detected.")
  3174.     print("RSID tunes require a much more complete C64 environment.")
  3175.     print("VIC/CIA I/O, ROM behavior and cycle timing are not fully emulated.")
  3176.     print("")
  3177. end
  3178.  
  3179. if tune.thirdSID ~= 0 then
  3180.     print("")
  3181.     print("WARNING: This tune declares a third SID.")
  3182.     print("SID #3 will be CPU-emulated; the standard sound card exposes only 8 audio channels.")
  3183.     print(string.format("Third SID address: $%04X", tune.thirdSID))
  3184.     print("")
  3185. end
  3186.  
  3187. local machine = nil
  3188. local usingCIA = false
  3189. local frameMilliseconds = 20
  3190. local frameDelay = 0.02
  3191.  
  3192. local paused = false
  3193. local running = true
  3194. local nextFrame = computer.uptime()
  3195.  
  3196. local song = requestedSong or tune.startSong
  3197.  
  3198. if song < 1 or song > tune.songs then
  3199.     error("Invalid song number. Valid range: 1-" .. tostring(tune.songs))
  3200. end
  3201.  
  3202. local function startMachine(songNumber)
  3203.     if machine then
  3204.         machine.audio:stop()
  3205.     end
  3206.  
  3207.     machine = Machine.new(tune)
  3208.  
  3209.     machine:load()
  3210.     machine:init(songNumber)
  3211.  
  3212.     local songBit = songNumber - 1
  3213.     local speedBit = 0
  3214.  
  3215.     if songBit < 32 then
  3216.         speedBit = bit.band(bit.rshift(tune.speed, songBit), 1)
  3217.     end
  3218.  
  3219.     usingCIA = speedBit ~= 0
  3220.  
  3221.     local ciaRate = nil
  3222.  
  3223.     if usingCIA then
  3224.         ciaRate = machine:ciaRate()
  3225.         machine:setFrameRate(ciaRate or NTSC_HZ)
  3226.     else
  3227.         machine:setFrameRate(machine.pal and PAL_HZ or NTSC_HZ)
  3228.     end
  3229.  
  3230.     frameMilliseconds = 1000 / machine.frameRate
  3231.     frameDelay = 1 / machine.frameRate
  3232.  
  3233.     if usingCIA then
  3234.         if ciaRate then
  3235.             print(
  3236.                 string.format(
  3237.                     "Playing song %d/%d, CIA timer latch -> %.2f Hz.",
  3238.                     songNumber,
  3239.                     tune.songs,
  3240.                     ciaRate
  3241.                 )
  3242.             )
  3243.         else
  3244.             print(
  3245.                 string.format(
  3246.                     "Playing song %d/%d, CIA default timing at %d Hz.",
  3247.                     songNumber,
  3248.                     tune.songs,
  3249.                     machine.frameRate
  3250.                 )
  3251.             )
  3252.         end
  3253.  
  3254.         print("Note: CIA interrupts are not cycle-emulated.")
  3255.     else
  3256.         print(
  3257.             string.format(
  3258.                 "Playing song %d/%d at %d Hz.",
  3259.                 songNumber,
  3260.                 tune.songs,
  3261.                 machine.frameRate
  3262.             )
  3263.         )
  3264.     end
  3265.  
  3266.     print(string.format("Sound frame: %.3f ms", frameMilliseconds))
  3267.     print("Pulse  : " .. machine.audio:pwmDescription())
  3268.     print(
  3269.         "Filter : " ..
  3270.         (machine.audio.filterEnabled and "approximated" or "off")
  3271.     )
  3272.     print("Drift  : " .. (ANALOG_DRIFT_ENABLED and "on" or "off"))
  3273.     print(
  3274.         "Envelope: " ..
  3275.         (ENV_ACCURATE and "SID ADSR emulated per voice" or "sound card ADSR")
  3276.     )
  3277.  
  3278.     if machine.sidCount >= 2 then
  3279.         print("Multi-SID audio: SID #1 = channels 1-3, SID #2 = channels 4-6.")
  3280.  
  3281.         if machine.sidCount >= 3 then
  3282.             print("SID #3 = channels 7-8; voice 3 remains CPU-emulated only on an 8-channel sound card.")
  3283.         end
  3284.  
  3285.         print(
  3286.             string.format(
  3287.                 "Audio queue batching: %d frames/process.",
  3288.                 machine.audio.batchFrames
  3289.             )
  3290.         )
  3291.     end
  3292.  
  3293.     print("")
  3294. end
  3295.  
  3296. local function changeSong(n)
  3297.     if n < 1 then
  3298.         n = tune.songs
  3299.     end
  3300.  
  3301.     if n > tune.songs then
  3302.         n = 1
  3303.     end
  3304.  
  3305.     song = n
  3306.  
  3307.     print("")
  3308.  
  3309.     startMachine(song)
  3310.  
  3311.     paused = false
  3312.     nextFrame = computer.uptime()
  3313. end
  3314.  
  3315. local function printVolume()
  3316.     print(
  3317.         string.format(
  3318.             "Volume: %d%%",
  3319.             math.floor(machine.audio.volume * 100 + 0.5)
  3320.         )
  3321.     )
  3322. end
  3323.  
  3324. local NOTE_NAMES = {
  3325.     "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"
  3326. }
  3327.  
  3328. local function noteName(hz)
  3329.     if not hz or hz < 16 then
  3330.         return "---"
  3331.     end
  3332.  
  3333.     local n = math.floor(12 * math.log(hz / 440) / math.log(2) + 69.5)
  3334.  
  3335.     if n < 0 or n > 127 then
  3336.         return "???"
  3337.     end
  3338.  
  3339.     return NOTE_NAMES[n % 12 + 1] .. tostring(math.floor(n / 12) - 1)
  3340. end
  3341.  
  3342. local function printVoiceStatus()
  3343.     print("")
  3344.  
  3345.     for sidIndex = 1, machine.sidCount do
  3346.         local chip = machine.sids[sidIndex]
  3347.         local reg = chip.reg
  3348.         local f = chip:filterState()
  3349.  
  3350.         local mode = ""
  3351.  
  3352.         if f.lp then mode = mode .. "LP " end
  3353.         if f.bp then mode = mode .. "BP " end
  3354.         if f.hp then mode = mode .. "HP " end
  3355.  
  3356.         if mode == "" then
  3357.             mode = "none"
  3358.         end
  3359.  
  3360.         print(
  3361.             string.format(
  3362.                 "SID %d: vol=%d filter=%s cutoff=%d res=%d route=%d",
  3363.                 sidIndex,
  3364.                 chip:masterVolume(),
  3365.                 mode,
  3366.                 f.cutoff,
  3367.                 f.resonance,
  3368.                 f.route
  3369.             )
  3370.         )
  3371.  
  3372.         for v = 1, 3 do
  3373.             local base = (v - 1) * 7
  3374.  
  3375.             local value = reg[base] + reg[base + 1] * 256
  3376.             local control = reg[base + 4]
  3377.             local pw = reg[base + 2] + (reg[base + 3] % 16) * 256
  3378.  
  3379.             local wave = ""
  3380.  
  3381.             if bit.band(control, 0x10) ~= 0 then wave = wave .. "T" end
  3382.             if bit.band(control, 0x20) ~= 0 then wave = wave .. "S" end
  3383.             if bit.band(control, 0x40) ~= 0 then wave = wave .. "P" end
  3384.             if bit.band(control, 0x80) ~= 0 then wave = wave .. "N" end
  3385.  
  3386.             if wave == "" then
  3387.                 wave = "-"
  3388.             end
  3389.  
  3390.             local extra = ""
  3391.  
  3392.             if bit.band(control, 0x02) ~= 0 then extra = extra .. " sync" end
  3393.             if bit.band(control, 0x04) ~= 0 then extra = extra .. " ring" end
  3394.             if bit.band(control, 0x08) ~= 0 then extra = extra .. " test" end
  3395.  
  3396.             if chip.noiseLocked[v] then
  3397.                 extra = extra .. " noise-locked"
  3398.             end
  3399.  
  3400.             local env = chip.envs[v]
  3401.  
  3402.             env:advanceTo(chip:now())
  3403.  
  3404.             local logical = (sidIndex - 1) * VOICES_PER_SID + v
  3405.  
  3406.             print(
  3407.                 string.format(
  3408.                     "  V%d %-4s %-4s pw=%4d env=%3d%% %s%s%s",
  3409.                     logical,
  3410.                     noteName(machine.audio:frequencyFromSID(value, machine.pal)),
  3411.                     wave,
  3412.                     pw,
  3413.                     math.floor(env.level * 100 / 255 + 0.5),
  3414.                     env.gate and "gate " or "     ",
  3415.                     machine.audio.muteMask[logical] and "[muted]" or "",
  3416.                     extra
  3417.                 )
  3418.             )
  3419.         end
  3420.     end
  3421.  
  3422.     print("")
  3423. end
  3424.  
  3425. local NEXT_PWM_MODE = {
  3426.     blend = "pair",
  3427.     pair = "morph",
  3428.     morph = "off",
  3429.     off = "blend"
  3430. }
  3431.  
  3432. local function handleKey(character)
  3433.     if character == 113 or character == 81 then
  3434.         running = false
  3435.  
  3436.     elseif character == 32 then
  3437.         if paused then
  3438.             paused = false
  3439.             nextFrame = computer.uptime()
  3440.             print("Resumed.")
  3441.         else
  3442.             paused = true
  3443.  
  3444.             machine.audio:stop()
  3445.             print("Paused.")
  3446.         end
  3447.  
  3448.     elseif character == 43 or character == 61 then
  3449.         machine.audio:setVolume(machine.audio.volume + 0.05)
  3450.         printVolume()
  3451.  
  3452.     elseif character == 45 then
  3453.         machine.audio:setVolume(machine.audio.volume - 0.05)
  3454.         printVolume()
  3455.  
  3456.     elseif character == 110 or character == 78 then
  3457.         changeSong(song + 1)
  3458.  
  3459.     elseif character == 112 or character == 80 then
  3460.         changeSong(song - 1)
  3461.  
  3462.     elseif character == 100 or character == 68 then
  3463.         machine.audio:setDrift(not ANALOG_DRIFT_ENABLED)
  3464.  
  3465.         print("Drift  : " .. (ANALOG_DRIFT_ENABLED and "on" or "off"))
  3466.  
  3467.     elseif character == 102 or character == 70 then
  3468.         FILTER_ENABLED = not machine.audio.filterEnabled
  3469.         machine.audio:setFilter(FILTER_ENABLED)
  3470.  
  3471.         print("Filter : " .. (FILTER_ENABLED and "approximated" or "off"))
  3472.  
  3473.     elseif character == 109 or character == 77 then
  3474.         PWM_MODE = NEXT_PWM_MODE[PWM_MODE] or "blend"
  3475.         machine.audio:setPWMMode(PWM_MODE)
  3476.  
  3477.         print("Pulse  : " .. machine.audio:pwmDescription())
  3478.  
  3479.     elseif character >= 49 and character <= 57 then
  3480.         local n = character - 48
  3481.  
  3482.         if n <= machine.sidCount * VOICES_PER_SID then
  3483.             local muted = machine.audio:toggleMute(n)
  3484.  
  3485.             print("Voice " .. n .. ": " .. (muted and "muted" or "on"))
  3486.         end
  3487.  
  3488.     elseif character == 118 or character == 86 then
  3489.         printVoiceStatus()
  3490.     end
  3491. end
  3492.  
  3493. printInfo(tune)
  3494.  
  3495. startMachine(song)
  3496.  
  3497. nextFrame = computer.uptime()
  3498.  
  3499. while running do
  3500.  
  3501.     if paused then
  3502.  
  3503.         local e1, e2, character = event.pull(0.05)
  3504.  
  3505.         if e1 == "key_down" then
  3506.             handleKey(character)
  3507.         end
  3508.  
  3509.     else
  3510.  
  3511.         local wait = nextFrame - computer.uptime()
  3512.  
  3513.         if wait > 0 then
  3514.  
  3515.             local e1, e2, character = event.pull(wait)
  3516.  
  3517.             if e1 == "key_down" then
  3518.                 handleKey(character)
  3519.             end
  3520.  
  3521.         else
  3522.  
  3523.             local ok, reason = machine:playFrame(frameMilliseconds)
  3524.  
  3525.             if not ok then
  3526.                 print("")
  3527.                 print("Playback stopped: " .. tostring(reason))
  3528.  
  3529.                 running = false
  3530.  
  3531.             else
  3532.                 if CIA_TRACKING and usingCIA then
  3533.                     local rate = machine:ciaRate()
  3534.  
  3535.                     if rate and math.abs(rate - machine.frameRate) > 0.5 then
  3536.                         machine:setFrameRate(rate)
  3537.  
  3538.                         frameMilliseconds = 1000 / rate
  3539.                         frameDelay = 1 / rate
  3540.                     end
  3541.                 end
  3542.  
  3543.                 nextFrame = nextFrame + frameDelay
  3544.  
  3545.                 local current = computer.uptime()
  3546.  
  3547.                 if current > nextFrame + frameDelay * 8 then
  3548.                     nextFrame = current + frameDelay
  3549.                 end
  3550.             end
  3551.         end
  3552.     end
  3553. end
  3554.  
  3555. machine.audio:stop()
  3556.  
  3557. print("")
  3558. print("SID playback stopped.")
Advertisement
Comments
  • User was banned
Add Comment
Please, Sign In to add comment