Last active
December 30, 2021 09:21
-
-
Save SwadicalRag/3479530980b2f46d98dd555470d983a0 to your computer and use it in GitHub Desktop.
Panasonic Voice Recorder Triple Rate Codec Decoder (for VM1 files) - uses LuaJIT FFI to call native code
This file contains 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
-- saved at 12000Hz, 16 bit PCM, little endian | |
local vcName = "SD_VC001" | |
local folder = "SD_VOICE/"..vcName | |
ffi=require'ffi' | |
ffi.cdef [[ | |
void vInitDecoder(void); | |
void vDecode(uint8_t* param_1,uint8_t *param_2); | |
void vSet_volume(uint32_t param_1,uint32_t param_2); | |
]] | |
function fileExists(name) local f = io.open(name,"rb") if f ~= nil then io.close(f) return true else return false end end | |
local trc = ffi.load("trcL.dll") | |
local rawMetadataF = io.open(folder.."/SD_VOICE.TKM","rb") | |
local rawMetadata = rawMetadataF:read("*a") | |
rawMetadataF:close() | |
local metadata = {} | |
for entry in rawMetadata:gmatch("TRC_HQ_(%d+/%d+/%d+ %d+%:%d+)\\TRC") do | |
metadata[#metadata + 1] = entry | |
end | |
local clk = os.clock() | |
local fileIdx = 1 | |
while true do | |
trc.vInitDecoder() | |
trc.vSet_volume(0x400,0x40) | |
local input = ffi.new("uint8_t[?]",8192) | |
local output = ffi.new("uint8_t[?]",8192) | |
local infile = io.open(string.format(folder.."/MOB%03d.VM1",fileIdx),"rb") | |
if infile == nil then print("Job complete!") break end | |
local outfileName = string.format("output/OUT_"..vcName.."_MOB%03d.pcm",fileIdx) | |
local outfile = io.open(outfileName,"wb") | |
print(string.format("Processing file "..folder.."/MOB%03d.VM1 (%s)",fileIdx,metadata[fileIdx] or "???")) | |
local curFileMetadata = metadata[fileIdx] | |
fileIdx = fileIdx + 1 | |
-- Dump first 512 bytes | |
infile:read(512) | |
local complete_input = {} | |
local len = 0 | |
while true do | |
local b = infile:read(1) | |
if b == nil then break end | |
complete_input[len] = string.byte(b) | |
len = len + 1 | |
end | |
infile:close() | |
local loc = 0 | |
while true do | |
local cancel = false | |
-- fill frame buffer | |
for i=1,0x200 do | |
if complete_input[i-1 + loc] == nil then cancel = true break end | |
input[i-1] = complete_input[i-1 + loc] | |
end | |
if cancel then break end | |
loc = loc + 0x200 | |
local remaining = 0x200 | |
local cur_loc = 0 | |
while remaining >= 0x18 do | |
local bytesPerFrameRef = 0x18 | |
if fin then break end | |
local cur_input = ffi.cast("uint8_t*",input) + cur_loc | |
local bVar1 = bit.band(cur_input[0], 0xc0) | |
local ok = false | |
if (bVar1 == 0) or (bVar1 == 0x40) then | |
ok = true | |
else | |
bytesPerFrameRef = 8 | |
if bVar1 == 0x80 then | |
ok = true | |
end | |
end | |
if ok then | |
trc.vDecode(output,cur_input) | |
for i=1,0x140 do | |
outfile:write(string.char(output[i-1])) | |
end | |
bytesPerFrameRef = 0x18 | |
end | |
cur_loc = cur_loc + bytesPerFrameRef | |
remaining = remaining - bytesPerFrameRef | |
end | |
if (os.clock() - clk) > 1 then | |
print(string.format("Decoding %.02f%%...",loc / #complete_input * 100)) | |
clk = os.clock() | |
end | |
end | |
outfile:close() | |
local niceOutFile = curFileMetadata or outfileName:gsub("%.pcm$","") | |
niceOutFile = niceOutFile:gsub("[/:]","-") | |
while fileExists("output/"..niceOutFile..".mp3") do niceOutFile = niceOutFile.."-copy" end | |
print("ffmpeg -f s16le -ar 12k -ac 1 -i "..outfileName.." \"output/"..niceOutFile..".mp3\"") | |
os.execute("ffmpeg -f s16le -ar 12k -ac 1 -i "..outfileName.." \"output/"..niceOutFile..".mp3\"") | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment