Advertisement
Enn3DevPlayer

AUKit

Feb 19th, 2025 (edited)
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 77.31 KB | Source Code | 0 0
  1. --- AUKit: Audio decoding and processing framework for ComputerCraft
  2. --
  3. -- ORIGINAL HERE: https://gist.github.com/MCJack123/c8a4a3205881c9b870e93321bd905d09
  4. --
  5. -- AUKit is a framework designed to simplify the process of loading, modifying,
  6. -- and playing audio files in various formats. It includes support for loading
  7. -- audio from many sources, including PCM, DFPWM, and IMA ADPCM codecs, as well
  8. -- as WAV, AIFF, AU, and FLAC files. It can also generate audio on-the-fly as
  9. -- tones, noise, or silence.
  10. --
  11. -- AUKit uses a structure called Audio to store information about each audio
  12. -- chunk. An audio object holds the sample rate of the audio, as well as the
  13. -- data for each channel stored as floating-point numbers. Audio objects can
  14. -- hold any number of channels at any sample rate with any duration.
  15. --
  16. -- To obtain an audio object, you can use any of the main functions in the aukit
  17. -- module. These allow loading from various raw codecs or file formats, with
  18. -- data sources as strings, or tables if using a raw codec loader.
  19. --
  20. -- Once the audio is loaded, various basic operations are available. A subset of
  21. -- the string library is available to simplify operations on the audio, and a
  22. -- number of operators (+, *, .., #) are overridden as well. There's also built-
  23. -- in functions for resampling the audio, with nearest-neighbor, linear, and
  24. -- cubic interpolation available; as well as mixing channels (including down to
  25. -- mono) and combining/splitting channels. Finally, audio objects can be exported
  26. -- back to PCM, DFPWM, or WAV data, allowing changes to be easily stored on disk.
  27. -- The stream function also automatically chunks data for use with a speaker.
  28. -- All of these functions return a new audio object, leaving the original intact.
  29. --
  30. -- There are also a number of effects available for audio. These are contained
  31. -- in the aukit.effects table, and modify the audio passed to them (as well as
  32. -- returning the audio for streamlining). The effects are intended to speed up
  33. -- common operations on audio. More effects may be added in future versions.
  34. --
  35. -- Be aware that processing large amounts of audio (especially loading FLAC or
  36. -- resampling with higher quality) is *very* slow. It's recommended to use audio
  37. -- files with lower data size (8-bit mono PCM/WAV/AIFF is ideal), and potentially
  38. -- a lower sample rate, to reduce the load on the system - especially as all
  39. -- data gets converted to 8-bit DFPWM data on playback anyway. The code yields
  40. -- internally when things take a long time to avoid abort timeouts.
  41. --
  42. -- For an example of how to use AUKit, see the accompanying auplay.lua file.
  43. --
  44. -- @author JackMacWindows
  45. -- @license MIT
  46. --
  47. -- <style>#content {width: unset !important;}</style>
  48. --
  49. -- @module aukit
  50. -- @set project=AUKit
  51.  
  52. -- MIT License
  53. --
  54. -- Copyright (c) 2021-2022 JackMacWindows
  55. --
  56. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  57. -- of this software and associated documentation files (the "Software"), to deal
  58. -- in the Software without restriction, including without limitation the rights
  59. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  60. -- copies of the Software, and to permit persons to whom the Software is
  61. -- furnished to do so, subject to the following conditions:
  62. --
  63. -- The above copyright notice and this permission notice shall be included in all
  64. -- copies or substantial portions of the Software.
  65. --
  66. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  67. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  68. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  69. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  70. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  71. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  72. -- SOFTWARE.
  73.  
  74. local expect = require "cc.expect"
  75. local dfpwm = require "cc.audio.dfpwm"
  76.  
  77. local aukit = {}
  78. aukit.effects, aukit.stream = {}, {}
  79.  
  80. --- @tfield "none"|"linear"|"cubic" defaultInterpolation Default interpolation mode for @{Audio:resample} and other functions that need to resample.
  81. aukit.defaultInterpolation = "linear"
  82.  
  83. --- @type Audio
  84. local Audio = {}
  85. local Audio_mt
  86.  
  87. local ima_index_table = {
  88.     [0] = -1, -1, -1, -1, 2, 4, 6, 8,
  89.     -1, -1, -1, -1, 2, 4, 6, 8
  90. }
  91.  
  92. local ima_step_table = {
  93.     [0] = 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
  94.     19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
  95.     50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
  96.     130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
  97.     337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
  98.     876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
  99.     2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
  100.     5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
  101.     15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
  102. }
  103.  
  104. local function clamp(n, min, max) return math.max(math.min(n, max), min) end
  105.  
  106. local function expectAudio(n, var)
  107.     if type(var) == "table" and getmetatable(var) == Audio_mt then return var end
  108.     expect(n, var, "Audio") -- always fails
  109. end
  110.  
  111. local function intunpack(str, pos, sz, signed, be)
  112.     local n = 0
  113.     if be then for i = 0, sz - 1 do n = n * 256 + str:byte(pos+i) end
  114.     else for i = 0, sz - 1 do n = n + str:byte(pos+i) * 2^(8*i) end end
  115.     if signed and n >= 2^(sz*8-1) then n = n - 2^(sz*8) end
  116.     return n, pos + sz
  117. end
  118.  
  119. local interpolate = {
  120.     none = function(data, x)
  121.         return data[math.floor(x)]
  122.     end,
  123.     linear = function(data, x)
  124.         return data[math.floor(x)] + ((data[math.ceil(x)] or data[math.floor(x)]) - data[math.floor(x)]) * (x - math.floor(x))
  125.     end,
  126.     cubic = function(data, x)
  127.         local p0, p1, p2, p3, fx = data[math.floor(x)-1], data[math.floor(x)], data[math.ceil(x)], data[math.ceil(x)+1], x - math.floor(x)
  128.         p0, p2, p3 = p0 or p1, p2 or p1, p3 or p2 or p1
  129.         return (-0.5*p0 + 1.5*p1 - 1.5*p2 + 0.5*p3)*fx^3 + (p0 - 2.5*p1 + 2*p2 - 0.5*p3)*fx^2 + (-0.5*p0 + 0.5*p2)*fx + p1
  130.     end
  131. }
  132. local interpolation_start = {none = 1, linear = 1, cubic = 0}
  133. local interpolation_end = {none = 1, linear = 2, cubic = 3}
  134.  
  135. local wavegen = {
  136.     sine = function(x, freq, amplitude)
  137.         return math.sin(2 * x * math.pi * freq) * amplitude
  138.     end,
  139.     triangle = function(x, freq, amplitude)
  140.         return 2.0 * math.abs(amplitude * math.fmod(2.0 * x * freq + 1.5, 2.0) - amplitude) - amplitude
  141.     end,
  142.     square = function(x, freq, amplitude, duty)
  143.         if (x * freq) % 1 >= duty then return -amplitude else return amplitude end
  144.     end,
  145.     sawtooth = function(x, freq, amplitude)
  146.         return amplitude * math.fmod(2.0 * x * freq + 1.0, 2.0) - amplitude
  147.     end
  148. }
  149.  
  150. local decodeFLAC do
  151.  
  152.     -- Simple FLAC decoder (Java)
  153.     --
  154.     -- Copyright (c) 2017 Project Nayuki. (MIT License)
  155.     -- https://www.nayuki.io/page/simple-flac-implementation
  156.     --
  157.     -- Permission is hereby granted, free of charge, to any person obtaining a copy of
  158.     -- this software and associated documentation files (the "Software"), to deal in
  159.     -- the Software without restriction, including without limitation the rights to
  160.     -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  161.     -- the Software, and to permit persons to whom the Software is furnished to do so,
  162.     -- subject to the following conditions:
  163.     -- - The above copyright notice and this permission notice shall be included in
  164.     --   all copies or substantial portions of the Software.
  165.     -- - The Software is provided "as is", without warranty of any kind, express or
  166.     --   implied, including but not limited to the warranties of merchantability,
  167.     --   fitness for a particular purpose and noninfringement. In no event shall the
  168.     --   authors or copyright holders be liable for any claim, damages or other
  169.     --   liability, whether in an action of contract, tort or otherwise, arising from,
  170.     --   out of or in connection with the Software or the use or other dealings in the
  171.     --   Software.
  172.  
  173.     local FIXED_PREDICTION_COEFFICIENTS = {
  174.         {},
  175.         {1},
  176.         {2, -1},
  177.         {3, -3, 1},
  178.         {4, -6, 4, -1},
  179.     };
  180.  
  181.     local function BitInputStream(data, pos)
  182.         local obj = {}
  183.         local bitBuffer, bitBufferLen = 0, 0
  184.         function obj.alignToByte()
  185.             bitBufferLen = bitBufferLen - bitBufferLen % 8
  186.         end
  187.         function obj.readByte()
  188.             return obj.readUint(8)
  189.         end
  190.         function obj.readUint(n)
  191.             if n == 0 then return 0 end
  192.             while bitBufferLen < n do
  193.                 local temp = data:byte(pos)
  194.                 pos = pos + 1
  195.                 if temp == nil then return nil end
  196.                 bitBuffer = (bitBuffer * 256 + temp) % 0x100000000000
  197.                 bitBufferLen = bitBufferLen + 8
  198.             end
  199.             bitBufferLen = bitBufferLen - n
  200.             local result = math.floor(bitBuffer / 2^bitBufferLen)
  201.             if n < 32 then result = result % 2^n end
  202.             return result
  203.         end
  204.         function obj.readSignedInt(n)
  205.             local v = obj.readUint(n)
  206.             if v >= 2^(n-1) then v = v - 2^n end
  207.             return v
  208.         end
  209.         function obj.readRiceSignedInt(param)
  210.             local val = 0
  211.             while (obj.readUint(1) == 0) do val = val + 1 end
  212.             val = val * 2^param + obj.readUint(param)
  213.             if bit32.btest(val, 1) then return -math.floor(val / 2) - 1
  214.             else return math.floor(val / 2) end
  215.         end
  216.         return obj
  217.     end
  218.  
  219.     local function decodeResiduals(inp, warmup, blockSize, result)
  220.         local method = inp.readUint(2);
  221.         if (method >= 2) then error("Reserved residual coding method " .. method) end
  222.         local paramBits = method == 0 and 4 or 5;
  223.         local escapeParam = method == 0 and 0xF or 0x1F;
  224.  
  225.         local partitionOrder = inp.readUint(4);
  226.         local numPartitions = 2^partitionOrder;
  227.         if (blockSize % numPartitions ~= 0) then
  228.             error("Block size not divisible by number of Rice partitions")
  229.         end
  230.         local partitionSize = math.floor(blockSize / numPartitions);
  231.  
  232.         for i = 0, numPartitions-1 do
  233.             local start = i * partitionSize + (i == 0 and warmup or 0);
  234.             local endd = (i + 1) * partitionSize;
  235.  
  236.             local param = inp.readUint(paramBits);
  237.             if (param < escapeParam) then
  238.                 for j = start, endd - 1 do
  239.                     result[j+1] = inp.readRiceSignedInt(param)
  240.                 end
  241.             else
  242.                 local numBits = inp.readUint(5);
  243.                 for j = start, endd - 1 do
  244.                     result[j+1] = inp.readSignedInt(numBits)
  245.                 end
  246.             end
  247.         end
  248.     end
  249.  
  250.     local function restoreLinearPrediction(result, coefs, shift, blockSize)
  251.         for i = #coefs, blockSize - 1 do
  252.             local sum = 0
  253.             for j = 0, #coefs - 1 do
  254.                 sum = sum + result[i - j] * coefs[j + 1]
  255.             end
  256.             result[i + 1] = result[i + 1] + math.floor(sum / 2^shift)
  257.         end
  258.     end
  259.  
  260.     local function decodeFixedPredictionSubframe(inp, predOrder, sampleDepth, blockSize, result)
  261.         for i = 1, predOrder do
  262.             result[i] = inp.readSignedInt(sampleDepth);
  263.         end
  264.         decodeResiduals(inp, predOrder, blockSize, result);
  265.         restoreLinearPrediction(result, FIXED_PREDICTION_COEFFICIENTS[predOrder+1], 0, blockSize);
  266.     end
  267.  
  268.     local function decodeLinearPredictiveCodingSubframe(inp, lpcOrder, sampleDepth, blockSize, result)
  269.         for i = 1, lpcOrder do
  270.             result[i] = inp.readSignedInt(sampleDepth);
  271.         end
  272.         local precision = inp.readUint(4) + 1;
  273.         local shift = inp.readSignedInt(5);
  274.         local coefs = {};
  275.         for i = 1, lpcOrder do
  276.             coefs[i] = inp.readSignedInt(precision);
  277.         end
  278.         decodeResiduals(inp, lpcOrder, blockSize, result);
  279.         restoreLinearPrediction(result, coefs, shift, blockSize);
  280.     end
  281.  
  282.     local function decodeSubframe(inp, sampleDepth, blockSize, result)
  283.         inp.readUint(1);
  284.         local type = inp.readUint(6);
  285.         local shift = inp.readUint(1);
  286.         if (shift == 1) then
  287.             while (inp.readUint(1) == 0) do shift = shift + 1 end
  288.         end
  289.         sampleDepth = sampleDepth - shift
  290.  
  291.         if (type == 0) then  -- Constant coding
  292.             local c = inp.readSignedInt(sampleDepth)
  293.             for i = 1, blockSize do result[i] = c end
  294.         elseif (type == 1) then  -- Verbatim coding
  295.             for i = 1, blockSize do
  296.                 result[i] = inp.readSignedInt(sampleDepth);
  297.             end
  298.         elseif (8 <= type and type <= 12) then
  299.             decodeFixedPredictionSubframe(inp, type - 8, sampleDepth, blockSize, result)
  300.         elseif (32 <= type and type <= 63) then
  301.             decodeLinearPredictiveCodingSubframe(inp, type - 31, sampleDepth, blockSize, result)
  302.         else
  303.             error("Reserved subframe type")
  304.         end
  305.  
  306.         for i = 1, blockSize do
  307.             result[i] = result[i] * 2^shift
  308.         end
  309.     end
  310.  
  311.     local function decodeSubframes(inp, sampleDepth, chanAsgn, blockSize, result)
  312.         local subframes = {}
  313.         for i = 1, #result do subframes[i] = {} end
  314.         if (0 <= chanAsgn and chanAsgn <= 7) then
  315.             for ch = 1, #result do
  316.                 decodeSubframe(inp, sampleDepth, blockSize, subframes[ch])
  317.             end
  318.         elseif (8 <= chanAsgn and chanAsgn <= 10) then
  319.             decodeSubframe(inp, sampleDepth + (chanAsgn == 9 and 1 or 0), blockSize, subframes[1])
  320.             decodeSubframe(inp, sampleDepth + (chanAsgn == 9 and 0 or 1), blockSize, subframes[2])
  321.             if (chanAsgn == 8) then
  322.                 for i = 1, blockSize do
  323.                     subframes[2][i] = subframes[1][i] - subframes[2][i]
  324.                 end
  325.             elseif (chanAsgn == 9) then
  326.                 for i = 1, blockSize do
  327.                     subframes[1][i] = subframes[1][i] + subframes[2][i]
  328.                 end
  329.             elseif (chanAsgn == 10) then
  330.                 for i = 1, blockSize do
  331.                     local side = subframes[2][i]
  332.                     local right = subframes[1][i] - math.floor(side / 2)
  333.                     subframes[2][i] = right
  334.                     subframes[1][i] = right + side
  335.                 end
  336.             end
  337.         else
  338.             error("Reserved channel assignment");
  339.         end
  340.         for ch = 1, #result do
  341.             for i = 1, blockSize do
  342.                 local s = subframes[ch][i]
  343.                 if s >= 2^(sampleDepth-1) then s = s - 2^sampleDepth end
  344.                 result[ch][i] = s / 2^sampleDepth
  345.             end
  346.         end
  347.     end
  348.  
  349.     local function decodeFrame(inp, numChannels, sampleDepth, out2, callback)
  350.         local out = {}
  351.         for i = 1, numChannels do out[i] = {} end
  352.         -- Read a ton of header fields, and ignore most of them
  353.         local temp = inp.readByte()
  354.         if temp == nil then
  355.             return false
  356.         end
  357.         local sync = temp * 64 + inp.readUint(6);
  358.         if sync ~= 0x3FFE then error("Sync code expected") end
  359.  
  360.         inp.readUint(1);
  361.         inp.readUint(1);
  362.         local blockSizeCode = inp.readUint(4);
  363.         local sampleRateCode = inp.readUint(4);
  364.         local chanAsgn = inp.readUint(4);
  365.         inp.readUint(3);
  366.         inp.readUint(1);
  367.  
  368.         temp = inp.readUint(8);
  369.         local t2 = -1
  370.         for i = 7, 0, -1 do if not bit32.btest(temp, 2^i) then break end t2 = t2 + 1 end
  371.         for i = 1, t2 do inp.readUint(8) end
  372.  
  373.         local blockSize
  374.         if (blockSizeCode == 1) then
  375.             blockSize = 192
  376.         elseif (2 <= blockSizeCode and blockSizeCode <= 5) then
  377.             blockSize = 576 * 2^(blockSizeCode - 2)
  378.         elseif (blockSizeCode == 6) then
  379.             blockSize = inp.readUint(8) + 1
  380.         elseif (blockSizeCode == 7) then
  381.             blockSize = inp.readUint(16) + 1
  382.         elseif (8 <= blockSizeCode and blockSizeCode <= 15) then
  383.             blockSize = 256 * 2^(blockSizeCode - 8)
  384.         else
  385.             error("Reserved block size")
  386.         end
  387.  
  388.         if (sampleRateCode == 12) then
  389.             inp.readUint(8)
  390.         elseif (sampleRateCode == 13 or sampleRateCode == 14) then
  391.             inp.readUint(16)
  392.         end
  393.  
  394.         inp.readUint(8)
  395.  
  396.         decodeSubframes(inp, sampleDepth, chanAsgn, blockSize, out)
  397.         inp.alignToByte()
  398.         inp.readUint(16)
  399.  
  400.         if callback then callback(out) else
  401.             for c = 1, numChannels do
  402.                 local n = #out2[c]
  403.                 for i = 1, blockSize do out2[c][n+i] = out[c][i] end
  404.             end
  405.         end
  406.  
  407.         return true
  408.     end
  409.  
  410.     function decodeFLAC(inp, callback)
  411.         local out = {}
  412.         local pos = 1
  413.         -- Handle FLAC header and metadata blocks
  414.         local temp temp, pos = intunpack(inp, pos, 4, false, true)
  415.         if temp ~= 0x664C6143 then error("Invalid magic string") end
  416.         local sampleRate, numChannels, sampleDepth, numSamples
  417.         local last = false
  418.         while not last do
  419.             temp, pos = string.byte(inp, pos), pos + 1
  420.             last = bit32.btest(temp, 0x80)
  421.             local type = bit32.band(temp, 0x7F);
  422.             local length length, pos = intunpack(inp, pos, 3, false, true)
  423.             if type == 0 then  -- Stream info block
  424.                 pos = pos + 10
  425.                 sampleRate, pos = intunpack(inp, pos, 2, false, true)
  426.                 sampleRate = sampleRate * 16 + bit32.rshift(inp:byte(pos), 4)
  427.                 numChannels = bit32.band(bit32.rshift(inp:byte(pos), 1), 7) + 1;
  428.                 sampleDepth = bit32.band(inp:byte(pos), 1) * 16 + bit32.rshift(inp:byte(pos+1), 4) + 1;
  429.                 numSamples, pos = intunpack(inp, pos + 2, 4, false, true)
  430.                 numSamples = numSamples + bit32.band(inp:byte(pos-5), 15) * 2^32
  431.                 pos = pos + 16
  432.             else
  433.                 pos = pos + length
  434.             end
  435.         end
  436.         if not sampleRate then error("Stream info metadata block absent") end
  437.         if sampleDepth % 8 ~= 0 then error("Sample depth not supported") end
  438.  
  439.         for i = 1, numChannels do out[i] = {} end
  440.  
  441.         if callback then callback(sampleRate, numSamples) end
  442.  
  443.         -- Decode FLAC audio frames and write raw samples
  444.         inp = BitInputStream(inp, pos)
  445.         repeat until not decodeFrame(inp, numChannels, sampleDepth, out, callback)
  446.         if not callback then return {sampleRate = sampleRate, data = out} end
  447.     end
  448.  
  449. end
  450.  
  451. --- Returns the length of the audio object in seconds.
  452. -- @treturn number The audio length
  453. function Audio:len()
  454.     return #self.data[1] / self.sampleRate
  455. end
  456.  
  457. --- Creates a new audio object with the data resampled to a different sample rate.
  458. -- If the target rate is the same, the object is copied without modification.
  459. -- @tparam number sampleRate The new sample rate in Hertz
  460. -- @tparam[opt=aukit.defaultInterpolation] "none"|"linear"|"cubic" interpolation The interpolation mode to use
  461. -- @treturn Audio A new audio object with the resampled data
  462. function Audio:resample(sampleRate, interpolation)
  463.     expect(1, sampleRate, "number")
  464.     interpolation = expect(2, interpolation, "string", "nil") or aukit.defaultInterpolation
  465.     if interpolation ~= "none" and interpolation ~= "linear" and interpolation ~= "cubic" then error("bad argument #2 (invalid interpolation type)", 2) end
  466.     local new = setmetatable({sampleRate = sampleRate, data = {}}, Audio_mt)
  467.     local ratio = sampleRate / self.sampleRate
  468.     local newlen = #self.data[1] * ratio
  469.     local interp = interpolate[interpolation]
  470.     local start = os.epoch "utc"
  471.     for y, c in ipairs(self.data) do
  472.         local line = {}
  473.         for i = 1, newlen do
  474.             if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  475.             local x = (i - 1) / ratio + 1
  476.             if x % 1 == 0 then line[i] = c[x]
  477.             else line[i] = clamp(interp(c, x), -1, 1) end
  478.         end
  479.         new.data[y] = line
  480.     end
  481.     return new
  482. end
  483.  
  484. --- Mixes down all channels to a new mono-channel audio object.
  485. -- @treturn Audio A new audio object with the audio mixed to mono
  486. function Audio:mono()
  487.     local new = setmetatable({sampleRate = self.sampleRate, data = {{}}}, Audio_mt)
  488.     local cn = #self.data
  489.     local start = os.epoch "utc"
  490.     for i = 1, #self.data[1] do
  491.         if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  492.         local s = 0
  493.         for c = 1, cn do s = s + self.data[c][i] end
  494.         new.data[1][i] = s / cn
  495.     end
  496.     return new
  497. end
  498.  
  499. --- Concatenates this audio object with another, adding the contents of each
  500. -- new channel to the end of each old channel, resampling the new channels to match
  501. -- this one (if necessary), and inserting silence in any missing channels.
  502. -- @tparam Audio ... The audio objects to concatenate
  503. -- @treturn Audio The new concatenated audio object
  504. function Audio:concat(...)
  505.     local audios = {self, ...}
  506.     local l = {#self.data[1]}
  507.     local cn = #self.data
  508.     for i = 2, #audios do
  509.         expectAudio(i-1, audios[i])
  510.         if audios[i].sampleRate ~= self.sampleRate then audios[i] = audios[i]:resample(self.sampleRate) end
  511.         l[i] = #audios[i].data[1]
  512.         cn = math.max(cn, #audios[i].data)
  513.     end
  514.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}}, Audio_mt)
  515.     for c = 1, cn do
  516.         local ch = {}
  517.         local pos = 0
  518.         for a = 1, #audios do
  519.             local sch = audios[a].data[c]
  520.             if sch then for i = 1, l[a] do ch[pos+i] = sch[i] end
  521.             else for i = 1, l[a] do ch[pos+i] = 0 end end
  522.             pos = pos + l[a]
  523.         end
  524.         obj.data[c] = ch
  525.     end
  526.     return obj
  527. end
  528.  
  529. --- Takes a subregion of the audio and returns a new audio object with its contents.
  530. -- This takes the same arguments as @{string.sub}, but positions start at 0.
  531. -- @tparam[opt=1] number start The start position of the audio in seconds
  532. -- @tparam[opt=-1] number last The end position of the audio in seconds
  533. -- @treturn Audio The new split audio object
  534. function Audio:sub(start, last)
  535.     start = math.floor(expect(1, start, "number", "nil") or 1)
  536.     last = math.floor(expect(2, last, "number", "nil") or -1)
  537.     local len = #self.data[1] / self.sampleRate
  538.     if start < 0 then start = len + start end
  539.     if last < 0 then last = len + last end
  540.     expect.range(start, 1, len)
  541.     expect.range(last, 1, len)
  542.     start, last = start * self.sampleRate + 1, last * self.sampleRate + 1
  543.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}}, Audio_mt)
  544.     for c = 1, #self.data do
  545.         local ch = {}
  546.         local sch = self.data[c]
  547.         for i = start, last do ch[i-start+1] = sch[i] end
  548.         obj.data[c] = ch
  549.     end
  550.     return obj
  551. end
  552.  
  553. --- Combines the channels of this audio object with another, adding the new
  554. -- channels on the end of the new object, resampling the new channels to match
  555. -- this one (if necessary), and extending any channels that are shorter than the
  556. -- longest channel with zeroes.
  557. -- @tparam Audio ... The audio objects to combine with
  558. -- @treturn Audio The new combined audio object
  559. function Audio:combine(...)
  560.     local audios = {self, ...}
  561.     local len = #self.data[1]
  562.     for i = 2, #audios do
  563.         expectAudio(i-1, audios[i])
  564.         if audios[i].sampleRate ~= self.sampleRate then audios[i] = audios[i]:resample(self.sampleRate) end
  565.         len = math.max(len, #audios[i].data[1])
  566.     end
  567.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}}, Audio_mt)
  568.     local pos = 0
  569.     for a = 1, #audios do
  570.         for c = 1, #audios[a].data do
  571.             local sch, ch = audios[a].data[c], {}
  572.             for i = 1, len do ch[i] = sch[i] or 0 end
  573.             obj.data[pos+c] = ch
  574.         end
  575.         pos = pos + #audios[a].data
  576.     end
  577.     return obj
  578. end
  579.  
  580. --- Splits this audio object into one or more objects with the specified channels.
  581. -- Passing a channel that doesn't exist will throw and error.
  582. -- @tparam {[number]...} ... The lists of channels in each new object
  583. -- @treturn Audio... The new audio objects created from the channels in each list
  584. -- @usage Split a stereo track into independent mono objects
  585. --
  586. --     local left, right = stereo:split({1}, {2})
  587. function Audio:split(...)
  588.     local retval = {}
  589.     for n, cl in ipairs{...} do
  590.         expect(n, cl, "table")
  591.         local obj = setmetatable({sampleRate = self.sampleRate, data = {}}, Audio_mt)
  592.         for cd, cs in ipairs(cl) do
  593.             local sch, ch = self.data[expect(cd, cs, "number")], {}
  594.             if not sch then error("channel " .. cs .. " (in argument " .. n .. ") out of range", 2) end
  595.             for i = 1, #sch do ch[i] = sch[i] end
  596.             obj[cd] = ch
  597.         end
  598.         retval[#retval+1] = obj
  599.     end
  600.     return table.unpack(retval)
  601. end
  602.  
  603. --- Mixes two or more audio objects into a single object, amplifying each sample
  604. -- with a multiplier (before clipping) if desired, and clipping any values
  605. -- outside the audio range ([-1, 1]). Channels that are shorter are padded with
  606. -- zeroes at the end, and non-existent channels are replaced with all zeroes.
  607. -- Any audio objects with a different sample rate are resampled to match this one.
  608. -- @tparam number|Audio amplifier The multiplier to apply, or the first audio object
  609. -- @tparam[opt] Audio ... The objects to mix with this one
  610. -- @treturn Audio The new mixed audio object
  611. function Audio:mix(amplifier, ...)
  612.     local audios = {self, ...}
  613.     local len = #self.data[1]
  614.     local cn = #self.data
  615.     for i = 2, #audios do
  616.         expectAudio(i, audios[i])
  617.         if audios[i].sampleRate ~= self.sampleRate then audios[i] = audios[i]:resample(self.sampleRate) end
  618.         len = math.max(len, #audios[i].data[1])
  619.         cn = math.max(cn, #audios[i].data)
  620.     end
  621.     if type(amplifier) ~= "number" then
  622.         expectAudio(1, amplifier)
  623.         if amplifier.sampleRate ~= self.sampleRate then amplifier = amplifier:resample(self.sampleRate) end
  624.         len = math.max(len, #amplifier.data[1])
  625.         cn = math.max(cn, #amplifier.data)
  626.         table.insert(audios, 2, amplifier)
  627.         amplifier = 1
  628.     end
  629.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}}, Audio_mt)
  630.     for c = 1, cn do
  631.         local ch = {}
  632.         local sch = {}
  633.         for a = 1, #audios do sch[a] = audios[a].data[c] end
  634.         for i = 1, len do
  635.             local s = 0
  636.             for a = 1, #audios do if sch[a] then s = s + (sch[a][i] or 0) end end
  637.             ch[i] = clamp(s * amplifier, -1, 1)
  638.         end
  639.         obj[c] = ch
  640.     end
  641.     return obj
  642. end
  643.  
  644. --- Returns a new audio object that repeats this audio a number of times.
  645. -- @tparam number count The number of times to play the audio
  646. -- @treturn Audio The repeated audio
  647. function Audio:rep(count)
  648.     if type(self) ~= "table" and type(count) == "table" then self, count = count, self end
  649.     expect(1, count, "number")
  650.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}}, Audio_mt)
  651.     for c = 1, #self.data do
  652.         local sch, ch = self.data[c], {}
  653.         for n = 0, count - 1 do
  654.             local pos = n * #sch
  655.             for i = 1, #sch do ch[pos+i] = sch[i] end
  656.         end
  657.         obj.data[c] = ch
  658.     end
  659.     return obj
  660. end
  661.  
  662. --- Returns a reversed version of this audio.
  663. -- @treturn Audio The reversed audio
  664. function Audio:reverse()
  665.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}}, Audio_mt)
  666.     for c = 1, #self.data do
  667.         local sch, ch = self.data[c], {}
  668.         local len = #sch
  669.         for i = 1, len do ch[len-i+1] = sch[i] end
  670.         obj.data[c] = ch
  671.     end
  672.     return obj
  673. end
  674.  
  675. local function encodePCM(info, pos)
  676.     local maxValue = 2^(info.bitDepth-1)
  677.     local add = info.dataType == "unsigned" and maxValue or 0
  678.     local source = info.audio.data
  679.     local function encode(d)
  680.         if info.dataType == "float" then return d
  681.         else return d * (d < 0 and maxValue or maxValue-1) + add end
  682.     end
  683.     local data = {}
  684.     local nc = #source
  685.     local len = #source[1]
  686.     if pos > len then return nil end
  687.     if info.interleaved then for n = pos, pos + info.len - 1 do for c = 1, nc do data[(n-1)*nc+c] = encode(source[c][n]) end end
  688.     elseif info.multiple then
  689.         for c = 1, nc do
  690.             data[c] = {}
  691.             for n = pos, pos + info.len - 1 do
  692.                 local s = source[c][n]
  693.                 if not s then break end
  694.                 data[c][n-pos+1] = encode(s)
  695.             end
  696.         end
  697.         return pos + info.len, table.unpack(data)
  698.     else for c = 1, nc do for n = pos, pos + info.len - 1 do data[(c-1)*len+n] = encode(source[c][n]) end end end
  699.     return data
  700. end
  701.  
  702. --- Converts the audio data to raw PCM samples.
  703. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32)
  704. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  705. -- @tparam[opt=true] boolean interleaved Whether to interleave each channel
  706. -- @treturn {[number]...} The resulting audio data
  707. function Audio:pcm(bitDepth, dataType, interleaved)
  708.     bitDepth = expect(1, bitDepth, "number", "nil") or 8
  709.     dataType = expect(2, dataType, "string", "nil") or "signed"
  710.     expect(3, interleaved, "boolean", "nil")
  711.     if interleaved == nil then interleaved = true end
  712.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  713.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  714.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  715.     return encodePCM({audio = self, bitDepth = bitDepth, dataType = dataType, interleaved = interleaved, len = #self.data[1]}, 1)
  716. end
  717.  
  718. --- Returns a function that can be called to encode PCM samples in chunks.
  719. -- This is useful as a for iterator, and can be used with @{aukit.play}.
  720. -- @tparam[opt=131072] number chunkSize The size of each chunk
  721. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32)
  722. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  723. -- @treturn function():{{[number]...}...},number An iterator function that returns
  724. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  725. -- the current position of the audio in seconds
  726. -- @treturn number The total length of the audio in seconds
  727. function Audio:stream(chunkSize, bitDepth, dataType)
  728.     chunkSize = expect(1, chunkSize, "number", "nil") or 131072
  729.     bitDepth = expect(2, bitDepth, "number", "nil") or 8
  730.     dataType = expect(3, dataType, "string", "nil") or "signed"
  731.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  732.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  733.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  734.     local info, pos = {audio = self, bitDepth = bitDepth, dataType = dataType, interleaved = false, multiple = true, len = chunkSize}, 1
  735.     return function()
  736.         if info == nil then return nil end
  737.         local p = pos / self.sampleRate
  738.         local v = {encodePCM(info, pos)}
  739.         if v[1] == nil then info = nil return nil end
  740.         pos = table.remove(v, 1)
  741.         return v, p
  742.     end, #self.data[1] / self.sampleRate
  743. end
  744.  
  745. --- Coverts the audio data to a WAV file.
  746. -- @tparam[opt=16] number bitDepth The bit depth of the audio (8, 16, 24, 32)
  747. -- @treturn string The resulting WAV file data
  748. function Audio:wav(bitDepth)
  749.     -- TODO: Support float data
  750.     bitDepth = expect(1, bitDepth, "number", "nil") or 16
  751.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  752.     local data = self:pcm(bitDepth, bitDepth == 8 and "unsigned" or "signed", true)
  753.     local str = ""
  754.     local csize = jit and 7680 or 32768
  755.     local format = ((bitDepth == 8 and "I" or "i") .. (bitDepth / 8)):rep(csize)
  756.     for i = 1, #data - csize, csize do str = str .. format:pack(table.unpack(data, i, i + csize - 1)) end
  757.     str = str .. ((bitDepth == 8 and "I" or "i") .. (bitDepth / 8)):rep(#data % csize):pack(table.unpack(data, math.floor(#data / csize) * csize))
  758.     return ("<c4Ic4c4IHHIIHHc4I"):pack("RIFF", #str + 36, "WAVE", "fmt ", 16, 1, #self.data, self.sampleRate, self.sampleRate * #self.data, #self.data * bitDepth / 8, bitDepth, "data", #str) .. str
  759. end
  760.  
  761. --- Converts the audio data to DFPWM. All channels share the same encoder, and
  762. -- channels are stored sequentially uninterleaved.
  763. -- @treturn string... The resulting DFPWM data for each channel
  764. function Audio:dfpwm()
  765.     local channels = {self:pcm(8, "signed", false)}
  766.     local encode = dfpwm.make_encoder()
  767.     for i = 1, #channels do channels[i] = encode(channels[i]) end
  768.     return table.unpack(channels)
  769. end
  770.  
  771. Audio_mt = {__index = Audio, __add = Audio.combine, __mul = Audio.rep, __concat = Audio.concat, __len = Audio.len, __name = "Audio"}
  772.  
  773. function Audio_mt:__tostring()
  774.     return "Audio: " .. self.sampleRate .. " Hz, " .. #self.data .. " channels, " .. (#self.data[1] / self.sampleRate) .. " seconds"
  775. end
  776.  
  777. --- aukit
  778. -- @section aukit
  779.  
  780. --- Creates a new audio object from the specified raw PCM data.
  781. -- @tparam string|table data The audio data, either as a raw string, or a table
  782. -- of values (in the format specified by `bitDepth` and `dataType`)
  783. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32); if `dataType` is "float" then this must be 32
  784. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  785. -- @tparam[opt=1] number channels The number of channels present in the audio
  786. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  787. -- @tparam[opt=true] boolean interleaved Whether each channel is interleaved or separate
  788. -- @tparam[opt=false] boolean bigEndian Whether the audio is big-endian or little-endian; ignored if data is a table
  789. -- @treturn Audio A new audio object containing the specified data
  790. function aukit.pcm(data, bitDepth, dataType, channels, sampleRate, interleaved, bigEndian)
  791.     expect(1, data, "string", "table")
  792.     bitDepth = expect(2, bitDepth, "number", "nil") or 8
  793.     dataType = expect(3, dataType, "string", "nil") or "signed"
  794.     channels = expect(4, channels, "number", "nil") or 1
  795.     sampleRate = expect(5, sampleRate, "number", "nil") or 48000
  796.     expect(6, interleaved, "boolean", "nil")
  797.     if interleaved == nil then interleaved = true end
  798.     expect(7, bigEndian, "boolean", "nil")
  799.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  800.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  801.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  802.     expect.range(channels, 1)
  803.     expect.range(sampleRate, 1)
  804.     local byteDepth = bitDepth / 8
  805.     if (#data / (type(data) == "table" and 1 or byteDepth)) % channels ~= 0 then error("bad argument #1 (uneven amount of data per channel)", 2) end
  806.     local len = (#data / (type(data) == "table" and 1 or byteDepth)) / channels
  807.     local csize = jit and 7680 or 32768
  808.     local format = (bigEndian and ">" or "<") .. (dataType == "float" and "f" or ((dataType == "signed" and "i" or "I") .. byteDepth)):rep(csize)
  809.     local maxValue = 2^(bitDepth-1)
  810.     local obj = setmetatable({sampleRate = sampleRate, data = {}}, Audio_mt)
  811.     for i = 1, channels do obj.data[i] = {} end
  812.     local pos, spos = 1, 1
  813.     local tmp = {}
  814.     local read
  815.     if type(data) == "table" then
  816.         if dataType == "signed" then
  817.             function read()
  818.                 local s = data[pos]
  819.                 pos = pos + 1
  820.                 return s / (s < 0 and maxValue or maxValue-1)
  821.             end
  822.         elseif dataType == "unsigned" then
  823.             function read()
  824.                 local s = data[pos]
  825.                 pos = pos + 1
  826.                 return (s - 128) / (s < 128 and maxValue or maxValue-1)
  827.             end
  828.         else
  829.             function read()
  830.                 local s = data[pos]
  831.                 pos = pos + 1
  832.                 return s
  833.             end
  834.         end
  835.     elseif dataType == "float" then
  836.         function read()
  837.             if pos > #tmp then
  838.                 if spos + (csize * byteDepth) > #data then
  839.                     local f = (bigEndian and ">" or "<") .. ("f"):rep((#data - spos + 1) / byteDepth)
  840.                     tmp = {f:unpack(data, spos)}
  841.                     spos = tmp[#tmp]
  842.                     tmp[#tmp] = nil
  843.                 else
  844.                     tmp = {format:unpack(data, spos)}
  845.                     spos = tmp[#tmp]
  846.                     tmp[#tmp] = nil
  847.                 end
  848.                 pos = 1
  849.             end
  850.             local s = tmp[pos]
  851.             pos = pos + 1
  852.             return s
  853.         end
  854.     elseif dataType == "signed" then
  855.         function read()
  856.             if pos > #tmp then
  857.                 if spos + (csize * byteDepth) > #data then
  858.                     local f = (bigEndian and ">" or "<") .. ("i" .. byteDepth):rep((#data - spos + 1) / byteDepth)
  859.                     tmp = {f:unpack(data, spos)}
  860.                     spos = tmp[#tmp]
  861.                     tmp[#tmp] = nil
  862.                 else
  863.                     tmp = {format:unpack(data, spos)}
  864.                     spos = tmp[#tmp]
  865.                     tmp[#tmp] = nil
  866.                 end
  867.                 pos = 1
  868.             end
  869.             local s = tmp[pos]
  870.             pos = pos + 1
  871.             return s / (s < 0 and maxValue or maxValue-1)
  872.         end
  873.     else -- unsigned
  874.         function read()
  875.             if pos > #tmp then
  876.                 if spos + (csize * byteDepth) > #data then
  877.                     local f = (bigEndian and ">" or "<") .. ("I" .. byteDepth):rep((#data - spos + 1) / byteDepth)
  878.                     tmp = {f:unpack(data, spos)}
  879.                     spos = tmp[#tmp]
  880.                     tmp[#tmp] = nil
  881.                 else
  882.                     tmp = {format:unpack(data, spos)}
  883.                     spos = tmp[#tmp]
  884.                     tmp[#tmp] = nil
  885.                 end
  886.                 pos = 1
  887.             end
  888.             local s = tmp[pos]
  889.             pos = pos + 1
  890.             return (s - 128) / (s < 128 and maxValue or maxValue-1)
  891.         end
  892.     end
  893.     local start = os.epoch "utc"
  894.     if interleaved and channels > 1 then
  895.         local d = obj.data
  896.         for i = 1, len do
  897.             if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  898.             for j = 1, channels do d[j][i] = read() end
  899.         end
  900.     else for j = 1, channels do
  901.         local line = {}
  902.         obj.data[j] = line
  903.         for i = 1, len do
  904.             if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  905.             line[i] = read()
  906.         end
  907.     end end
  908.     return obj
  909. end
  910.  
  911. --- Creates a new audio object from IMA ADPCM data.
  912. -- @tparam string|table data The audio data, either as a raw string, or a table of nibbles
  913. -- @tparam[opt=1] number channels The number of channels present in the audio
  914. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  915. -- @tparam[opt=true] boolean topFirst Whether the top nibble is the first nibble
  916. -- (true) or last (false); ignored if `data` is a table
  917. -- @tparam[opt=true] boolean interleaved Whether each channel is interleaved or separate
  918. -- @tparam[opt=0] number|table predictor The initial predictor value(s)
  919. -- @tparam[opt=0] number|table step_index The initial step index(es)
  920. -- @treturn Audio A new audio object containing the decoded data
  921. function aukit.adpcm(data, channels, sampleRate, topFirst, interleaved, predictor, step_index)
  922.     expect(1, data, "string", "table")
  923.     channels = expect(2, channels, "number", "nil") or 1
  924.     sampleRate = expect(3, sampleRate, "number", "nil") or 48000
  925.     expect(4, topFirst, "boolean", "nil")
  926.     if topFirst == nil then topFirst = true end
  927.     expect(5, interleaved, "boolean", "nil")
  928.     if interleaved == nil then interleaved = true end
  929.     predictor = expect(6, predictor, "number", "table", "nil")
  930.     step_index = expect(7, step_index, "number", "table", "nil")
  931.     expect.range(channels, 1)
  932.     expect.range(sampleRate, 1)
  933.     if predictor == nil then
  934.         predictor = {}
  935.         for i = 1, channels do predictor[i] = 0 end
  936.     elseif type(predictor) == "number" then
  937.         if channels ~= 1 then error("bad argument #6 (table too short)", 2) end
  938.         predictor = {expect.range(predictor, -32768, 32767)}
  939.     else
  940.         if channels > #predictor then error("bad argument #6 (table too short)", 2) end
  941.         for i = 1, channels do expect.range(predictor[i], -32768, 32767) end
  942.     end
  943.     if step_index == nil then
  944.         step_index = {}
  945.         for i = 1, channels do step_index[i] = 0 end
  946.     elseif type(step_index) == "number" then
  947.         if channels ~= 1 then error("bad argument #7 (table too short)", 2) end
  948.         step_index = {expect.range(step_index, 0, 15)}
  949.     else
  950.         if channels > #step_index then error("bad argument #7 (table too short)", 2) end
  951.         for i = 1, channels do expect.range(step_index[i], 0, 15) end
  952.     end
  953.     local pos = 1
  954.     local read, tmp, len
  955.     if type(data) == "string" then
  956.         function read()
  957.             if tmp then
  958.                 local v = tmp
  959.                 tmp = nil
  960.                 return v
  961.             else
  962.                 local b = data:byte(pos)
  963.                 pos = pos + 1
  964.                 if topFirst then tmp, b = bit32.band(b, 0x0F), bit32.rshift(b, 4)
  965.                 else tmp, b = bit32.rshift(b, 4), bit32.band(b, 0x0F) end
  966.                 return b
  967.             end
  968.         end
  969.         len = math.floor(#data * 2 / channels)
  970.     else
  971.         function read()
  972.             local v = data[pos]
  973.             pos = pos + 1
  974.             return v
  975.         end
  976.         len = #data / channels
  977.     end
  978.     local obj = setmetatable({sampleRate = sampleRate, data = {}}, Audio_mt)
  979.     local step = {}
  980.     local start = os.epoch "utc"
  981.     if interleaved then
  982.         local d = obj.data
  983.         for i = 1, len do
  984.             if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  985.             for j = 1, channels do
  986.                 local nibble = read()
  987.                 step_index[j] = clamp(step_index[j] + ima_index_table[nibble], 0, 88)
  988.                 local diff = ((nibble >= 8 and nibble - 16 or nibble) + 0.5) * step[j] / 4
  989.                 predictor[j] = clamp(predictor[j] + diff, -32768, 32767)
  990.                 step[j] = ima_step_table[step_index]
  991.                 d[j][i] = predictor[j] / (predictor[j] < 0 and 32768 or 32767)
  992.             end
  993.         end
  994.     else for j = 1, channels do
  995.         local line = {}
  996.         local predictor, step_index, step = predictor[j], step_index[j], nil
  997.         for i = 1, len do
  998.             if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  999.             local nibble = read()
  1000.             step_index = clamp(step_index + ima_index_table[nibble], 0, 88)
  1001.             local diff = ((nibble >= 8 and nibble - 16 or nibble) + 0.5) * step / 4
  1002.             predictor = clamp(predictor + diff, -32768, 32767)
  1003.             step = ima_step_table[step_index]
  1004.             line[i] = predictor / (predictor < 0 and 32768 or 32767)
  1005.         end
  1006.         obj.data[j] = line
  1007.     end end
  1008.     return obj
  1009. end
  1010.  
  1011. --- Creates a new audio object from DFPWM1a data. All channels are expected to
  1012. -- share the same decoder, and are stored uninterleaved sequentially.
  1013. -- @tparam string data The audio data as a raw string
  1014. -- @tparam[opt=1] number channels The number of channels present in the audio
  1015. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1016. -- @treturn Audio A new audio object containing the decoded data
  1017. function aukit.dfpwm(data, channels, sampleRate)
  1018.     expect(1, data, "string")
  1019.     channels = expect(2, channels, "number", "nil") or 1
  1020.     sampleRate = expect(3, sampleRate, "number", "nil") or 48000
  1021.     expect.range(channels, 1)
  1022.     expect.range(sampleRate, 1)
  1023.     if #data % channels ~= 0 then error("bad argument #1 (uneven amount of data per channel)", 2) end
  1024.     local audio = {}
  1025.     local decoder = dfpwm.make_decoder()
  1026.     local pos = 1
  1027.     local last = 0
  1028.     local start = os.epoch "utc"
  1029.     while pos <= #data do
  1030.         if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  1031.         local temp = decoder(data:sub(pos, pos + 6000))
  1032.         if temp == nil or #temp == 0 then break end
  1033.         for i=1,#temp do
  1034.             audio[last+i] = temp[i]
  1035.         end
  1036.         last = last + #temp
  1037.         pos = pos + 6000
  1038.     end
  1039.     return aukit.pcm(audio, 8, "signed", channels, sampleRate, false, false)
  1040. end
  1041.  
  1042. --- Creates a new audio object from a WAV file.
  1043. -- @tparam string data The WAV data to load
  1044. -- @treturn Audio A new audio object with the contents of the WAV file
  1045. function aukit.wav(data)
  1046.     -- TODO: add float support
  1047.     expect(1, data, "string")
  1048.     local channels, sampleRate, bitDepth, length
  1049.     local temp, pos = ("c4"):unpack(data)
  1050.     if temp ~= "RIFF" then error("bad argument #1 (not a WAV file)", 2) end
  1051.     pos = pos + 4
  1052.     temp, pos = ("c4"):unpack(data, pos)
  1053.     if temp ~= "WAVE" then error("bad argument #1 (not a WAV file)", 2) end
  1054.     while pos <= #data do
  1055.         local size
  1056.         temp, pos = ("c4"):unpack(data, pos)
  1057.         size, pos = ("<I"):unpack(data, pos)
  1058.         if temp == "fmt " then
  1059.             if size ~= 16 then error("unsupported WAV file", 2) end
  1060.             temp, pos = ("<H"):unpack(data, pos)
  1061.             if temp ~= 1 then error("unsupported WAV file", 2) end
  1062.             channels, sampleRate, pos = ("<HI"):unpack(data, pos)
  1063.             pos = pos + 6
  1064.             bitDepth, pos = ("<H"):unpack(data, pos)
  1065.         elseif temp == "data" then
  1066.             local data = data:sub(pos, pos + size - 1)
  1067.             if #data < size then error("invalid WAV file", 2) end
  1068.             return aukit.pcm(data, bitDepth, bitDepth == 8 and "unsigned" or "signed", channels, sampleRate, true, false)
  1069.         elseif temp == "fact" then
  1070.             -- TODO
  1071.             pos = pos + size
  1072.         else pos = pos + size end
  1073.     end
  1074.     error("invalid WAV file", 2)
  1075. end
  1076.  
  1077. --- Creates a new audio object from an AIFF file.
  1078. -- @tparam string data The AIFF data to load
  1079. -- @treturn Audio A new audio object with the contents of the AIFF file
  1080. function aukit.aiff(data)
  1081.     expect(1, data, "string")
  1082.     local channels, sampleRate, bitDepth, length, offset
  1083.     local temp, pos = ("c4"):unpack(data)
  1084.     if temp ~= "FORM" then error("bad argument #1 (not an AIFF file)", 2) end
  1085.     pos = pos + 4
  1086.     temp, pos = ("c4"):unpack(data, pos)
  1087.     if temp ~= "AIFF" then error("bad argument #1 (not an AIFF file)", 2) end
  1088.     while pos <= #data do
  1089.         local size
  1090.         temp, pos = ("c4"):unpack(data, pos)
  1091.         size, pos = (">I"):unpack(data, pos)
  1092.         if temp == "COMM" then
  1093.             local e, m
  1094.             channels, length, bitDepth, e, m, pos = (">hIhHI7x"):unpack(data, pos)
  1095.             length = length * channels * math.floor(bitDepth / 8)
  1096.             local s = bit32.btest(e, 0x8000)
  1097.             e = ((bit32.band(e, 0x7FFF) - 0x3FFE) % 0x800)
  1098.             sampleRate = math.ldexp(m * (s and -1 or 1) / 0x100000000000000, e)
  1099.         elseif temp == "SSND" then
  1100.             offset, _, pos = (">II"):unpack(data, pos)
  1101.             local data = data:sub(pos + offset, pos + offset + length - 1)
  1102.             if #data < length then error("invalid AIFF file", 2) end
  1103.             return aukit.pcm(data, bitDepth, "signed", channels, sampleRate, true, true)
  1104.         else pos = pos + size end
  1105.     end
  1106.     error("invalid AIFF file", 2)
  1107. end
  1108.  
  1109. --- Creates a new audio object from an AU file.
  1110. -- @tparam string data The AU data to load
  1111. -- @treturn Audio A new audio object with the contents of the AU file
  1112. function aukit.au(data)
  1113.     expect(1, data, "string")
  1114.     local magic, offset, size, encoding, sampleRate, channels = (">c4IIIII"):unpack(data)
  1115.     if magic ~= ".snd" then error("invalid AU file", 2) end
  1116.     if encoding == 2 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 8, "signed", channels, sampleRate, true, true)
  1117.     elseif encoding == 3 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 16, "signed", channels, sampleRate, true, true)
  1118.     elseif encoding == 4 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 24, "signed", channels, sampleRate, true, true)
  1119.     elseif encoding == 5 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 32, "signed", channels, sampleRate, true, true)
  1120.     elseif encoding == 6 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 32, "float", channels, sampleRate, true, true)
  1121.     else error("unsupported encoding type " .. encoding, 2) end
  1122. end
  1123.  
  1124. --- Creates a new audio object from a FLAC file.
  1125. -- @tparam string data The FLAC data to load
  1126. -- @treturn Audio A new audio object with the contents of the FLAC file
  1127. function aukit.flac(data)
  1128.     expect(1, data, "string")
  1129.     return setmetatable(decodeFLAC(data), Audio_mt)
  1130. end
  1131.  
  1132. --- Creates a new empty audio object with the specified duration.
  1133. -- @tparam number duration The length of the audio in seconds
  1134. -- @tparam[opt=1] number channels The number of channels present in the audio
  1135. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1136. -- @treturn Audio The new empty audio object
  1137. function aukit.new(duration, channels, sampleRate)
  1138.     expect(1, duration, "number")
  1139.     channels = expect(2, channels, "number", "nil") or 1
  1140.     sampleRate = expect(3, sampleRate, "number", "nil") or 48000
  1141.     expect.range(channels, 1)
  1142.     expect.range(sampleRate, 1)
  1143.     local obj = setmetatable({sampleRate = sampleRate, data = {}}, Audio_mt)
  1144.     for c = 1, channels do
  1145.         local l = {}
  1146.         for i = 1, duration * sampleRate do l[i] = 0 end
  1147.         obj.data[c] = l
  1148.     end
  1149.     return obj
  1150. end
  1151.  
  1152. --- Creates a new audio object with a tone of the specified frequency and duration.
  1153. -- @tparam number frequency The frequency of the tone in Hertz
  1154. -- @tparam number duration The length of the audio in seconds
  1155. -- @tparam[opt=1] number amplitude The amplitude of the audio from 0.0 to 1.0
  1156. -- @tparam[opt="sine"] "sine"|"triangle"|"sawtooth"|"square" waveType The type of wave to generate
  1157. -- @tparam[opt=0.5] number duty The duty cycle of the square wave if selected; ignored otherwise
  1158. -- @tparam[opt=1] number channels The number of channels present in the audio
  1159. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1160. -- @treturn Audio A new audio object with the tone
  1161. function aukit.tone(frequency, duration, amplitude, waveType, duty, channels, sampleRate)
  1162.     expect(1, frequency, "number")
  1163.     expect(2, duration, "number")
  1164.     amplitude = expect(3, amplitude, "number", "nil") or 1
  1165.     waveType = expect(4, waveType, "string", "nil") or "sine"
  1166.     duty = expect(5, duty, "number", "nil") or 0.5
  1167.     channels = expect(6, channels, "number", "nil") or 1
  1168.     sampleRate = expect(7, sampleRate, "number", "nil") or 48000
  1169.     expect.range(amplitude, 0, 1)
  1170.     local f = wavegen[waveType]
  1171.     if not f then error("bad argument #4 (invalid wave type)", 2) end
  1172.     expect.range(duty, 0, 1)
  1173.     expect.range(channels, 1)
  1174.     expect.range(sampleRate, 1)
  1175.     local obj = setmetatable({sampleRate = sampleRate, data = {}}, Audio_mt)
  1176.     for c = 1, channels do
  1177.         local l = {}
  1178.         for i = 1, duration * sampleRate do l[i] = f(i / sampleRate, frequency, amplitude, duty) end
  1179.         obj.data[c] = l
  1180.     end
  1181.     return obj
  1182. end
  1183.  
  1184. --- Creates a new audio object with white noise for the specified duration.
  1185. -- @tparam number duration The length of the audio in seconds
  1186. -- @tparam[opt=1] number amplitude The amplitude of the audio from 0.0 to 1.0
  1187. -- @tparam[opt=1] number channels The number of channels present in the audio
  1188. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1189. -- @treturn Audio A new audio object with noise
  1190. function aukit.noise(duration, amplitude, channels, sampleRate)
  1191.     expect(1, duration, "number")
  1192.     amplitude = expect(2, amplitude, "number", "nil") or 1
  1193.     channels = expect(3, channels, "number", "nil") or 1
  1194.     sampleRate = expect(4, sampleRate, "number", "nil") or 48000
  1195.     expect.range(amplitude, 0, 1)
  1196.     expect.range(channels, 1)
  1197.     expect.range(sampleRate, 1)
  1198.     local obj = setmetatable({sampleRate = sampleRate, data = {}}, Audio_mt)
  1199.     for c = 1, channels do
  1200.         local l = {}
  1201.         for i = 1, duration * sampleRate do l[i] = (math.random() * 2 - 1) * amplitude end
  1202.         obj.data[c] = l
  1203.     end
  1204.     return obj
  1205. end
  1206.  
  1207. --- Packs a table with PCM data into a string using the specified data type.
  1208. -- @tparam {[number]...} data The PCM data to pack
  1209. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32); if `dataType` is "float" then this must be 32
  1210. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  1211. -- @tparam[opt=false] boolean bigEndian Whether the data should be big-endian or little-endian
  1212. -- @treturn string The packed PCM data
  1213. function aukit.pack(data, bitDepth, dataType, bigEndian)
  1214.     expect(1, data, "string", "table")
  1215.     bitDepth = expect(2, bitDepth, "number", "nil") or 8
  1216.     dataType = expect(3, dataType, "string", "nil") or "signed"
  1217.     expect(4, bigEndian, "boolean", "nil")
  1218.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  1219.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  1220.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  1221.     local byteDepth = bitDepth / 8
  1222.     local format = (bigEndian and ">" or "<") .. (dataType == "float" and "f" or ((dataType == "signed" and "i" or "I") .. byteDepth))
  1223.     local formatChunk = format:sub(1, 1) .. format:sub(2):rep(512)
  1224.     local retval = ""
  1225.     for i = 1, #data, 512 do
  1226.         if #data < i + 512 then retval = retval .. format:rep(#data % 512):pack(table.unpack(data, i, #data))
  1227.         else retval = retval .. formatChunk:pack(table.unpack(data, i, i+511)) end
  1228.     end
  1229.     return retval
  1230. end
  1231.  
  1232. --- Plays back stream functions created by one of the @{aukit.stream} functions
  1233. -- or @{Audio:stream}.
  1234. -- @tparam function():{{[number]...}...} callback The iterator function that returns each chunk
  1235. -- @tparam speaker ... The speakers to play on
  1236. function aukit.play(callback, ...)
  1237.     expect(1, callback, "function")
  1238.     local speakers = {...}
  1239.     local chunks = {}
  1240.     local complete = false
  1241.     parallel.waitForAll(function()
  1242.         for chunk in callback do chunks[#chunks+1] = chunk sleep(0) end
  1243.         complete = true
  1244.     end, function()
  1245.         while not complete or #chunks > 0 do
  1246.             while not chunks[1] do sleep(0) end
  1247.             local chunk = table.remove(chunks, 1)
  1248.             local fn = {}
  1249.             for i, v in ipairs(speakers) do fn[i] = function()
  1250.                 local name = peripheral.getName(v)
  1251.                 if config and not config.get("standardsMode") then
  1252.                     v.playAudio(chunk[i] or chunk[1], 3)
  1253.                     repeat until select(2, os.pullEvent("speaker_audio_empty")) == name
  1254.                 else while not v.playAudio(chunk[i] or chunk[1]) do
  1255.                     repeat until select(2, os.pullEvent("speaker_audio_empty")) == name
  1256.                 end end
  1257.             end end
  1258.             parallel.waitForAll(table.unpack(fn))
  1259.         end
  1260.     end)
  1261. end
  1262.  
  1263. --- aukit.stream
  1264. -- @section aukit.stream
  1265.  
  1266. --- Returns an iterator to stream raw PCM data in CC format. Audio will automatically
  1267. -- be resampled to 48 kHz, and optionally mixed down to mono. Data *must* be
  1268. -- interleaved - this will not work with planar audio.
  1269. -- @tparam string|table data The audio data, either as a raw string, or a table
  1270. -- of values (in the format specified by `bitDepth` and `dataType`)
  1271. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32); if `dataType` is "float" then this must be 32
  1272. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  1273. -- @tparam[opt=1] number channels The number of channels present in the audio
  1274. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1275. -- @tparam[opt=false] boolean bigEndian Whether the audio is big-endian or little-endian; ignored if data is a table
  1276. -- @tparam[opt=false] boolean mono Whether to mix the audio down to mono
  1277. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1278. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1279. -- the current position of the audio in seconds
  1280. -- @treturn number The total length of the audio in seconds
  1281. function aukit.stream.pcm(data, bitDepth, dataType, channels, sampleRate, bigEndian, mono)
  1282.     expect(1, data, "string", "table")
  1283.     bitDepth = expect(2, bitDepth, "number", "nil") or 8
  1284.     dataType = expect(3, dataType, "string", "nil") or "signed"
  1285.     channels = expect(4, channels, "number", "nil") or 1
  1286.     sampleRate = expect(5, sampleRate, "number", "nil") or 48000
  1287.     expect(6, bigEndian, "boolean", "nil")
  1288.     expect(7, mono, "boolean", "nil")
  1289.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  1290.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  1291.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  1292.     expect.range(channels, 1)
  1293.     expect.range(sampleRate, 1)
  1294.     local byteDepth = bitDepth / 8
  1295.     local len = (#data / (type(data) == "table" and 1 or byteDepth)) / channels
  1296.     local csize = jit and 7680 or 32768
  1297.     local format = (bigEndian and ">" or "<") .. (dataType == "float" and "f" or ((dataType == "signed" and "i" or "I") .. byteDepth)):rep(csize)
  1298.     local maxValue = 2^(bitDepth-1)
  1299.     local pos, spos = 1, 1
  1300.     local tmp = {}
  1301.     local read
  1302.     if type(data) == "table" then
  1303.         if dataType == "signed" then
  1304.             function read()
  1305.                 local s = data[pos]
  1306.                 pos = pos + 1
  1307.                 return s / (s < 0 and maxValue or maxValue-1)
  1308.             end
  1309.         elseif dataType == "unsigned" then
  1310.             function read()
  1311.                 local s = data[pos]
  1312.                 pos = pos + 1
  1313.                 return (s - 128) / (s < 128 and maxValue or maxValue-1)
  1314.             end
  1315.         else
  1316.             function read()
  1317.                 local s = data[pos]
  1318.                 pos = pos + 1
  1319.                 return s
  1320.             end
  1321.         end
  1322.     elseif dataType == "float" then
  1323.         function read()
  1324.             if pos > #tmp then
  1325.                 if spos + (csize * byteDepth) > #data then
  1326.                     local f = (bigEndian and ">" or "<") .. ("f"):rep((#data - spos + 1) / byteDepth)
  1327.                     tmp = {f:unpack(data, spos)}
  1328.                     spos = tmp[#tmp]
  1329.                     tmp[#tmp] = nil
  1330.                 else
  1331.                     tmp = {format:unpack(data, spos)}
  1332.                     spos = tmp[#tmp]
  1333.                     tmp[#tmp] = nil
  1334.                 end
  1335.                 pos = 1
  1336.             end
  1337.             local s = tmp[pos]
  1338.             pos = pos + 1
  1339.             return s
  1340.         end
  1341.     elseif dataType == "signed" then
  1342.         function read()
  1343.             if pos > #tmp then
  1344.                 if spos + (csize * byteDepth) > #data then
  1345.                     local f = (bigEndian and ">" or "<") .. ("i" .. byteDepth):rep((#data - spos + 1) / byteDepth)
  1346.                     tmp = {f:unpack(data, spos)}
  1347.                     spos = tmp[#tmp]
  1348.                     tmp[#tmp] = nil
  1349.                 else
  1350.                     tmp = {format:unpack(data, spos)}
  1351.                     spos = tmp[#tmp]
  1352.                     tmp[#tmp] = nil
  1353.                 end
  1354.                 pos = 1
  1355.             end
  1356.             local s = tmp[pos]
  1357.             pos = pos + 1
  1358.             return s / (s < 0 and maxValue or maxValue-1)
  1359.         end
  1360.     else -- unsigned
  1361.         function read()
  1362.             if pos > #tmp then
  1363.                 if spos + (csize * byteDepth) > #data then
  1364.                     local f = (bigEndian and ">" or "<") .. ("I" .. byteDepth):rep((#data - spos + 1) / byteDepth)
  1365.                     tmp = {f:unpack(data, spos)}
  1366.                     spos = tmp[#tmp]
  1367.                     tmp[#tmp] = nil
  1368.                 else
  1369.                     tmp = {format:unpack(data, spos)}
  1370.                     spos = tmp[#tmp]
  1371.                     tmp[#tmp] = nil
  1372.                 end
  1373.                 pos = 1
  1374.             end
  1375.             local s = tmp[pos]
  1376.             pos = pos + 1
  1377.             return (s - 128) / (s < 128 and maxValue or maxValue-1)
  1378.         end
  1379.     end
  1380.     local d = {}
  1381.     local ratio = 48000 / sampleRate
  1382.     local interp = interpolate[aukit.defaultInterpolation]
  1383.     for j = 1, (mono and 1 or channels) do d[j] = setmetatable({}, {__index = function(self, i)
  1384.         if mono then for _ = 1, channels do self[i] = (rawget(self, i) or 0) + read() end self[i] = self[i] / channels
  1385.         else self[i] = read() end
  1386.         return rawget(self, i)
  1387.     end}) end
  1388.     local n = 0
  1389.     local ok = true
  1390.     return function()
  1391.         if not ok then return nil end
  1392.         for i = (n == 0 and interpolation_start[aukit.defaultInterpolation] or 1), interpolation_end[aukit.defaultInterpolation] do
  1393.             if mono then
  1394.                 local s = 0
  1395.                 for j = 1, channels do
  1396.                     local c = read()
  1397.                     if not c then return nil end
  1398.                     s = s + c
  1399.                 end
  1400.                 d[1][i] = s / channels
  1401.             else for j = 1, channels do d[j][i] = read() if not d[j][i] then return nil end end end
  1402.         end
  1403.         local chunk = {}
  1404.         for j = 1, #d do chunk[j] = {} end
  1405.         ok = pcall(function()
  1406.             for i = 1, 48000 do
  1407.                 for y = 1, #d do
  1408.                     local x = ((n * 48000 + i - 1) / ratio) + 1
  1409.                     if x % 1 == 0 then chunk[y][i] = d[y][x]
  1410.                     else chunk[y][i] = interp(d[y], x) end
  1411.                     chunk[y][i] = clamp(chunk[y][i] * (chunk[y][i] < 0 and 128 or 127), -128, 127)
  1412.                 end
  1413.             end
  1414.         end)
  1415.         if #chunk[1] == 0 then return nil end
  1416.         n = n + 1
  1417.         return chunk, n - 1
  1418.     end, len / sampleRate
  1419. end
  1420.  
  1421. --- Returns an iterator to stream data from DFPWM data. Audio will automatically
  1422. -- be resampled to 48 kHz. This only supports mono audio.
  1423. -- @tparam string data The DFPWM data to decode
  1424. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1425. -- @treturn function():{{[number]...}...},number An iterator function that
  1426. -- returns chunks of the only channel's data as arrays of signed 8-bit 48kHz PCM,
  1427. -- as well as the current position of the audio in seconds
  1428. -- @treturn number The total length of the audio in seconds
  1429. function aukit.stream.dfpwm(data, sampleRate)
  1430.     expect(1, data, "string")
  1431.     sampleRate = expect(2, sampleRate, "number", "nil") or 48000
  1432.     expect.range(sampleRate, 1)
  1433.     local decoder = dfpwm.make_decoder()
  1434.     local pos = 1
  1435.     local last = 0
  1436.     return function()
  1437.         if pos > #data then return nil end
  1438.         local audio = decoder(data:sub(pos, pos + 6000))
  1439.         if audio == nil or #audio == 0 then return nil end
  1440.         audio[0], last = last, audio[#audio]
  1441.         sleep(0)
  1442.         local ratio = 48000 / sampleRate
  1443.         local newlen = #audio * ratio
  1444.         local interp = interpolate[aukit.defaultInterpolation]
  1445.         local line = {}
  1446.         for i = 1, newlen do
  1447.             local x = (i - 1) / ratio + 1
  1448.             if x % 1 == 0 then line[i] = audio[x]
  1449.             else line[i] = clamp(interp(audio, x), -128, 127) end
  1450.         end
  1451.         sleep(0)
  1452.         local p = pos
  1453.         pos = pos + 6000
  1454.         return {line}, p * 8 / sampleRate
  1455.     end, #data * 8 / sampleRate
  1456. end
  1457.  
  1458. --- Returns an iterator to stream data from a WAV file. Audio will automatically
  1459. -- be resampled to 48 kHz, and optionally mixed down to mono.
  1460. -- @tparam string data The WAV file to decode
  1461. -- @tparam[opt=false] boolean mono Whether to mix the audio to mono
  1462. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1463. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1464. -- the current position of the audio in seconds
  1465. -- @treturn number The total length of the audio in seconds
  1466. function aukit.stream.wav(data, mono)
  1467.     expect(1, data, "string")
  1468.     local channels, sampleRate, bitDepth, length
  1469.     local temp, pos = ("c4"):unpack(data)
  1470.     if temp ~= "RIFF" then error("bad argument #1 (not a WAV file)", 2) end
  1471.     pos = pos + 4
  1472.     temp, pos = ("c4"):unpack(data, pos)
  1473.     if temp ~= "WAVE" then error("bad argument #1 (not a WAV file)", 2) end
  1474.     while pos <= #data do
  1475.         local size
  1476.         temp, pos = ("c4"):unpack(data, pos)
  1477.         size, pos = ("<I"):unpack(data, pos)
  1478.         if temp == "fmt " then
  1479.             if size ~= 16 then error("unsupported WAV file", 2) end
  1480.             temp, pos = ("<H"):unpack(data, pos)
  1481.             if temp ~= 1 then error("unsupported WAV file", 2) end
  1482.             channels, sampleRate, pos = ("<HI"):unpack(data, pos)
  1483.             pos = pos + 6
  1484.             bitDepth, pos = ("<H"):unpack(data, pos)
  1485.         elseif temp == "data" then
  1486.             local data = data:sub(pos, pos + size - 1)
  1487.             if #data < size then error("invalid WAV file", 2) end
  1488.             return aukit.stream.pcm(data, bitDepth, bitDepth == 8 and "unsigned" or "signed", channels, sampleRate, false, mono)
  1489.         elseif temp == "fact" then
  1490.             -- TODO
  1491.             pos = pos + size
  1492.         else pos = pos + size end
  1493.     end
  1494.     error("invalid WAV file", 2)
  1495. end
  1496.  
  1497. --- Returns an iterator to stream data from an AIFF file. Audio will automatically
  1498. -- be resampled to 48 kHz, and optionally mixed down to mono.
  1499. -- @tparam string data The AIFF file to decode
  1500. -- @tparam[opt=false] boolean mono Whether to mix the audio to mono
  1501. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1502. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1503. -- the current position of the audio in seconds
  1504. -- @treturn number The total length of the audio in seconds
  1505. function aukit.stream.aiff(data, mono)
  1506.     expect(1, data, "string")
  1507.     expect(2, mono, "boolean", "nil")
  1508.     local channels, sampleRate, bitDepth, length, offset
  1509.     local temp, pos = ("c4"):unpack(data)
  1510.     if temp ~= "FORM" then error("bad argument #1 (not an AIFF file)", 2) end
  1511.     pos = pos + 4
  1512.     temp, pos = ("c4"):unpack(data, pos)
  1513.     if temp ~= "AIFF" then error("bad argument #1 (not an AIFF file)", 2) end
  1514.     while pos <= #data do
  1515.         local size
  1516.         temp, pos = ("c4"):unpack(data, pos)
  1517.         size, pos = (">I"):unpack(data, pos)
  1518.         if temp == "COMM" then
  1519.             local e, m
  1520.             channels, length, bitDepth, e, m, pos = (">hIhHI7x"):unpack(data, pos)
  1521.             length = length * channels * math.floor(bitDepth / 8)
  1522.             local s = bit32.btest(e, 0x8000)
  1523.             e = ((bit32.band(e, 0x7FFF) - 0x3FFE) % 0x800)
  1524.             sampleRate = math.ldexp(m * (s and -1 or 1) / 0x100000000000000, e)
  1525.         elseif temp == "SSND" then
  1526.             offset, _, pos = (">II"):unpack(data, pos)
  1527.             local data = data:sub(pos + offset, pos + offset + length - 1)
  1528.             if #data < length then error("invalid AIFF file", 2) end
  1529.             return aukit.stream.pcm(data, bitDepth, "signed", channels, sampleRate, true, mono)
  1530.         else pos = pos + size end
  1531.     end
  1532.     error("invalid AIFF file", 2)
  1533. end
  1534.  
  1535. --- Returns an iterator to stream data from an AU file. Audio will automatically
  1536. -- be resampled to 48 kHz, and optionally mixed down to mono.
  1537. -- @tparam string data The AU file to decode
  1538. -- @tparam[opt=false] boolean mono Whether to mix the audio to mono
  1539. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1540. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1541. -- the current position of the audio in seconds
  1542. -- @treturn number The total length of the audio in seconds
  1543. function aukit.stream.au(data, mono)
  1544.     expect(1, data, "string")
  1545.     expect(2, mono, "boolean", "nil")
  1546.     local magic, offset, size, encoding, sampleRate, channels = (">c4IIIII"):unpack(data)
  1547.     if magic ~= ".snd" then error("invalid AU file", 2) end
  1548.     if encoding == 2 then return aukit.stream.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 8, "signed", channels, sampleRate, true, mono)
  1549.     elseif encoding == 3 then return aukit.stream.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 16, "signed", channels, sampleRate, true, mono)
  1550.     elseif encoding == 4 then return aukit.stream.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 24, "signed", channels, sampleRate, true, mono)
  1551.     elseif encoding == 5 then return aukit.stream.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 32, "signed", channels, sampleRate, true, mono)
  1552.     elseif encoding == 6 then return aukit.stream.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 32, "float", channels, sampleRate, true, mono)
  1553.     else error("unsupported encoding type " .. encoding, 2) end
  1554. end
  1555.  
  1556. --- Returns an iterator to stream data from a FLAC file. Audio will automatically
  1557. -- be resampled to 48 kHz, and optionally mixed down to mono.
  1558. -- @tparam string data The FLAC file to decode
  1559. -- @tparam[opt=false] boolean mono Whether to mix the audio to mono
  1560. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1561. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1562. -- the current position of the audio in seconds
  1563. -- @treturn number The total length of the audio in seconds
  1564. function aukit.stream.flac(data, mono)
  1565.     expect(1, data, "string")
  1566.     expect(2, mono, "boolean", "nil")
  1567.     local coro = coroutine.create(decodeFLAC)
  1568.     local _, sampleRate, len = coroutine.resume(coro, data, coroutine.yield)
  1569.     local pos = 0
  1570.     return function()
  1571.         if coroutine.status(coro) == "dead" then return nil end
  1572.         local chunk = {{}}
  1573.         while #chunk[1] < sampleRate do
  1574.             local ok, res = coroutine.resume(coro)
  1575.             if not ok or res == nil or res.sampleRate then break end
  1576.             sleep(0)
  1577.             for c = 1, #res do
  1578.                 chunk[c] = chunk[c] or {}
  1579.                 local src, dest = res[c], chunk[c]
  1580.                 local start = #dest
  1581.                 for i = 1, #res[c] do dest[start+i] = src[i] end
  1582.             end
  1583.             sleep(0)
  1584.         end
  1585.         local audio = setmetatable({sampleRate = sampleRate, data = chunk}, Audio_mt)
  1586.         if mono and #chunk > 1 then audio = audio:mono() end
  1587.         sleep(0)
  1588.         audio = audio:resample(48000)
  1589.         sleep(0)
  1590.         chunk = {}
  1591.         for c = 1, #audio.data do
  1592.             local src, dest = audio.data[c], {}
  1593.             for i = 1, #src do dest[i] = src[i] * (src[i] < 0 and 128 or 127) end
  1594.             chunk[c] = dest
  1595.         end
  1596.         local p = pos
  1597.         pos = pos + #audio.data[1] / 48000
  1598.         return chunk, p
  1599.     end, len / sampleRate
  1600. end
  1601.  
  1602. --- aukit.effects
  1603. -- @section aukit.effects
  1604.  
  1605. --- Amplifies the audio by the multiplier specified.
  1606. -- @tparam Audio audio The audio to modify
  1607. -- @tparam number multiplier The multiplier to apply
  1608. -- @treturn Audio The audio modified
  1609. function aukit.effects.amplify(audio, multiplier)
  1610.     expectAudio(1, audio)
  1611.     expect(2, multiplier, "number")
  1612.     if multiplier == 1 then return audio end
  1613.     local start = os.epoch "utc"
  1614.     for c = 1, #audio.data do
  1615.         local ch = audio.data[c]
  1616.         for i = 1, #ch do
  1617.             if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  1618.             ch[i] = clamp(ch[i] * multiplier, -1, 1)
  1619.         end
  1620.     end
  1621.     return audio
  1622. end
  1623.  
  1624. --- Changes the speed and pitch of audio by a multiplier, resampling to keep the
  1625. -- same sample rate.
  1626. -- @tparam Audio audio The audio to modify
  1627. -- @tparam number multiplier The multiplier to apply
  1628. -- @treturn Audio The audio modified
  1629. function aukit.effects.speed(audio, multiplier)
  1630.     expectAudio(1, audio)
  1631.     expect(2, multiplier, "number")
  1632.     if multiplier == 1 then return audio end
  1633.     local rate = audio.sampleRate
  1634.     audio.sampleRate = audio.sampleRate * multiplier
  1635.     local new = audio:resample(rate)
  1636.     audio.sampleRate, audio.data = rate, new.data
  1637.     return audio
  1638. end
  1639.  
  1640. --- Fades a period of music from one amplitude to another.
  1641. -- @tparam Audio audio The audio to modify
  1642. -- @tparam number startTime The start time of the fade, in seconds
  1643. -- @tparam number startAmplitude The amplitude of the beginning of the fade
  1644. -- @tparam number endTime The end time of the fade, in seconds
  1645. -- @tparam number endAmplitude The amplitude of the end of the fade
  1646. -- @treturn Audio The audio modified
  1647. function aukit.effects.fade(audio, startTime, startAmplitude, endTime, endAmplitude)
  1648.     expectAudio(1, audio)
  1649.     expect(2, startTime, "number")
  1650.     expect(3, startAmplitude, "number")
  1651.     expect(4, endTime, "number")
  1652.     expect(5, endAmplitude, "number")
  1653.     if startAmplitude == 1 and endAmplitude == 1 then return audio end
  1654.     local startt = os.epoch "utc"
  1655.     for c = 1, #audio.data do
  1656.         local ch = audio.data[c]
  1657.         local start = startTime * audio.sampleRate
  1658.         local m = (endAmplitude - startAmplitude) / ((endTime - startTime) * audio.sampleRate)
  1659.         for i = start, endTime * audio.sampleRate do
  1660.             if os.epoch "utc" - startt > 5000 then startt = os.epoch "utc" sleep(0) end
  1661.             ch[i] = clamp(ch[i] * (m * (i - start) + startAmplitude), -1, 1)
  1662.         end
  1663.     end
  1664.     return audio
  1665. end
  1666.  
  1667. --- Inverts all channels in the specified audio.
  1668. -- @tparam Audio audio The audio to modify
  1669. -- @treturn Audio The audio modified
  1670. function aukit.effects.invert(audio)
  1671.     expectAudio(1, audio)
  1672.     for c = 1, #audio.data do
  1673.         local ch = audio.data[c]
  1674.         for i = 1, #ch do ch[i] = -ch[i] end
  1675.     end
  1676.     return audio
  1677. end
  1678.  
  1679. --- Normalizes audio to the specified peak amplitude.
  1680. -- @tparam Audio audio The audio to modify
  1681. -- @tparam[opt=1] number peakAmplitude The maximum amplitude
  1682. -- @tparam[opt=false] boolean independent Whether to normalize each channel independently
  1683. -- @treturn Audio The audio modified
  1684. function aukit.effects.normalize(audio, peakAmplitude, independent)
  1685.     expectAudio(1, audio)
  1686.     peakAmplitude = expect(2, peakAmplitude, "number", "nil") or 1
  1687.     expect(3, independent, "boolean", "nil")
  1688.     local mult
  1689.     local start, sampleRate = os.epoch "utc", audio.sampleRate
  1690.     if not independent then
  1691.         local max = 0
  1692.         for c = 1, #audio.data do
  1693.             local ch = audio.data[c]
  1694.             if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  1695.             for i = 1, #ch do max = math.max(max, math.abs(ch[i])) end
  1696.         end
  1697.         mult = peakAmplitude / max
  1698.     end
  1699.     for c = 1, #audio.data do
  1700.         local ch = audio.data[c]
  1701.         if independent then
  1702.             local max = 0
  1703.             for i = 1, #ch do max = math.max(max, math.abs(ch[i])) end
  1704.             mult = peakAmplitude / max
  1705.         end
  1706.         if os.epoch "utc" - start > 3000 then start = os.epoch "utc" sleep(0) end
  1707.         for i = 1, #ch do
  1708.             ch[i] = clamp(ch[i] * mult, -1, 1)
  1709.         end
  1710.     end
  1711.     return audio
  1712. end
  1713.  
  1714. --- Centers the DC offset of each channel.
  1715. -- @tparam Audio audio The audio to modify
  1716. -- @treturn Audio The audio modified
  1717. function aukit.effects.center(audio)
  1718.     expectAudio(1, audio)
  1719.     for c = 1, #audio.data do
  1720.         local ch = audio.data[c]
  1721.         for i = 0, #ch - 1, audio.sampleRate do
  1722.             local avg = 0
  1723.             local l = math.min(#ch - i, audio.sampleRate)
  1724.             for j = 1, l do avg = avg + ch[i+j] end
  1725.             avg = avg / l
  1726.             for j = 1, l do ch[i+j] = clamp(ch[i+j] - avg, -1, 1) end
  1727.         end
  1728.     end
  1729.     return audio
  1730. end
  1731.  
  1732. --- Trims any extra silence on either end of the specified audio.
  1733. -- @tparam Audio audio The audio to modify
  1734. -- @tparam[opt=1/65536] number threshold The maximum value to register as silence
  1735. -- @treturn Audio The audio modified
  1736. function aukit.effects.trim(audio, threshold)
  1737.     expectAudio(1, audio)
  1738.     threshold = expect(2, threshold, "number", "nil") or (1/65536)
  1739.     local s, e
  1740.     for i = 1, #audio.data[1] do
  1741.         for c = 1, #audio.data do if math.abs(audio.data[c][i]) > threshold then s = i break end end
  1742.         if s then break end
  1743.     end
  1744.     for i = #audio.data[1], 1, -1 do
  1745.         for c = 1, #audio.data do if math.abs(audio.data[c][i]) > threshold then e = i break end end
  1746.         if e then break end
  1747.     end
  1748.     local new = audio:sub(s / audio.sampleRate, e / audio.sampleRate)
  1749.     audio.data = new.data
  1750.     return audio
  1751. end
  1752.  
  1753. return aukit
  1754.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement