local wav = {
create_context = function(filename)
if type(filename) ~= "string" then
error("invalid function parameter, expected string filename", 2)
end
local absolute_path = love.filesystem.getSaveDirectory()..'/'..filename
love.filesystem.write(absolute_path, '')
local file = io.open(absolute_path, "wb")
if not file then
error(string.format("couldn't open file %q", filename), 2)
end
local function ntob(n, len)
local n, bytes = math.max(math.floor(n), 0), {}
for i=1, len do
bytes[i] = n % 256
n = math.floor(n / 256)
end
return string.char(unpack(bytes))
end
local function isint(n)
return type(n) == "number" and n == math.floor(n)
end
local channels_number_private, bytes_per_sample
return {
init = function(channels_number, sample_rate, bits_per_sample)
if not isint(channels_number) or channels_number < 1 or
not isint(sample_rate) or sample_rate < 2 or
not (bits_per_sample == 8 or bits_per_sample == 16 or bits_per_sample == 24 or bits_per_sample == 32) then
error("valid channels number, sample rate and bits per sample expected", 2)
end
file:write("RIFF????WAVE") file:write("fmt ",
ntob(16, 4),
ntob(1, 2),
ntob(channels_number, 2),
ntob(sample_rate, 4),
ntob(sample_rate * channels_number * (bits_per_sample / 8), 4),
ntob(channels_number * (bits_per_sample / 8), 2),
ntob(bits_per_sample, 2))
file:write("data????") channels_number_private, bytes_per_sample = channels_number, bits_per_sample / 8
end,
write_samples_interlaced = function(samples)
if type(samples) ~= "table" then
error("samples table expected", 2)
end
local samples_n = #samples
if samples_n == 0 or samples_n % channels_number_private ~= 0 then
error("valid number of samples expected (multiple of channels)", 2)
elseif not file then
error("already finished", 2)
elseif file:seek() == 0 then
error("initialize before writing samples", 2)
end
for i=1, samples_n do
if type(samples[i]) ~= "number" then
error("samples have to be numbers", 2)
end
end
local sample
if bytes_per_sample == 1 then
for i=1, samples_n do
sample = samples[i]
file:write(ntob(sample < 0 and sample + 256 or sample, 1))
end
elseif bytes_per_sample == 2 then
for i=1, samples_n do
sample = samples[i]
file:write(ntob(sample < 0 and sample + 65536 or sample, 2))
end
elseif bytes_per_sample == 3 then
for i=1, samples_n do
sample = samples[i]
file:write(ntob(sample < 0 and sample + 16777216 or sample, 3))
end
else for i=1, samples_n do
sample = samples[i]
file:write(ntob(sample < 0 and sample + 4294967296 or sample, 4))
end
end
end,
finish = function()
if not file then
error("already finished", 2)
elseif file:seek() == 0 then
error("initialize before finishing", 2)
end
local file_size = file:seek()
file:seek("set", 4)
file:write(ntob(file_size - 8, 4))
file:seek("set", 40)
file:write(ntob(file_size - 44, 4))
file:close()
file = nil
end
}
end,
}
function save_wav(filename, sounddata)
local samples = {}
for i = 0, sounddata:getSampleCount() - 1 do
local sample = sounddata:getSample(i)
local n
local to16bit = sample * 32767
if (to16bit > 0) then
n = math.floor(math.min(to16bit, 32767))
else
n = math.floor(math.max(to16bit, -32768))
end
table.insert(samples, n)
end
local w = wav.create_context(filename, "w")
w.init(sounddata:getChannelCount(), sounddata:getSampleRate(), sounddata:getBitDepth())
w.write_samples_interlaced(samples)
w.finish()
end