ericek111

aukit for tekkit 2, test

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