∅:D[
2.165] → [
3.1913:2104]
B:BD[
3.1913] → [
3.1913:2104]
B:BD[
3.2104] → [
2.166:203]
∅:D[
2.203] → [
3.2147:2178]
B:BD[
3.2147] → [
3.2147:2178]
B:BD[
3.2178] → [
2.204:309]
∅:D[
2.309] → [
3.2337:2366]
B:BD[
3.2337] → [
3.2337:2366]
B:BD[
3.2366] → [
2.310:349]
∅:D[
2.349] → [
3.2429:2516]
B:BD[
3.2429] → [
3.2429:2516]
B:BD[
3.2516] → [
2.350:421]
∅:D[
2.421] → [
3.2836:3145]
B:BD[
3.2836] → [
3.2836:3145]
B:BD[
3.3196] → [
3.3196:3226]
B:BD[
3.9146] → [
3.9146:9236]
B:BD[
3.9348] → [
3.9348:9756]
B:BD[
3.9943] → [
3.9943:12605]
B:BD[
3.12611] → [
3.12611:12617]
- init(channels_number, sample_rate, bits_per_sample)
- write_samples_interlaced(samples)
- finish()
(WAVE format: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/)
]]
create_context = function(filename)
-- Check function parameters
if type(filename) ~= "string" then
error("invalid function parameter, expected string filename", 2)
end
-- Audio file handle
local file = io.open(filename, "wb")
if not file then
error(string.format("couldn't open file %q", filename), 2)
end
-- Byte-string(unsigned integer,little endian)<-Lua-number converter
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
-- Check for integer
local function isint(n)
return type(n) == "number" and n == math.floor(n)
end
-- Audio meta informations
local channels_number_private, bytes_per_sample
-- Return audio handler
return {
init = function(channels_number, sample_rate, bits_per_sample)
-- Check function parameters
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
-- Write file type
file:write("RIFF????WAVE") -- file size to insert later
-- Write format chunk
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))
-- Write data chunk (so far)
file:write("data????") -- data size to insert later
-- Set format memory
channels_number_private, bytes_per_sample = channels_number, bits_per_sample / 8
end,
write_samples_interlaced = function(samples)
-- Check function parameters
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)
-- Already finished?
elseif not file then
error("already finished", 2)
-- Already initialized?
elseif file:seek() == 0 then
error("initialize before writing samples", 2)
end
-- All samples are numbers?
for i=1, samples_n do
if type(samples[i]) ~= "number" then
error("samples have to be numbers", 2)
end
end
-- Write samples to file
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 -- if bytes_per_sample == 4 then
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()
-- Already finished?
if not file then
error("already finished", 2)
-- Already initialized?
elseif file:seek() == 0 then
error("initialize before finishing", 2)
end
-- Get file size
local file_size = file:seek()
-- Save file size
file:seek("set", 4)
file:write(ntob(file_size - 8, 4))
-- Save data size
file:seek("set", 40)
file:write(ntob(file_size - 44, 4))
-- Finalize file for secure reading
file:close()
file = nil
end
}
end,
- init(channels_number, sample_rate, bits_per_sample)
- write_samples_interlaced(samples)
- finish()
(WAVE format: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/)
]]
create_context = function(filename)
-- Check function parameters
if type(filename) ~= "string" then
error("invalid function parameter, expected string filename", 2)
end
-- Audio file handle
local file = io.open(filename, "wb")
if not file then
error(string.format("couldn't open file %q", filename), 2)
end
-- Byte-string(unsigned integer,little endian)<-Lua-number converter
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
-- Check for integer
local function isint(n)
return type(n) == "number" and n == math.floor(n)
end
-- Audio meta informations
local channels_number_private, bytes_per_sample
-- Return audio handler
return {
init = function(channels_number, sample_rate, bits_per_sample)
-- Check function parameters
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
-- Write file type
file:write("RIFF????WAVE") -- file size to insert later
-- Write format chunk
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))
-- Write data chunk (so far)
file:write("data????") -- data size to insert later
-- Set format memory
channels_number_private, bytes_per_sample = channels_number, bits_per_sample / 8
end,
write_samples_interlaced = function(samples)
-- Check function parameters
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)
-- Already finished?
elseif not file then
error("already finished", 2)
-- Already initialized?
elseif file:seek() == 0 then
error("initialize before writing samples", 2)
end
-- All samples are numbers?
for i=1, samples_n do
if type(samples[i]) ~= "number" then
error("samples have to be numbers", 2)
end
end
-- Write samples to file
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 -- if bytes_per_sample == 4 then
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()
-- Already finished?
if not file then
error("already finished", 2)
-- Already initialized?
elseif file:seek() == 0 then
error("initialize before finishing", 2)
end
-- Get file size
local file_size = file:seek()
-- Save file size
file:seek("set", 4)
file:write(ntob(file_size - 8, 4))
-- Save data size
file:seek("set", 40)
file:write(ntob(file_size - 44, 4))
-- Finalize file for secure reading
file:close()
file = nil
end
}
end,