Advertisement
Guest User

songplayer.lua

a guest
May 23rd, 2016
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.70 KB | None | 0 0
  1. local _conf = {
  2.     pal = true,
  3.     rate = 1,
  4. }
  5.  
  6. local args = {...}
  7. if #args ~= 1 then
  8.     print("Usage: songplayer.lua filename")
  9.     return
  10. end
  11.  
  12. local datfile, err = io.open(args[1],"rb")
  13. if not datfile then
  14.     print("Failed to open file: " .. err)
  15.     return
  16. end
  17.  
  18. local framems, freqdiv
  19. if _conf.pal then
  20.     framems = 1000/50
  21.     freqdiv = 17734475/(18*2^24)
  22. else
  23.     framems = 1000/60
  24.     freqdiv = 14318182/(14*2^24)
  25. end
  26.  
  27. local attackrates = {[0]=2,8,16,24,38,56,68,80,100,250,500,800,1000,3000,5000,8000}
  28. local decayrates = {[0]=6,24,48,72,114,168,204,240,300,750,1500,2400,3000,9000,15000,24000}
  29.  
  30. local bit = require("bit32")
  31. local component = require("component")
  32. local sound = component.sound
  33.  
  34. sound.clear()
  35. sound.setTotalVolume(1)
  36. for i = 1,8 do
  37.     sound.resetEnvelope(i)
  38.     sound.resetAM(i)
  39.     sound.resetFM(i)
  40.     sound.setVolume(i,1)
  41.     sound.close(i)
  42. end
  43. sound.process()
  44.  
  45. os.sleep(0.05)
  46.  
  47. local sid = {
  48.     c1 = {
  49.         freq=0,
  50.         waveform=0,
  51.         attack=0,
  52.         decay=0,
  53.         sustain=0,
  54.         release=0,
  55.         pulse=0,
  56.         stat = {
  57.             mode=0,
  58.             pos=0,
  59.         },
  60.     },
  61.     c2 = {
  62.         freq=0,
  63.         waveform=0,
  64.         attack=0,
  65.         decay=0,
  66.         sustain=0,
  67.         release=0,
  68.         pulse=0,
  69.         stat = {
  70.             mode=0,
  71.             pos=0,
  72.         },
  73.     },
  74.     c3 = {
  75.         freq=0,
  76.         waveform=0,
  77.         attack=0,
  78.         decay=0,
  79.         sustain=0,
  80.         release=0,
  81.         pulse=0,
  82.         stat = {
  83.             mode=0,
  84.             pos=0,
  85.         },
  86.     },
  87.     cutoff=0,
  88.     kind=0,
  89.     volume=0,
  90. }
  91.  
  92. local function getFreq(x)
  93.     return x*freqdiv
  94. end
  95.  
  96. local function moveTowards(cur,targ,amt)
  97.     if cur == targ then
  98.         return targ, true
  99.     elseif cur < targ then
  100.         cur = cur + amt
  101.         if cur >= targ then
  102.             return targ, true
  103.         end
  104.     elseif cur > targ then
  105.         cur = cur - amt
  106.         if cur <= targ then
  107.             return targ, true
  108.         end
  109.     end
  110.     return cur, false
  111. end
  112.  
  113. local lastchannel=0
  114. local chadata={}
  115. local function emulateADSR(chan)
  116.     local key = "c" .. chan
  117.  
  118.     local freq = getFreq(sid[key].freq)
  119.  
  120.     local mvol = (sid.volume/15)
  121.  
  122.     local tenab = math.floor(sid[key].waveform/2^0)%2 == 1
  123.     local senab = math.floor(sid[key].waveform/2^1)%2 == 1
  124.     local penab = math.floor(sid[key].waveform/2^2)%2 == 1
  125.     local nenab = math.floor(sid[key].waveform/2^3)%2 == 1
  126.  
  127.     local sus = sid[key].sustain/15
  128.  
  129.     for i = 1,framems/_conf.rate do
  130.         local tv,ep
  131.         if sid[key].stat.mode == 0 then
  132.             tv,ep = 1,attackrates[sid[key].attack]
  133.         elseif sid[key].stat.mode == 1 then
  134.             tv,ep = sus,decayrates[sid[key].decay]
  135.         elseif sid[key].stat.mode == 2 then
  136.             tv,ep = sus,math.huge
  137.         elseif sid[key].stat.mode == 3 then
  138.             tv,ep = 0,decayrates[sid[key].release]
  139.         else
  140.             tv,ep = 0,math.huge
  141.         end
  142.         local nextv
  143.         sid[key].stat.pos, nextv = moveTowards(sid[key].stat.pos, tv, 1/ep)
  144.         if nextv and sid[key].stat.mode < 2 then
  145.             sid[key].stat.mode = sid[key].stat.mode + 1
  146.         end
  147.     end
  148.  
  149.     local vol = sid[key].stat.pos*mvol
  150.  
  151.     if not (nenab and (tenab or senab or penab)) then
  152.         if tenab then
  153.             lastchannel = lastchannel + 1
  154.             sound.setWave(lastchannel,sound.modes.triangle,freq)
  155.             sound.setVolume(lastchannel,vol)
  156.             chadata[lastchannel] = true
  157.         end
  158.         if senab then
  159.             lastchannel = lastchannel + 1
  160.             sound.setWave(lastchannel,sound.modes.sawtooth,freq)
  161.             sound.setVolume(lastchannel,vol)
  162.             chadata[lastchannel] = true
  163.         end
  164.         if penab then
  165.             lastchannel = lastchannel + 1
  166.             sound.setWave(lastchannel,sound.modes.square,freq)
  167.             sound.setVolume(lastchannel,vol)
  168.             chadata[lastchannel] = true
  169.         end
  170.         if nenab then
  171.             lastchannel = lastchannel + 1
  172.             sound.setWave(lastchannel,sound.modes.noise,freq*8)
  173.             sound.setVolume(lastchannel,vol)
  174.             chadata[lastchannel] = true
  175.         end
  176.     end
  177. end
  178.  
  179. local stat = 0
  180. while true do
  181.     local line = datfile:read("*l")
  182.     if not line then
  183.         break
  184.     end
  185.     if #line ~= 47 then
  186.         _conf.rate = line/(_conf.pal and 50 or 60)
  187.         goto continue
  188.     end
  189.     local c = {{},{},{}}
  190.     c[1].freq = line:sub(1,4)
  191.     c[1].wf = line:sub(5,6)
  192.     c[1].adsr = line:sub(7,10)
  193.     c[1].pulse = line:sub(11,13)
  194.  
  195.     c[2].freq = line:sub(14,17)
  196.     c[2].wf = line:sub(18,19)
  197.     c[2].adsr = line:sub(20,23)
  198.     c[2].pulse = line:sub(24,26)
  199.  
  200.     c[3].freq = line:sub(27,30)
  201.     c[3].wf = line:sub(31,32)
  202.     c[3].adsr = line:sub(33,36)
  203.     c[3].pulse = line:sub(37,39)
  204.  
  205.     local cut = line:sub(40,43)
  206.     local ft = line:sub(44,46)
  207.     local volume = line:sub(47,47)
  208.  
  209.     for i = 1,3 do
  210.         local key = "c" .. i
  211.         if c[i].freq ~= "...." then sid[key].freq = tonumber(c[i].freq,16) end
  212.         if c[i].wf ~= ".." then
  213.             sid[key].waveform = math.floor(tonumber(c[i].wf,16)/16)
  214.             local gate = math.floor(tonumber(c[i].wf,16)/2^0)%2 == 1
  215.             sid[key].sync = math.floor(tonumber(c[i].wf,16)/2^1)%2 == 1
  216.             sid[key].ring = math.floor(tonumber(c[i].wf,16)/2^2)%2 == 1
  217.             sid[key].test = math.floor(tonumber(c[i].wf,16)/2^3)%2 == 1
  218.             if gate and sid[key].stat.mode >= 3 then
  219.                 sid[key].stat.mode = 0
  220.             elseif not gate and sid[key].stat.mode < 3 then
  221.                 sid[key].stat.mode = 3
  222.             end
  223.         end
  224.         if c[i].pulse ~= "..." then sid[key].pulse = tonumber(c[i].pulse,16) end
  225.         if c[i].adsr ~= "...." then
  226.             sid[key].attack  = math.floor(tonumber(c[i].adsr,16)/2^12)%16
  227.             sid[key].decay   = math.floor(tonumber(c[i].adsr,16)/2^8)%16
  228.             sid[key].sustain = math.floor(tonumber(c[i].adsr,16)/2^4)%16
  229.             sid[key].release = math.floor(tonumber(c[i].adsr,16)/2^0)%16
  230.         end
  231.     end
  232.  
  233.     if volume ~= "." then sid.volume = tonumber(volume,16) end
  234.  
  235.     lastchannel = 0
  236.     local lcs = #chadata
  237.     for i = 1,3 do
  238.         local key = "c" .. i
  239.         if not sid[key].test then
  240.             emulateADSR(i)
  241.         end
  242.     end
  243.  
  244.     if lcs < lastchannel then
  245.         for i = lcs + 1,lastchannel do
  246.             sound.open(i)
  247.         end
  248.     elseif lcs > lastchannel then
  249.         for i = lastchannel + 1,lcs do
  250.             sound.close(i)
  251.             chadata[i]=nil
  252.         end
  253.     end
  254.  
  255.     sound.delay(framems/_conf.rate)
  256.     stat = stat + 1
  257.     if stat >= 50/2*_conf.rate then
  258.         stat = 0
  259.         while not sound.process() do
  260.             os.sleep(0.05)
  261.         end
  262.         os.sleep(0.05)
  263.     end
  264.     ::continue::
  265. end
  266.  
  267. for i = 1,8 do
  268.     sound.resetEnvelope(i)
  269.     sound.resetAM(i)
  270.     sound.resetFM(i)
  271.     sound.setVolume(i, 1)
  272.     sound.close(i)
  273. end
  274.  
  275. sound.delay(1000)
  276.  
  277. while not sound.process() do
  278.     os.sleep(0.05)
  279. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement