Created
July 29, 2020 04:58
-
-
Save MikuAuahDark/36c379c286b9dc93d7f323419038ad5f to your computer and use it in GitHub Desktop.
Reorder WAV chunks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Reorder WAV chunks files | |
-- This often useful if particular program expects "WAVE" identifier | |
-- followed by "fmt " chunk and followed by "data " chunk. Particularly | |
-- GTA San Andreas User Tracks. | |
-- You can use part or all of this code without my permissions. | |
local arg = {...} | |
local fin = assert(io.open(assert(arg[1], "need input file"), "rb")) | |
local fout = assert(io.open(assert(arg[2], "need output file"), "wb")) | |
assert(fin:read(3) == "RIF", "Not RIFF") | |
local last = fin:read(1) | |
local big = last == "X" | |
assert(last == "X" or last == "F", "Not RIFF") | |
fin:read(4) -- ignore length, recompute later | |
assert(fin:read(4) == "WAVE", "Not WAVE") | |
local function string2dword(s, big) | |
local a, b, c, d = s:byte(1, 4) | |
if big then | |
return a * 16777216 + b * 65536 + c * 256 + d | |
else | |
return d * 16777216 + c * 65536 + b * 256 + a | |
end | |
end | |
local function dword2string(n, big) | |
n = n % 4294967296 | |
local a = n % 256 | |
local b = math.floor(n / 256) % 256 | |
local c = math.floor(n / 65536) % 256 | |
local d = math.floor(n / 16777216) | |
if big then | |
return string.char(d, c, b, a) | |
else | |
return string.char(a, b, c, d) | |
end | |
end | |
-- We store chunks in memory for sake of simplicity | |
local chunks = {} | |
while true do | |
io.write("position ", fin:seek("cur"), "\n") | |
local fourcc = fin:read(4) | |
if not(fourcc) then | |
break -- ok EOF | |
elseif #fourcc < 4 then | |
io.write("Ignoring data at ", fin:seek("cur") - #fourcc, "\n") | |
break | |
end | |
local length = fin:read(4) | |
if not(length) or #length < 4 then | |
io.write("Ignoring fourcc ", fourcc, " at ", fin:seek("cur") - #length, "\n") | |
break | |
end | |
length = string2dword(length, big) | |
io.write(fourcc, " size of ", length, "\n") | |
local chunk = fin:read(length) | |
if not(chunk) or #chunk < length then | |
io.write("Ignoring fourcc ", fourcc, " at ", fin:seek("cur") - #chunk, ". Expected ", length, ", got ", #chunk, "\n") | |
break | |
end | |
chunks[#chunks + 1] = { | |
name = fourcc, | |
data = chunk | |
} | |
end | |
fin:close() | |
-- Reorder "fmt " chunk | |
local hasfmt = false | |
for i, v in ipairs(chunks) do | |
if v.name == "fmt " then | |
table.insert(chunks, 1, table.remove(chunks, i)) | |
hasfmt = true | |
break | |
end | |
end | |
assert(hasfmt, "missing \"fmt \" chunk") | |
-- Reorder "data" chunk | |
local hasdata = false | |
for i, v in ipairs(chunks) do | |
if v.name == "data" then | |
table.insert(chunks, 2, table.remove(chunks, i)) | |
hasdata = true | |
break | |
end | |
end | |
assert(hasdata, "missing \"data\" chunk") | |
-- Rewrite wav file | |
local length = 4 -- "WAVE" | |
for _, v in ipairs(chunks) do | |
length = length + #v.data + 8 -- 4cc + length + data | |
end | |
-- Write header | |
fout:write("RIF", last, dword2string(length, big), "WAVE") | |
for _, v in ipairs(chunks) do | |
fout:write(v.name, dword2string(#v.data, big), v.data) | |
end | |
fout:close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment