Advertisement
TechManDylan

aukit

Feb 24th, 2023
753
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 100.48 KB | None | 0 0
  1. --- AUKit: Audio decoding and processing framework for ComputerCraft
  2. --
  3. -- AUKit is a framework designed to simplify the process of loading, modifying,
  4. -- and playing audio files in various formats. It includes support for loading
  5. -- audio from many sources, including PCM, DFPWM, and IMA ADPCM codecs, as well
  6. -- as WAV, AIFF, AU, and FLAC files. It can also generate audio on-the-fly as
  7. -- tones, noise, or silence.
  8. --
  9. -- AUKit uses a structure called Audio to store information about each audio
  10. -- chunk. An audio object holds the sample rate of the audio, as well as the
  11. -- data for each channel stored as floating-point numbers. Audio objects can
  12. -- hold any number of channels at any sample rate with any duration.
  13. --
  14. -- To obtain an audio object, you can use any of the main functions in the aukit
  15. -- module. These allow loading from various raw codecs or file formats, with
  16. -- data sources as strings, or tables if using a raw codec loader.
  17. --
  18. -- Once the audio is loaded, various basic operations are available. A subset of
  19. -- the string library is available to simplify operations on the audio, and a
  20. -- number of operators (+, *, .., #) are overridden as well. There's also built-
  21. -- in functions for resampling the audio, with nearest-neighbor, linear, and
  22. -- cubic interpolation available; as well as mixing channels (including down to
  23. -- mono) and combining/splitting channels. Finally, audio objects can be exported
  24. -- back to PCM, DFPWM, or WAV data, allowing changes to be easily stored on disk.
  25. -- The stream function also automatically chunks data for use with a speaker.
  26. -- All of these functions return a new audio object, leaving the original intact.
  27. --
  28. -- There are also a number of effects available for audio. These are contained
  29. -- in the aukit.effects table, and modify the audio passed to them (as well as
  30. -- returning the audio for streamlining). The effects are intended to speed up
  31. -- common operations on audio. More effects may be added in future versions.
  32. --
  33. -- Be aware that processing large amounts of audio (especially loading FLAC or
  34. -- resampling with higher quality) is *very* slow. It's recommended to use audio
  35. -- files with lower data size (8-bit mono PCM/WAV/AIFF is ideal), and potentially
  36. -- a lower sample rate, to reduce the load on the system - especially as all
  37. -- data gets converted to 8-bit DFPWM data on playback anyway. The code yields
  38. -- internally when things take a long time to avoid abort timeouts.
  39. --
  40. -- For an example of how to use AUKit, see the accompanying auplay.lua file.
  41. --
  42. -- @author JackMacWindows
  43. -- @license MIT
  44. --
  45. -- <style>#content {width: unset !important;}</style>
  46. --
  47. -- @module aukit
  48. -- @set project=AUKit
  49.  
  50. -- MIT License
  51. --
  52. -- Copyright (c) 2021-2023 JackMacWindows
  53. --
  54. -- Permission is hereby granted, free of charge, to any person obtaining a copy
  55. -- of this software and associated documentation files (the "Software"), to deal
  56. -- in the Software without restriction, including without limitation the rights
  57. -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  58. -- copies of the Software, and to permit persons to whom the Software is
  59. -- furnished to do so, subject to the following conditions:
  60. --
  61. -- The above copyright notice and this permission notice shall be included in all
  62. -- copies or substantial portions of the Software.
  63. --
  64. -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  65. -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  66. -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  67. -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  68. -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  69. -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  70. -- SOFTWARE.
  71.  
  72. local expect = require "cc.expect"
  73. local dfpwm = require "cc.audio.dfpwm"
  74.  
  75. local bit32_band, bit32_rshift, bit32_btest = bit32.band, bit32.rshift, bit32.btest
  76. local math_floor, math_ceil, math_sin, math_abs, math_fmod = math.floor, math.ceil, math.sin, math.abs, math.fmod
  77. local os_epoch = os.epoch
  78. local str_pack, str_unpack, str_sub, str_byte, str_rep = string.pack, string.unpack, string.sub, string.byte, string.rep
  79. local table_unpack = table.unpack
  80.  
  81. local aukit = {}
  82. aukit.effects, aukit.stream = {}, {}
  83.  
  84. --- @tfield string _VERSION The version of AUKit that is loaded. This follows [SemVer](https://semver.org) format.
  85. aukit._VERSION = "1.4.1"
  86.  
  87. --- @tfield "none"|"linear"|"cubic" defaultInterpolation Default interpolation mode for @{Audio:resample} and other functions that need to resample.
  88. aukit.defaultInterpolation = "linear"
  89.  
  90. --- @type Audio
  91. local Audio = {}
  92. local Audio_mt
  93.  
  94. --- @tfield number sampleRate The sample rate of the audio.
  95. Audio.sampleRate = nil
  96.  
  97. --- @tfield table metadata Stores any metadata read from the file if present.
  98. Audio.metadata = nil
  99.  
  100. --- @tfield table info Stores any decoder-specific information, including `bitDepth` and `dataType`.
  101. Audio.info = nil
  102.  
  103. local dfpwmUUID = "3ac1fa38-811d-4361-a40d-ce53ca607cd1" -- UUID for DFPWM in WAV files
  104.  
  105. local function uuidBytes(uuid) return uuid:gsub("-", ""):gsub("%x%x", function(c) return string.char(tonumber(c, 16)) end) end
  106.  
  107. local wavExtensible = {
  108.     dfpwm = uuidBytes(dfpwmUUID),
  109.     pcm = uuidBytes "01000000-0000-1000-8000-00aa00389b71",
  110.     adpcm = uuidBytes "02000000-0000-1000-8000-00aa00389b71",
  111.     pcm_float = uuidBytes "03000000-0000-1000-8000-00aa00389b71"
  112. }
  113.  
  114. local wavExtensibleChannels = {
  115.     0x04,
  116.     0x03,
  117.     0x07,
  118.     0x33,
  119.     0x37,
  120.     0x3F,
  121.     0x637,
  122.     0x63F,
  123.     0x50F7,
  124.     0x50FF,
  125.     0x56F7,
  126.     0x56FF
  127. }
  128.  
  129. local ima_index_table = {
  130.     [0] = -1, -1, -1, -1, 2, 4, 6, 8,
  131.     -1, -1, -1, -1, 2, 4, 6, 8
  132. }
  133.  
  134. local ima_step_table = {
  135.     [0] = 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
  136.     19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
  137.     50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
  138.     130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
  139.     337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
  140.     876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
  141.     2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
  142.     5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
  143.     15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
  144. }
  145.  
  146. local flacMetadata = {
  147.     tracknumber = "trackNumber",
  148.     ["encoded-by"] = "encodedBy",
  149.     sourcemedia = "sourceMedia",
  150.     labelno = "labelNumber",
  151.     discnumber = "discNumber",
  152.     partnumber = "partNumber",
  153.     productnumber = "productNumber",
  154.     catalognumber = "catalogNumber",
  155.     ["release date"] = "releaseDate",
  156.     ["source medium"] = "sourceMedium",
  157.     ["source artist"] = "sourceArtist",
  158.     ["guest artist"] = "guestArtist",
  159.     ["source work"] = "sourceWork",
  160.     disctotal = "discCount",
  161.     tracktotal = "trackCount",
  162.     parttotal = "partCount",
  163.     tcm = "composer"
  164. }
  165.  
  166. local wavMetadata = {
  167.     IPRD = "album",
  168.     INAM = "title",
  169.     IART = "artist",
  170.     IWRI = "author",
  171.     IMUS = "composer",
  172.     IPRO = "producer",
  173.     IPRT = "trackNumber",
  174.     ITRK = "trackNumber",
  175.     IFRM = "trackCount",
  176.     PRT1 = "partNumber",
  177.     PRT2 = "partCount",
  178.     TLEN = "length",
  179.     IRTD = "rating",
  180.     ICRD = "date",
  181.     ITCH = "encodedBy",
  182.     ISFT = "encoder",
  183.     ISRF = "media",
  184.     IGNR = "genre",
  185.     ICMT = "comment",
  186.     ICOP = "copyright",
  187.     ILNG = "language"
  188. }
  189.  
  190. local function utf8decode(str, pos)
  191.     local codes = {utf8.codepoint(str, 1, -1)}
  192.     for i, v in ipairs(codes) do if v > 0xFF then codes[i] = 0x3F end end
  193.     return string.char(table_unpack(codes)), pos
  194. end
  195.  
  196. local function clamp(n, min, max) return math.max(math.min(n, max), min) end
  197.  
  198. local function expectAudio(n, var)
  199.     if type(var) == "table" and getmetatable(var) == Audio_mt then return var end
  200.     expect(n, var, "Audio") -- always fails
  201. end
  202.  
  203. local function copy(tab)
  204.     local t = {}
  205.     for k, v in pairs(tab) do t[k] = v end
  206.     return t
  207. end
  208.  
  209. local function intunpack(str, pos, sz, signed, be)
  210.     local n = 0
  211.     if be then for i = 0, sz - 1 do n = n * 256 + str_byte(str, pos+i) end
  212.     else for i = 0, sz - 1 do n = n + str_byte(str, pos+i) * 2^(8*i) end end
  213.     if signed and n >= 2^(sz*8-1) then n = n - 2^(sz*8) end
  214.     return n, pos + sz
  215. end
  216.  
  217. local interpolate = {
  218.     none = function(data, x)
  219.         return data[math_floor(x)]
  220.     end,
  221.     linear = function(data, x)
  222.         return data[math_floor(x)] + ((data[math_ceil(x)] or data[math_floor(x)]) - data[math_floor(x)]) * (x - math_floor(x))
  223.     end,
  224.     cubic = function(data, x)
  225.         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)
  226.         p0, p2, p3 = p0 or p1, p2 or p1, p3 or p2 or p1
  227.         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
  228.     end
  229. }
  230. local interpolation_start = {none = 1, linear = 1, cubic = 0}
  231. local interpolation_end = {none = 1, linear = 2, cubic = 3}
  232.  
  233. local wavegen = {
  234.     sine = function(x, freq, amplitude)
  235.         return math_sin(2 * x * math.pi * freq) * amplitude
  236.     end,
  237.     triangle = function(x, freq, amplitude)
  238.         return 2.0 * math_abs(amplitude * math_fmod(2.0 * x * freq + 1.5, 2.0) - amplitude) - amplitude
  239.     end,
  240.     square = function(x, freq, amplitude, duty)
  241.         if (x * freq) % 1 >= duty then return -amplitude else return amplitude end
  242.     end,
  243.     sawtooth = function(x, freq, amplitude)
  244.         return amplitude * math_fmod(2.0 * x * freq + 1.0, 2.0) - amplitude
  245.     end
  246. }
  247.  
  248. local decodeFLAC do
  249.  
  250.     -- Simple FLAC decoder (Java)
  251.     --
  252.     -- Copyright (c) 2017 Project Nayuki. (MIT License)
  253.     -- https://www.nayuki.io/page/simple-flac-implementation
  254.     --
  255.     -- Permission is hereby granted, free of charge, to any person obtaining a copy of
  256.     -- this software and associated documentation files (the "Software"), to deal in
  257.     -- the Software without restriction, including without limitation the rights to
  258.     -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  259.     -- the Software, and to permit persons to whom the Software is furnished to do so,
  260.     -- subject to the following conditions:
  261.     -- - The above copyright notice and this permission notice shall be included in
  262.     --   all copies or substantial portions of the Software.
  263.     -- - The Software is provided "as is", without warranty of any kind, express or
  264.     --   implied, including but not limited to the warranties of merchantability,
  265.     --   fitness for a particular purpose and noninfringement. In no event shall the
  266.     --   authors or copyright holders be liable for any claim, damages or other
  267.     --   liability, whether in an action of contract, tort or otherwise, arising from,
  268.     --   out of or in connection with the Software or the use or other dealings in the
  269.     --   Software.
  270.  
  271.     local FIXED_PREDICTION_COEFFICIENTS = {
  272.         {},
  273.         {1},
  274.         {2, -1},
  275.         {3, -3, 1},
  276.         {4, -6, 4, -1},
  277.     };
  278.  
  279.     local function BitInputStream(data, pos)
  280.         local obj = {}
  281.         local bitBuffer, bitBufferLen = 0, 0
  282.         function obj.alignToByte()
  283.             bitBufferLen = bitBufferLen - bitBufferLen % 8
  284.         end
  285.         function obj.readByte()
  286.             return obj.readUint(8)
  287.         end
  288.         function obj.readUint(n)
  289.             if n == 0 then return 0 end
  290.             while bitBufferLen < n do
  291.                 local temp = str_byte(data, pos)
  292.                 pos = pos + 1
  293.                 if temp == nil then return nil end
  294.                 bitBuffer = (bitBuffer * 256 + temp) % 0x100000000000
  295.                 bitBufferLen = bitBufferLen + 8
  296.             end
  297.             bitBufferLen = bitBufferLen - n
  298.             local result = math_floor(bitBuffer / 2^bitBufferLen)
  299.             if n < 32 then result = result % 2^n end
  300.             return result
  301.         end
  302.         function obj.readSignedInt(n)
  303.             local v = obj.readUint(n)
  304.             if v >= 2^(n-1) then v = v - 2^n end
  305.             return v
  306.         end
  307.         function obj.readRiceSignedInt(param)
  308.             local val = 0
  309.             while (obj.readUint(1) == 0) do val = val + 1 end
  310.             val = val * 2^param + obj.readUint(param)
  311.             if bit32_btest(val, 1) then return -math_floor(val / 2) - 1
  312.             else return math_floor(val / 2) end
  313.         end
  314.         return obj
  315.     end
  316.  
  317.     local function decodeResiduals(inp, warmup, blockSize, result)
  318.         local method = inp.readUint(2);
  319.         if (method >= 2) then error("Reserved residual coding method " .. method) end
  320.         local paramBits = method == 0 and 4 or 5;
  321.         local escapeParam = method == 0 and 0xF or 0x1F;
  322.  
  323.         local partitionOrder = inp.readUint(4);
  324.         local numPartitions = 2^partitionOrder;
  325.         if (blockSize % numPartitions ~= 0) then
  326.             error("Block size not divisible by number of Rice partitions")
  327.         end
  328.         local partitionSize = math_floor(blockSize / numPartitions);
  329.  
  330.         for i = 0, numPartitions-1 do
  331.             local start = i * partitionSize + (i == 0 and warmup or 0);
  332.             local endd = (i + 1) * partitionSize;
  333.  
  334.             local param = inp.readUint(paramBits);
  335.             if (param < escapeParam) then
  336.                 for j = start, endd - 1 do
  337.                     result[j+1] = inp.readRiceSignedInt(param)
  338.                 end
  339.             else
  340.                 local numBits = inp.readUint(5);
  341.                 for j = start, endd - 1 do
  342.                     result[j+1] = inp.readSignedInt(numBits)
  343.                 end
  344.             end
  345.         end
  346.     end
  347.  
  348.     local function restoreLinearPrediction(result, coefs, shift, blockSize)
  349.         for i = #coefs, blockSize - 1 do
  350.             local sum = 0
  351.             for j = 0, #coefs - 1 do
  352.                 sum = sum + result[i - j] * coefs[j + 1]
  353.             end
  354.             result[i + 1] = result[i + 1] + math_floor(sum / 2^shift)
  355.         end
  356.     end
  357.  
  358.     local function decodeFixedPredictionSubframe(inp, predOrder, sampleDepth, blockSize, result)
  359.         for i = 1, predOrder do
  360.             result[i] = inp.readSignedInt(sampleDepth);
  361.         end
  362.         decodeResiduals(inp, predOrder, blockSize, result);
  363.         restoreLinearPrediction(result, FIXED_PREDICTION_COEFFICIENTS[predOrder+1], 0, blockSize);
  364.     end
  365.  
  366.     local function decodeLinearPredictiveCodingSubframe(inp, lpcOrder, sampleDepth, blockSize, result)
  367.         for i = 1, lpcOrder do
  368.             result[i] = inp.readSignedInt(sampleDepth);
  369.         end
  370.         local precision = inp.readUint(4) + 1;
  371.         local shift = inp.readSignedInt(5);
  372.         local coefs = {};
  373.         for i = 1, lpcOrder do
  374.             coefs[i] = inp.readSignedInt(precision);
  375.         end
  376.         decodeResiduals(inp, lpcOrder, blockSize, result);
  377.         restoreLinearPrediction(result, coefs, shift, blockSize);
  378.     end
  379.  
  380.     local function decodeSubframe(inp, sampleDepth, blockSize, result)
  381.         inp.readUint(1);
  382.         local type = inp.readUint(6);
  383.         local shift = inp.readUint(1);
  384.         if (shift == 1) then
  385.             while (inp.readUint(1) == 0) do shift = shift + 1 end
  386.         end
  387.         sampleDepth = sampleDepth - shift
  388.  
  389.         if (type == 0) then  -- Constant coding
  390.             local c = inp.readSignedInt(sampleDepth)
  391.             for i = 1, blockSize do result[i] = c end
  392.         elseif (type == 1) then  -- Verbatim coding
  393.             for i = 1, blockSize do
  394.                 result[i] = inp.readSignedInt(sampleDepth);
  395.             end
  396.         elseif (8 <= type and type <= 12) then
  397.             decodeFixedPredictionSubframe(inp, type - 8, sampleDepth, blockSize, result)
  398.         elseif (32 <= type and type <= 63) then
  399.             decodeLinearPredictiveCodingSubframe(inp, type - 31, sampleDepth, blockSize, result)
  400.         else
  401.             error("Reserved subframe type")
  402.         end
  403.  
  404.         for i = 1, blockSize do
  405.             result[i] = result[i] * 2^shift
  406.         end
  407.     end
  408.  
  409.     local function decodeSubframes(inp, sampleDepth, chanAsgn, blockSize, result)
  410.         local subframes = {}
  411.         for i = 1, #result do subframes[i] = {} end
  412.         if (0 <= chanAsgn and chanAsgn <= 7) then
  413.             for ch = 1, #result do
  414.                 decodeSubframe(inp, sampleDepth, blockSize, subframes[ch])
  415.             end
  416.         elseif (8 <= chanAsgn and chanAsgn <= 10) then
  417.             decodeSubframe(inp, sampleDepth + (chanAsgn == 9 and 1 or 0), blockSize, subframes[1])
  418.             decodeSubframe(inp, sampleDepth + (chanAsgn == 9 and 0 or 1), blockSize, subframes[2])
  419.             if (chanAsgn == 8) then
  420.                 for i = 1, blockSize do
  421.                     subframes[2][i] = subframes[1][i] - subframes[2][i]
  422.                 end
  423.             elseif (chanAsgn == 9) then
  424.                 for i = 1, blockSize do
  425.                     subframes[1][i] = subframes[1][i] + subframes[2][i]
  426.                 end
  427.             elseif (chanAsgn == 10) then
  428.                 for i = 1, blockSize do
  429.                     local side = subframes[2][i]
  430.                     local right = subframes[1][i] - math_floor(side / 2)
  431.                     subframes[2][i] = right
  432.                     subframes[1][i] = right + side
  433.                 end
  434.             end
  435.         else
  436.             error("Reserved channel assignment");
  437.         end
  438.         for ch = 1, #result do
  439.             for i = 1, blockSize do
  440.                 local s = subframes[ch][i]
  441.                 if s >= 2^(sampleDepth-1) then s = s - 2^sampleDepth end
  442.                 result[ch][i] = s / 2^sampleDepth
  443.             end
  444.         end
  445.     end
  446.  
  447.     local function decodeFrame(inp, numChannels, sampleDepth, out2, callback)
  448.         local out = {}
  449.         for i = 1, numChannels do out[i] = {} end
  450.         -- Read a ton of header fields, and ignore most of them
  451.         local temp = inp.readByte()
  452.         if temp == nil then
  453.             return false
  454.         end
  455.         local sync = temp * 64 + inp.readUint(6);
  456.         if sync ~= 0x3FFE then error("Sync code expected") end
  457.  
  458.         inp.readUint(2);
  459.         local blockSizeCode = inp.readUint(4);
  460.         local sampleRateCode = inp.readUint(4);
  461.         local chanAsgn = inp.readUint(4);
  462.         inp.readUint(4);
  463.  
  464.         temp = inp.readUint(8);
  465.         local t2 = -1
  466.         for i = 7, 0, -1 do if not bit32_btest(temp, 2^i) then break end t2 = t2 + 1 end
  467.         for i = 1, t2 do inp.readUint(8) end
  468.  
  469.         local blockSize
  470.         if (blockSizeCode == 1) then
  471.             blockSize = 192
  472.         elseif (2 <= blockSizeCode and blockSizeCode <= 5) then
  473.             blockSize = 576 * 2^(blockSizeCode - 2)
  474.         elseif (blockSizeCode == 6) then
  475.             blockSize = inp.readUint(8) + 1
  476.         elseif (blockSizeCode == 7) then
  477.             blockSize = inp.readUint(16) + 1
  478.         elseif (8 <= blockSizeCode and blockSizeCode <= 15) then
  479.             blockSize = 256 * 2^(blockSizeCode - 8)
  480.         else
  481.             error("Reserved block size")
  482.         end
  483.  
  484.         if (sampleRateCode == 12) then
  485.             inp.readUint(8)
  486.         elseif (sampleRateCode == 13 or sampleRateCode == 14) then
  487.             inp.readUint(16)
  488.         end
  489.  
  490.         inp.readUint(8)
  491.  
  492.         decodeSubframes(inp, sampleDepth, chanAsgn, blockSize, out)
  493.         inp.alignToByte()
  494.         inp.readUint(16)
  495.  
  496.         if callback then callback(out) else
  497.             for c = 1, numChannels do
  498.                 local n = #out2[c]
  499.                 for i = 1, blockSize do out2[c][n+i] = out[c][i] end
  500.             end
  501.         end
  502.  
  503.         return true
  504.     end
  505.  
  506.     function decodeFLAC(inp, callback)
  507.         local out = {}
  508.         local pos = 1
  509.         -- Handle FLAC header and metadata blocks
  510.         local temp temp, pos = intunpack(inp, pos, 4, false, true)
  511.         if temp ~= 0x664C6143 then error("Invalid magic string") end
  512.         local sampleRate, numChannels, sampleDepth, numSamples
  513.         local last = false
  514.         local meta = {}
  515.         while not last do
  516.             temp, pos = inp:byte(pos), pos + 1
  517.             last = bit32_btest(temp, 0x80)
  518.             local type = bit32_band(temp, 0x7F);
  519.             local length length, pos = intunpack(inp, pos, 3, false, true)
  520.             if type == 0 then  -- Stream info block
  521.                 pos = pos + 10
  522.                 sampleRate, pos = intunpack(inp, pos, 2, false, true)
  523.                 sampleRate = sampleRate * 16 + bit32_rshift(inp:byte(pos), 4)
  524.                 numChannels = bit32_band(bit32_rshift(inp:byte(pos), 1), 7) + 1;
  525.                 sampleDepth = bit32_band(inp:byte(pos), 1) * 16 + bit32_rshift(inp:byte(pos+1), 4) + 1;
  526.                 numSamples, pos = intunpack(inp, pos + 2, 4, false, true)
  527.                 numSamples = numSamples + bit32_band(inp:byte(pos-5), 15) * 2^32
  528.                 pos = pos + 16
  529.             elseif type == 4 then
  530.                 local ncomments
  531.                 meta.vendor, ncomments, pos = ("<s4I4"):unpack(inp, pos)
  532.                 for i = 1, ncomments do
  533.                     local str
  534.                     str, pos = utf8decode(("<s4"):unpack(inp, pos))
  535.                     local k, v = str:match "^([^=]+)=(.*)$"
  536.                     if k then meta[flacMetadata[k:lower()] or k:lower()] = v end
  537.                 end
  538.             else
  539.                 pos = pos + length
  540.             end
  541.         end
  542.         if not sampleRate then error("Stream info metadata block absent") end
  543.         if sampleDepth % 8 ~= 0 then error("Sample depth not supported") end
  544.  
  545.         for i = 1, numChannels do out[i] = {} end
  546.  
  547.         if callback then callback(sampleRate, numSamples) end
  548.  
  549.         -- Decode FLAC audio frames and write raw samples
  550.         inp = BitInputStream(inp, pos)
  551.         repeat until not decodeFrame(inp, numChannels, sampleDepth, out, callback)
  552.         if not callback then return {sampleRate = sampleRate, data = out, metadata = meta, info = {bitDepth = sampleDepth, dataType = "signed"}} end
  553.     end
  554.  
  555. end
  556.  
  557. --- Returns the length of the audio object in seconds.
  558. -- @treturn number The audio length
  559. function Audio:len()
  560.     return #self.data[1] / self.sampleRate
  561. end
  562.  
  563. --- Returns the number of channels in the audio object.
  564. -- @treturn number The number of channels
  565. function Audio:channels()
  566.     return #self.data
  567. end
  568.  
  569. --- Creates a new audio object with the data resampled to a different sample rate.
  570. -- If the target rate is the same, the object is copied without modification.
  571. -- @tparam number sampleRate The new sample rate in Hertz
  572. -- @tparam[opt=aukit.defaultInterpolation] "none"|"linear"|"cubic" interpolation The interpolation mode to use
  573. -- @treturn Audio A new audio object with the resampled data
  574. function Audio:resample(sampleRate, interpolation)
  575.     expect(1, sampleRate, "number")
  576.     interpolation = expect(2, interpolation, "string", "nil") or aukit.defaultInterpolation
  577.     if interpolation ~= "none" and interpolation ~= "linear" and interpolation ~= "cubic" then error("bad argument #2 (invalid interpolation type)", 2) end
  578.     local new = setmetatable({sampleRate = sampleRate, data = {}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  579.     local ratio = sampleRate / self.sampleRate
  580.     local newlen = #self.data[1] * ratio
  581.     local interp = interpolate[interpolation]
  582.     local start = os_epoch "utc"
  583.     for y, c in ipairs(self.data) do
  584.         local line = {}
  585.         for i = 1, newlen do
  586.             if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  587.             local x = (i - 1) / ratio + 1
  588.             if x % 1 == 0 then line[i] = c[x]
  589.             else line[i] = clamp(interp(c, x), -1, 1) end
  590.         end
  591.         new.data[y] = line
  592.     end
  593.     return new
  594. end
  595.  
  596. --- Mixes down all channels to a new mono-channel audio object.
  597. -- @treturn Audio A new audio object with the audio mixed to mono
  598. function Audio:mono()
  599.     local new = setmetatable({sampleRate = self.sampleRate, data = {{}}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  600.     local ndata = new.data[1]
  601.     local cn = #self.data
  602.     local start = os_epoch "utc"
  603.     for i = 1, #self.data[1] do
  604.         if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  605.         local s = 0
  606.         for c = 1, cn do s = s + self.data[c][i] end
  607.         ndata[i] = s / cn
  608.     end
  609.     return new
  610. end
  611.  
  612. --- Concatenates this audio object with another, adding the contents of each
  613. -- new channel to the end of each old channel, resampling the new channels to match
  614. -- this one (if necessary), and inserting silence in any missing channels.
  615. -- @tparam Audio ... The audio objects to concatenate
  616. -- @treturn Audio The new concatenated audio object
  617. function Audio:concat(...)
  618.     local audios = {self, ...}
  619.     local l = {#self.data[1]}
  620.     local cn = #self.data
  621.     for i = 2, #audios do
  622.         expectAudio(i-1, audios[i])
  623.         if audios[i].sampleRate ~= self.sampleRate then audios[i] = audios[i]:resample(self.sampleRate) end
  624.         l[i] = #audios[i].data[1]
  625.         cn = math.max(cn, #audios[i].data)
  626.     end
  627.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  628.     for c = 1, cn do
  629.         local ch = {}
  630.         local pos = 0
  631.         for a = 1, #audios do
  632.             local sch = audios[a].data[c]
  633.             if sch then for i = 1, l[a] do ch[pos+i] = sch[i] end
  634.             else for i = 1, l[a] do ch[pos+i] = 0 end end
  635.             pos = pos + l[a]
  636.         end
  637.         obj.data[c] = ch
  638.     end
  639.     return obj
  640. end
  641.  
  642. --- Takes a subregion of the audio and returns a new audio object with its contents.
  643. -- This takes the same arguments as @{string.sub}, but positions start at 0.
  644. -- @tparam[opt=0] number start The start position of the audio in seconds
  645. -- @tparam[opt=0] number last The end position of the audio in seconds (0 means end of file)
  646. -- @treturn Audio The new split audio object
  647. function Audio:sub(start, last)
  648.     start = math_floor(expect(1, start, "number", "nil") or 0)
  649.     last = math_floor(expect(2, last, "number", "nil") or 0)
  650.     local len = #self.data[1] / self.sampleRate
  651.     if start < 0 then start = len + start end
  652.     if last <= 0 then last = len + last end
  653.     expect.range(start, 0, len)
  654.     expect.range(last, 0, len)
  655.     start, last = start * self.sampleRate + 1, last * self.sampleRate + 1
  656.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  657.     for c = 1, #self.data do
  658.         local ch = {}
  659.         local sch = self.data[c]
  660.         for i = start, last do ch[i-start+1] = sch[i] end
  661.         obj.data[c] = ch
  662.     end
  663.     return obj
  664. end
  665.  
  666. --- Combines the channels of this audio object with another, adding the new
  667. -- channels on the end of the new object, resampling the new channels to match
  668. -- this one (if necessary), and extending any channels that are shorter than the
  669. -- longest channel with zeroes.
  670. -- @tparam Audio ... The audio objects to combine with
  671. -- @treturn Audio The new combined audio object
  672. function Audio:combine(...)
  673.     local audios = {self, ...}
  674.     local len = #self.data[1]
  675.     for i = 2, #audios do
  676.         expectAudio(i-1, audios[i])
  677.         if audios[i].sampleRate ~= self.sampleRate then audios[i] = audios[i]:resample(self.sampleRate) end
  678.         len = math.max(len, #audios[i].data[1])
  679.     end
  680.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  681.     local pos = 0
  682.     for a = 1, #audios do
  683.         for c = 1, #audios[a].data do
  684.             local sch, ch = audios[a].data[c], {}
  685.             for i = 1, len do ch[i] = sch[i] or 0 end
  686.             obj.data[pos+c] = ch
  687.         end
  688.         pos = pos + #audios[a].data
  689.     end
  690.     return obj
  691. end
  692.  
  693. --- Splits this audio object into one or more objects with the specified channels.
  694. -- Passing a channel that doesn't exist will throw an error.
  695. -- @tparam {[number]...} ... The lists of channels in each new object
  696. -- @treturn Audio... The new audio objects created from the channels in each list
  697. -- @usage Split a stereo track into independent mono objects
  698. --
  699. --     local left, right = stereo:split({1}, {2})
  700. function Audio:split(...)
  701.     local retval = {}
  702.     for n, cl in ipairs{...} do
  703.         expect(n, cl, "table")
  704.         if #cl == 0 then error("bad argument #" .. n .. " (cannot use empty table)") end
  705.         local obj = setmetatable({sampleRate = self.sampleRate, data = {}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  706.         for cd, cs in ipairs(cl) do
  707.             local sch, ch = self.data[expect(cd, cs, "number")], {}
  708.             if not sch then error("channel " .. cs .. " (in argument " .. n .. ") out of range", 2) end
  709.             for i = 1, #sch do ch[i] = sch[i] end
  710.             obj.data[cd] = ch
  711.         end
  712.         retval[#retval+1] = obj
  713.     end
  714.     return table_unpack(retval)
  715. end
  716.  
  717. --- Mixes two or more audio objects into a single object, amplifying each sample
  718. -- with a multiplier (before clipping) if desired, and clipping any values
  719. -- outside the audio range ([-1, 1]). Channels that are shorter are padded with
  720. -- zeroes at the end, and non-existent channels are replaced with all zeroes.
  721. -- Any audio objects with a different sample rate are resampled to match this one.
  722. -- @tparam number|Audio amplifier The multiplier to apply, or the first audio object
  723. -- @tparam[opt] Audio ... The objects to mix with this one
  724. -- @treturn Audio The new mixed audio object
  725. function Audio:mix(amplifier, ...)
  726.     local audios = {self, ...}
  727.     local len = #self.data[1]
  728.     local cn = #self.data
  729.     for i = 2, #audios do
  730.         expectAudio(i, audios[i])
  731.         if audios[i].sampleRate ~= self.sampleRate then audios[i] = audios[i]:resample(self.sampleRate) end
  732.         len = math.max(len, #audios[i].data[1])
  733.         cn = math.max(cn, #audios[i].data)
  734.     end
  735.     if type(amplifier) ~= "number" then
  736.         expectAudio(1, amplifier)
  737.         if amplifier.sampleRate ~= self.sampleRate then amplifier = amplifier:resample(self.sampleRate) end
  738.         len = math.max(len, #amplifier.data[1])
  739.         cn = math.max(cn, #amplifier.data)
  740.         table.insert(audios, 2, amplifier)
  741.         amplifier = 1
  742.     end
  743.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  744.     for c = 1, cn do
  745.         local ch = {}
  746.         local sch = {}
  747.         for a = 1, #audios do sch[a] = audios[a].data[c] end
  748.         for i = 1, len do
  749.             local s = 0
  750.             for a = 1, #audios do if sch[a] then s = s + (sch[a][i] or 0) end end
  751.             ch[i] = clamp(s * amplifier, -1, 1)
  752.         end
  753.         obj.data[c] = ch
  754.     end
  755.     return obj
  756. end
  757.  
  758. --- Returns a new audio object that repeats this audio a number of times.
  759. -- @tparam number count The number of times to play the audio
  760. -- @treturn Audio The repeated audio
  761. function Audio:rep(count)
  762.     if type(self) ~= "table" and type(count) == "table" then self, count = count, self end
  763.     expect(1, count, "number")
  764.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  765.     for c = 1, #self.data do
  766.         local sch, ch = self.data[c], {}
  767.         for n = 0, count - 1 do
  768.             local pos = n * #sch
  769.             for i = 1, #sch do ch[pos+i] = sch[i] end
  770.         end
  771.         obj.data[c] = ch
  772.     end
  773.     return obj
  774. end
  775.  
  776. --- Returns a reversed version of this audio.
  777. -- @treturn Audio The reversed audio
  778. function Audio:reverse()
  779.     local obj = setmetatable({sampleRate = self.sampleRate, data = {}, metadata = copy(self.metadata), info = copy(self.info)}, Audio_mt)
  780.     for c = 1, #self.data do
  781.         local sch, ch = self.data[c], {}
  782.         local len = #sch
  783.         for i = 1, len do ch[len-i+1] = sch[i] end
  784.         obj.data[c] = ch
  785.     end
  786.     return obj
  787. end
  788.  
  789. local function encodePCM(info, pos)
  790.     local maxValue = 2^(info.bitDepth-1)
  791.     local add = info.dataType == "unsigned" and maxValue or 0
  792.     local source = info.audio.data
  793.     local encode
  794.     if info.dataType == "float" then encode = function(d) return d end
  795.     else encode = function(d) return d * (d < 0 and maxValue or maxValue-1) + add end end
  796.     local data = {}
  797.     local nc = #source
  798.     local len = #source[1]
  799.     if pos > len then return nil end
  800.     local start = os_epoch "utc"
  801.     if info.interleaved then for n = pos, pos + info.len - 1 do if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end for c = 1, nc do data[(n-1)*nc+c] = encode(source[c][n]) end end
  802.     elseif info.multiple then
  803.         for c = 1, nc do
  804.             data[c] = {}
  805.             for n = pos, pos + info.len - 1 do
  806.                 if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  807.                 local s = source[c][n]
  808.                 if not s then break end
  809.                 data[c][n-pos+1] = encode(s)
  810.             end
  811.         end
  812.         return pos + info.len, table_unpack(data)
  813.     else for c = 1, nc do for n = pos, pos + info.len - 1 do if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end data[(c-1)*len+n] = encode(source[c][n]) end end end
  814.     return data
  815. end
  816.  
  817. --- Converts the audio data to raw PCM samples.
  818. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32)
  819. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  820. -- @tparam[opt=true] boolean interleaved Whether to interleave each channel
  821. -- @treturn {[number]...} The resulting audio data
  822. function Audio:pcm(bitDepth, dataType, interleaved)
  823.     bitDepth = expect(1, bitDepth, "number", "nil") or 8
  824.     dataType = expect(2, dataType, "string", "nil") or "signed"
  825.     expect(3, interleaved, "boolean", "nil")
  826.     if interleaved == nil then interleaved = true end
  827.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  828.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  829.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  830.     return encodePCM({audio = self, bitDepth = bitDepth, dataType = dataType, interleaved = interleaved, len = #self.data[1]}, 1)
  831. end
  832.  
  833. --- Returns a function that can be called to encode PCM samples in chunks.
  834. -- This is useful as a for iterator, and can be used with @{aukit.play}.
  835. -- @tparam[opt=131072] number chunkSize The size of each chunk
  836. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32)
  837. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  838. -- @treturn function():{{[number]...}...},number An iterator function that returns
  839. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  840. -- the current position of the audio in seconds
  841. -- @treturn number The total length of the audio in seconds
  842. function Audio:stream(chunkSize, bitDepth, dataType)
  843.     chunkSize = expect(1, chunkSize, "number", "nil") or 131072
  844.     bitDepth = expect(2, bitDepth, "number", "nil") or 8
  845.     dataType = expect(3, dataType, "string", "nil") or "signed"
  846.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  847.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  848.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  849.     local info, pos = {audio = self, bitDepth = bitDepth, dataType = dataType, interleaved = false, multiple = true, len = chunkSize}, 1
  850.     return function()
  851.         if info == nil then return nil end
  852.         local p = pos / self.sampleRate
  853.         local v = {encodePCM(info, pos)}
  854.         if v[1] == nil then info = nil return nil end
  855.         pos = table.remove(v, 1)
  856.         return v, p
  857.     end, #self.data[1] / self.sampleRate
  858. end
  859.  
  860. --- Coverts the audio data to a WAV file.
  861. -- @tparam[opt=16] number bitDepth The bit depth of the audio (1 = DFPWM, 8, 16, 24, 32)
  862. -- @treturn string The resulting WAV file data
  863. function Audio:wav(bitDepth)
  864.     -- TODO: Support float data
  865.     bitDepth = expect(1, bitDepth, "number", "nil") or 16
  866.     if bitDepth == 1 then
  867.         local str = self:dfpwm(true)
  868.         return ("<c4Ic4c4IHHIIHHHHIc16c4IIc4I"):pack(
  869.             "RIFF", #str + 72, "WAVE",
  870.             "fmt ", 40, 0xFFFE, #self.data, self.sampleRate, self.sampleRate * #self.data / 8, math_ceil(#self.data / 8), 1,
  871.                 22, 1, wavExtensibleChannels[#self.data] or 0, wavExtensible.dfpwm,
  872.             "fact", 4, #self.data[1],
  873.             "data", #str) .. str
  874.     elseif bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  875.     local data = self:pcm(bitDepth, bitDepth == 8 and "unsigned" or "signed", true)
  876.     local str = ""
  877.     local csize = jit and 7680 or 32768
  878.     local format = ((bitDepth == 8 and "I" or "i") .. (bitDepth / 8)):rep(csize)
  879.     for i = 1, #data - csize, csize do str = str .. format:pack(table_unpack(data, i, i + csize - 1)) end
  880.     str = str .. ((bitDepth == 8 and "I" or "i") .. (bitDepth / 8)):rep(#data % csize):pack(table_unpack(data, math_floor(#data / csize) * csize))
  881.     return ("<c4Ic4c4IHHIIHHc4I"):pack("RIFF", #str + 36, "WAVE", "fmt ", 16, 1, #self.data, self.sampleRate, self.sampleRate * #self.data * bitDepth / 8, #self.data * bitDepth / 8, bitDepth, "data", #str) .. str
  882. end
  883.  
  884. --- Converts the audio data to DFPWM. All channels share the same encoder, and
  885. -- channels are stored sequentially uninterleaved if `interleaved` is false, or
  886. -- in one interleaved string if `interleaved` is true.
  887. -- @tparam[opt=true] boolean interleaved Whether to interleave the channels
  888. -- @treturn string... The resulting DFPWM data for each channel (only one string
  889. -- if `interleaved` is true)
  890. function Audio:dfpwm(interleaved)
  891.     expect(1, interleaved, "boolean", "nil")
  892.     if interleaved == nil then interleaved = true end
  893.     if interleaved then
  894.         return dfpwm.encode(self:pcm(8, "signed", true))
  895.     else
  896.         local channels = {self:pcm(8, "signed", false)}
  897.         local encode = dfpwm.make_encoder()
  898.         for i = 1, #channels do channels[i] = encode(channels[i]) end
  899.         return table_unpack(channels)
  900.     end
  901. end
  902.  
  903. Audio_mt = {__index = Audio, __add = Audio.combine, __mul = Audio.rep, __concat = Audio.concat, __len = Audio.len, __name = "Audio"}
  904.  
  905. function Audio_mt:__tostring()
  906.     return "Audio: " .. self.sampleRate .. " Hz, " .. #self.data .. " channels, " .. (#self.data[1] / self.sampleRate) .. " seconds"
  907. end
  908.  
  909. --- aukit
  910. -- @section aukit
  911.  
  912. --- Creates a new audio object from the specified raw PCM data.
  913. -- @tparam string|table data The audio data, either as a raw string, or a table
  914. -- of values (in the format specified by `bitDepth` and `dataType`)
  915. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32); if `dataType` is "float" then this must be 32
  916. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  917. -- @tparam[opt=1] number channels The number of channels present in the audio
  918. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  919. -- @tparam[opt=true] boolean interleaved Whether each channel is interleaved or separate
  920. -- @tparam[opt=false] boolean bigEndian Whether the audio is big-endian or little-endian; ignored if data is a table
  921. -- @treturn Audio A new audio object containing the specified data
  922. function aukit.pcm(data, bitDepth, dataType, channels, sampleRate, interleaved, bigEndian)
  923.     expect(1, data, "string", "table")
  924.     bitDepth = expect(2, bitDepth, "number", "nil") or 8
  925.     dataType = expect(3, dataType, "string", "nil") or "signed"
  926.     channels = expect(4, channels, "number", "nil") or 1
  927.     sampleRate = expect(5, sampleRate, "number", "nil") or 48000
  928.     expect(6, interleaved, "boolean", "nil")
  929.     if interleaved == nil then interleaved = true end
  930.     expect(7, bigEndian, "boolean", "nil")
  931.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  932.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  933.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  934.     expect.range(channels, 1)
  935.     expect.range(sampleRate, 1)
  936.     local byteDepth = bitDepth / 8
  937.     if (#data / (type(data) == "table" and 1 or byteDepth)) % channels ~= 0 then error("bad argument #1 (uneven amount of data per channel)", 2) end
  938.     local len = (#data / (type(data) == "table" and 1 or byteDepth)) / channels
  939.     local csize = jit and 7680 or 32768
  940.     local csizeb = csize * byteDepth
  941.     local bitDir = bigEndian and ">" or "<"
  942.     local sformat = dataType == "float" and "f" or ((dataType == "signed" and "i" or "I") .. byteDepth)
  943.     local format = bitDir .. str_rep(sformat, csize)
  944.     local maxValue = 2^(bitDepth-1)
  945.     local obj = setmetatable({sampleRate = sampleRate, data = {}, metadata = {}, info = {bitDepth = bitDepth, dataType = dataType}}, Audio_mt)
  946.     for i = 1, channels do obj.data[i] = {} end
  947.     local pos, spos = 1, 1
  948.     local tmp = {}
  949.     local read
  950.     if type(data) == "table" then
  951.         if dataType == "signed" then
  952.             function read()
  953.                 local s = data[pos]
  954.                 pos = pos + 1
  955.                 return s / (s < 0 and maxValue or maxValue-1)
  956.             end
  957.         elseif dataType == "unsigned" then
  958.             function read()
  959.                 local s = data[pos]
  960.                 pos = pos + 1
  961.                 return (s - 128) / (s < 128 and maxValue or maxValue-1)
  962.             end
  963.         else
  964.             function read()
  965.                 local s = data[pos]
  966.                 pos = pos + 1
  967.                 return s
  968.             end
  969.         end
  970.     elseif dataType == "float" then
  971.         function read()
  972.             if pos > #tmp then
  973.                 if spos + csizeb > #data then
  974.                     local f = bitDir .. str_rep(sformat, (#data - spos + 1) / byteDepth)
  975.                     tmp = {str_unpack(f, data, spos)}
  976.                     spos = tmp[#tmp]
  977.                     tmp[#tmp] = nil
  978.                 else
  979.                     tmp = {str_unpack(format, data, spos)}
  980.                     spos = tmp[#tmp]
  981.                     tmp[#tmp] = nil
  982.                 end
  983.                 pos = 1
  984.             end
  985.             local s = tmp[pos]
  986.             pos = pos + 1
  987.             return s
  988.         end
  989.     elseif dataType == "signed" then
  990.         function read()
  991.             if pos > #tmp then
  992.                 if spos + csizeb > #data then
  993.                     local f = bitDir .. str_rep(sformat, (#data - spos + 1) / byteDepth)
  994.                     tmp = {str_unpack(f, data, spos)}
  995.                     spos = tmp[#tmp]
  996.                     tmp[#tmp] = nil
  997.                 else
  998.                     tmp = {str_unpack(format, data, spos)}
  999.                     spos = tmp[#tmp]
  1000.                     tmp[#tmp] = nil
  1001.                 end
  1002.                 pos = 1
  1003.             end
  1004.             local s = tmp[pos]
  1005.             pos = pos + 1
  1006.             return s / (s < 0 and maxValue or maxValue-1)
  1007.         end
  1008.     else -- unsigned
  1009.         function read()
  1010.             if pos > #tmp then
  1011.                 if spos + csizeb > #data then
  1012.                     local f = bitDir .. str_rep(sformat, (#data - spos + 1) / byteDepth)
  1013.                     tmp = {str_unpack(f, data, spos)}
  1014.                     spos = tmp[#tmp]
  1015.                     tmp[#tmp] = nil
  1016.                 else
  1017.                     tmp = {str_unpack(format, data, spos)}
  1018.                     spos = tmp[#tmp]
  1019.                     tmp[#tmp] = nil
  1020.                 end
  1021.                 pos = 1
  1022.             end
  1023.             local s = tmp[pos]
  1024.             pos = pos + 1
  1025.             return (s - 128) / (s < 128 and maxValue or maxValue-1)
  1026.         end
  1027.     end
  1028.     local start = os_epoch "utc"
  1029.     if interleaved and channels > 1 then
  1030.         local d = obj.data
  1031.         for i = 1, len do
  1032.             if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  1033.             for j = 1, channels do d[j][i] = read() end
  1034.         end
  1035.     else for j = 1, channels do
  1036.         local line = {}
  1037.         obj.data[j] = line
  1038.         for i = 1, len do
  1039.             if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  1040.             line[i] = read()
  1041.         end
  1042.     end end
  1043.     return obj
  1044. end
  1045.  
  1046. --- Creates a new audio object from IMA ADPCM data.
  1047. -- @tparam string|table data The audio data, either as a raw string, or a table of nibbles
  1048. -- @tparam[opt=1] number channels The number of channels present in the audio
  1049. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1050. -- @tparam[opt=true] boolean topFirst Whether the top nibble is the first nibble
  1051. -- (true) or last (false); ignored if `data` is a table
  1052. -- @tparam[opt=true] boolean interleaved Whether each channel is interleaved or separate
  1053. -- @tparam[opt=0] number|table predictor The initial predictor value(s)
  1054. -- @tparam[opt=0] number|table step_index The initial step index(es)
  1055. -- @treturn Audio A new audio object containing the decoded data
  1056. function aukit.adpcm(data, channels, sampleRate, topFirst, interleaved, predictor, step_index)
  1057.     expect(1, data, "string", "table")
  1058.     channels = expect(2, channels, "number", "nil") or 1
  1059.     sampleRate = expect(3, sampleRate, "number", "nil") or 48000
  1060.     expect(4, topFirst, "boolean", "nil")
  1061.     if topFirst == nil then topFirst = true end
  1062.     expect(5, interleaved, "boolean", "nil")
  1063.     if interleaved == nil then interleaved = true end
  1064.     predictor = expect(6, predictor, "number", "table", "nil")
  1065.     step_index = expect(7, step_index, "number", "table", "nil")
  1066.     expect.range(channels, 1)
  1067.     expect.range(sampleRate, 1)
  1068.     if predictor == nil then
  1069.         predictor = {}
  1070.         for i = 1, channels do predictor[i] = 0 end
  1071.     elseif type(predictor) == "number" then
  1072.         if channels ~= 1 then error("bad argument #6 (table too short)", 2) end
  1073.         predictor = {expect.range(predictor, -32768, 32767)}
  1074.     else
  1075.         if channels > #predictor then error("bad argument #6 (table too short)", 2) end
  1076.         for i = 1, channels do expect.range(predictor[i], -32768, 32767) end
  1077.     end
  1078.     if step_index == nil then
  1079.         step_index = {}
  1080.         for i = 1, channels do step_index[i] = 0 end
  1081.     elseif type(step_index) == "number" then
  1082.         if channels ~= 1 then error("bad argument #7 (table too short)", 2) end
  1083.         step_index = {expect.range(step_index, 0, 15)}
  1084.     else
  1085.         if channels > #step_index then error("bad argument #7 (table too short)", 2) end
  1086.         for i = 1, channels do expect.range(step_index[i], 0, 15) end
  1087.     end
  1088.     local pos = 1
  1089.     local read, tmp, len
  1090.     if type(data) == "string" then
  1091.         function read()
  1092.             if tmp then
  1093.                 local v = tmp
  1094.                 tmp = nil
  1095.                 return v
  1096.             else
  1097.                 local b = str_byte(data, pos)
  1098.                 pos = pos + 1
  1099.                 if topFirst then tmp, b = bit32_band(b, 0x0F), bit32_rshift(b, 4)
  1100.                 else tmp, b = bit32_rshift(b, 4), bit32_band(b, 0x0F) end
  1101.                 return b
  1102.             end
  1103.         end
  1104.         len = math_floor(#data * 2 / channels)
  1105.     else
  1106.         function read()
  1107.             local v = data[pos]
  1108.             pos = pos + 1
  1109.             return v
  1110.         end
  1111.         len = #data / channels
  1112.     end
  1113.     local obj = setmetatable({sampleRate = sampleRate, data = {}, metadata = {}, info = {bitDepth = 16, dataType = "signed"}}, Audio_mt)
  1114.     local step = {}
  1115.     local start = os_epoch "utc"
  1116.     if interleaved then
  1117.         local d = obj.data
  1118.         for i = 1, len do
  1119.             if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  1120.             for j = 1, channels do
  1121.                 local nibble = read()
  1122.                 step_index[j] = clamp(step_index[j] + ima_index_table[nibble], 0, 88)
  1123.                 local diff = ((nibble >= 8 and nibble - 16 or nibble) + 0.5) * step[j] / 4
  1124.                 predictor[j] = clamp(predictor[j] + diff, -32768, 32767)
  1125.                 step[j] = ima_step_table[step_index]
  1126.                 d[j][i] = predictor[j] / (predictor[j] < 0 and 32768 or 32767)
  1127.             end
  1128.         end
  1129.     else for j = 1, channels do
  1130.         local line = {}
  1131.         local predictor, step_index, step = predictor[j], step_index[j], nil
  1132.         for i = 1, len do
  1133.             if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  1134.             local nibble = read()
  1135.             step_index = clamp(step_index + ima_index_table[nibble], 0, 88)
  1136.             local diff = ((nibble >= 8 and nibble - 16 or nibble) + 0.5) * step / 4
  1137.             predictor = clamp(predictor + diff, -32768, 32767)
  1138.             step = ima_step_table[step_index]
  1139.             line[i] = predictor / (predictor < 0 and 32768 or 32767)
  1140.         end
  1141.         obj.data[j] = line
  1142.     end end
  1143.     return obj
  1144. end
  1145.  
  1146. --- Creates a new audio object from DFPWM1a data. All channels are expected to
  1147. -- share the same decoder, and are stored interleaved in a single stream.
  1148. -- @tparam string data The audio data as a raw string
  1149. -- @tparam[opt=1] number channels The number of channels present in the audio
  1150. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1151. -- @treturn Audio A new audio object containing the decoded data
  1152. function aukit.dfpwm(data, channels, sampleRate)
  1153.     expect(1, data, "string")
  1154.     channels = expect(2, channels, "number", "nil") or 1
  1155.     sampleRate = expect(3, sampleRate, "number", "nil") or 48000
  1156.     expect.range(channels, 1)
  1157.     expect.range(sampleRate, 1)
  1158.     local audio = {}
  1159.     local decoder = dfpwm.make_decoder()
  1160.     local pos = 1
  1161.     local last = 0
  1162.     local start = os_epoch "utc"
  1163.     while pos <= #data do
  1164.         if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  1165.         local temp = decoder(str_sub(data, pos, pos + 6000))
  1166.         if temp == nil or #temp == 0 then break end
  1167.         for i=1,#temp do
  1168.             audio[last+i] = temp[i]
  1169.         end
  1170.         last = last + #temp
  1171.         pos = pos + 6000
  1172.     end
  1173.     return aukit.pcm(audio, 8, "signed", channels, sampleRate, true, false)
  1174. end
  1175.  
  1176. --- Creates a new audio object from a WAV file. This accepts PCM files up to 32
  1177. -- bits, including float data, as well as DFPWM files [as specified here](https://gist.github.com/MCJack123/90c24b64c8e626c7f130b57e9800962c).
  1178. -- @tparam string data The WAV data to load
  1179. -- @treturn Audio A new audio object with the contents of the WAV file
  1180. function aukit.wav(data)
  1181.     expect(1, data, "string")
  1182.     local channels, sampleRate, bitDepth, length, dataType, predictor, step_index
  1183.     local temp, pos = ("c4"):unpack(data)
  1184.     if temp ~= "RIFF" then error("bad argument #1 (not a WAV file)", 2) end
  1185.     pos = pos + 4
  1186.     temp, pos = ("c4"):unpack(data, pos)
  1187.     if temp ~= "WAVE" then error("bad argument #1 (not a WAV file)", 2) end
  1188.     local meta = {}
  1189.     while pos <= #data do
  1190.         local size
  1191.         temp, size, pos = ("<c4I"):unpack(data, pos)
  1192.         if temp == "fmt " then
  1193.             local chunk = data:sub(pos, pos + size - 1)
  1194.             pos = pos + size
  1195.             local format
  1196.             format, channels, sampleRate, bitDepth = ("<HHIxxxxxxH"):unpack(chunk)
  1197.             if format ~= 1 and format ~= 2 and format ~= 3 and format ~= 0xFFFE then error("unsupported WAV file", 2) end
  1198.             if format == 1 then
  1199.                 dataType = bitDepth == 8 and "unsigned" or "signed"
  1200.             elseif format == 0x11 then
  1201.                 dataType = "adpcm"
  1202.                 -- TODO: read in the correct length values
  1203.             elseif format == 3 then
  1204.                 dataType = "float"
  1205.             elseif format == 0xFFFE then
  1206.                 bitDepth = ("<H"):unpack(chunk, 19)
  1207.                 local uuid = chunk:sub(25, 40)
  1208.                 if uuid == wavExtensible.pcm then dataType = bitDepth == 8 and "unsigned" or "signed"
  1209.                 elseif uuid == wavExtensible.adpcm then dataType = "adpcm"
  1210.                 elseif uuid == wavExtensible.pcm_float then dataType = "float"
  1211.                 elseif uuid == wavExtensible.dfpwm then dataType = "dfpwm"
  1212.                 else error("unsupported WAV file", 2) end
  1213.             end
  1214.         elseif temp == "data" then
  1215.             local data = str_sub(data, pos, pos + size - 1)
  1216.             if #data < size then error("invalid WAV file", 2) end
  1217.             local obj
  1218.             if dataType == "adpcm" then error("unsupported WAV file", 2) -- TODO
  1219.             elseif dataType == "dfpwm" then obj = aukit.dfpwm(data, channels, sampleRate)
  1220.             else obj = aukit.pcm(data, bitDepth, dataType, channels, sampleRate, true, false) end
  1221.             obj.metadata = meta
  1222.             obj.info = {dataType = dataType, bitDepth = bitDepth}
  1223.             return obj
  1224.         elseif temp == "fact" then
  1225.             -- TODO
  1226.             pos = pos + size
  1227.         elseif temp == "LIST" then
  1228.             local type = ("c4"):unpack(data, pos)
  1229.             if type == "INFO" then
  1230.                 local e = pos + size
  1231.                 pos = pos + 4
  1232.                 while pos < e do
  1233.                     local str
  1234.                     type, str, pos = ("!2<c4s4Xh"):unpack(data, pos)
  1235.                     if wavMetadata[type] then meta[wavMetadata[type]] = tonumber(str) or str end
  1236.                 end
  1237.             else pos = pos + size end
  1238.         else pos = pos + size end
  1239.     end
  1240.     error("invalid WAV file", 2)
  1241. end
  1242.  
  1243. --- Creates a new audio object from an AIFF file.
  1244. -- @tparam string data The AIFF data to load
  1245. -- @treturn Audio A new audio object with the contents of the AIFF file
  1246. function aukit.aiff(data)
  1247.     expect(1, data, "string")
  1248.     local channels, sampleRate, bitDepth, length, offset
  1249.     local temp, pos = ("c4"):unpack(data)
  1250.     if temp ~= "FORM" then error("bad argument #1 (not an AIFF file)", 2) end
  1251.     pos = pos + 4
  1252.     temp, pos = ("c4"):unpack(data, pos)
  1253.     if temp ~= "AIFF" then error("bad argument #1 (not an AIFF file)", 2) end
  1254.     local meta = {}
  1255.     while pos <= #data do
  1256.         local size
  1257.         temp, size, pos = (">c4I"):unpack(data, pos)
  1258.         if temp == "COMM" then
  1259.             local e, m
  1260.             channels, length, bitDepth, e, m, pos = (">hIhHI7x"):unpack(data, pos)
  1261.             length = length * channels * math_floor(bitDepth / 8)
  1262.             local s = bit32_btest(e, 0x8000)
  1263.             e = ((bit32_band(e, 0x7FFF) - 0x3FFE) % 0x800)
  1264.             sampleRate = math.ldexp(m * (s and -1 or 1) / 0x100000000000000, e)
  1265.         elseif temp == "SSND" then
  1266.             offset, _, pos = (">II"):unpack(data, pos)
  1267.             local data = data:sub(pos + offset, pos + offset + length - 1)
  1268.             if #data < length then error("invalid AIFF file", 2) end
  1269.             local obj = aukit.pcm(data, bitDepth, "signed", channels, sampleRate, true, true)
  1270.             obj.metadata = meta
  1271.             return obj
  1272.         elseif temp == "NAME" then
  1273.             meta.title = data:sub(pos, pos + size - 1)
  1274.             pos = pos + size
  1275.         elseif temp == "AUTH" then
  1276.             meta.artist = data:sub(pos, pos + size - 1)
  1277.             pos = pos + size
  1278.         elseif temp == "(c) " then
  1279.             meta.copyright = data:sub(pos, pos + size - 1)
  1280.             pos = pos + size
  1281.         elseif temp == "ANNO" then
  1282.             meta.comment = data:sub(pos, pos + size - 1)
  1283.             pos = pos + size
  1284.         else pos = pos + size end
  1285.     end
  1286.     error("invalid AIFF file", 2)
  1287. end
  1288.  
  1289. --- Creates a new audio object from an AU file.
  1290. -- @tparam string data The AU data to load
  1291. -- @treturn Audio A new audio object with the contents of the AU file
  1292. function aukit.au(data)
  1293.     expect(1, data, "string")
  1294.     local magic, offset, size, encoding, sampleRate, channels = (">c4IIIII"):unpack(data)
  1295.     if magic ~= ".snd" then error("invalid AU file", 2) end
  1296.     if encoding == 2 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 8, "signed", channels, sampleRate, true, true)
  1297.     elseif encoding == 3 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 16, "signed", channels, sampleRate, true, true)
  1298.     elseif encoding == 4 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 24, "signed", channels, sampleRate, true, true)
  1299.     elseif encoding == 5 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 32, "signed", channels, sampleRate, true, true)
  1300.     elseif encoding == 6 then return aukit.pcm(data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), 32, "float", channels, sampleRate, true, true)
  1301.     else error("unsupported encoding type " .. encoding, 2) end
  1302. end
  1303.  
  1304. --- Creates a new audio object from a FLAC file.
  1305. -- @tparam string data The FLAC data to load
  1306. -- @treturn Audio A new audio object with the contents of the FLAC file
  1307. function aukit.flac(data)
  1308.     expect(1, data, "string")
  1309.     return setmetatable(decodeFLAC(data), Audio_mt)
  1310. end
  1311.  
  1312. --- Creates a new empty audio object with the specified duration.
  1313. -- @tparam number duration The length of the audio in seconds
  1314. -- @tparam[opt=1] number channels The number of channels present in the audio
  1315. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1316. -- @treturn Audio The new empty audio object
  1317. function aukit.new(duration, channels, sampleRate)
  1318.     expect(1, duration, "number")
  1319.     channels = expect(2, channels, "number", "nil") or 1
  1320.     sampleRate = expect(3, sampleRate, "number", "nil") or 48000
  1321.     expect.range(channels, 1)
  1322.     expect.range(sampleRate, 1)
  1323.     local obj = setmetatable({sampleRate = sampleRate, data = {}, metadata = {}, info = {}}, Audio_mt)
  1324.     for c = 1, channels do
  1325.         local l = {}
  1326.         for i = 1, duration * sampleRate do l[i] = 0 end
  1327.         obj.data[c] = l
  1328.     end
  1329.     return obj
  1330. end
  1331.  
  1332. --- Creates a new audio object with a tone of the specified frequency and duration.
  1333. -- @tparam number frequency The frequency of the tone in Hertz
  1334. -- @tparam number duration The length of the audio in seconds
  1335. -- @tparam[opt=1] number amplitude The amplitude of the audio from 0.0 to 1.0
  1336. -- @tparam[opt="sine"] "sine"|"triangle"|"sawtooth"|"square" waveType The type of wave to generate
  1337. -- @tparam[opt=0.5] number duty The duty cycle of the square wave if selected; ignored otherwise
  1338. -- @tparam[opt=1] number channels The number of channels present in the audio
  1339. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1340. -- @treturn Audio A new audio object with the tone
  1341. function aukit.tone(frequency, duration, amplitude, waveType, duty, channels, sampleRate)
  1342.     expect(1, frequency, "number")
  1343.     expect(2, duration, "number")
  1344.     amplitude = expect(3, amplitude, "number", "nil") or 1
  1345.     waveType = expect(4, waveType, "string", "nil") or "sine"
  1346.     duty = expect(5, duty, "number", "nil") or 0.5
  1347.     channels = expect(6, channels, "number", "nil") or 1
  1348.     sampleRate = expect(7, sampleRate, "number", "nil") or 48000
  1349.     expect.range(amplitude, 0, 1)
  1350.     local f = wavegen[waveType]
  1351.     if not f then error("bad argument #4 (invalid wave type)", 2) end
  1352.     expect.range(duty, 0, 1)
  1353.     expect.range(channels, 1)
  1354.     expect.range(sampleRate, 1)
  1355.     local obj = setmetatable({sampleRate = sampleRate, data = {}, metadata = {}, info = {}}, Audio_mt)
  1356.     for c = 1, channels do
  1357.         local l = {}
  1358.         for i = 1, duration * sampleRate do l[i] = f(i / sampleRate, frequency, amplitude, duty) end
  1359.         obj.data[c] = l
  1360.     end
  1361.     return obj
  1362. end
  1363.  
  1364. --- Creates a new audio object with white noise for the specified duration.
  1365. -- @tparam number duration The length of the audio in seconds
  1366. -- @tparam[opt=1] number amplitude The amplitude of the audio from 0.0 to 1.0
  1367. -- @tparam[opt=1] number channels The number of channels present in the audio
  1368. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1369. -- @treturn Audio A new audio object with noise
  1370. function aukit.noise(duration, amplitude, channels, sampleRate)
  1371.     expect(1, duration, "number")
  1372.     amplitude = expect(2, amplitude, "number", "nil") or 1
  1373.     channels = expect(3, channels, "number", "nil") or 1
  1374.     sampleRate = expect(4, sampleRate, "number", "nil") or 48000
  1375.     expect.range(amplitude, 0, 1)
  1376.     expect.range(channels, 1)
  1377.     expect.range(sampleRate, 1)
  1378.     local obj = setmetatable({sampleRate = sampleRate, data = {}, metadata = {}, info = {}}, Audio_mt)
  1379.     local random = math.random
  1380.     for c = 1, channels do
  1381.         local l = {}
  1382.         for i = 1, duration * sampleRate do l[i] = (random() * 2 - 1) * amplitude end
  1383.         obj.data[c] = l
  1384.     end
  1385.     return obj
  1386. end
  1387.  
  1388. --- Packs a table with PCM data into a string using the specified data type.
  1389. -- @tparam {[number]...} data The PCM data to pack
  1390. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32); if `dataType` is "float" then this must be 32
  1391. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  1392. -- @tparam[opt=false] boolean bigEndian Whether the data should be big-endian or little-endian
  1393. -- @treturn string The packed PCM data
  1394. function aukit.pack(data, bitDepth, dataType, bigEndian)
  1395.     expect(1, data, "string", "table")
  1396.     bitDepth = expect(2, bitDepth, "number", "nil") or 8
  1397.     dataType = expect(3, dataType, "string", "nil") or "signed"
  1398.     expect(4, bigEndian, "boolean", "nil")
  1399.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  1400.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  1401.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  1402.     local byteDepth = bitDepth / 8
  1403.     local format = (bigEndian and ">" or "<") .. (dataType == "float" and "f" or ((dataType == "signed" and "i" or "I") .. byteDepth))
  1404.     local formatChunk = format:sub(1, 1) .. format:sub(2):rep(512)
  1405.     local retval = ""
  1406.     for i = 1, #data, 512 do
  1407.         if #data < i + 512 then retval = retval .. str_pack(str_rep(format, #data % 512), table_unpack(data, i, #data))
  1408.         else retval = retval .. str_pack(formatChunk, table_unpack(data, i, i+511)) end
  1409.     end
  1410.     return retval
  1411. end
  1412.  
  1413. --- Plays back stream functions created by one of the @{aukit.stream} functions
  1414. -- or @{Audio:stream}.
  1415. -- @tparam function():{{[number]...}...} callback The iterator function that returns each chunk
  1416. -- @tparam[opt] function(pos:number) progress A callback to report progress to
  1417. -- the caller; if omitted then this argument is the first speaker
  1418. -- @tparam[opt] number volume The volume to play the audio at; if omitted then
  1419. -- this argument is the second speaker (if provided)
  1420. -- @tparam speaker ... The speakers to play on
  1421. function aukit.play(callback, progress, volume, ...)
  1422.     expect(1, callback, "function")
  1423.     expect(2, progress, "function", "table")
  1424.     expect(3, volume, "number", "table", "nil")
  1425.     local speakers = {...}
  1426.     if type(volume) == "table" then
  1427.         table.insert(speakers, 1, volume)
  1428.         volume = nil
  1429.     end
  1430.     if type(progress) == "table" then
  1431.         table.insert(speakers, 1, progress)
  1432.         progress = nil
  1433.     end
  1434.     if #speakers == 0 then error("bad argument #2 (expected speakers, got nil)", 2) end
  1435.     local chunks = {}
  1436.     local complete = false
  1437.     local a, b = coroutine.create(function()
  1438.         for chunk, pos in callback do chunks[#chunks+1] = {chunk, pos} coroutine.yield(speakers) end
  1439.         complete = true
  1440.     end), coroutine.create(function()
  1441.         while not complete or #chunks > 0 do
  1442.             while not chunks[1] do if complete then return end coroutine.yield(speakers) end
  1443.             local chunk = table.remove(chunks, 1)
  1444.             local fn = {}
  1445.             if progress then progress(chunk[2]) end
  1446.             chunk = chunk[1]
  1447.             for i, v in ipairs(speakers) do fn[i] = function()
  1448.                 local name = peripheral.getName(v)
  1449.                 if _HOST:find("CraftOS-PC v2.6.4") and config and not config.get("standardsMode") then
  1450.                     v.playAudio(chunk[i] or chunk[1], volume)
  1451.                     repeat until select(2, os.pullEvent("speaker_audio_empty")) == name
  1452.                 else while not v.playAudio(chunk[i] or chunk[1], volume) do
  1453.                     repeat until select(2, os.pullEvent("speaker_audio_empty")) == name
  1454.                 end end
  1455.             end end
  1456.             parallel.waitForAll(table_unpack(fn))
  1457.         end
  1458.     end)
  1459.     local ok, af, bf
  1460.     local aq, bq = {{}}, {{}}
  1461.     repeat
  1462.         if #aq > 0 then
  1463.             local event = table.remove(aq, 1)
  1464.             if af == speakers then
  1465.                 af = nil
  1466.                 table.insert(aq, 1, event)
  1467.             end
  1468.             if af == nil or event[1] == af then
  1469.                 ok, af = coroutine.resume(a, table_unpack(event, 1, event.n))
  1470.                 if not ok then error(af, 2) end
  1471.             end
  1472.         end
  1473.         if #bq > 0 then
  1474.             local event = table.remove(bq, 1)
  1475.             if bf == speakers then
  1476.                 bf = nil
  1477.                 table.insert(bq, 1, event)
  1478.             end
  1479.             if bf == nil or event[1] == bf then
  1480.                 ok, bf = coroutine.resume(b, table_unpack(event, 1, event.n))
  1481.                 if not ok then error(bf, 2) end
  1482.             end
  1483.         end
  1484.         if coroutine.status(b) == "suspended" and (#aq == 0 or #bq == 0) then
  1485.             os.queueEvent("__queue_end")
  1486.             while true do
  1487.                 local event = table.pack(os.pullEvent())
  1488.                 if event[1] == "__queue_end" then break end
  1489.                 aq[#aq+1] = event
  1490.                 bq[#bq+1] = event
  1491.             end
  1492.         end
  1493.     until coroutine.status(b) == "dead" or complete
  1494.     while coroutine.status(b) == "suspended" and #bq > 0 do
  1495.         local event = table.remove(bq, 1)
  1496.         if bf == nil or event[1] == bf then
  1497.             ok, bf = coroutine.resume(b, table_unpack(event, 1, event.n))
  1498.             if not ok then error(bf, 2) end
  1499.         end
  1500.     end
  1501.     while coroutine.status(b) == "suspended" do
  1502.         ok, bf = coroutine.resume(b, os.pullEvent())
  1503.         if not ok then error(bf, 2) end
  1504.     end
  1505. end
  1506.  
  1507. local datafmts = {
  1508.     {"bbbbbbbb", 8, "signed"},
  1509.     {"BBBBBBBB", 8, "unsigned"},
  1510.     {"hhhhhhhh", 16, "signed"},
  1511.     {"iiiiiiii", 32, "signed"},
  1512.     {"ffffffff", 32, "float"},
  1513.     {"i3i3i3i3i3i3i3i3", 24, "signed"},
  1514.     {"IIIIIIII", 32, "unsigned"},
  1515.     {"I3I3I3I3I3I3I3I3", 24, "unsigned"},
  1516.     {"HHHHHHHH", 16, "unsigned"},
  1517. }
  1518.  
  1519. --- Detect the type of audio file from the specified data. This uses heuristic
  1520. -- detection methods to attempt to find the correct data type for files without
  1521. -- headers. It is not recommended to rely on the data type/bit depth reported
  1522. -- for PCM files - they are merely a suggestion.
  1523. -- @tparam string data The audio file to check
  1524. -- @treturn "pcm"|"dfpwm"|"wav"|"aiff"|"au"|"flac"|nil The type of audio file detected, or `nil` if none could be found
  1525. -- @treturn number|nil The bit depth for PCM data, if the type is "pcm" and the bit depth can be detected
  1526. -- @treturn "signed"|"unsigned"|"float"|nil The data type for PCM data, if the type is "pcm" and the type can be detected
  1527. function aukit.detect(data)
  1528.     expect(1, data, "string")
  1529.     if data:match "^RIFF....WAVE" then return "wav"
  1530.     elseif data:match "^FORM....AIFF" then return "aiff"
  1531.     elseif data:match "^%.snd" then return "au"
  1532.     elseif data:match "^fLaC" then return "flac"
  1533.     else
  1534.         -- Detect data type otherwise
  1535.         -- This expects the start or end of the audio to be (near) silence
  1536.         for _, bits in pairs(datafmts) do
  1537.             local mid, gap = bits[3] == "unsigned" and 2^(bits[2]-1) or 0, bits[3] == "float" and 0.001 or 8 * 2^(bits[2]-8)
  1538.             local nums = {pcall(string.unpack, bits[1], data)}
  1539.             nums[#nums] = nil
  1540.             if table.remove(nums, 1) then
  1541.                 local allzero, ok = true, true
  1542.                 for _, v in ipairs(nums) do
  1543.                     if v ~= mid then allzero = false end
  1544.                     if v < mid - gap or v > mid + gap then ok = false break end
  1545.                 end
  1546.                 if ok and not allzero then return "pcm", table_unpack(bits, 2) end
  1547.             end
  1548.             nums = {pcall(string.unpack, bits[1], data, #data - bits[2])}
  1549.             nums[#nums] = nil
  1550.             if table.remove(nums, 1) then
  1551.                 local allzero, ok = true, true
  1552.                 for _, v in ipairs(nums) do
  1553.                     if v ~= mid then allzero = false end
  1554.                     if v < mid - gap or v > mid + gap then ok = false break end
  1555.                 end
  1556.                 if ok and not allzero then return "pcm", table_unpack(bits, 2) end
  1557.             end
  1558.         end
  1559.         if data:match(("\x55"):rep(12)) or data:match(("\xAA"):rep(12)) then return "dfpwm" end
  1560.     end
  1561.     return nil
  1562. end
  1563.  
  1564. --- aukit.stream
  1565. -- @section aukit.stream
  1566.  
  1567. --- Returns an iterator to stream raw PCM data in CC format. Audio will automatically
  1568. -- be resampled to 48 kHz, and optionally mixed down to mono. Data *must* be
  1569. -- interleaved - this will not work with planar audio.
  1570. -- @tparam string|table|function data The audio data, either as a raw string, a
  1571. -- table of values (in the format specified by `bitDepth` and `dataType`), or a
  1572. -- function that returns either of those types. Functions will be called at
  1573. -- least once before returning to get the type of data to use.
  1574. -- @tparam[opt=8] number bitDepth The bit depth of the audio (8, 16, 24, 32); if `dataType` is "float" then this must be 32
  1575. -- @tparam[opt="signed"] "signed"|"unsigned"|"float" dataType The type of each sample
  1576. -- @tparam[opt=1] number channels The number of channels present in the audio
  1577. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1578. -- @tparam[opt=false] boolean bigEndian Whether the audio is big-endian or little-endian; ignored if data is a table
  1579. -- @tparam[opt=false] boolean mono Whether to mix the audio down to mono
  1580. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1581. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1582. -- the current position of the audio in seconds
  1583. -- @treturn number The total length of the audio in seconds, or the length of
  1584. -- the first chunk if using a function
  1585. function aukit.stream.pcm(data, bitDepth, dataType, channels, sampleRate, bigEndian, mono)
  1586.     local fn, complete
  1587.     if type(data) == "function" then fn, data = data, data() end
  1588.     expect(1, data, "string", "table")
  1589.     bitDepth = expect(2, bitDepth, "number", "nil") or 8
  1590.     dataType = expect(3, dataType, "string", "nil") or "signed"
  1591.     channels = expect(4, channels, "number", "nil") or 1
  1592.     sampleRate = expect(5, sampleRate, "number", "nil") or 48000
  1593.     expect(6, bigEndian, "boolean", "nil")
  1594.     expect(7, mono, "boolean", "nil")
  1595.     if bitDepth ~= 8 and bitDepth ~= 16 and bitDepth ~= 24 and bitDepth ~= 32 then error("bad argument #2 (invalid bit depth)", 2) end
  1596.     if dataType ~= "signed" and dataType ~= "unsigned" and dataType ~= "float" then error("bad argument #3 (invalid data type)", 2) end
  1597.     if dataType == "float" and bitDepth ~= 32 then error("bad argument #2 (float audio must have 32-bit depth)", 2) end
  1598.     expect.range(channels, 1)
  1599.     expect.range(sampleRate, 1)
  1600.     if channels == 1 then mono = false end
  1601.     local byteDepth = bitDepth / 8
  1602.     local len = (#data / (type(data) == "table" and 1 or byteDepth)) / channels
  1603.     local csize = jit and 7680 or 32768
  1604.     local csizeb = csize * byteDepth
  1605.     local bitDir = bigEndian and ">" or "<"
  1606.     local sformat = dataType == "float" and "f" or ((dataType == "signed" and "i" or "I") .. byteDepth)
  1607.     local format = bitDir .. str_rep(sformat, csize)
  1608.     local maxValue = 2^(bitDepth-1)
  1609.     local pos, spos = 1, 1
  1610.     local tmp = {}
  1611.     local read
  1612.     if type(data) == "table" then
  1613.         if dataType == "signed" then
  1614.             function read()
  1615.                 if complete then return nil end
  1616.                 if fn and pos > #data then
  1617.                     data, pos = fn(), 1
  1618.                     if not data then complete = true return nil end
  1619.                 end
  1620.                 local s = data[pos]
  1621.                 pos = pos + 1
  1622.                 return s / (s < 0 and maxValue or maxValue-1)
  1623.             end
  1624.         elseif dataType == "unsigned" then
  1625.             function read()
  1626.                 if complete then return nil end
  1627.                 if fn and pos > #data then
  1628.                     data, pos = fn(), 1
  1629.                     if not data then complete = true return nil end
  1630.                 end
  1631.                 local s = data[pos]
  1632.                 pos = pos + 1
  1633.                 return (s - 128) / (s < 128 and maxValue or maxValue-1)
  1634.             end
  1635.         else
  1636.             function read()
  1637.                 if complete then return nil end
  1638.                 if fn and pos > #data then
  1639.                     data, pos = fn(), 1
  1640.                     if not data then complete = true return nil end
  1641.                 end
  1642.                 local s = data[pos]
  1643.                 pos = pos + 1
  1644.                 return s
  1645.             end
  1646.         end
  1647.     elseif dataType == "float" then
  1648.         function read()
  1649.             if complete then return nil end
  1650.             if pos > #tmp then
  1651.                 if fn and spos > #data then
  1652.                     data, spos = fn(), 1
  1653.                     if not data then complete = true return nil end
  1654.                 end
  1655.                 if spos + csizeb > #data then
  1656.                     local f = bitDir .. str_rep(sformat, (#data - spos + 1) / byteDepth)
  1657.                     tmp = {str_unpack(f, data, spos)}
  1658.                     spos = tmp[#tmp]
  1659.                     tmp[#tmp] = nil
  1660.                 else
  1661.                     tmp = {str_unpack(format, data, spos)}
  1662.                     spos = tmp[#tmp]
  1663.                     tmp[#tmp] = nil
  1664.                 end
  1665.                 pos = 1
  1666.             end
  1667.             local s = tmp[pos]
  1668.             pos = pos + 1
  1669.             return s
  1670.         end
  1671.     elseif dataType == "signed" then
  1672.         function read()
  1673.             if complete then return nil end
  1674.             if pos > #tmp then
  1675.                 if fn and spos > #data then
  1676.                     data, spos = fn(), 1
  1677.                     if not data then complete = true return nil end
  1678.                 end
  1679.                 if spos + csizeb > #data then
  1680.                     local f = bitDir .. str_rep(sformat, (#data - spos + 1) / byteDepth)
  1681.                     tmp = {str_unpack(f, data, spos)}
  1682.                     spos = tmp[#tmp]
  1683.                     tmp[#tmp] = nil
  1684.                 else
  1685.                     tmp = {str_unpack(format, data, spos)}
  1686.                     spos = tmp[#tmp]
  1687.                     tmp[#tmp] = nil
  1688.                 end
  1689.                 pos = 1
  1690.             end
  1691.             local s = tmp[pos]
  1692.             pos = pos + 1
  1693.             return s / (s < 0 and maxValue or maxValue-1)
  1694.         end
  1695.     else -- unsigned
  1696.         function read()
  1697.             if complete then return nil end
  1698.             if pos > #tmp then
  1699.                 if fn and spos > #data then
  1700.                     data, spos = fn(), 1
  1701.                     if not data then complete = true return nil end
  1702.                 end
  1703.                 if spos + csizeb > #data then
  1704.                     local f = bitDir .. str_rep(sformat, (#data - spos + 1) / byteDepth)
  1705.                     tmp = {str_unpack(f, data, spos)}
  1706.                     spos = tmp[#tmp]
  1707.                     tmp[#tmp] = nil
  1708.                 else
  1709.                     tmp = {str_unpack(format, data, spos)}
  1710.                     spos = tmp[#tmp]
  1711.                     tmp[#tmp] = nil
  1712.                 end
  1713.                 pos = 1
  1714.             end
  1715.             local s = tmp[pos]
  1716.             pos = pos + 1
  1717.             return (s - 128) / (s < 128 and maxValue or maxValue-1)
  1718.         end
  1719.     end
  1720.     local d = {}
  1721.     local ratio = 48000 / sampleRate
  1722.     local interp = interpolate[aukit.defaultInterpolation]
  1723.     for j = 1, (mono and 1 or channels) do d[j] = setmetatable({}, {__index = function(self, i)
  1724.         if mono then for _ = 1, channels do self[i] = (rawget(self, i) or 0) + read() end self[i] = self[i] / channels
  1725.         else self[i] = read() end
  1726.         return rawget(self, i)
  1727.     end}) end
  1728.     local n = 0
  1729.     local ok = true
  1730.     return function()
  1731.         if not ok or complete then return nil end
  1732.         for i = (n == 0 and interpolation_start[aukit.defaultInterpolation] or 1), interpolation_end[aukit.defaultInterpolation] do
  1733.             if mono then
  1734.                 local s = 0
  1735.                 for j = 1, channels do
  1736.                     local c = read()
  1737.                     if not c then return nil end
  1738.                     s = s + c
  1739.                 end
  1740.                 d[1][i] = s / channels
  1741.             else for j = 1, channels do d[j][i] = read() if not d[j][i] then return nil end end end
  1742.         end
  1743.         local chunk = {}
  1744.         for j = 1, #d do chunk[j] = {} end
  1745.         ok = pcall(function()
  1746.             for i = 1, 48000 do
  1747.                 for y = 1, #d do
  1748.                     local x = ((i - 1) / ratio) + 1
  1749.                     if x % 1 == 0 then chunk[y][i] = d[y][x]
  1750.                     else chunk[y][i] = interp(d[y], x) end
  1751.                     chunk[y][i] = clamp(chunk[y][i] * (chunk[y][i] < 0 and 128 or 127), -128, 127)
  1752.                 end
  1753.             end
  1754.         end)
  1755.         if #chunk[1] == 0 then return nil end
  1756.         n = n + #chunk[1]
  1757.         for y = 1, #d do
  1758.             local l2, l1 = d[y][#d[y]-1], d[y][#d[y]]
  1759.             d[y] = setmetatable({}, getmetatable(d[y]))
  1760.             d[y][-1], d[y][0] = l2, l1
  1761.         end
  1762.         return chunk, (n - #chunk[1]) / 48000
  1763.     end, len / sampleRate
  1764. end
  1765.  
  1766. --- Returns an iterator to stream data from DFPWM data. Audio will automatically
  1767. -- be resampled to 48 kHz. Multiple channels are expected to be interleaved in
  1768. -- the encoded DFPWM data.
  1769. -- @tparam string|function():string data The DFPWM data to decode, or a function
  1770. -- returning chunks to decode
  1771. -- @tparam[opt=48000] number sampleRate The sample rate of the audio in Hertz
  1772. -- @tparam[opt=1] number channels The number of channels present in the audio
  1773. -- @tparam[opt=false] boolean mono Whether to mix the audio down to mono
  1774. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1775. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1776. -- the current position of the audio in seconds
  1777. -- @treturn number The total length of the audio in seconds, or the length of
  1778. -- the first chunk if using a function
  1779. function aukit.stream.dfpwm(data, sampleRate, channels, mono)
  1780.     expect(1, data, "string", "function")
  1781.     sampleRate = expect(2, sampleRate, "number", "nil") or 48000
  1782.     channels = expect(3, channels, "number", "nil") or 1
  1783.     expect.range(sampleRate, 1)
  1784.     expect.range(channels, 1)
  1785.     if channels == 1 then mono = false end
  1786.     local decoder = dfpwm.make_decoder()
  1787.     local pos = 1
  1788.     local last = 0
  1789.     local isstr = type(data) == "string"
  1790.     return function()
  1791.         if pos > #data then return nil end
  1792.         local d
  1793.         if isstr then d = data:sub(pos, pos + 6000 * channels)
  1794.         else d = data() if not d then return nil end end
  1795.         local audio = decoder(d)
  1796.         if audio == nil or #audio == 0 then return nil end
  1797.         audio[0], last = last, audio[#audio]
  1798.         sleep(0)
  1799.         local ratio = 48000 / sampleRate
  1800.         local newlen = #audio * ratio
  1801.         local interp = interpolate[aukit.defaultInterpolation]
  1802.         local lines = {{}}
  1803.         if not mono then for j = 1, channels do lines[j] = {} end end
  1804.         for i = 1, newlen, channels do
  1805.             local n = 0
  1806.             for j = 1, channels do
  1807.                 local x = (i - 1) / ratio + 1
  1808.                 local s
  1809.                 if x % 1 == 0 then s = audio[x]
  1810.                 else s = clamp(interp(audio, x), -128, 127) end
  1811.                 if mono then n = n + s
  1812.                 else lines[j][math_ceil(i / channels)] = s end
  1813.             end
  1814.             if mono then lines[1][math_ceil(i / channels)] = n / channels end
  1815.         end
  1816.         sleep(0)
  1817.         local p = pos
  1818.         pos = pos + 6000 * channels
  1819.         return lines, p * 8 / sampleRate / channels
  1820.     end, #data * 8 / sampleRate / channels
  1821. end
  1822.  
  1823. --- Returns an iterator to stream data from a WAV file. Audio will automatically
  1824. -- be resampled to 48 kHz, and optionally mixed down to mono. This accepts PCM
  1825. -- files up to 32 bits, including float data, as well as DFPWM files [as specified here](https://gist.github.com/MCJack123/90c24b64c8e626c7f130b57e9800962c).
  1826. -- @tparam string|function():string data The WAV file to decode, or a function
  1827. -- returning chunks to decode (the first chunk MUST contain the ENTIRE header)
  1828. -- @tparam[opt=false] boolean mono Whether to mix the audio to mono
  1829. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1830. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1831. -- the current position of the audio in seconds
  1832. -- @treturn number The total length of the audio in seconds
  1833. function aukit.stream.wav(data, mono)
  1834.     local fn
  1835.     if type(data) == "function" then fn, data = data, data() end
  1836.     expect(1, data, "string")
  1837.     local channels, sampleRate, bitDepth, length, dataType
  1838.     local temp, pos = ("c4"):unpack(data)
  1839.     if temp ~= "RIFF" then error("bad argument #1 (not a WAV file)", 2) end
  1840.     pos = pos + 4
  1841.     temp, pos = ("c4"):unpack(data, pos)
  1842.     if temp ~= "WAVE" then error("bad argument #1 (not a WAV file)", 2) end
  1843.     while pos <= #data do
  1844.         local size
  1845.         temp, pos = ("c4"):unpack(data, pos)
  1846.         size, pos = ("<I"):unpack(data, pos)
  1847.         if temp == "fmt " then
  1848.             local chunk = data:sub(pos, pos + size - 1)
  1849.             pos = pos + size
  1850.             local format
  1851.             format, channels, sampleRate, bitDepth = ("<HHIxxxxxxH"):unpack(chunk)
  1852.             if format ~= 1 and format ~= 2 and format ~= 3 and format ~= 0xFFFE then error("unsupported WAV file", 2) end
  1853.             if format == 1 then
  1854.                 dataType = bitDepth == 8 and "unsigned" or "signed"
  1855.             elseif format == 0x11 then
  1856.                 dataType = "adpcm"
  1857.                 -- TODO: read in the correct length values
  1858.             elseif format == 3 then
  1859.                 dataType = "float"
  1860.             elseif format == 0xFFFE then
  1861.                 bitDepth = ("<H"):unpack(chunk, 19)
  1862.                 local uuid = chunk:sub(25, 40)
  1863.                 if uuid == wavExtensible.pcm then dataType = bitDepth == 8 and "unsigned" or "signed"
  1864.                 elseif uuid == wavExtensible.adpcm then dataType = "adpcm"
  1865.                 elseif uuid == wavExtensible.pcm_float then dataType = "float"
  1866.                 elseif uuid == wavExtensible.dfpwm then dataType = "dfpwm"
  1867.                 else error("unsupported WAV file", 2) end
  1868.             end
  1869.         elseif temp == "data" then
  1870.             local data = data:sub(pos, pos + size - 1)
  1871.             if not fn and #data < size then error("invalid WAV file", 2) end
  1872.             if fn then
  1873.                 local first, f = data
  1874.                 data = function()
  1875.                     if first then f, first = first return f
  1876.                     else return fn() end
  1877.                 end
  1878.             end
  1879.             if dataType == "adpcm" then error("unsupported WAV file", 2) -- TODO
  1880.             elseif dataType == "dfpwm" then return aukit.stream.dfpwm(data, sampleRate, channels, mono), size / channels / (bitDepth / 8) / sampleRate
  1881.             else return aukit.stream.pcm(data, bitDepth, dataType, channels, sampleRate, false, mono), size / channels / (bitDepth / 8) / sampleRate end
  1882.         elseif temp == "fact" then
  1883.             -- TODO
  1884.             pos = pos + size
  1885.         else pos = pos + size end
  1886.     end
  1887.     error("invalid WAV file", 2)
  1888. end
  1889.  
  1890. --- Returns an iterator to stream data from an AIFF file. Audio will automatically
  1891. -- be resampled to 48 kHz, and optionally mixed down to mono.
  1892. -- @tparam string|function():string data The AIFF file to decode, or a function
  1893. -- returning chunks to decode (the first chunk MUST contain the ENTIRE header)
  1894. -- @tparam[opt=false] boolean mono Whether to mix the audio to mono
  1895. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1896. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1897. -- the current position of the audio in seconds
  1898. -- @treturn number The total length of the audio in seconds
  1899. function aukit.stream.aiff(data, mono)
  1900.     local fn
  1901.     if type(data) == "function" then fn, data = data, data() end
  1902.     expect(1, data, "string")
  1903.     expect(2, mono, "boolean", "nil")
  1904.     local channels, sampleRate, bitDepth, length, offset
  1905.     local temp, pos = ("c4"):unpack(data)
  1906.     if temp ~= "FORM" then error("bad argument #1 (not an AIFF file)", 2) end
  1907.     pos = pos + 4
  1908.     temp, pos = ("c4"):unpack(data, pos)
  1909.     if temp ~= "AIFF" then error("bad argument #1 (not an AIFF file)", 2) end
  1910.     while pos <= #data do
  1911.         local size
  1912.         temp, pos = ("c4"):unpack(data, pos)
  1913.         size, pos = (">I"):unpack(data, pos)
  1914.         if temp == "COMM" then
  1915.             local e, m
  1916.             channels, length, bitDepth, e, m, pos = (">hIhHI7x"):unpack(data, pos)
  1917.             length = length * channels * math_floor(bitDepth / 8)
  1918.             local s = bit32_btest(e, 0x8000)
  1919.             e = ((bit32_band(e, 0x7FFF) - 0x3FFE) % 0x800)
  1920.             sampleRate = math.ldexp(m * (s and -1 or 1) / 0x100000000000000, e)
  1921.         elseif temp == "SSND" then
  1922.             offset, _, pos = (">II"):unpack(data, pos)
  1923.             local data = data:sub(pos + offset, pos + offset + length - 1)
  1924.             if not fn and #data < length then error("invalid AIFF file", 2) end
  1925.             if fn then
  1926.                 local first, f = data
  1927.                 data = function()
  1928.                     if first then f, first = first return f
  1929.                     else return fn() end
  1930.                 end
  1931.             end
  1932.             return aukit.stream.pcm(data, bitDepth, "signed", channels, sampleRate, true, mono), length / channels / (bitDepth / 8) / sampleRate
  1933.         else pos = pos + size end
  1934.     end
  1935.     error("invalid AIFF file", 2)
  1936. end
  1937.  
  1938. --- Returns an iterator to stream data from an AU file. Audio will automatically
  1939. -- be resampled to 48 kHz, and optionally mixed down to mono.
  1940. -- @tparam string|function():string data The AU file to decode, or a function
  1941. -- returning chunks to decode (the first chunk MUST contain the ENTIRE header)
  1942. -- @tparam[opt=false] boolean mono Whether to mix the audio to mono
  1943. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1944. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1945. -- the current position of the audio in seconds
  1946. -- @treturn number The total length of the audio in seconds
  1947. function aukit.stream.au(data, mono)
  1948.     local fn
  1949.     if type(data) == "function" then fn, data = data, data() end
  1950.     expect(1, data, "string")
  1951.     expect(2, mono, "boolean", "nil")
  1952.     local magic, offset, size, encoding, sampleRate, channels = (">c4IIIII"):unpack(data)
  1953.     if magic ~= ".snd" then error("invalid AU file", 2) end
  1954.     if fn then
  1955.         local first, f = data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil), nil
  1956.         data = function()
  1957.             if first then f, first = first return f
  1958.             else return fn() end
  1959.         end
  1960.     else data = data:sub(offset, size ~= 0xFFFFFFFF and offset + size - 1 or nil) end
  1961.     if encoding == 2 then return aukit.stream.pcm(data, 8, "signed", channels, sampleRate, true, mono), size / channels / sampleRate
  1962.     elseif encoding == 3 then return aukit.stream.pcm(data, 16, "signed", channels, sampleRate, true, mono), size / channels / 2 / sampleRate
  1963.     elseif encoding == 4 then return aukit.stream.pcm(data, 24, "signed", channels, sampleRate, true, mono), size / channels / 3 / sampleRate
  1964.     elseif encoding == 5 then return aukit.stream.pcm(data, 32, "signed", channels, sampleRate, true, mono), size / channels / 4 / sampleRate
  1965.     elseif encoding == 6 then return aukit.stream.pcm(data, 32, "float", channels, sampleRate, true, mono), size / channels / 4 / sampleRate
  1966.     else error("unsupported encoding type " .. encoding, 2) end
  1967. end
  1968.  
  1969. --- Returns an iterator to stream data from a FLAC file. Audio will automatically
  1970. -- be resampled to 48 kHz, and optionally mixed down to mono.
  1971. -- @tparam string|function():string data The FLAC file to decode, or a function
  1972. -- returning chunks to decode
  1973. -- @tparam[opt=false] boolean mono Whether to mix the audio to mono
  1974. -- @treturn function():{{[number]...}...},number An iterator function that returns
  1975. -- chunks of each channel's data as arrays of signed 8-bit 48kHz PCM, as well as
  1976. -- the current position of the audio in seconds
  1977. -- @treturn number The total length of the audio in seconds
  1978. function aukit.stream.flac(data, mono)
  1979.     expect(1, data, "string", "function")
  1980.     expect(2, mono, "boolean", "nil")
  1981.     local infn = false
  1982.     if type(data) == "function" then data = setmetatable({str = "", fn = data, final = false, byte = function(self, start, e)
  1983.         while start > #self.str do
  1984.             infn = true
  1985.             local d = self.fn()
  1986.             infn = false
  1987.             if not d then self.final = true return nil end
  1988.             self.str = self.str .. d
  1989.         end
  1990.         while e and e > #self.str do
  1991.             infn = true
  1992.             local d = self.fn()
  1993.             infn = false
  1994.             if not d then self.final = true return nil end
  1995.             self.str = self.str .. d
  1996.         end
  1997.         return self.str:byte(start, e)
  1998.     end}, {__len = function(self) return self.final and #self.str or math.huge end}) end
  1999.     local function saferesume(coro, ...)
  2000.         local res = table.pack(coroutine.resume(coro, ...))
  2001.         while res[1] and infn do res = table.pack(coroutine.resume(coro, coroutine.yield(table_unpack(res, 2, res.n)))) end
  2002.         return table_unpack(res, 1, res.n)
  2003.     end
  2004.     local coro = coroutine.create(decodeFLAC)
  2005.     local ok, sampleRate, len = saferesume(coro, data, coroutine.yield)
  2006.     if not ok then error(sampleRate, 2) end
  2007.     local pos = 0
  2008.     return function()
  2009.         if coroutine.status(coro) == "dead" then return nil end
  2010.         local chunk = {{}}
  2011.         while #chunk[1] < sampleRate do
  2012.             local ok, res = saferesume(coro)
  2013.             if not ok or res == nil or res.sampleRate then break end
  2014.             sleep(0)
  2015.             for c = 1, #res do
  2016.                 chunk[c] = chunk[c] or {}
  2017.                 local src, dest = res[c], chunk[c]
  2018.                 local start = #dest
  2019.                 for i = 1, #res[c] do dest[start+i] = src[i] end
  2020.             end
  2021.             sleep(0)
  2022.         end
  2023.         local audio = setmetatable({sampleRate = sampleRate, data = chunk, metadata = {}, info = {}}, Audio_mt)
  2024.         if mono and #chunk > 1 then audio = audio:mono() end
  2025.         sleep(0)
  2026.         audio = audio:resample(48000)
  2027.         sleep(0)
  2028.         chunk = {}
  2029.         for c = 1, #audio.data do
  2030.             local src, dest = audio.data[c], {}
  2031.             for i = 1, #src do dest[i] = src[i] * (src[i] < 0 and 128 or 127) end
  2032.             chunk[c] = dest
  2033.         end
  2034.         local p = pos
  2035.         pos = pos + #audio.data[1] / 48000
  2036.         return chunk, p
  2037.     end, len / sampleRate
  2038. end
  2039.  
  2040. --- aukit.effects
  2041. -- @section aukit.effects
  2042.  
  2043. --- Amplifies the audio by the multiplier specified.
  2044. -- @tparam Audio audio The audio to modify
  2045. -- @tparam number multiplier The multiplier to apply
  2046. -- @treturn Audio The audio modified
  2047. function aukit.effects.amplify(audio, multiplier)
  2048.     expectAudio(1, audio)
  2049.     expect(2, multiplier, "number")
  2050.     if multiplier == 1 then return audio end
  2051.     local start = os_epoch "utc"
  2052.     for c = 1, #audio.data do
  2053.         local ch = audio.data[c]
  2054.         for i = 1, #ch do
  2055.             if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  2056.             ch[i] = clamp(ch[i] * multiplier, -1, 1)
  2057.         end
  2058.     end
  2059.     return audio
  2060. end
  2061.  
  2062. --- Changes the speed and pitch of audio by a multiplier, resampling to keep the
  2063. -- same sample rate.
  2064. -- @tparam Audio audio The audio to modify
  2065. -- @tparam number multiplier The multiplier to apply
  2066. -- @treturn Audio The audio modified
  2067. function aukit.effects.speed(audio, multiplier)
  2068.     expectAudio(1, audio)
  2069.     expect(2, multiplier, "number")
  2070.     if multiplier == 1 then return audio end
  2071.     local rate = audio.sampleRate
  2072.     audio.sampleRate = audio.sampleRate * multiplier
  2073.     local new = audio:resample(rate)
  2074.     audio.sampleRate, audio.data = rate, new.data
  2075.     return audio
  2076. end
  2077.  
  2078. --- Fades a period of music from one amplitude to another.
  2079. -- @tparam Audio audio The audio to modify
  2080. -- @tparam number startTime The start time of the fade, in seconds
  2081. -- @tparam number startAmplitude The amplitude of the beginning of the fade
  2082. -- @tparam number endTime The end time of the fade, in seconds
  2083. -- @tparam number endAmplitude The amplitude of the end of the fade
  2084. -- @treturn Audio The audio modified
  2085. function aukit.effects.fade(audio, startTime, startAmplitude, endTime, endAmplitude)
  2086.     expectAudio(1, audio)
  2087.     expect(2, startTime, "number")
  2088.     expect(3, startAmplitude, "number")
  2089.     expect(4, endTime, "number")
  2090.     expect(5, endAmplitude, "number")
  2091.     if startAmplitude == 1 and endAmplitude == 1 then return audio end
  2092.     local startt = os_epoch "utc"
  2093.     for c = 1, #audio.data do
  2094.         local ch = audio.data[c]
  2095.         local start = startTime * audio.sampleRate
  2096.         local m = (endAmplitude - startAmplitude) / ((endTime - startTime) * audio.sampleRate)
  2097.         for i = start, endTime * audio.sampleRate do
  2098.             if os_epoch "utc" - startt > 5000 then startt = os_epoch "utc" sleep(0) end
  2099.             ch[i] = clamp(ch[i] * (m * (i - start) + startAmplitude), -1, 1)
  2100.         end
  2101.     end
  2102.     return audio
  2103. end
  2104.  
  2105. --- Inverts all channels in the specified audio.
  2106. -- @tparam Audio audio The audio to modify
  2107. -- @treturn Audio The audio modified
  2108. function aukit.effects.invert(audio)
  2109.     expectAudio(1, audio)
  2110.     for c = 1, #audio.data do
  2111.         local ch = audio.data[c]
  2112.         for i = 1, #ch do ch[i] = -ch[i] end
  2113.     end
  2114.     return audio
  2115. end
  2116.  
  2117. --- Normalizes audio to the specified peak amplitude.
  2118. -- @tparam Audio audio The audio to modify
  2119. -- @tparam[opt=1] number peakAmplitude The maximum amplitude
  2120. -- @tparam[opt=false] boolean independent Whether to normalize each channel independently
  2121. -- @treturn Audio The audio modified
  2122. function aukit.effects.normalize(audio, peakAmplitude, independent)
  2123.     expectAudio(1, audio)
  2124.     peakAmplitude = expect(2, peakAmplitude, "number", "nil") or 1
  2125.     expect(3, independent, "boolean", "nil")
  2126.     local mult
  2127.     local start, sampleRate = os_epoch "utc", audio.sampleRate
  2128.     if not independent then
  2129.         local max = 0
  2130.         for c = 1, #audio.data do
  2131.             local ch = audio.data[c]
  2132.             if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  2133.             for i = 1, #ch do max = math.max(max, math_abs(ch[i])) end
  2134.         end
  2135.         mult = peakAmplitude / max
  2136.     end
  2137.     for c = 1, #audio.data do
  2138.         local ch = audio.data[c]
  2139.         if independent then
  2140.             local max = 0
  2141.             for i = 1, #ch do max = math.max(max, math_abs(ch[i])) end
  2142.             mult = peakAmplitude / max
  2143.         end
  2144.         if os_epoch "utc" - start > 3000 then start = os_epoch "utc" sleep(0) end
  2145.         for i = 1, #ch do
  2146.             ch[i] = clamp(ch[i] * mult, -1, 1)
  2147.         end
  2148.     end
  2149.     return audio
  2150. end
  2151.  
  2152. --- Centers the DC offset of each channel.
  2153. -- @tparam Audio audio The audio to modify
  2154. -- @treturn Audio The audio modified
  2155. function aukit.effects.center(audio)
  2156.     expectAudio(1, audio)
  2157.     for c = 1, #audio.data do
  2158.         local ch = audio.data[c]
  2159.         for i = 0, #ch - 1, audio.sampleRate do
  2160.             local avg = 0
  2161.             local l = math.min(#ch - i, audio.sampleRate)
  2162.             for j = 1, l do avg = avg + ch[i+j] end
  2163.             avg = avg / l
  2164.             for j = 1, l do ch[i+j] = clamp(ch[i+j] - avg, -1, 1) end
  2165.         end
  2166.     end
  2167.     return audio
  2168. end
  2169.  
  2170. --- Trims any extra silence on either end of the specified audio.
  2171. -- @tparam Audio audio The audio to modify
  2172. -- @tparam[opt=1/65536] number threshold The maximum value to register as silence
  2173. -- @treturn Audio The audio modified
  2174. function aukit.effects.trim(audio, threshold)
  2175.     expectAudio(1, audio)
  2176.     threshold = expect(2, threshold, "number", "nil") or (1/65536)
  2177.     local s, e
  2178.     for i = 1, #audio.data[1] do
  2179.         for c = 1, #audio.data do if math_abs(audio.data[c][i]) > threshold then s = i break end end
  2180.         if s then break end
  2181.     end
  2182.     for i = #audio.data[1], 1, -1 do
  2183.         for c = 1, #audio.data do if math_abs(audio.data[c][i]) > threshold then e = i break end end
  2184.         if e then break end
  2185.     end
  2186.     local new = audio:sub(s / audio.sampleRate, e / audio.sampleRate)
  2187.     audio.data = new.data
  2188.     return audio
  2189. end
  2190.  
  2191. --- Adds a delay to the specified audio.
  2192. -- @tparam Audio audio The audio to modify
  2193. -- @tparam number delay The amount of time to delay for, in seconds
  2194. -- @tparam[opt=0.5] number multiplier The multiplier to apply to the delayed audio
  2195. -- @treturn Audio The audio modified
  2196. function aukit.effects.delay(audio, delay, multiplier)
  2197.     expectAudio(1, audio)
  2198.     expect(2, delay, "number")
  2199.     multiplier = expect(3, multiplier, "number", "nil") or 0.5
  2200.     local samples = math_floor(delay * audio.sampleRate)
  2201.     for c = 1, #audio.data do
  2202.         local original = {}
  2203.         local o = audio.data[c]
  2204.         for i = 1, #o do original[i] = o[i] end
  2205.         for i = samples + 1, #o do o[i] = clamp(o[i] + original[i - samples] * multiplier, -1, 1) end
  2206.     end
  2207.     return audio
  2208. end
  2209.  
  2210. --- Adds an echo to the specified audio.
  2211. -- @tparam Audio audio The audio to modify
  2212. -- @tparam[opt=1] number delay The amount of time to echo after, in seconds
  2213. -- @tparam[opt=0.5] number multiplier The decay multiplier to apply to the echoed audio
  2214. -- @treturn Audio The audio modified
  2215. function aukit.effects.echo(audio, delay, multiplier)
  2216.     expectAudio(1, audio)
  2217.     delay = expect(2, delay, "number", "nil") or 1
  2218.     multiplier = expect(3, multiplier, "number", "nil") or 0.5
  2219.     local samples = math_floor(delay * audio.sampleRate)
  2220.     for c = 1, #audio.data do
  2221.         local o = audio.data[c]
  2222.         for i = samples + 1, #o do o[i] = clamp(o[i] + o[i - samples] * multiplier, -1, 1) end
  2223.     end
  2224.     return audio
  2225. end
  2226.  
  2227. local combDelayShift = {0, -11.73, 19.31, -7.97}
  2228. local combDecayShift = {0, 0.1313, 0.2743, 0.31}
  2229.  
  2230. --- Adds reverb to the specified audio.
  2231. -- @tparam Audio audio The audio to modify
  2232. -- @tparam[opt=100] number delay The amount of time to reverb after, in **milliseconds**
  2233. -- @tparam[opt=0.3] number decay The decay factor to use
  2234. -- @tparam[opt=1] number wetMultiplier The wet (reverbed) mix amount
  2235. -- @tparam[opt=0] number dryMultiplier The dry (original) mix amount
  2236. -- @treturn Audio The audio modified
  2237. function aukit.effects.reverb(audio, delay, decay, wetMultiplier, dryMultiplier)
  2238.     expectAudio(1, audio)
  2239.     delay = expect(2, delay, "number", "nil") or 100
  2240.     decay = expect(3, decay, "number", "nil") or 0.3
  2241.     wetMultiplier = expect(4, wetMultiplier, "number", "nil") or 1
  2242.     dryMultiplier = expect(5, dryMultiplier, "number", "nil") or 0
  2243.     for c = 1, #audio.data do
  2244.         -- four comb filters
  2245.         local sum = {}
  2246.         local o = audio.data[c]
  2247.         for n = 1, 4 do
  2248.             local comb = {}
  2249.             local samples = math_floor((delay + combDelayShift[n]) / 1000 * audio.sampleRate)
  2250.             local multiplier = decay - combDecayShift[n]
  2251.             for i = 1, math_min(samples, #o) do
  2252.                 comb[i] = o[i]
  2253.                 sum[i] = (sum[i] or 0) + o[i]
  2254.             end
  2255.             for i = samples + 1, #o do
  2256.                 local s = o[i] + comb[i - samples] * multiplier
  2257.                 comb[i] = s
  2258.                 sum[i] = (sum[i] or 0) + s
  2259.             end
  2260.         end
  2261.         -- mix wet/dry
  2262.         for i = 1, #sum do sum[i] = sum[i] * wetMultiplier + o[i] * dryMultiplier end
  2263.         -- two all pass filters
  2264.         local samples = math_floor(0.08927 * audio.sampleRate)
  2265.         sum[samples+1] = sum[samples+1] - 0.131 * sum[1]
  2266.         for i = samples + 2, #sum do sum[i] = sum[i] - 0.131 * sum[i - samples] + 0.131 * sum[i + 20 - samples] end
  2267.         o[samples+1] = clamp(sum[samples+1] - 0.131 * sum[1], -1, 1)
  2268.         for i = samples + 2, #sum do o[i] = clamp(sum[i] - 0.131 * sum[i - samples] + 0.131 * sum[i + 20 - samples], -1, 1) end
  2269.     end
  2270.     return audio
  2271. end
  2272.  
  2273. return aukit
  2274.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement