Created
March 17, 2023 07:07
-
-
Save MCJack123/d076bfcab67767cef6fd0292655e03ae to your computer and use it in GitHub Desktop.
Pure Lua 5.2 port of reSID Commodore 64 SID emulator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
------------------------------------------------------------------------------- | |
-- This file is reSID, a MOS6581 SID emulator engine, ported to Lua. | |
-- Copyright (C) 2004 Dag Lem <[email protected]> | |
-- Lua port Copyright (C) 2023 JackMacWindows <[email protected]> | |
-- | |
-- This program is free software; you can redistribute it and/or modify | |
-- it under the terms of the GNU General Public License as published by | |
-- the Free Software Foundation; either version 2 of the License, or | |
-- (at your option) any later version. | |
-- | |
-- This program is distributed in the hope that it will be useful, | |
-- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
-- GNU General Public License for more details. | |
-- | |
-- You should have received a copy of the GNU General Public License | |
-- along with this program; if not, write to the Free Software | |
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
------------------------------------------------------------------------------- | |
local band, bor, bxor, bnot, btest, lshift, rshift = bit32.band, bit32.bor, bit32.bxor, bit32.bnot, bit32.btest, bit32.lshift, bit32.rshift | |
local floor, min, max, pi, log, ceil, abs, sqrt, sin = math.floor, math.min, math.max, math.pi, math.log, math.ceil, math.abs, math.sqrt, math.sin | |
local function arshift(a, s) | |
return floor(a / 2^s) | |
end | |
-- * siddefs * | |
local chip_model = { | |
MOS6581 = 0, | |
MOS8580 = 1 | |
} | |
local sampling_method = { | |
SAMPLE_FAST = 0, | |
SAMPLE_INTERPOLATE = 1, | |
SAMPLE_RESAMPLE_INTERPOLATE = 2, | |
SAMPLE_RESAMPLE_FAST = 3 | |
} | |
-- * envelope * | |
local EnvelopeGenerator = {} | |
EnvelopeGenerator.__index = EnvelopeGenerator | |
EnvelopeGenerator.State = { | |
ATTACK = 0, | |
DECAY_SUSTAIN = 1, | |
RELEASE = 2 | |
} | |
function EnvelopeGenerator:new() | |
local obj = setmetatable({}, self) | |
obj:reset() | |
return obj | |
end | |
function EnvelopeGenerator:reset() | |
self.envelope_counter = 0 | |
self.attack = 0 | |
self.decay = 0 | |
self.sustain = 0 | |
self.release = 0 | |
self.gate = 0 | |
self.rate_counter = 0 | |
self.exponential_counter = 0 | |
self.exponential_counter_period = 1 | |
self.state = EnvelopeGenerator.State.RELEASE | |
self.rate_period = EnvelopeGenerator.rate_counter_period[self.release] | |
self.hold_zero = true | |
end | |
EnvelopeGenerator.rate_counter_period = { | |
[0] = 9, -- 2ms*1.0MHz/256 = 7.81 | |
32, -- 8ms*1.0MHz/256 = 31.25 | |
63, -- 16ms*1.0MHz/256 = 62.50 | |
95, -- 24ms*1.0MHz/256 = 93.75 | |
149, -- 38ms*1.0MHz/256 = 148.44 | |
220, -- 56ms*1.0MHz/256 = 218.75 | |
267, -- 68ms*1.0MHz/256 = 265.63 | |
313, -- 80ms*1.0MHz/256 = 312.50 | |
392, -- 100ms*1.0MHz/256 = 390.63 | |
977, -- 250ms*1.0MHz/256 = 976.56 | |
1954, -- 500ms*1.0MHz/256 = 1953.13 | |
3126, -- 800ms*1.0MHz/256 = 3125.00 | |
3907, -- 1 s*1.0MHz/256 = 3906.25 | |
11720, -- 3 s*1.0MHz/256 = 11718.75 | |
19532, -- 5 s*1.0MHz/256 = 19531.25 | |
31251 -- 8 s*1.0MHz/256 = 31250.00 | |
} | |
EnvelopeGenerator.sustain_level = { | |
[0] = 0x00, | |
0x11, | |
0x22, | |
0x33, | |
0x44, | |
0x55, | |
0x66, | |
0x77, | |
0x88, | |
0x99, | |
0xaa, | |
0xbb, | |
0xcc, | |
0xdd, | |
0xee, | |
0xff, | |
} | |
function EnvelopeGenerator:writeCONTROL_REG(control) | |
local gate_next = btest(control, 0x01) | |
if not self.gate and gate_next then | |
self.state = EnvelopeGenerator.State.ATTACK | |
self.rate_period = EnvelopeGenerator.rate_counter_period[self.attack] | |
self.hold_zero = false | |
elseif self.gate and not gate_next then | |
self.state = EnvelopeGenerator.State.RELEASE | |
self.rate_period = EnvelopeGenerator.rate_counter_period[self.release] | |
end | |
self.gate = gate_next | |
end | |
function EnvelopeGenerator:writeATTACK_DECAY(attack_decay) | |
self.attack = band(rshift(attack_decay, 4), 0x0f) | |
self.decay = band(attack_decay, 0x0f) | |
if self.state == EnvelopeGenerator.State.ATTACK then | |
self.rate_period = EnvelopeGenerator.rate_counter_period[self.attack] | |
elseif self.state == EnvelopeGenerator.State.DECAY_SUSTAIN then | |
self.rate_period = EnvelopeGenerator.rate_counter_period[self.decay] | |
end | |
end | |
function EnvelopeGenerator:writeSUSTAIN_RELEASE(sustain_release) | |
self.sustain = band(rshift(sustain_release, 4), 0x0f) | |
self.release = band(sustain_release, 0x0f) | |
if self.state == EnvelopeGenerator.State.RELEASE then | |
self.rate_period = EnvelopeGenerator.rate_counter_period[self.release] | |
end | |
end | |
function EnvelopeGenerator:readENV() | |
return self:output() | |
end | |
function EnvelopeGenerator:_inc_exponential_counter() self.exponential_counter = self.exponential_counter + 1 return self.exponential_counter end | |
function EnvelopeGenerator:clock_0() | |
self.rate_counter = self.rate_counter + 1 | |
if self.rate_counter >= 0x8000 then | |
self.rate_counter = band(self.rate_counter + 1, 0x7fff) | |
end | |
if self.rate_counter ~= self.rate_period then | |
return | |
end | |
self.rate_counter = 0 | |
if self.state == EnvelopeGenerator.State.ATTACK or self:_inc_exponential_counter() == self.exponential_counter_period then | |
self.exponential_counter = 0 | |
if self.hold_zero then | |
return | |
end | |
if self.state == EnvelopeGenerator.State.ATTACK then | |
self.envelope_counter = band(self.envelope_counter + 1, 0xff) | |
if self.envelope_counter == 0xff then | |
self.state = EnvelopeGenerator.State.DECAY_SUSTAIN | |
self.rate_period = EnvelopeGenerator.rate_counter_period[self.decay] | |
end | |
elseif self.state == EnvelopeGenerator.State.DECAY_SUSTAIN then | |
if self.envelope_counter ~= EnvelopeGenerator.sustain_level[self.sustain] then | |
self.envelope_counter = self.envelope_counter - 1 | |
end | |
elseif self.state == EnvelopeGenerator.State.RELEASE then | |
self.envelope_counter = band(self.envelope_counter - 1, 0xff) | |
end | |
local e = self.envelope_counter | |
if e == 0xff then | |
self.exponential_counter_period = 1 | |
elseif e == 0x5d then | |
self.exponential_counter_period = 2 | |
elseif e == 0x36 then | |
self.exponential_counter_period = 4 | |
elseif e == 0x1a then | |
self.exponential_counter_period = 8 | |
elseif e == 0x0e then | |
self.exponential_counter_period = 16 | |
elseif e == 0x06 then | |
self.exponential_counter_period = 30 | |
elseif e == 0x00 then | |
self.exponential_counter_period = 1 | |
self.hold_zero = true | |
end | |
end | |
end | |
function EnvelopeGenerator:clock(delta_t) | |
if not delta_t then return self:clock_0() end | |
local rate_step = self.rate_period - self.rate_counter | |
if rate_step <= 0 then | |
rate_step = rate_step + 0x7fff | |
end | |
if delta_t < rate_step then | |
self.rate_counter = self.rate_counter + delta_t | |
if self.rate_counter >= 0x8000 then | |
self.rate_counter = band(self.rate_counter + 1, 0x7fff) | |
end | |
return | |
end | |
local ATTACK, DECAY_SUSTAIN, RELEASE, decay, sustain = EnvelopeGenerator.State.ATTACK, EnvelopeGenerator.State.DECAY_SUSTAIN, EnvelopeGenerator.State.RELEASE, EnvelopeGenerator.rate_counter_period[self.decay], EnvelopeGenerator.sustain_level[self.sustain] | |
local state, exponential_counter, exponential_counter_period, rate_period, envelope_counter, hold_zero = self.state, self.exponential_counter, self.exponential_counter_period, self.rate_period, self.envelope_counter, self.hold_zero | |
while delta_t ~= 0 do | |
if delta_t < rate_step then | |
if delta_t >= 0x8000 then | |
self.rate_counter = band(delta_t + 1, 0x7fff) | |
else | |
self.rate_counter = delta_t | |
end | |
self.state, self.exponential_counter, self.exponential_counter_period, self.rate_period, self.envelope_counter, self.hold_zero = state, exponential_counter, exponential_counter_period, rate_period, envelope_counter, hold_zero | |
return | |
end | |
delta_t = delta_t - rate_step | |
if state == ATTACK or exponential_counter + 1 == exponential_counter_period then | |
exponential_counter = 0 | |
if hold_zero then | |
rate_step = rate_period | |
else | |
if state == ATTACK then | |
envelope_counter = band(envelope_counter + 1, 0xff) | |
if envelope_counter == 0xff then | |
state = DECAY_SUSTAIN | |
rate_period = decay | |
end | |
elseif state == DECAY_SUSTAIN then | |
if envelope_counter ~= sustain then | |
envelope_counter = envelope_counter - 1 | |
end | |
elseif state == RELEASE then | |
envelope_counter = band(envelope_counter - 1, 0xff) | |
end | |
if envelope_counter == 0xff then | |
exponential_counter_period = 1 | |
elseif envelope_counter == 0x5d then | |
exponential_counter_period = 2 | |
elseif envelope_counter == 0x36 then | |
exponential_counter_period = 4 | |
elseif envelope_counter == 0x1a then | |
exponential_counter_period = 8 | |
elseif envelope_counter == 0x0e then | |
exponential_counter_period = 16 | |
elseif envelope_counter == 0x06 then | |
exponential_counter_period = 30 | |
elseif envelope_counter == 0x00 then | |
exponential_counter_period = 1 | |
hold_zero = true | |
end | |
end | |
else exponential_counter = exponential_counter + 1 end | |
rate_step = rate_period | |
end | |
self.rate_counter = 0 | |
self.state, self.exponential_counter, self.exponential_counter_period, self.rate_period, self.envelope_counter, self.hold_zero = state, exponential_counter, exponential_counter_period, rate_period, envelope_counter, hold_zero | |
end | |
function EnvelopeGenerator:output() | |
return self.envelope_counter | |
end | |
-- * extfilt * | |
local ExternalFilter = {} | |
ExternalFilter.__index = ExternalFilter | |
function ExternalFilter:new() | |
local obj = setmetatable({}, self) | |
obj:reset() | |
obj:enable_filter(true) | |
obj:set_chip_model(chip_model.MOS6581) | |
self.w0lp = 104858 | |
self.w0hp = 105 | |
return obj | |
end | |
function ExternalFilter:enable_filter(enable) | |
self.enabled = enable | |
end | |
function ExternalFilter:set_chip_model(model) | |
if model == chip_model.MOS6581 then | |
--self.mixer_DC = rshift((((0x800 - 0x380) + 0x800)*0xff*3 - 0xfff*0xff/18), 7)*0x0f | |
self.mixer_DC = 0x44601 | |
else | |
self.mixer_DC = 0 | |
end | |
end | |
function ExternalFilter:clock_1(Vi) | |
if not self.enabled then | |
self.Vlp, self.Vhp = 0, 0 | |
self.Vo = Vi - self.mixer_DC | |
return | |
end | |
local dVlp = arshift(arshift(self.w0lp, 8)*(Vi - self.Vlp), 12) | |
local dVhp = arshift(self.w0hp*(self.Vlp - self.Vhp), 20) | |
self.Vo = self.Vlp - self.Vhp | |
self.Vlp = self.Vlp + dVlp | |
self.Vhp = self.Vhp + dVhp | |
end | |
function ExternalFilter:clock(delta_t, Vi) | |
if not Vi then return self:clock_1(delta_t) end | |
if not self.enabled then | |
self.Vlp, self.Vhp = 0, 0 | |
self.Vo = Vi - self.mixer_DC | |
return | |
end | |
local Vo, Vlp, Vhp, w0hp, w0lp = self.Vo, self.Vlp, self.Vhp, self.w0hp / 131072, floor(self.w0lp / 32) / 4096 | |
for delta_t = delta_t, 0, -8 do | |
if delta_t < 8 then | |
local dVlp = arshift(arshift(w0lp*delta_t, 8)*(Vi - Vlp), 12) | |
local dVhp = arshift(w0hp*delta_t*(Vlp - Vhp), 20) | |
Vo = Vlp - Vhp | |
Vlp = Vlp + dVlp | |
Vhp = Vhp + dVhp | |
break | |
end | |
local dVlp = floor(w0lp*(Vi - Vlp)) | |
local dVhp = floor(w0hp*(Vlp - Vhp)) | |
Vo = Vlp - Vhp | |
Vlp = Vlp + dVlp | |
Vhp = Vhp + dVhp | |
end | |
self.Vo, self.Vlp, self.Vhp = Vo, Vlp, Vhp | |
end | |
function ExternalFilter:reset() | |
self.Vlp = 0 | |
self.Vhp = 0 | |
self.Vo = 0 | |
end | |
function ExternalFilter:output() | |
return self.Vo | |
end | |
-- * spline * | |
local function cubic_coefficients(x1, y1, x2, y2, k1, k2) | |
local dx, dy = x2 - x1, y2 - y1 | |
local a = ((k1 + k2) - 2*dy/dx)/(dx*dx) | |
local b = ((k2 - k1)/dx - 3*(x1 + x2)*a)/2 | |
local c = k1 - (3*x1*a + 2*b)*x1 | |
local d = y1 - ((x1*a + b)*x1 + c)*x1 | |
return a, b, c, d | |
end | |
local function interpolate_brute_force(x1, y1, x2, y2, k1, k2, plot, res) | |
local a, b, c, d = cubic_coefficients(x1, y1, x2, y2, k1, k2) | |
for x = x1, x2, res do | |
local y = ((a*x + b)*x + c)*x + d | |
plot(x, y) | |
end | |
end | |
local function interpolate_forward_difference(x1, y1, x2, y2, k1, k2, plot, res) | |
local a, b, c, d = cubic_coefficients(x1, y1, x2, y2, k1, k2) | |
local y = ((a*x1 + b)*x1 + c)*x1 + d; | |
local dy = (3*a*(x1 + res) + 2*b)*x1*res + ((a*res + b)*res + c)*res; | |
local d2y = (6*a*(x1 + res) + 2*b)*res*res; | |
local d3y = 6*a*res*res*res; | |
for x = x1, x2, res do | |
plot(x, y) | |
y, dy, d2y = y + dy, dy + d2y, d2y + d3y | |
end | |
end | |
local interpolate_segment | |
if SPLINE_BRUTE_FORCE then interpolate_segment = interpolate_brute_force | |
else interpolate_segment = interpolate_forward_difference end | |
local function interpolate(list, plot, res) | |
local p0, p1, p2, p3 = list[1], list[2], list[3], list[4] | |
for x = 5, #list + 1 do | |
if p1[1] ~= p2[1] then | |
local k1, k2 | |
if p0[1] == p1[1] and p2[1] == p3[1] then | |
k1 = (p2[2] - p1[2])/(p2[1] - p1[1]) | |
k2 = k1 | |
elseif p0[1] == p1[1] then | |
k2 = (p3[2] - p1[2])/(p3[1] - p1[1]) | |
k1 = (3*(p2[2] - p1[2])/(p2[1] - p1[1]) - k2)/2 | |
elseif p2[1] == p3[1] then | |
k1 = (p2[2] - p0[2])/(p2[1] - p0[1]) | |
k2 = (3*(p2[2] - p1[2])/(p2[1] - p1[1]) - k1)/2 | |
else | |
k1 = (p2[2] - p0[2])/(p2[1] - p0[1]) | |
k2 = (p3[2] - p1[2])/(p3[1] - p1[1]) | |
end | |
interpolate_segment(p1[1], p1[2], p2[1], p2[2], k1, k2, plot, res) | |
end | |
p0, p1, p2, p3 = p1, p2, p3, list[x] | |
end | |
end | |
local function PointPlotter(arr) | |
return function(x, y) | |
if y < 0 then y = 0 end | |
arr[floor(x)] = floor(y) | |
end | |
end | |
-- * filter * | |
local Filter = {} | |
Filter.__index = Filter | |
Filter.f0_points_6581 = { | |
-- FC f FCHI FCLO | |
------------------------------- | |
{ 0, 220 }, -- 0x00 - repeated end point | |
{ 0, 220 }, -- 0x00 | |
{ 128, 230 }, -- 0x10 | |
{ 256, 250 }, -- 0x20 | |
{ 384, 300 }, -- 0x30 | |
{ 512, 420 }, -- 0x40 | |
{ 640, 780 }, -- 0x50 | |
{ 768, 1600 }, -- 0x60 | |
{ 832, 2300 }, -- 0x68 | |
{ 896, 3200 }, -- 0x70 | |
{ 960, 4300 }, -- 0x78 | |
{ 992, 5000 }, -- 0x7c | |
{ 1008, 5400 }, -- 0x7e | |
{ 1016, 5700 }, -- 0x7f | |
{ 1023, 6000 }, -- 0x7f 0x07 | |
{ 1023, 6000 }, -- 0x7f 0x07 - discontinuity | |
{ 1024, 4600 }, -- 0x80 - | |
{ 1024, 4600 }, -- 0x80 | |
{ 1032, 4800 }, -- 0x81 | |
{ 1056, 5300 }, -- 0x84 | |
{ 1088, 6000 }, -- 0x88 | |
{ 1120, 6600 }, -- 0x8c | |
{ 1152, 7200 }, -- 0x90 | |
{ 1280, 9500 }, -- 0xa0 | |
{ 1408, 12000 }, -- 0xb0 | |
{ 1536, 14500 }, -- 0xc0 | |
{ 1664, 16000 }, -- 0xd0 | |
{ 1792, 17100 }, -- 0xe0 | |
{ 1920, 17700 }, -- 0xf0 | |
{ 2047, 18000 }, -- 0xff 0x07 | |
{ 2047, 18000 } -- 0xff 0x07 - repeated end point | |
} | |
Filter.f0_points_8580 = { | |
-- FC f FCHI FCLO | |
------------------------------- | |
{ 0, 0 }, -- 0x00 - repeated end point | |
{ 0, 0 }, -- 0x00 | |
{ 128, 800 }, -- 0x10 | |
{ 256, 1600 }, -- 0x20 | |
{ 384, 2500 }, -- 0x30 | |
{ 512, 3300 }, -- 0x40 | |
{ 640, 4100 }, -- 0x50 | |
{ 768, 4800 }, -- 0x60 | |
{ 896, 5600 }, -- 0x70 | |
{ 1024, 6500 }, -- 0x80 | |
{ 1152, 7500 }, -- 0x90 | |
{ 1280, 8400 }, -- 0xa0 | |
{ 1408, 9200 }, -- 0xb0 | |
{ 1536, 9800 }, -- 0xc0 | |
{ 1664, 10500 }, -- 0xd0 | |
{ 1792, 11000 }, -- 0xe0 | |
{ 1920, 11700 }, -- 0xf0 | |
{ 2047, 12500 }, -- 0xff 0x07 | |
{ 2047, 12500 } -- 0xff 0x07 - repeated end point | |
} | |
function Filter:new() | |
local obj = setmetatable({f0_6581 = {}, f0_8580 = {}}, self) | |
obj.fc = 0 | |
obj.res = 0 | |
obj.filt = 0 | |
obj.voice3off = false | |
obj.hp_bp_lp = 0 | |
obj.vol = 0 | |
obj.Vhp = 0 | |
obj.Vbp = 0 | |
obj.Vlp = 0 | |
obj.Vnf = 0 | |
obj:enable_filter(true) | |
interpolate(self.f0_points_6581, PointPlotter(obj.f0_6581), 1.0) | |
interpolate(self.f0_points_8580, PointPlotter(obj.f0_8580), 1.0) | |
obj:set_chip_model(chip_model.MOS6581) | |
return obj | |
end | |
function Filter:enable_filter(enable) | |
self.enabled = enable | |
end | |
function Filter:set_chip_model(model) | |
if model == chip_model.MOS6581 then | |
self.mixer_DC = -0x1C5 | |
self.f0 = self.f0_6581 | |
self.f0_points = Filter.f0_points_6581 | |
self.f0_count = #self.f0_points | |
else | |
self.mixer_DC = 0 | |
self.f0 = self.f0_8580 | |
self.f0_points = Filter.f0_points_8580 | |
self.f0_count = #self.f0_points | |
end | |
self:set_w0() | |
self:set_Q() | |
end | |
function Filter:clock_4(voice1, voice2, voice3, ext_in) | |
voice1 = arshift(voice1, 7) | |
voice2 = arshift(voice2, 7) | |
if self.voice3off and not btest(self.filt, 0x04) then | |
voice3 = 0 | |
else | |
voice3 = arshift(voice3, 7) | |
end | |
--ext_in = arshift(ext_in, 7) | |
if not self.enabled then | |
self.Vnf = voice1 + voice2 + voice3 --+ ext_in | |
self.Vhp, self.Vbp, self.Vlp = 0, 0, 0 | |
return | |
end | |
local Vi = (btest(self.filt, 1) and voice1 or 0) + | |
(btest(self.filt, 2) and voice2 or 0) + | |
(btest(self.filt, 4) and voice3 or 0) | |
--(btest(self.filt, 8) and ext_in or 0) | |
self.Vnf = (btest(self.filt, 1) and 0 or voice1) + | |
(btest(self.filt, 2) and 0 or voice2) + | |
(btest(self.filt, 4) and 0 or voice3) | |
--(btest(self.filt, 8) and 0 or ext_in) | |
local dVbp = arshift(self.w0_ceil_1*self.Vhp, 20) | |
local dVlp = arshift(self.w0_ceil_1*self.Vbp, 20) | |
self.Vbp = self.Vbp - dVbp | |
self.Vlp = self.Vlp - dVlp | |
self.Vhp = arshift(self.Vbp*self._1024_div_Q, 10) - self.Vlp - Vi | |
end | |
function Filter:clock(delta_t, voice1, voice2, voice3, ext_in) | |
if not ext_in then return self:clock_4(delta_t, voice1, voice2, voice3) end | |
voice1 = arshift(voice1, 7) | |
voice2 = arshift(voice2, 7) | |
if self.voice3off and not btest(self.filt, 0x04) then | |
voice3 = 0 | |
else | |
voice3 = arshift(voice3, 7) | |
end | |
--ext_in = arshift(ext_in, 7) | |
if not self.enabled then | |
self.Vnf = voice1 + voice2 + voice3 --+ ext_in | |
self.Vhp, self.Vbp, self.Vlp = 0, 0, 0 | |
return | |
end | |
local Vi = (btest(self.filt, 1) and voice1 or 0) + | |
(btest(self.filt, 2) and voice2 or 0) + | |
(btest(self.filt, 4) and voice3 or 0) | |
--(btest(self.filt, 8) and ext_in or 0) | |
self.Vnf = (btest(self.filt, 1) and 0 or voice1) + | |
(btest(self.filt, 2) and 0 or voice2) + | |
(btest(self.filt, 4) and 0 or voice3) | |
--(btest(self.filt, 8) and 0 or ext_in) | |
local Vbp, Vlp, Vhp, w0_ceil_dt, Q = self.Vbp, self.Vlp, self.Vhp, self.w0_ceil_dt, self._1024_div_Q / 1024 | |
local w0_delta_t = floor(w0_ceil_dt / 8) / 0x4000 | |
for delta_t = delta_t, 0, -8 do | |
if delta_t < 8 then | |
w0_delta_t = floor(w0_ceil_dt*delta_t / 64) / 0x4000 | |
local dVbp = floor(w0_delta_t*Vhp) | |
local dVlp = floor(w0_delta_t*Vbp) | |
Vbp = Vbp - dVbp | |
Vlp = Vlp - dVlp | |
Vhp = floor(Vbp*Q) - Vlp - Vi | |
break | |
end | |
local dVbp = floor(w0_delta_t*Vhp) | |
local dVlp = floor(w0_delta_t*Vbp) | |
Vbp = Vbp - dVbp | |
Vlp = Vlp - dVlp | |
Vhp = floor(Vbp*Q) - Vlp - Vi | |
end | |
self.Vbp, self.Vlp, self.Vhp = Vbp, Vlp, Vhp | |
end | |
function Filter:reset() | |
self.fc = 0 | |
self.res = 0 | |
self.filt = 0 | |
self.voice3off = false | |
self.hp_bp_lp = 0 | |
self.vol = 0 | |
self.Vhp = 0 | |
self.Vbp = 0 | |
self.Vlp = 0 | |
self.Vnf = 0 | |
self:set_w0() | |
self:set_Q() | |
end | |
function Filter:writeFC_LO(fc_lo) | |
self.fc = bor(band(self.fc, 0x7f8), band(fc_lo, 0x007)) | |
self:set_w0() | |
end | |
function Filter:writeFC_HI(fc_hi) | |
self.fc = bor(band(lshift(fc_hi, 3), 0x7f8), band(self.fc, 0x007)) | |
self:set_w0() | |
end | |
function Filter:writeRES_FILT(res_filt) | |
self.res = band(rshift(res_filt, 4), 0x0f) | |
self:set_Q() | |
self.filt = band(res_filt, 0x0f) | |
end | |
function Filter:writeMODE_VOL(mode_vol) | |
self.voice3off = btest(mode_vol, 0x80) | |
self.hp_bp_lp = band(rshift(mode_vol, 4), 0x07) | |
self.vol = band(mode_vol, 0x0f) | |
end | |
function Filter:output() | |
if not self.enabled then | |
return (self.Vnf + self.mixer_DC)*self.vol | |
end | |
local Vf = (btest(self.hp_bp_lp, 1) and self.Vlp or 0) + | |
(btest(self.hp_bp_lp, 2) and self.Vbp or 0) + | |
(btest(self.hp_bp_lp, 4) and self.Vhp or 0) | |
return (self.Vnf + Vf + self.mixer_DC)*self.vol | |
end | |
function Filter:fc_default() | |
return self.f0_points, self.f0_count | |
end | |
function Filter:fc_plotter() | |
return PointPlotter(self.f0) | |
end | |
function Filter:set_w0() | |
self.w0 = floor(2*pi*self.f0[self.fc]*1.048576) | |
local w0_max_1 = floor(2*pi*16000*1.048576) | |
self.w0_ceil_1 = min(self.w0, w0_max_1) | |
local w0_max_dt = floor(2*pi*4000*1.048576) | |
self.w0_ceil_dt = min(self.w0, w0_max_dt) | |
end | |
function Filter:set_Q() | |
self._1024_div_Q = floor(1024.0/(0.707 + 1.0*self.res/0x0f)) | |
end | |
-- * wave * | |
local WaveformGenerator = {} | |
WaveformGenerator.__index = WaveformGenerator | |
function WaveformGenerator:new() | |
local obj = setmetatable({}, self) | |
obj.sync_source = obj | |
obj:set_chip_model(chip_model.MOS6581) | |
obj:reset() | |
return obj | |
end | |
function WaveformGenerator:set_sync_source(source) | |
self.sync_source = source | |
source.sync_dest = self | |
end | |
function WaveformGenerator:set_chip_model(model) | |
if model == chip_model.MOS6581 then | |
self.wave__ST = WaveformGenerator.wave6581__ST | |
self.wave_P_T = WaveformGenerator.wave6581_P_T | |
self.wave_PS_ = WaveformGenerator.wave6581_PS_ | |
self.wave_PST = WaveformGenerator.wave6581_PST | |
else | |
self.wave__ST = WaveformGenerator.wave8580__ST | |
self.wave_P_T = WaveformGenerator.wave8580_P_T | |
self.wave_PS_ = WaveformGenerator.wave8580_PS_ | |
self.wave_PST = WaveformGenerator.wave8580_PST | |
end | |
end | |
function WaveformGenerator:clock_0() | |
if self.test then | |
return | |
end | |
local accumulator_prev = self.accumulator | |
self.accumulator = band(self.accumulator + self.freq, 0xffffff) | |
self.msb_rising = accumulator_prev < 0x800000 and self.accumulator >= 0x800000 | |
if not btest(accumulator_prev, 0x080000) and btest(self.accumulator, 0x080000) then | |
local bit0 = band(bxor(rshift(self.shift_register, 22), rshift(self.shift_register, 17)), 0x1) | |
self.shift_register = bor(band(lshift(self.shift_register, 1), 0x7fffff), bit0) | |
end | |
end | |
function WaveformGenerator:clock(delta_t) | |
if not delta_t then return self:clock_0() end | |
if self.test then | |
return | |
end | |
local accumulator_prev = self.accumulator | |
local delta_accumulator = delta_t*self.freq | |
self.accumulator = band(self.accumulator + delta_accumulator, 0xffffff) | |
self.msb_rising = accumulator_prev < 0x800000 and self.accumulator >= 0x800000 | |
local shift_period = 0x100000 | |
local shift_register = self.shift_register | |
while delta_accumulator ~= 0 do | |
if delta_accumulator < shift_period then | |
shift_period = delta_accumulator | |
if shift_period <= 0x080000 then | |
if btest(self.accumulator - shift_period, 0x080000) or not btest(self.accumulator, 0x080000) then | |
break | |
end | |
else | |
if btest(self.accumulator - shift_period, 0x080000) and not btest(self.accumulator, 0x080000) then | |
break | |
end | |
end | |
end | |
local bit0 = bxor(rshift(shift_register, 22), rshift(shift_register, 17)) % 2 | |
shift_register = band(lshift(shift_register, 1), 0x7fffff) + bit0 | |
delta_accumulator = delta_accumulator - shift_period | |
end | |
self.shift_register = shift_register | |
end | |
function WaveformGenerator:synchronize() | |
if self.msb_rising and self.sync_dest.sync and not (self.sync and self.sync_source.msb_rising) then | |
self.sync_dest.accumulator = 0 | |
end | |
end | |
function WaveformGenerator:reset() | |
self.accumulator = 0 | |
self.shift_register = 0x7ffff8 | |
self.freq = 0 | |
self.pw = 0 | |
self.waveform = 0 | |
self.output = WaveformGenerator.outputs[0] | |
self.test = 0 | |
self.ring_mod = 0 | |
self.sync = false | |
self.msb_rising = false | |
end | |
function WaveformGenerator:writeFREQ_LO(freq_lo) | |
self.freq = bor(band(self.freq, 0xff00), band(freq_lo, 0x00ff)) | |
end | |
function WaveformGenerator:writeFREQ_HI(freq_hi) | |
self.freq = bor(band(lshift(freq_hi, 8), 0xff00), band(self.freq, 0x00ff)) | |
end | |
function WaveformGenerator:writePW_LO(pw_lo) | |
self.pw = bor(band(self.pw, 0xf00), band(pw_lo, 0x0ff)) | |
end | |
function WaveformGenerator:writePW_HI(pw_hi) | |
self.pw = bor(band(lshift(pw_hi, 8), 0xf00), band(self.pw, 0x0ff)) | |
end | |
function WaveformGenerator:writeCONTROL_REG(control) | |
self.waveform = band(rshift(control, 4), 0x0f) | |
self.output = WaveformGenerator.outputs[self.waveform] | |
self.ring_mod = btest(control, 0x04) | |
self.sync = btest(control, 0x02) | |
local test_next = btest(control, 0x08) | |
if test_next then | |
self.accumulator = 0 | |
self.shift_register = 0 | |
elseif self.test then | |
self.shift_register = 0x7ffff8 | |
end | |
self.test = test_next | |
end | |
function WaveformGenerator:readOSC() | |
return rshift(self:output(), 4) | |
end | |
function WaveformGenerator:output() | |
--return WaveformGenerator.outputs[self.waveform](self) | |
-- O(log n) search for the correct output type | |
if self.waveform < 8 then | |
if self.waveform % 8 < 4 then | |
if self.waveform % 4 < 2 then | |
if self.waveform % 2 == 0 then | |
return 0x000 | |
else | |
local msb = (self.ring_mod and bxor(self.accumulator, self.sync_source.accumulator) or self.accumulator) >= 0x800000 | |
return band(rshift(msb and bnot(self.accumulator) or self.accumulator, 11), 0xfff) | |
end | |
else | |
if self.waveform % 2 == 0 then | |
return rshift(self.accumulator, 12) | |
else | |
local s = rshift(self.accumulator, 12) | |
return lshift(self.wave__ST[s], 4) | |
end | |
end | |
else | |
local p = (self.test or rshift(self.accumulator, 12) >= self.pw) and 0xfff or 0x000 | |
if self.waveform % 4 < 2 then | |
if self.waveform % 2 == 0 then | |
return p | |
else | |
local msb = (self.ring_mod and bxor(self.accumulator, self.sync_source.accumulator) or self.accumulator) >= 0x800000 | |
local t = band(rshift(msb and bnot(self.accumulator) or self.accumulator, 11), 0xfff) | |
return band(lshift(self.wave_P_T[rshift(t, 1)], 4), p) | |
end | |
else | |
local s = rshift(self.accumulator, 12) | |
local t = self.waveform % 2 == 0 and self.wave_PS_ or self.wave_PST | |
return band(lshift(t[s], 4), p) | |
end | |
end | |
elseif self.waveform == 8 then | |
return bor( | |
rshift(band(self.shift_register, 0x400000), 11), | |
rshift(band(self.shift_register, 0x100000), 10), | |
rshift(band(self.shift_register, 0x010000), 7), | |
rshift(band(self.shift_register, 0x002000), 5), | |
rshift(band(self.shift_register, 0x000800), 4), | |
rshift(band(self.shift_register, 0x000080), 1), | |
lshift(band(self.shift_register, 0x000010), 1), | |
lshift(band(self.shift_register, 0x000004), 2) | |
) | |
else return 0 end | |
end | |
WaveformGenerator.outputs = { | |
[0] = function(self) -- ____ | |
return 0x000 | |
end, | |
function(self) -- ___T | |
local msb = (self.ring_mod and bxor(self.accumulator, self.sync_source.accumulator) or self.accumulator) >= 0x800000 | |
return band(rshift(msb and bnot(self.accumulator) or self.accumulator, 11), 0xfff) | |
end, | |
function(self) -- __S_ | |
return rshift(self.accumulator, 12) | |
end, | |
function(self) -- __ST | |
return lshift(self.wave__ST[rshift(self.accumulator, 12)], 4) | |
end, | |
function(self) -- _P__ | |
return (self.test or rshift(self.accumulator, 12) >= self.pw) and 0xfff or 0x000 | |
end, | |
function(self) -- _P_T | |
local p = (self.test or rshift(self.accumulator, 12) >= self.pw) and 0xfff or 0x000 | |
local msb = (self.ring_mod and bxor(self.accumulator, self.sync_source.accumulator) or self.accumulator) >= 0x800000 | |
local t = band(rshift(msb and bnot(self.accumulator) or self.accumulator, 11), 0xfff) | |
return band(lshift(self.wave_P_T[rshift(t, 1)], 4), p) | |
end, | |
function(self) -- _PS_ | |
local p = (self.test or rshift(self.accumulator, 12) >= self.pw) and 0xfff or 0x000 | |
local s = rshift(self.accumulator, 12) | |
return band(lshift(self.wave_PS_[s], 4), p) | |
end, | |
function(self) -- _PST | |
local p = (self.test or rshift(self.accumulator, 12) >= self.pw) and 0xfff or 0x000 | |
local s = rshift(self.accumulator, 12) | |
return band(lshift(self.wave_PST[s], 4), p) | |
end, | |
function(self) -- N___ | |
return bor( | |
rshift(band(self.shift_register, 0x400000), 11), | |
rshift(band(self.shift_register, 0x100000), 10), | |
rshift(band(self.shift_register, 0x010000), 7), | |
rshift(band(self.shift_register, 0x002000), 5), | |
rshift(band(self.shift_register, 0x000800), 4), | |
rshift(band(self.shift_register, 0x000080), 1), | |
lshift(band(self.shift_register, 0x000010), 1), | |
lshift(band(self.shift_register, 0x000004), 2) | |
) | |
end, | |
function(self) -- N__T | |
return 0 | |
end, | |
function(self) -- N_S_ | |
return 0 | |
end, | |
function(self) -- N_ST | |
return 0 | |
end, | |
function(self) -- NP__ | |
return 0 | |
end, | |
function(self) -- NP_T | |
return 0 | |
end, | |
function(self) -- NPS_ | |
return 0 | |
end, | |
function(self) -- NPST | |
return 0 | |
end | |
} | |
-- * wavetables * | |
local function unrle(s) | |
local r = "" | |
for c, n in s:gmatch "(.)(.)" do r = r .. c:rep(n:byte()) end | |
local t = {r:byte(2, -1)} | |
t[0] = r:byte() | |
return t | |
end | |
WaveformGenerator.wave6581__ST = unrle "\0~\x03\x02\0?\x01\x01\0<\x07\x04\0?\x01\x01\0>\x03\x02\0?\x01\x01\0008\x0E\x04\x0F\x04\0~\x03\x02\0?\x01\x01\0<\x07\x04\0?\x01\x01\0>\x03\x02\0?\x01\x01\0\x30\x1C\x08\x1E\x04\x1F\x02?\x02\0~\x03\x02\0?\x01\x01\0<\x07\x04\0?\x01\x01\0>\x03\x02\0?\x01\x01\0008\x0E\x04\x0F\x03\x1F\x01\0~\x03\x02\0?\x01\x01\0<\x07\x04\0?\x01\x01\0>\x03\x02\0?\x01\x01\0\x208\x10<\x08>\x02?\x02\x7F\x04\0~\x03\x02\0?\x01\x01\0<\x07\x04\0?\x01\x01\0>\x03\x02\0?\x01\x01\0008\x0E\x04\x0F\x04\0~\x03\x02\0?\x01\x01\0<\x07\x04\0?\x01\x01\0>\x03\x02\0?\x01\x01\0\x30\x1C\x08\x1E\x04\x1F\x02?\x02\0~\x03\x02\0?\x01\x01\0<\x07\x04\0?\x01\x01\0>\x03\x02\0?\x01\x01\0008\x0E\x04\x0F\x03\x1F\x01\0~\x03\x02\0?\x01\x01\0<\x07\x04\0?\x01\x01\0>\x03\x02\0?\x01\x01\0\x208\x10<\x08>\x02?\x02\x7F\x04" | |
WaveformGenerator.wave6581_P_T = unrle "\0\xFF\0\xFE \x018\x01?\x01\0\xFB@\x01\0\x01@\x02_\x01\0o@\x01\0\x07@\x01\0\x03`\x01\0\x01`\x02o\x01\0\x1F@\x01\0\x0F`\x01\0\x07`\x01\0\x03`\x01\0\x01`\x01p\x01w\x01\0\x0F`\x01\0\x07`\x01\0\x03p\x01@\x01p\x02{\x01\0\x06@\x01p\x01\0\x01@\x02p\x01`\x01p\x01x\x01}\x01\0\x01@\x01`\x01x\x01`\x01x\x02~\x01p\x01|\x02\x7F\x01~\x01\x7F\x03\0\x7F\x80\x01\0?\x80\x01\0\x1F\x80\x01\0\x0F\x80\x01\0\x07\x80\x01\0\x03\x80\x04\x9F\x01\0?\x80\x01\0\x1F\x80\x01\0\x0F\x80\x01\0\x07\x80\x01\0\x01\x80\x04\xA0\x02\xAF\x01\0\x1F\x80\x01\0\x0D\x80\x03\0\x03\x80\x01\0\x01\x80\x02\xA0\x01\0\x01\x80\x02\xA0\x01\x80\x01\xA0\x01\xB0\x01\xB7\x01\0\x07\x80\x01\0\x03\x80\x01\0\x01\x80\x02\xA0\x01\0\x03\x80\x01\0\x01\x80\x02\xA0\x01\0\x01\x80\x02\xA0\x01\x80\x01\xB0\x02\xBB\x01\0\x03\x80\x04\xB0\x01\x80\x03\xB0\x01\x80\x01\xB0\x01\xB8\x01\xBD\x01\x80\x03\xB8\x01\xA0\x01\xB8\x02\xBE\x01\xA0\x01\xB8\x01\xBC\x01\xBF\x01\xBE\x01\xBF\x03\0?\xC0\x01\0\x1D\x80\x02\xC0\x01\0\x0B\x80\x01\0\x01\x80\x02\xC0\x01\0\x03\x80\x01\0\x01\x80\x02\xC0\x01\0\x01\x80\x02\xC0\x04\xCF\x01\0\x0F\x80\x01\0\x07\x80\x01\0\x03\x80\x01\0\x01\x80\x02\xC0\x01\0\x07\x80\x01\0\x03\x80\x01\0\x01\x80\x02\xC0\x01\0\x03\x80\x01\0\x01\x80\x01\xC0\x02\x80\x01\xC0\x05\xD0\x01\xD7\x01\0\x07\x80\x01\0\x03\x80\x03\xC0\x02\0\x01\x80\x02\xC0\x01\x80\x01\xC0\x03\x80\x01\xC0\x04\xD0\x02\xDB\x01\0\x01\x80\x02\xC0\x01\x80\x01\xC0\x02\xD0\x01\x80\x01\xC0\x02\xD0\x01\xC0\x01\xD0\x01\xD8\x01\xDD\x01\xC0\x03\xD0\x01\xC0\x01\xD8\x02\xDE\x01\xC0\x01\xD8\x01\xDC\x01\xDF\x01\xDC\x01\xDF\x03\0\x0F\x80\x01\0\x07\x80\x01\0\x03\x80\x02\xC0\x02\xE0\x01\0\x07\x80\x01\0\x01\x80\x02\xC0\x01\x80\x01\xC0\x02\xE0\x01\0\x01\x80\x02\xC0\x01\x80\x01\xC0\x02\xE0\x01\x80\x01\xC0\x02\xE0\x01\xC0\x01\xE0\x02\xE7\x01\0\x03\x80\x01\0\x01\x80\x02\xC0\x01\0\x01\x80\x02\xC0\x01\x80\x01\xC0\x02\xE0\x01\0\x01\x80\x02\xC0\x01\x80\x01\xC0\x02\xE0\x01\xC0\x03\xE0\x04\xEB\x01\x80\x02\xC0\x05\xE0\x01\xC0\x01\xE0\x06\xED\x01\xC0\x01\xE0\x04\xE8\x02\xEE\x01\xE0\x01\xE8\x01\xEC\x01\xEF\x01\xEC\x01\xEF\x03\0\x03\x80\x04\xC0\x01\x80\x02\xC0\x05\xF0\x01\x80\x01\xC0\x04\xE0\x02\xF0\x01\xC0\x01\xE0\x02\xF0\x01\xE0\x01\xF0\x02\xF3\x01\x80\x01\xC0\x02\xE0\x01\xC0\x01\xE0\x02\xF0\x01\xC0\x01\xE0\x02\xF0\x01\xE0\x01\xF0\x02\xF5\x01\xE0\x03\xF0\x04\xF6\x01\xF0\x02\xF4\x01\xF7\x01\xF4\x01\xF7\x03\xC0\x03\xE0\x04\xF0\x01\xE0\x03\xF8\x01\xF0\x01\xF8\x02\xF9\x01\xE0\x01\xF0\x02\xF8\x01\xF0\x01\xF8\x02\xFA\x01\xF0\x01\xF8\x02\xFB\x01\xF8\x01\xFB\x03\xE0\x01\xF0\x02\xF8\x01\xF0\x01\xF8\x01\xFC\x02\xF8\x01\xFC\x02\xFD\x01\xFC\x01\xFD\x03\xF8\x01\xFC\x01\xFE\x07\xFF\x0E\xFE\x07\xFC\x01\xF8\x01\xFD\x03\xFC\x01\xFD\x01\xFC\x02\xF8\x01\xFC\x03\xF0\x01\xF8\x01\xF0\x02\xE0\x01\xFB\x03\xF8\x01\xFB\x01\xF8\x02\xF0\x01\xFA\x01\xF8\x02\xF0\x01\xF8\x01\xF0\x02\xE0\x01\xF9\x01\xF8\x02\xF0\x01\xF8\x01\xF0\x01\xE0\x02\xF0\x01\xE0\x04\xC0\x03\xF7\x03\xF4\x01\xF7\x01\xF4\x01\xF0\x02\xF6\x01\xF0\x04\xE0\x03\xF5\x01\xF0\x02\xE0\x01\xF0\x01\xE0\x02\xC0\x01\xF0\x01\xE0\x02\xC0\x01\xE0\x01\xC0\x02\x80\x01\xF3\x01\xF0\x02\xE0\x01\xF0\x01\xE0\x02\xC0\x01\xF0\x01\xE0\x02\xC0\x04\x80\x01\xF0\x01\xE0\x01\xC0\x04\x80\x02\xC0\x01\x80\x04\0\x03\xEF\x03\xEC\x01\xEF\x01\xEC\x01\xE8\x01\xE0\x01\xEE\x01\xE8\x02\xE0\x04\xC0\x01\xED\x01\xE8\x01\xE0\x05\xC0\x01\xE0\x02\xC0\x04\x80\x02\xEB\x01\xE0\x04\xC0\x03\xE0\x01\xC0\x02\x80\x01\xC0\x01\x80\x02\0\x01\xE0\x01\xC0\x02\x80\x01\xC0\x01\x80\x02\0\x01\xC0\x01\x80\x02\0\x01\x80\x01\0\x03\xE7\x01\xE0\x02\xC0\x01\xE0\x01\xC0\x02\x80\x01\xE0\x01\xC0\x02\x80\x01\xC0\x01\x80\x02\0\x01\xE0\x01\xC0\x02\x80\x01\xC0\x01\x80\x02\0\x01\x80\x02\0\x06\xE0\x01\xC0\x02\x80\x02\0\x03\x80\x01\0\x07\x80\x01\0\x0F\xDF\x03\xDC\x01\xDF\x01\xDC\x01\xD8\x01\xC0\x01\xDE\x01\xD8\x02\xC0\x01\xD8\x01\xC0\x03\xDD\x01\xD8\x01\xD0\x01\xC0\x01\xD0\x01\xC0\x02\x80\x01\xD0\x01\xC0\x02\x80\x01\xC0\x01\x80\x02\0\x01\xDB\x01\xD0\x02\xC0\x04\x80\x01\xC0\x03\x80\x01\xC0\x01\x80\x02\0\x01\xC0\x02\x80\x03\0\x03\x80\x01\0\x07\xD7\x01\xD0\x01\xC0\x05\x80\x01\xC0\x02\x80\x01\0\x01\x80\x01\0\x03\xC0\x01\x80\x02\0\x01\x80\x01\0\x03\x80\x01\0\x07\xC0\x01\x80\x02\0\x01\x80\x01\0\x03\x80\x01\0\x07\x80\x01\0\x0F\xCF\x01\xC0\x04\x80\x02\0\x01\xC0\x01\x80\x02\0\x01\x80\x01\0\x03\xC0\x01\x80\x02\0\x01\x80\x01\0\x0B\xC0\x01\x80\x02\0\x1D\xC0\x01\x80\x01\0>\xBF\x03\xBE\x01\xBF\x01\xBC\x02\xA0\x01\xBE\x01\xBC\x01\xB8\x01\xA0\x01\xB8\x01\xA0\x01\x80\x02\xBD\x01\xB8\x01\xB0\x01\x80\x01\xB0\x01\x80\x03\xB0\x01\x80\x04\0\x03\xBB\x01\xB0\x02\x80\x01\xA0\x01\x80\x02\0\x01\xA0\x01\x80\x02\0\x01\x80\x01\0\x03\xA0\x01\x80\x02\0\x01\x80\x01\0\x03\x80\x01\0\x07\xB7\x01\xB0\x01\xA0\x01\x80\x01\xA0\x01\x80\x02\0\x01\xA0\x01\x80\x02\0\x01\x80\x01\0\x03\x80\x03\0\x0D\x80\x02\0\x1E\xAF\x01\xA0\x02\x80\x04\0\x01\x80\x02\0\x06\x80\x01\0\x0F\x80\x01\0\x1F\x80\x01\0?\x9F\x01\x90\x01\x80\x03\0\x03\x80\x01\0\x07\x80\x01\0\x0F\x80\x01\0\x1F\x80\x01\0?\x80\x01\0\x7F\x7F\x03~\x01\x7F\x01|\x02p\x01~\x01|\x01x\x01`\x01x\x01`\x02\0\x01}\x01x\x02`\x01p\x01@\x02\0\x01p\x01@\x01\0\x06{\x01x\x01p\x01@\x01p\x01@\x01\0\x02`\x01\0\x07`\x01\0\x0Fw\x01p\x02\0\x01`\x01\0\x03`\x01\0\x07`\x01\0\x0F@\x01\0\x1Fo\x01`\x02\0\x01`\x01\0\x03@\x01\0\x07@\x01\0o_\x01X\x01@\x01\0\x01@\x01\0\x03@\x01\0\xF7?\x01<\x010\x01\0\xFF\0\xFE" | |
WaveformGenerator.wave6581_PS_ = unrle "\0\xFF\x07\x01\0\x7F\x03\x01\0?\x03\x01\0>\x02\x01\x1F\x01\0\x7F\x03\x01\0?\x01\x01\0?\x2F\x01\0\x7F7\x01\0?;\x01\0\x1F=\x01\0\x0F>\x01\0\x06\x30\x01?\x01\0\x01\x30\x018\x01?\x01>\x01?\x03\0\x7F\x03\x01\0\x7FO\x01\0\x7FW\x01\0?[\x01\0\x1F]\x01\0\x0F^\x01\0\x06@\x01_\x01\0\x01@\x02_\x01\x5C\x01_\x03\0\x7Fg\x01\0>@\x01k\x01\0\x1D@\x02m\x01\0\x07@\x01\0\x03@\x01\0\x01@\x02n\x01\0\x03@\x01\0\x01`\x02o\x01\0\x01`\x02o\x01`\x01o\x03\0\x1F@\x01\0\x0F@\x01\0\x07@\x01\0\x03@\x01\0\x01@\x01`\x01s\x01\0\x0F@\x01\0\x07@\x01\0\x03@\x01\0\x01`\x02u\x01\0\x07`\x01\0\x03`\x01\0\x01`\x02v\x01\0\x03`\x01\0\x01`\x02w\x01\0\x01p\x02w\x01p\x01w\x03\0\x0F`\x01\0\x07`\x01\0\x03`\x01\0\x01`\x02y\x01\0\x07`\x01\0\x03`\x01\0\x01p\x02z\x01\0\x03p\x01\0\x01p\x02{\x01@\x01p\x02{\x01x\x01{\x03\0\x07p\x01\0\x03p\x01\0\x01p\x02|\x01\0\x03p\x01@\x01p\x02}\x01@\x01p\x01x\x01}\x01x\x01}\x03\0\x01@\x02x\x01`\x01x\x02~\x01`\x01x\x02~\x01|\x01~\x03p\x01|\x02\x7F\x01~\x01\x7F\x03~\x01\x7F\x07\0\xFF\x07\x01\0\x7F\x03\x01\0?\x03\x01\0>\x02\x01\x1F\x01\0\x7F\x03\x01\0?\x01\x01\0?\x2F\x01\0\x7F7\x01\0?;\x01\0\x1F=\x01\0\x0F>\x01\0\x06\x30\x01?\x01\0\x01\x30\x018\x01?\x01>\x01?\x03\0\x7F\x03\x01\0\x7FO\x01\0\x7FW\x01\0?[\x01\0\x1F]\x01\0\x0F^\x01\0\x06@\x01_\x01\0\x01@\x02_\x01\x5C\x01_\x03\0\x7Fg\x01\0>@\x01k\x01\0\x1E@\x01m\x01\0\x07@\x01\0\x03@\x01\0\x01@\x02n\x01\0\x03@\x01\0\x01`\x02o\x01\0\x01`\x02o\x01`\x01o\x03\0\x1F@\x01\0\x0F@\x01\0\x07@\x01\0\x03@\x01\0\x01@\x01`\x01s\x01\0\x0F@\x01\0\x07@\x01\0\x03@\x01\0\x01`\x02u\x01\0\x07`\x01\0\x03`\x01\0\x01`\x02v\x01\0\x03`\x01\0\x01`\x02w\x01\0\x01p\x02w\x01p\x01w\x03\0\x0F`\x01\0\x07`\x01\0\x03`\x01\0\x01`\x02y\x01\0\x07`\x01\0\x03`\x01\0\x01p\x02z\x01\0\x03p\x01\0\x01p\x02{\x01@\x01p\x02{\x01x\x01{\x03\0\x07p\x01\0\x03p\x01\0\x01p\x02|\x01\0\x03p\x01@\x01p\x02}\x01@\x01p\x01x\x01}\x01x\x01}\x03\0\x01@\x02x\x01`\x01x\x02~\x01`\x01x\x02~\x01|\x01~\x03p\x01|\x02\x7F\x01|\x01\x7F\x03~\x01\x7F\x07" | |
WaveformGenerator.wave6581_PST = unrle "\0\xFF\0\xFF\0\xFF\0\xFF\0\x03?\x01\0\xFF\0\xFF\0\xFF\0\xF2 \x01\0\x070\x01\0\x03x\x02~\x01\x7F\x02\0\xFF\0\xFF\0\xFF\0\xFF\0\x03?\x01\0\xFF\0\xFF\0\xFF\0\xF2 \x01\0\x070\x01\0\x03x\x02~\x01\x7F\x02" | |
WaveformGenerator.wave8580__ST = unrle "\0~\x03\x02\0|\x07\x04\0~\x03\x02\0x\x0E\x04\x0F\x04\0~\x03\x02\0|\x07\x04\0~\x03\x02\0?\x01\x01\0000\x1C\x08\x1E\x02\x1F\x06\0~\x03\x02\0|\x07\x04\0~\x03\x02\0x\x0E\x04\x0F\x03\x1F\x01\0~\x03\x02\0|\x07\x04\0~\x03\x02\0?\x01\x01\0 8\x10<\x07>\x01\x7F\x08\0~\x03\x02\0|\x07\x04\0~\x03\x02\0x\x0E\x04\x0F\x04\0~\x03\x02\0|\x07\x04\0~\x03\x02\0?\x01\x01\0000\x1C\x08\x1E\x02\x1F\x04?\x02\0~\x03\x02\0|\x07\x04\0~\x03\x02\0?\x01\x01\0008\x0E\x04\x0F\x02\x1F\x02\0|\x80\x01\0\x01\x83\x02\x80|\x87\x03\x8F\x01\xC0\x01\xE0\x02\xC0\x02\xE0\x04\xC0\x08\xE0\x02\xC0\x05\xE0\x01\xC0\x08\xE0\x02\xC0\x02\xE0\x06\xC0\x01\xE0\x01\xC0\x01\xE0P\xE3\x02\xF0?\xF1\x01\xF8 \xFC\x10\xFE\x08\xFF\x08" | |
WaveformGenerator.wave8580_P_T = unrle "\0\xFF\x07\x01\0\xFB\x1C\x01\0\x01<\x01?\x02\0\xFD\x0C\x01^\x01_\x01\0w@\x01\0\x03@\x02`\x02o\x01\0\x1F@\x01\0\x0E@\x02\0\x03@\x04`\x01@\x02`\x04p\x01w\x01\0\x05@\x08`\x03@\x03`\x04p\x01`\x03p\x03x\x01{\x01`\x03p\x01`\x01p\x06x\x04|\x01x\x03|\x01x\x01|\x02~\x01|\x01~\x02\x7F\x05\0\x7F\x80\x01\0=\x80\x03\0\x0F\x80\x01\0\x07\x80\x01\0\x02\x80\x06\0\x03\x80\x1B\x8E\x01\x9F\x01\0\x1F\x80\x01\0\x0B\x80\x01\0\x01\x80\x03\0\x02\x80\x0E\0\x03\x80\x01\0\x01\x80:\xAF\x01\x80;\xA0\x04\xB7\x01\x80\x0F\xA0\x01\x80\x06\xA0\x05\xB0\x01\xA0\x01\xB0\x02\xBB\x01\xA0\x06\xB0\x02\xA0\x01\xB0\x02\xB8\x01\xB0\x01\xB8\x02\xBC\x01\xB0\x01\xB8\x04\xBC\x02\xBE\x01\xBC\x02\xBE\x01\xBF\x01\xBE\x01\xBF\x03\x80>\xC0\x02\x80\x17\xC0\x01\x80\x02\xC0\x06\x80\x03\xC0\x01\x80\x01\xC0\x1A\xCF\x01\x80\x06\xC0\x03\x80\x01\xC05\xD7\x01\xC0\x1D\xD0\x02\xD9\x01\xC0\x07\xD0\x01\xC0\x01\xD0\x04\xD8\x02\xDC\x01\xD0\x02\xD8\x03\xDC\x02\xDE\x01\xDC\x02\xDE\x01\xDF\x01\xDE\x01\xDF\x03\xC0\x1B\xE0\x01\xC0\x01\xE0\x03\xC0\x07\xE0\x01\xC0\x02\xE0\x15\xE7\x01\xE0\x1F\xE8\x01\xE0\x0E\xE8\x01\xEC\x01\xE0\x03\xE8\x03\xEC\x01\xEE\x01\xEC\x03\xEE\x02\xEF\x03\xE0\x0D\xF0\x03\xE0\x02\xF0\x1D\xF4\x01\xF0\x07\xF4\x01\xF0\x01\xF4\x02\xF6\x02\xF7\x03\xF0\x03\xF8\x01\xF0\x01\xF8\x16\xFA\x02\xFB\x03\xF8\x01\xFC\x0C\xFD\x03\xFE\x08\xFF\x10\xFE\x07\xFC\x01\xFD\x03\xFC\x0C\xF8\x01\xFB\x03\xFA\x02\xF8\x16\xF0\x05\xF7\x03\xF6\x02\xF4\x02\xF0\x01\xF4\x01\xF0\x07\xF4\x01\xF0\x1D\xE0\x02\xF0\x03\xE0\x0D\xEF\x03\xEE\x02\xEC\x02\xE8\x01\xEE\x01\xEC\x01\xE8\x03\xE0\x03\xEC\x01\xE8\x01\xE0\x0E\xE8\x01\xE0\x1F\xE7\x01\xE0\x15\xC0\x02\xE0\x01\xC0\x07\xE0\x03\xC0\x1D\xDF\x03\xDE\x01\xDF\x01\xDE\x01\xDC\x02\xDE\x01\xDC\x02\xD8\x03\xD0\x02\xDC\x01\xD8\x02\xD0\x04\xC0\x01\xD0\x01\xC0\x07\xD9\x01\xD0\x02\xC0\x1D\xD7\x01\xC06\x80\x01\xC0\x03\x80\x05\xCF\x01\xC0\x1A\x80\x01\xC0\x01\x80\x03\xC0\x06\x80\x02\xC0\x01\x80\x17\xC0\x03\x80=\xBF\x03\xBE\x01\xBF\x01\xBE\x01\xBC\x02\xBE\x01\xBC\x02\xB8\x04\xB0\x01\xBC\x01\xB8\x02\xB0\x01\xB8\x01\xB0\x05\xA0\x06\xBB\x01\xB0\x02\xA0\x01\xB0\x01\xA0\x06\x80\x05\xA0\x01\x80\x0F\xB7\x01\xB0\x01\xA0\x03\x80;\xAF\x01\x80:\0\x01\x80\x01\0\x03\x80\x0E\0\x02\x80\x02\0\x02\x80\x01\0\x0B\x80\x02\0\x1E\x9F\x01\x9E\x01\x88\x01\x80\x1A\0\x03\x80\x05\0\x03\x80\x01\0\x07\x80\x01\0\x0F\x80\x03\0\x01\x80\x01\0;\x80\x01\0\x7F\x7F\x05~\x02|\x01~\x01|\x02x\x01|\x01x\x03|\x01x\x04p\x03x\x01p\x02`\x01p\x01`\x03{\x01x\x01p\x03`\x03p\x01`\x04@\x03`\x03@\x08\0\x01@\x01\0\x03w\x01p\x01`\x04@\x02`\x01@\x04\0\x03@\x03\0\x0D@\x01\0\x1Fo\x01d\x01`\x01@\x02\0\x03@\x01\0w_\x01^\x01L\x01\0\xFD?\x02>\x01\0\x01\x1C\x01\0\xFB\x07\x01\0\xFF" | |
WaveformGenerator.wave8580_PS_ = unrle "\0\x7F\x03\x01\0?\x01\x01\0?\x0F\x01\0\x7F\x07\x01\0?\x03\x01\0\x1F\x01\x01\0\x1D\x07\x02\x1F\x01\0\x7F\x03\x01\0?\x03\x01\0\x1F\x01\x01\0\x1E\x01\x01\x0F\x01\0?\x01\x01\0?\x17\x01\0?;\x01\0\x1F=\x01\0\x0F>\x01\0\x07?\x01\0\x01\x0C\x01\x1C\x01?\x01\x1E\x01?\x03\0\x7F\x03\x01\0?\x01\x01\0?\x0F\x01\0?\x01\x01\0?\x07\x01\0?\x0B\x01\0\x1F\x0A\x01\0\x0F^\x01\0\x07_\x01\0\x03_\x01\x0C\x01_\x03\0?\x01\x01\0?G\x01\0?C\x01\0\x1Fe\x01\0\x0Fn\x01\0\x07o\x01\0\x01@\x02o\x01@\x01o\x03\0?c\x01\0\x1E@\x01a\x01\0\x07@\x01\0\x03@\x01\0\x01@\x02p\x01\0\x02@\x05p\x01@\x01`\x02w\x01`\x01w\x03\0\x0F@\x01\0\x06@\x01`\x01\0\x01@\x02`\x01@\x01`\x02y\x01\0\x01@\x06`\x01@\x03`\x04x\x01@\x01`\x06x\x01`\x01p\x02x\x01p\x01y\x01{\x02`\x07p\x01`\x03p\x01`\x01p\x02|\x01`\x01p\x06|\x01p\x01x\x02|\x01x\x01|\x02}\x01p\x01x\x06|\x01x\x01|\x02~\x01|\x01~\x03|\x03~\x02\x7F\x03~\x01\x7F\x06\xFF\x01\0\x7F\x03\x01\0?\x01\x01\0?\x8F\x01\0?\x01\x01\0?\x87\x01\0?\x83\x01\0\x1E\x80\x01\x8D\x01\0\x07\x80\x01\0\x03\x80\x01\0\x01\x80\x02\x8E\x01\0\x03\x80\x04\x8F\x01\x80\x03\x9F\x01\x80\x01\x9F\x03\0?\x01\x01\0\x2F\x80\x01\0\x07\x80\x01\0\x03\x80\x01\0\x01\x80\x02\x87\x01\0\x1F\x80\x01\0\x0F\x80\x01\0\x07\x80\x01\0\x03\x80\x04\x83\x01\0\x0F\x80\x01\0\x05\x80\x03\0\x01\x80\x06\x81\x01\x80\x0F\x84\x01\x80\x07\x87\x01\x80\x03\x87\x01\x80\x01\x8F\x01\xAF\x02\0\x0F\x80\x01\0\x07\x80\x01\0\x03\x80\x05\0\x03\x80\x01\0\x02\x80\x02\0\x01\x80\x16\x83\x01\x80\x1F\x81\x01\x80\x0F\xA0\x01\x80\x07\xA0\x01\x80\x03\xA0\x01\x80\x01\xA3\x01\xB7\x02\x80\x1F\xB1\x01\x80\x0F\xB0\x01\x80\x07\xB0\x01\x80\x01\xA0\x02\xB0\x01\xA0\x01\xB8\x01\xB9\x01\xBB\x01\x80\x07\xA0\x01\x80\x03\xA0\x01\x80\x01\xA0\x02\xB8\x01\x80\x01\xA0\x06\xB8\x01\xA0\x01\xB0\x02\xB8\x01\xB0\x01\xBC\x02\xBD\x01\xA0\x01\xB0\x04\xB8\x02\xBC\x01\xB0\x01\xB8\x02\xBC\x01\xB8\x01\xBC\x01\xBE\x02\xB8\x01\xBC\x02\xBE\x01\xBC\x01\xBE\x02\xBF\x01\xBE\x01\xBF\x07\0\x03\x80\x01\0\x03\x80\x01\0\x03\x80\x01\0\x03\x80\x01\0\x01\x80\x07\0\x01\x80\x26\x81\x01\x80?\xC7\x01\x80>\xC0\x01\xC3\x01\x80\x0F\xC0\x01\x80\x07\xC0\x01\x80\x03\xC0\x01\x80\x01\xC0\x02\xC1\x01\x80\x07\xC0\x01\x80\x03\xC0\x0C\xC7\x01\xC0\x03\xC7\x01\xC0\x01\xCF\x03\x80\x1F\xC0\x01\x80\x0F\xC0\x01\x80\x06\xC0\x02\x80\x01\xC0\x06\xC3\x01\x80\x07\xC0\x01\x80\x03\xC0\x01\x80\x01\xC0\x03\x80\x01\xC0\x0E\xC1\x01\xC0\x1D\xC1\x01\xC7\x01\xD7\x01\xC0\x2F\xD0\x01\xC0\x07\xD0\x01\xC0\x03\xD0\x01\xC0\x01\xD0\x01\xD8\x01\xDB\x01\xC0\x0F\xD8\x01\xC0\x07\xD8\x01\xC0\x03\xD8\x01\xD0\x01\xD8\x02\xDD\x01\xC0\x03\xD0\x01\xC0\x01\xD0\x02\xDC\x01\xD0\x01\xD8\x02\xDC\x01\xD8\x01\xDC\x02\xDE\x01\xD8\x01\xDC\x02\xDE\x01\xDC\x01\xDE\x02\xDF\x01\xDE\x01\xDF\x07\xC0?\xE3\x01\xC0\x17\xE0\x01\xC0\x03\xE0\x01\xC0\x01\xE0\x02\xE1\x01\xC0\x07\xE0\x01\xC0\x03\xE0\x05\xC0\x01\xE0\x0C\xE1\x01\xE3\x01\xE7\x01\xC0\x07\xE0\x01\xC0\x03\xE0\x01\xC0\x01\xE0\x03\xC0\x03\xE0\x01\xC0\x01\xE0\x2A\xEB\x01\xE0\x1B\xE8\x01\xE0\x01\xE8\x02\xED\x01\xE0\x07\xEC\x01\xE0\x03\xEC\x01\xE8\x01\xEC\x02\xEE\x01\xE8\x03\xEC\x02\xEE\x02\xEF\x01\xEC\x01\xEF\x07\xE0\x1F\xF0\x01\xE0\x07\xF0\x01\xE0\x03\xF0\x01\xE0\x01\xF0\x03\xE0\x03\xF0\x0C\xF3\x01\xE0\x03\xF0\x1C\xF5\x01\xF0\x0D\xF4\x02\xF6\x01\xF0\x03\xF4\x01\xF0\x01\xF4\x01\xF6\x01\xF7\x01\xF4\x01\xF6\x02\xF7\x05\xF0\x07\xF8\x01\xF0\x05\xF8\x03\xF0\x03\xF8\x01\xF0\x01\xF8\x0A\xF9\x01\xF8\x0F\xFA\x01\xF8\x07\xFB\x01\xF8\x01\xFA\x02\xFB\x05\xF8\x03\xFC\x01\xF8\x01\xFC\x12\xFD\x01\xFC\x03\xFD\x05\xFC\x02\xFE\x0E\xFF\x10" | |
WaveformGenerator.wave8580_PST = unrle "\0\xFF\0\xFF\0\xFF\0\xFF\0\x03\x1F\x01\0\xFF\0\xFF\0\xFF\0\xF1\x20\x01p\x01`\x01\x20\x01p\x05x\x03|\x02~\x02\x7F\x02\0\xFF\0\xFF\0\xFF\0\xFF\0\x01\x08\x01\x1E\x01?\x01\0\xFF\0\xF8\x80\x07\x8C\x01\x9F\x01\0>\x80\x02\0\x1E\x80\x02\0\x06\x80\x01\0\x03\x80\x16\0\x02\x80\x01\0\x02\x80\x04\0\x01\x80d\xC0\x11\xCF\x01\xC0o\xE0\x01\xC0\x04\xE0\x0B\xE3\x01\xE06\xF0\x24\xF8\x11\xFC\x0A\xFE\x04\xFF\x07" | |
-- * voice * | |
local Voice = {} | |
Voice.__index = Voice | |
function Voice:new() | |
local obj = setmetatable({ | |
control = 0, | |
wave = WaveformGenerator:new(), | |
envelope = EnvelopeGenerator:new() | |
}, self) | |
obj:set_chip_model(chip_model.MOS6581) | |
return obj | |
end | |
function Voice:set_chip_model(model) | |
self.wave:set_chip_model(model) | |
if model == chip_model.MOS6581 then | |
self.wave_zero = 0x380 | |
self.voice_DC = 0x7F800 | |
else | |
self.wave_zero = 0x800 | |
self.voice_DC = 0 | |
end | |
end | |
function Voice:set_sync_source(source) | |
self.wave:set_sync_source(source.wave) | |
end | |
function Voice:reset() | |
self.wave:reset() | |
self.envelope:reset() | |
end | |
function Voice:writeCONTROL_REG(control) | |
self.wave:writeCONTROL_REG(control) | |
self.envelope:writeCONTROL_REG(control) | |
self.control = control | |
end | |
function Voice:output() | |
return (self.wave:output() - self.wave_zero)*self.envelope.envelope_counter + self.voice_DC | |
end | |
-- * sid * | |
local SID = {} | |
SID.__index = SID | |
function SID:new() | |
local obj = setmetatable({ | |
voice = {[0] = Voice:new(), Voice:new(), Voice:new()}, | |
filter = Filter:new(), | |
extfilt = ExternalFilter:new(), | |
envtime = 0, | |
wavetime = 0, | |
filtertime = 0, | |
extfilttime = 0 | |
}, self) | |
obj.sample = 0 | |
obj.fir = 0 | |
obj.voice[0]:set_sync_source(obj.voice[2]) | |
obj.voice[1]:set_sync_source(obj.voice[0]) | |
obj.voice[2]:set_sync_source(obj.voice[1]) | |
obj:set_sampling_parameters(985248, sampling_method.SAMPLE_FAST, 48000) | |
obj.bus_value = 0 | |
obj.bus_value_ttl = 0 | |
obj.ext_in = 0 | |
return obj | |
end | |
function SID:set_chip_model(model) | |
for i = 0, 2 do | |
self.voice[i]:set_chip_model(model) | |
end | |
self.filter:set_chip_model(model) | |
self.extfilt:set_chip_model(model) | |
end | |
function SID:enable_filter(enable) | |
self.filter:enable_filter(enable) | |
end | |
function SID:enable_external_filter(enable) | |
self.extfilt:enable_filter(enable) | |
end | |
function SID:set_sampling_parameters(clock_freq, method, sample_freq, pass_freq, filter_scale) | |
pass_freq = pass_freq or -1 | |
filter_scale = filter_scale or 0.97 | |
if method == sampling_method.SAMPLE_RESAMPLE_INTERPOLATE or method == sampling_method.SAMPLE_RESAMPLE_FAST then | |
if SID.FIR_N*clock_freq/sample_freq >= SID.RINGSIZE then | |
return false | |
end | |
if pass_freq < 0 then | |
pass_freq = 20000 | |
if 2*pass_freq/sample_freq >= 0.9 then | |
pass_freq = 0.9*sample_freq/2 | |
end | |
elseif pass_freq > 0.9*sample_freq/2 then | |
return false | |
end | |
if filter_scale < 0.9 or filter_scale > 1.0 then | |
return false | |
end | |
end | |
self.clock_frequency = clock_freq | |
self.sampling = method | |
self.cycles_per_sample = floor(clock_freq/sample_freq*2^SID.FIXP_SHIFT + 0.5) | |
self.sample_offset = 0 | |
self.sample_prev = 0 | |
if method ~= sampling_method.SAMPLE_RESAMPLE_INTERPOLATE and method ~= sampling_method.SAMPLE_RESAMPLE_FAST then | |
self.sample = nil | |
self.fir = nil | |
return true | |
end | |
local A = -20*log(1/65536, 10) | |
local dw = (1 - 2*pass_freq/sample_freq)*pi | |
local wc = (2*pass_freq/sample_freq + 1)*pi/2 | |
local beta = 0.1102*(A - 8.7) | |
local I0beta = SID.I0(beta) | |
local N = floor((A - 7.95)/(2.285*dw) + 0.5) | |
N = N + band(N, 1) | |
local f_samples_per_cycle = sample_freq/clock_freq | |
local f_cycles_per_sample = clock_freq/sample_freq | |
self.fir_N = floor(N*f_cycles_per_sample) + 1 | |
self.fir_N = bor(self.fir_N, 1) | |
local res = method == sampling_method.SAMPLE_RESAMPLE_INTERPOLATE and SID.FIR_RES_INTERPOLATE or SID.FIR_RES_FAST | |
local n = ceil(log(res/f_cycles_per_sample, 2)) | |
self.fir_RES = 2^n | |
self.fir = {} | |
for i = 0, self.fir_RES-1 do | |
local fir_offset = i*self.fir_N + floor(self.fir_N / 2) | |
local j_offset = i/self.fir_RES | |
for j = -floor(self.fir_N/2), floor(self.fir_N/2) do | |
local jx = j - j_offset | |
local wt = wc*jx/f_cycles_per_sample | |
local temp = jx/(self.fir_N/2) | |
local Kaiser = abs(temp) <= 1 and SID.I0(beta*sqrt(1 - temp*temp))/I0beta or 0 | |
local sincwt = abs(wt) >= 1e-6 and sin(wt)/wt or 1 | |
local val = 2^SID.FIR_SHIFT*filter_scale*f_samples_per_cycle*wc/pi*sincwt*Kaiser | |
self.fir[fir_offset + j] = floor(val + 0.5) % 32768 -- band(val + 0.5, 0xffff) | |
end | |
end | |
if not self.sample then | |
self.sample = {} | |
end | |
for j = 0, SID.RINGSIZE*2-1 do | |
self.sample[j] = 0 | |
end | |
self.sample_index = 0 | |
return true | |
end | |
function SID:adjust_sampling_frequency(sample_freq) | |
self.cycles_per_sample = floor(self.clock_frequency/sample_freq*2^SID.FIXP_SHIFT + 0.5) | |
end | |
function SID:fc_default() | |
return self.filter:fc_default() | |
end | |
function SID:fc_plotter() | |
return self.filter:fc_plotter() | |
end | |
function SID:clock_0() | |
self.bus_value_ttl = self.bus_value_ttl - 1 | |
if self.bus_value_ttl <= 0 then | |
self.bus_value = 0 | |
self.bus_value_ttl = 0 | |
end | |
for i = 0, 2 do | |
self.voice[i].envelope:clock() | |
end | |
for i = 0, 2 do | |
self.voice[i].wave:clock() | |
end | |
for i = 0, 2 do | |
self.voice[i].wave:synchronize() | |
end | |
self.filter:clock(self.voice[0]:output(), self.voice[1]:output(), self.voice[2]:output(), self.ext_in) | |
self.extfilt:clock(self.filter:output()) | |
end | |
function SID:clock_1(delta_t) | |
if delta_t <= 0 then | |
return | |
end | |
self.bus_value_ttl = self.bus_value_ttl - 1 | |
if self.bus_value_ttl <= 0 then | |
self.bus_value = 0 | |
self.bus_value_ttl = 0 | |
end | |
--local start = os.epoch "nano" | |
for i = 0, 2 do | |
self.voice[i].envelope:clock(delta_t) | |
end | |
--self.envtime = self.envtime + (os.epoch "nano" - start) | |
--start = os.epoch "nano" | |
local delta_t_osc = delta_t | |
while delta_t_osc ~= 0 do | |
local delta_t_min = delta_t_osc | |
for i = 0, 2 do | |
local wave = self.voice[i].wave | |
if wave.sync_dest.sync and wave.freq ~= 0 then | |
local freq = wave.freq | |
local accumulator = wave.accumulator | |
local delta_accumulator = (accumulator >= 0x800000 and 0x1000000 or 0x800000) - accumulator | |
local delta_t_next = floor(delta_accumulator / freq) | |
if delta_accumulator % freq ~= 0 then | |
delta_t_next = delta_t_next + 1 | |
end | |
if delta_t_next < delta_t_min then | |
delta_t_min = delta_t_next | |
end | |
end | |
end | |
for i = 0, 2 do | |
self.voice[i].wave:clock(delta_t_min) | |
end | |
for i = 0, 2 do | |
self.voice[i].wave:synchronize() | |
end | |
delta_t_osc = delta_t_osc - delta_t_min | |
end | |
--self.wavetime = self.wavetime + (os.epoch "nano" - start) | |
--start = os.epoch "nano" | |
self.filter:clock(delta_t, self.voice[0]:output(), self.voice[1]:output(), self.voice[2]:output(), self.ext_in) | |
--self.filtertime = self.filtertime + (os.epoch "nano" - start) | |
--start = os.epoch "nano" | |
self.extfilt:clock(delta_t, self.filter:output()) | |
--self.extfilttime = self.extfilttime + (os.epoch "nano" - start) | |
end | |
function SID:clock_5(delta_t, buf, start, n, interleave) | |
interleave = interleave or 1 | |
if self.sampling == sampling_method.SAMPLE_INTERPOLATE then | |
return self:clock_interpolate(delta_t, buf, start, n, interleave) | |
elseif self.sampling == sampling_method.SAMPLE_RESAMPLE_INTERPOLATE then | |
return self:clock_resample_interpolate(delta_t, buf, start, n, interleave) | |
elseif self.sampling == sampling_method.SAMPLE_RESAMPLE_FAST then | |
return self:clock_resample_fast(delta_t, buf, start, n, interleave) | |
else | |
return self:clock_fast(delta_t, buf, start, n, interleave) | |
end | |
end | |
function SID:clock(a, b, c, d, e) | |
if b then return self:clock_5(a, b, c, d, e) | |
elseif a then return self:clock_1(a) | |
else return self:clock_0() end | |
end | |
function SID:reset() | |
for i = 0, 2 do | |
self.voice[i]:reset() | |
end | |
self.filter:reset() | |
self.extfilt:reset() | |
self.bus_value = 0 | |
self.bus_value_ttl = 0 | |
end | |
function SID:read(offset) | |
if offset == 0x19 or offset == 0x1a then return 0 | |
elseif offset == 0x1b then return self.voice[2].wave:readOSC() | |
elseif offset == 0x1c then return self.voice[2].envelope:readENV() | |
else return self.bus_value end | |
end | |
local SID_write_table = { | |
[0] = function(self, v) return self.voice[0].wave:writeFREQ_LO(v) end, | |
function(self, v) return self.voice[0].wave:writeFREQ_HI(v) end, | |
function(self, v) return self.voice[0].wave:writePW_LO(v) end, | |
function(self, v) return self.voice[0].wave:writePW_HI(v) end, | |
function(self, v) return self.voice[0]:writeCONTROL_REG(v) end, | |
function(self, v) return self.voice[0].envelope:writeATTACK_DECAY(v) end, | |
function(self, v) return self.voice[0].envelope:writeSUSTAIN_RELEASE(v) end, | |
function(self, v) return self.voice[1].wave:writeFREQ_LO(v) end, | |
function(self, v) return self.voice[1].wave:writeFREQ_HI(v) end, | |
function(self, v) return self.voice[1].wave:writePW_LO(v) end, | |
function(self, v) return self.voice[1].wave:writePW_HI(v) end, | |
function(self, v) return self.voice[1]:writeCONTROL_REG(v) end, | |
function(self, v) return self.voice[1].envelope:writeATTACK_DECAY(v) end, | |
function(self, v) return self.voice[1].envelope:writeSUSTAIN_RELEASE(v) end, | |
function(self, v) return self.voice[2].wave:writeFREQ_LO(v) end, | |
function(self, v) return self.voice[2].wave:writeFREQ_HI(v) end, | |
function(self, v) return self.voice[2].wave:writePW_LO(v) end, | |
function(self, v) return self.voice[2].wave:writePW_HI(v) end, | |
function(self, v) return self.voice[2]:writeCONTROL_REG(v) end, | |
function(self, v) return self.voice[2].envelope:writeATTACK_DECAY(v) end, | |
function(self, v) return self.voice[2].envelope:writeSUSTAIN_RELEASE(v) end, | |
function(self, v) return self.filter:writeFC_LO(v) end, | |
function(self, v) return self.filter:writeFC_HI(v) end, | |
function(self, v) return self.filter:writeRES_FILT(v) end, | |
function(self, v) return self.filter:writeMODE_VOL(v) end, | |
} | |
function SID:write(offset, value) | |
self.bus_value = value | |
self.bus_value_ttl = 0x2000 | |
local f = SID_write_table[offset] | |
if f then return f(self, value) end | |
end | |
function SID:read_state() | |
local state = SID.State:new() | |
local j = 0 | |
for i = 0, 2 do | |
local wave = self.voice[i].wave | |
local envelope = self.voice[i].envelope | |
state.sid_register[j + 0] = band(wave.freq, 0xff) | |
state.sid_register[j + 1] = rshift(wave.freq, 8) | |
state.sid_register[j + 2] = band(wave.pw, 0xff) | |
state.sid_register[j + 3] = rshift(wave.pw, 8) | |
state.sid_register[j + 4] = bor( | |
lshift(wave.waveform, 4), | |
wave.test and 0x08 or 0, | |
wave.ring_mod and 0x04 or 0, | |
wave.sync and 0x02 or 0, | |
envelope.gate and 0x01 or 0 | |
) | |
state.sid_register[j + 5] = bor(lshift(envelope.attack, 4), envelope.decay) | |
state.sid_register[j + 6] = bor(lshift(envelope.sustain, 4), envelope.release) | |
j = j + 7 | |
end | |
state.sid_register[j + 0] = band(self.filter.fc, 0x007) | |
state.sid_register[j + 1] = rshift(self.filter.fc, 3) | |
state.sid_register[j + 2] = bor(lshift(self.filter.res, 4), self.filter.filt) | |
state.sid_register[j + 3] = bor( | |
self.filter.voice3off and 0x80 or 0, | |
lshift(self.filter.hp_bp_lp, 4), | |
self.filter.vol | |
) | |
j = j + 4 | |
while j < 0x1d do | |
state.sid_register[j] = self:read(j) | |
j = j + 1 | |
end | |
while j < 0x20 do | |
state.sid_register[j] = 0 | |
j = j + 1 | |
end | |
state.bus_value = self.bus_value | |
state.bus_value_ttl = self.bus_value_ttl | |
for i = 0, 2 do | |
state.accumulator[i] = self.voice[i].wave.accumulator | |
state.shift_register[i] = self.voice[i].wave.shift_register | |
state.rate_counter[i] = self.voice[i].envelope.rate_counter | |
state.rate_counter_period[i] = self.voice[i].envelope.rate_period | |
state.exponential_counter[i] = self.voice[i].envelope.exponential_counter | |
state.exponential_counter_period[i] = self.voice[i].envelope.exponential_counter_period | |
state.envelope_counter[i] = self.voice[i].envelope.envelope_counter | |
state.envelope_state[i] = self.voice[i].envelope.state | |
state.hold_zero[i] = self.voice[i].envelope.hold_zero | |
end | |
return state | |
end | |
function SID:write_state(state) | |
for i = 0, 0x18 do | |
self:write(i, state.sid_register[i]) | |
end | |
self.bus_value = state.bus_value | |
self.bus_value_ttl = state.bus_value_ttl | |
for i = 0, 2 do | |
self.voice[i].wave.accumulator = state.accumulator[i] | |
self.voice[i].wave.shift_register = state.shift_register[i] | |
self.voice[i].envelope.rate_counter = state.rate_counter[i] | |
self.voice[i].envelope.rate_period = state.rate_counter_period[i] | |
self.voice[i].envelope.exponential_counter = state.exponential_counter[i] | |
self.voice[i].envelope.exponential_counter_period = state.exponential_counter_period[i] | |
self.voice[i].envelope.envelope_counter = state.envelope_counter[i] | |
self.voice[i].envelope.state = state.envelope_state[i] | |
self.voice[i].envelope.hold_zero = state.hold_zero[i] | |
end | |
end | |
function SID:input(sample) | |
self.ext_in = lshift(sample, 4)*3 | |
end | |
function SID:output(bits) | |
if not bits then return min(max(floor(self.extfilt:output()/11), -0x8000), 0x7fff) end | |
local range = 2^bits | |
local half = rshift(range, 1) | |
local sample = floor(self.extfilt:output()/floor(734220/range)) | |
if sample >= half then | |
return half - 1 | |
end | |
if sample < -half then | |
return -half | |
end | |
return sample | |
end | |
function SID.I0(x) | |
local I0e = 1e-6 | |
local sum, u, halfx, temp, n = 1, 1, x / 2, nil, 1 | |
repeat | |
temp = halfx/n | |
n = n + 1 | |
u = u * temp * temp | |
sum = sum + u | |
until u < I0e*sum | |
return sum | |
end | |
-- returns s, delta_t | |
function SID:clock_fast(delta_t, buf, start, n, interleave) | |
local s = 0 | |
while true do | |
local next_sample_offset = self.sample_offset + self.cycles_per_sample + 0x8000 -- 2^(SID.FIXP_SHIFT-1) | |
local delta_t_sample = rshift(next_sample_offset, SID.FIXP_SHIFT) | |
if delta_t_sample > delta_t then | |
break | |
end | |
if s >= n then | |
return s, delta_t | |
end | |
self:clock(delta_t_sample) | |
delta_t = delta_t - delta_t_sample | |
self.sample_offset = band(next_sample_offset, SID.FIXP_MASK) - 0x8000 --2^(SID.FIXP_SHIFT-1) | |
buf[start+s*interleave] = self:output() | |
s = s + 1 | |
end | |
self:clock(delta_t) | |
self.sample_offset = self.sample_offset - lshift(delta_t, SID.FIXP_SHIFT) | |
return s, 0 | |
end | |
function SID:clock_interpolate(delta_t, buf, start, n, interleave) | |
local s = 0 | |
while true do | |
local next_sample_offset = self.sample_offset + self.cycles_per_sample | |
local delta_t_sample = rshift(next_sample_offset, SID.FIXP_SHIFT) | |
if delta_t_sample > delta_t then | |
break | |
end | |
if s >= n then | |
return s, delta_t | |
end | |
for i = 1, delta_t_sample - 1 do | |
self:clock() | |
end | |
if delta_t_sample >= 0 then | |
self.sample_prev = self:output() | |
self:clock() | |
end | |
delta_t = delta_t - delta_t_sample | |
self.sample_offset = band(next_sample_offset, SID.FIXP_MASK) | |
local sample_now = self:output() | |
buf[start+s*interleave] = (self.sample_prev + rshift(self.sample_offset*(sample_now - self.sample_prev), SID.FIXP_SHIFT)) % 32768 | |
self.sample_prev = sample_now | |
end | |
for i = 1, delta_t - 1 do | |
self:clock() | |
end | |
if delta_t >= 0 then | |
self.sample_prev = self:output() | |
self:clock() | |
end | |
self.sample_offset = self.sample_offset - lshift(delta_t, SID.FIXP_SHIFT) | |
return s, 0 | |
end | |
function SID:clock_resample_interpolate(delta_t, buf, start, n, interleave) | |
error("Unimplemented") | |
end | |
function SID:clock_resample_fast(delta_t, buf, start, n, interleave) | |
error("Unimplemented") | |
end | |
SID.FIR_N = 125 | |
SID.FIR_RES_INTERPOLATE = 285 | |
SID.FIR_RES_FAST = 51473 | |
SID.FIR_SHIFT = 15 | |
SID.RINGSIZE = 16384 | |
SID.FIXP_SHIFT = 16 | |
SID.FIXP_MASK = 0xffff | |
SID.State = {} | |
SID.State.__index = SID.State | |
function SID.State:new() | |
local obj = setmetatable({ | |
sid_register = {}, | |
accumulator = {}, | |
shift_register = {}, | |
rate_counter = {}, | |
rate_counter_period = {}, | |
exponential_counter = {}, | |
exponential_counter_period = {}, | |
envelope_counter = {}, | |
envelope_state = {}, | |
hold_zero = {} | |
}, self) | |
for i = 0, 0x1f do | |
obj.sid_register[i] = 0 | |
end | |
obj.bus_value = 0 | |
obj.bus_value_ttl = 0 | |
for i = 0, 2 do | |
obj.accumulator[i] = 0 | |
obj.shift_register[i] = 0x7ffff8 | |
obj.rate_counter[i] = 0 | |
obj.rate_counter_period[i] = 9 | |
obj.exponential_counter[i] = 0 | |
obj.exponential_counter_period[i] = 1 | |
obj.envelope_counter[i] = 0 | |
obj.envelope_state[i] = EnvelopeGenerator.State.RELEASE | |
obj.hold_zero[i] = true | |
end | |
return obj | |
end | |
SID.chip_model = chip_model | |
SID.sampling_method = sampling_method | |
SID._VERSION = "5.0.0" | |
return SID |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment