Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- ####--------------------------------####
- -- #--# Author: by uriid1 #--#
- -- #--# License: GNU GPLv3 #--#
- -- #--# Telegram: @main_moderator #--#
- -- #--# E-mail: appdurov@gmail.com #--#
- -- ####--------------------------------####
- -- Описание .wav
- -- http://soundfile.sapp.org/doc/WaveFormat/
- -- Эта функция взята с
- -- https://stackoverflow.com/questions/5241799/lua-dealing-with-non-ascii-byte-streams-byteorder-change
- -- И изменена под этот скрипт
- function bytes2int(str, endian)
- -- Получаем все байты из строки
- -- в таблицу t
- local t = {
- str:byte(1, -1)
- }
- -- Если это big-endian
- -- то делаем reverse таблицы
- if endian == "big" then
- local tt = {}
- for i = #t, 1, -1 do
- table.insert(tt, t[i])
- end
- t = tt
- end
- local n = 0
- for k = 1, #t do
- n = n + t[k] * 2^( (k-1)*8 )
- end
- return math.floor(n)
- end
- function int2bytes(num, endian, byte_count)
- local res = {}
- local n = math.ceil(select(2, math.frexp(num)) / 8) -- number of bytes to be used.
- for k = n, 1, -1 do -- 256 = 2^8 bits per char.
- local mul = 2^(8*(k-1))
- res[k] = math.floor(num / mul)
- num = num - res[k] * mul
- end
- if endian == "big" then
- local t = {}
- for k = 1,n do
- t[k] = res[n-k+1]
- end
- res = t
- end
- while #res ~= byte_count do
- table.insert(res, 0)
- end
- return string.char(table.unpack(res))
- end
- -- Парсим заголовок и содержимое
- local function parse_wave(path)
- local wav = {}
- local file = io.open(path, 'rb')
- wav.chunkId = file:read(4)
- wav.chunkSize = bytes2int(file:read(4), 'little')
- wav.format = file:read(4)
- wav.subchunk1Id = file:read(4)
- wav.subchunk1Size = bytes2int(file:read(4), 'little')
- wav.audioFormat = bytes2int(file:read(2), 'little')
- wav.numChannels = bytes2int(file:read(2), 'little')
- wav.sampleRate = bytes2int(file:read(4), 'little')
- wav.byteRate = bytes2int(file:read(4), 'little')
- wav.blockAlign = bytes2int(file:read(2), 'little')
- wav.bitsPerSample = bytes2int(file:read(2), 'little')
- wav.subchunk2Id = file:read(4)
- -- d = 100
- -- a = 97
- -- t = 116
- -- Некоторые конвертеры добавляют свои данные -
- -- до блока 'date', поэтому пропускаем эти данные и ищем 'date'
- -- пример ffmpeg -i example.mp3 -f wav example.wav
- -- Запоминаем сколько байт пропустили
- -- Это хак иногда нужно пропустить два байта
- wav.byteOffset = 0
- wav.undefendedData = ''
- if wav.subchunk2Id ~= 'data' then
- -- Помещаем полученные байты в таблицу
- local b = {}
- string.gsub(wav.subchunk2Id, '(.)', function(s)
- table.insert(b, s)
- end)
- if #b < 4 then
- for i = 1, 4 do
- b[i] = b[i] or 0
- end
- end
- -- Хак для некоторых жопных .wav
- if b[3] == 'd' and b[4] == 'a' then
- wav.byteOffset = wav.byteOffset + 2
- end
- -- Ищем слово data, со смещением в 2 байта
- while true do
- local c, d = file:read(2):byte(1, -1)
- b[1], b[2] = b[3], b[4]
- b[3] = string.char(c)
- b[4] = string.char(d)
- if table.concat(b) == 'data' then
- wav.subchunk2Id = 'data'
- break
- end
- -- Неизвестные данные тоже записываем
- wav.undefendedData = wav.undefendedData..b[3]..b[4]
- end
- end
- wav.subchunk2Size = bytes2int(file:read(4), 'little')
- wav.data = file:read(wav.subchunk2Size)
- file:close()
- return wav
- end
- -- Записываем Wav файл
- local function write_wave(path, wav_t)
- local file = io.open(path, 'wb')
- local res = ''
- res = res
- .. wav_t.chunkId
- .. int2bytes(wav_t.chunkSize, 'little', 4)
- .. wav_t.format
- .. wav_t.subchunk1Id
- .. int2bytes(wav_t.subchunk1Size, 'little', 4)
- .. int2bytes(wav_t.audioFormat, 'little', 2)
- .. int2bytes(wav_t.numChannels, 'little', 2)
- .. int2bytes(wav_t.sampleRate, 'little', 4)
- .. int2bytes(wav_t.byteRate, 'little', 4)
- .. int2bytes(wav_t.blockAlign, 'little', 2)
- .. int2bytes(wav_t.bitsPerSample, 'little', 2 + wav_t.byteOffset)
- .. wav_t.subchunk2Id
- .. int2bytes(wav_t.subchunk2Size, 'little', 4)
- .. wav_t.data
- file:write(res)
- file:close()
- end
- ------------------
- -- Парсим
- ------------------
- local wav = parse_wave(arg[1])
- -- Можно засейвить
- -- write_wave('result.wav', wav)
- print('RIFF chunk')
- print('\tchunkId:', wav.chunkId)
- print('\tchunkSize:', wav.chunkSize)
- print('\n')
- print('fmt sub-chunk')
- print('\tformat:\t', wav.format)
- print('\tsubchunk1Id:', wav.subchunk1Id)
- print('\tsubchunk1Size:', wav.subchunk1Size)
- print('\taudioFormat:', wav.audioFormat)
- print('\tnumChannels:', wav.numChannels)
- print('\tsampleRate:', wav.sampleRate)
- print('\tbyteRate:', wav.byteRate)
- print('\tblockAlign:', wav.blockAlign)
- print('\tbitsPerSample:', wav.bitsPerSample)
- print('\n')
- print('data sub-chunk')
- print('\tsubchunk2Id:', wav.subchunk2Id)
- print('\tsubchunk2Size:', wav.subchunk2Size)
- print('\n')
- -- Посчитаем длительность воспроизведения в секундах
- local seconds = 1.0 * wav.subchunk2Size / (wav.bitsPerSample / 8) / wav.numChannels / wav.sampleRate
- local min = math.floor(seconds) / 60
- local sec = math.floor(60 * (min - math.floor(min)))
- local str_min = string.format('%02d', math.floor(min))
- local str_sec = string.format('%02d', sec)
- print("Duration: " .. str_min .. ':' .. str_sec)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement