From e959bf30768a30be6e3a2fb81222d6bea442dc45 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Fri, 22 Apr 2011 18:17:00 +0200 Subject: beta 2011.04.22 18:17 --- scripts/context/lua/mtx-colors.lua | 2 +- scripts/context/lua/mtx-flac.lua | 216 +++++++++++++++++++++++++++++++++ scripts/context/lua/mtxrun.lua | 93 +++++++++----- scripts/context/stubs/mswin/mtxrun.lua | 93 +++++++++----- scripts/context/stubs/unix/mtxrun | 93 +++++++++----- 5 files changed, 409 insertions(+), 88 deletions(-) create mode 100644 scripts/context/lua/mtx-flac.lua (limited to 'scripts') diff --git a/scripts/context/lua/mtx-colors.lua b/scripts/context/lua/mtx-colors.lua index ee825a42c..2a51d5099 100644 --- a/scripts/context/lua/mtx-colors.lua +++ b/scripts/context/lua/mtx-colors.lua @@ -17,7 +17,7 @@ mtxrun --script color --table somename ]] local application = logs.application { - name = "mtx-cache", + name = "mtx-colors", banner = "ConTeXt Color Management 0.10", helpinfo = helpinfo, } diff --git a/scripts/context/lua/mtx-flac.lua b/scripts/context/lua/mtx-flac.lua new file mode 100644 index 000000000..dc7f89218 --- /dev/null +++ b/scripts/context/lua/mtx-flac.lua @@ -0,0 +1,216 @@ +if not modules then modules = { } end modules ['mtx-flac'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- Written with Within Temptation's "The Unforgiven" in loopmode on +-- the speakers. The following code is also used for my occasional music +-- repository cleanup session using the code below. + +-- this can become l-flac.lua + +local sub, match, byte, lower = string.sub, string.match, string.byte, string.lower +local readstring, readnumber = io.readstring, io.readnumber +local concat = table.concat +local tonumber = tonumber +local tobitstring = number.tobitstring + +flac = flac or { } + +flac.report = string.format + +local splitter = lpeg.splitat("=") +local readers = { } + +readers[0] = function(f,size,target) -- not yet ok + local info = { } + target.info = info + info.minimum_block_size = readnumber(f,-2) + info.maximum_block_size = readnumber(f,-2) + info.minimum_frame_size = readnumber(f,-3) + info.maximum_frame_size = readnumber(f,-3) + local buffer = { } + for i=1,8 do + buffer[i] = tobitstring(readnumber(f,1)) + end + local bytes = concat(buffer) + info.sample_rate_in_hz = tonumber(sub(bytes, 1,20),2) -- 20 + info.number_of_channels = tonumber(sub(bytes,21,23),2) -- 3 + info.bits_per_sample = tonumber(sub(bytes,24,28),2) -- 5 + info.samples_in_stream = tonumber(sub(bytes,29,64),2) -- 36 + info.md5_signature = readstring(f,16) -- 128 +end + +readers[4] = function(f,size,target,banner) + local tags = { } + target.tags = tags + target.vendor = readstring(f,readnumber(f,-4)) + for i=1,readnumber(f,-4) do + local key, value = lpeg.match(splitter,readstring(f,readnumber(f,-4))) + tags[lower(key)] = value + end +end + +readers.default = function(f,size,target) + f:seek("cur",size) +end + +function flac.getmetadata(filename) + local f = io.open(filename, "rb") + if f then + local banner = readstring(f,4) + if banner == "fLaC" then + local data = { + banner = banner, + filename = filename, + filesize = lfs.attributes(filename,"size"), + } + while true do + local flag = readnumber(f,1) + local size = readnumber(f,3) + local last = flag > 127 + if last then + flag = flag - 128 + end + local reader = readers[flag] or readers.default + reader(f,size,data,banner) + if last then + return data + end + end + else + flac.report("no flac file: %s (%s)",filename,banner) + end + f:close() + else + flac.report("no file: %s",filename) + end +end + +function flac.savecollection(pattern,filename) + pattern = (pattern ~= "" and pattern) or "**/*.flac" + filename = (filename ~= "" and filename) or "music-collection.xml" + flac.report("identifying files using pattern %q" ,pattern) + local files = dir.glob(pattern) + flac.report("%s files found, analyzing files",#files) + local music = { } + for i=1,#files do + local data = flac.getmetadata(files[i]) + if data then + local tags = data.tags + local info = data.info + local artist = tags.artist + local album = tags.album + local albums = music[artist] + if not albums then + albums = { } + music[artist] = albums + end + local albumx = albums[album] + if not albumx then + albumx = { + year = tags.date, + tracks = { }, + } + albums[album] = albumx + end + albumx.tracks[tonumber(tags.tracknumber) or 0] = { + title = tags.title, + length = math.round((info.samples_in_stream/info.sample_rate_in_hz)), + } + end + end + -- inspect(music) + local nofartists, nofalbums, noftracks, noferrors = 0, 0, 0, 0 + local f = io.open(filename,"wb") + if f then + f:write("\n\n") + f:write("\n") + for artist, albums in table.sortedpairs(music) do + nofartists = nofartists + 1 + f:write("\t\n") + f:write("\t\t" .. artist .. "\n") + f:write("\t\t\t\n") + for album, data in table.sortedpairs(albums) do + nofalbums = nofalbums + 1 + f:write("\t\t\t\t\n") + f:write("\t\t\t\t\t" .. album .. "\n") + f:write("\t\t\t\t\t\n") + local tracks = data.tracks + for i=1,#tracks do + local track = tracks[i] + if track then + noftracks = noftracks + 1 + f:write("\t\t\t\t\t\t" .. track.title .. "\n") + else + noferrors = noferrors + 1 + flac.report("error in album: %q of artist",album,artist) + f:write("\t\t\t\t\t\t\n") + end + end + f:write("\t\t\t\t\t\n") + f:write("\t\t\t\t\n") + end + f:write("\t\t\t\n") + f:write("\t\t\n") + end + f:write("\n") + end + f:close() + flac.report("%s tracks of %s albums of %s artists saved in %q (%s errors)",noftracks,nofalbums,nofartists,filename,noferrors) +end + +-- + +local helpinfo = [[ +--collect collect albums in xml file + +example: + +mtxrun --collect somename.flac +mtxrun --collect --pattern="m:/music/**") +]] + +local application = logs.application { + name = "mtx-flac", + banner = "ConTeXt Flac Helpers 0.10", + helpinfo = helpinfo, +} + +flac.report = application.report + +-- script code + +scripts = scripts or { } +scripts.flac = scripts.flac or { } + +function scripts.flac.collect() + local files = environment.files + local pattern = environment.arguments.pattern + if #files > 0 then + for i=1,#files do + local filename = files[1] + if file.suffix(filename) == "flac" then + flac.savecollection(filename,file.replacesuffix(filename,"xml")) + elseif lfs.isdir(filename) then + local pattern = filename .. "/**.flac" + flac.savecollection(pattern,file.addsuffix(file.basename(filename),"xml")) + else + flac.savecollection(file.replacesuffix(filename,"flac"),file.replacesuffix(filename,"xml")) + end + end + elseif pattern then + flac.savecollection(file.addsuffix(pattern,"flac"),"music-collection.xml") + else + flac.report("no file(s) or pattern given" ) + end +end + +if environment.argument("collect") then + scripts.flac.collect() +else + application.help() +end diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 2f81b4629..f399b90a4 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -1683,8 +1683,6 @@ local nextchar = { function io.characters(f,n) if f then return nextchar[n or 1], f - else - return nil, nil end end @@ -1693,40 +1691,42 @@ local nextbyte = { local a, b, c, d = f:read(1,1,1,1) if d then return byte(a), byte(b), byte(c), byte(d) - else - return nil, nil, nil, nil + end + end, + [3] = function(f) + local a, b, c = f:read(1,1,1) + if b then + return byte(a), byte(b), byte(c) end end, [2] = function(f) local a, b = f:read(1,1) if b then return byte(a), byte(b) - else - return nil, nil end end, [1] = function (f) local a = f:read(1) if a then return byte(a) - else - return nil end end, [-2] = function (f) local a, b = f:read(1,1) if b then return byte(b), byte(a) - else - return nil, nil + end + end, + [-3] = function(f) + local a, b, c = f:read(1,1,1) + if b then + return byte(c), byte(b), byte(a) end end, [-4] = function(f) local a, b, c, d = f:read(1,1,1,1) if d then return byte(d), byte(c), byte(b), byte(a) - else - return nil, nil, nil, nil end end } @@ -1782,10 +1782,13 @@ local function readnumber(f,n,m) return byte(f:read(1)) elseif n == 2 then local a, b = byte(f:read(2),1,2) - return 256*a + b + return 256 * a + b + elseif n == 3 then + local a, b, c = byte(f:read(3),1,3) + return 256*256 * a + 256 * b + c elseif n == 4 then local a, b, c, d = byte(f:read(4),1,4) - return 256*256*256 * a + 256*256 * b + 256*c + d + return 256*256*256 * a + 256*256 * b + 256 * c + d elseif n == 8 then local a, b = readnumber(f,4), readnumber(f,4) return 256 * a + b @@ -1795,9 +1798,22 @@ local function readnumber(f,n,m) elseif n == -2 then local b, a = byte(f:read(2),1,2) return 256*a + b + elseif n == -3 then + local c, b, a = byte(f:read(3),1,3) + return 256*256 * a + 256 * b + c elseif n == -4 then local d, c, b, a = byte(f:read(4),1,4) return 256*256*256 * a + 256*256 * b + 256*c + d + elseif n == -8 then + local h, g, f, e, d, c, b, a = byte(f:read(8),1,8) + return 256*256*256*256*256*256*256 * a + + 256*256*256*256*256*256 * b + + 256*256*256*256*256 * c + + 256*256*256*256 * d + + 256*256*256 * e + + 256*256 * f + + 256 * g + + h else return 0 end @@ -1830,7 +1846,7 @@ if not modules then modules = { } end modules ['l-number'] = { -- this module will be replaced when we have the bit library local tostring = tostring -local format, floor, insert, match = string.format, math.floor, string.match +local format, floor, match, rep = string.format, math.floor, string.match, string.rep local concat, insert = table.concat, table.insert local lpegmatch = lpeg.match @@ -1900,27 +1916,37 @@ function number.clearbit(x, p) end -function number.tobitstring(n) +function number.tobitstring(n,m) if n == 0 then - return "00000000" + if m then + rep("00000000",m) + else + return "00000000" + end else - tc = 0 - t = {} + local t = { } while n > 0 do - table.insert(t,1,n % 2 > 0 and 1 or 0) - n = math.floor(n/2) - tc = tc + 1 - end - while tc % 8 > 0 do - table.insert(t,1,0) - tc = tc + 1 - end - n = table.concat(t) - return n + insert(t,1,n % 2 > 0 and 1 or 0) + n = floor(n/2) + end + local nn = 8 - #t % 8 + if nn > 0 and nn < 8 then + for i=1,nn do + insert(t,1,0) + end + end + if m then + m = m * 8 - #t + if m > 0 then + insert(t,1,rep("0",m)) + end + end + return concat(t) end end + end -- of closure do -- create closure to overcome 200 locals limit @@ -8638,6 +8664,15 @@ function xml.collected(root,pattern,reverse) -- e return wrap(function() end) end +-- handy + +function xml.inspect(collection,pattern) + pattern = pattern or "." + for e in xml.collected(collection,pattern or ".") do + report_lpath("pattern %q\n\n%s\n",pattern,xml.tostring(e)) + end +end + end -- of closure diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 2f81b4629..f399b90a4 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -1683,8 +1683,6 @@ local nextchar = { function io.characters(f,n) if f then return nextchar[n or 1], f - else - return nil, nil end end @@ -1693,40 +1691,42 @@ local nextbyte = { local a, b, c, d = f:read(1,1,1,1) if d then return byte(a), byte(b), byte(c), byte(d) - else - return nil, nil, nil, nil + end + end, + [3] = function(f) + local a, b, c = f:read(1,1,1) + if b then + return byte(a), byte(b), byte(c) end end, [2] = function(f) local a, b = f:read(1,1) if b then return byte(a), byte(b) - else - return nil, nil end end, [1] = function (f) local a = f:read(1) if a then return byte(a) - else - return nil end end, [-2] = function (f) local a, b = f:read(1,1) if b then return byte(b), byte(a) - else - return nil, nil + end + end, + [-3] = function(f) + local a, b, c = f:read(1,1,1) + if b then + return byte(c), byte(b), byte(a) end end, [-4] = function(f) local a, b, c, d = f:read(1,1,1,1) if d then return byte(d), byte(c), byte(b), byte(a) - else - return nil, nil, nil, nil end end } @@ -1782,10 +1782,13 @@ local function readnumber(f,n,m) return byte(f:read(1)) elseif n == 2 then local a, b = byte(f:read(2),1,2) - return 256*a + b + return 256 * a + b + elseif n == 3 then + local a, b, c = byte(f:read(3),1,3) + return 256*256 * a + 256 * b + c elseif n == 4 then local a, b, c, d = byte(f:read(4),1,4) - return 256*256*256 * a + 256*256 * b + 256*c + d + return 256*256*256 * a + 256*256 * b + 256 * c + d elseif n == 8 then local a, b = readnumber(f,4), readnumber(f,4) return 256 * a + b @@ -1795,9 +1798,22 @@ local function readnumber(f,n,m) elseif n == -2 then local b, a = byte(f:read(2),1,2) return 256*a + b + elseif n == -3 then + local c, b, a = byte(f:read(3),1,3) + return 256*256 * a + 256 * b + c elseif n == -4 then local d, c, b, a = byte(f:read(4),1,4) return 256*256*256 * a + 256*256 * b + 256*c + d + elseif n == -8 then + local h, g, f, e, d, c, b, a = byte(f:read(8),1,8) + return 256*256*256*256*256*256*256 * a + + 256*256*256*256*256*256 * b + + 256*256*256*256*256 * c + + 256*256*256*256 * d + + 256*256*256 * e + + 256*256 * f + + 256 * g + + h else return 0 end @@ -1830,7 +1846,7 @@ if not modules then modules = { } end modules ['l-number'] = { -- this module will be replaced when we have the bit library local tostring = tostring -local format, floor, insert, match = string.format, math.floor, string.match +local format, floor, match, rep = string.format, math.floor, string.match, string.rep local concat, insert = table.concat, table.insert local lpegmatch = lpeg.match @@ -1900,27 +1916,37 @@ function number.clearbit(x, p) end -function number.tobitstring(n) +function number.tobitstring(n,m) if n == 0 then - return "00000000" + if m then + rep("00000000",m) + else + return "00000000" + end else - tc = 0 - t = {} + local t = { } while n > 0 do - table.insert(t,1,n % 2 > 0 and 1 or 0) - n = math.floor(n/2) - tc = tc + 1 - end - while tc % 8 > 0 do - table.insert(t,1,0) - tc = tc + 1 - end - n = table.concat(t) - return n + insert(t,1,n % 2 > 0 and 1 or 0) + n = floor(n/2) + end + local nn = 8 - #t % 8 + if nn > 0 and nn < 8 then + for i=1,nn do + insert(t,1,0) + end + end + if m then + m = m * 8 - #t + if m > 0 then + insert(t,1,rep("0",m)) + end + end + return concat(t) end end + end -- of closure do -- create closure to overcome 200 locals limit @@ -8638,6 +8664,15 @@ function xml.collected(root,pattern,reverse) -- e return wrap(function() end) end +-- handy + +function xml.inspect(collection,pattern) + pattern = pattern or "." + for e in xml.collected(collection,pattern or ".") do + report_lpath("pattern %q\n\n%s\n",pattern,xml.tostring(e)) + end +end + end -- of closure diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 2f81b4629..f399b90a4 100755 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -1683,8 +1683,6 @@ local nextchar = { function io.characters(f,n) if f then return nextchar[n or 1], f - else - return nil, nil end end @@ -1693,40 +1691,42 @@ local nextbyte = { local a, b, c, d = f:read(1,1,1,1) if d then return byte(a), byte(b), byte(c), byte(d) - else - return nil, nil, nil, nil + end + end, + [3] = function(f) + local a, b, c = f:read(1,1,1) + if b then + return byte(a), byte(b), byte(c) end end, [2] = function(f) local a, b = f:read(1,1) if b then return byte(a), byte(b) - else - return nil, nil end end, [1] = function (f) local a = f:read(1) if a then return byte(a) - else - return nil end end, [-2] = function (f) local a, b = f:read(1,1) if b then return byte(b), byte(a) - else - return nil, nil + end + end, + [-3] = function(f) + local a, b, c = f:read(1,1,1) + if b then + return byte(c), byte(b), byte(a) end end, [-4] = function(f) local a, b, c, d = f:read(1,1,1,1) if d then return byte(d), byte(c), byte(b), byte(a) - else - return nil, nil, nil, nil end end } @@ -1782,10 +1782,13 @@ local function readnumber(f,n,m) return byte(f:read(1)) elseif n == 2 then local a, b = byte(f:read(2),1,2) - return 256*a + b + return 256 * a + b + elseif n == 3 then + local a, b, c = byte(f:read(3),1,3) + return 256*256 * a + 256 * b + c elseif n == 4 then local a, b, c, d = byte(f:read(4),1,4) - return 256*256*256 * a + 256*256 * b + 256*c + d + return 256*256*256 * a + 256*256 * b + 256 * c + d elseif n == 8 then local a, b = readnumber(f,4), readnumber(f,4) return 256 * a + b @@ -1795,9 +1798,22 @@ local function readnumber(f,n,m) elseif n == -2 then local b, a = byte(f:read(2),1,2) return 256*a + b + elseif n == -3 then + local c, b, a = byte(f:read(3),1,3) + return 256*256 * a + 256 * b + c elseif n == -4 then local d, c, b, a = byte(f:read(4),1,4) return 256*256*256 * a + 256*256 * b + 256*c + d + elseif n == -8 then + local h, g, f, e, d, c, b, a = byte(f:read(8),1,8) + return 256*256*256*256*256*256*256 * a + + 256*256*256*256*256*256 * b + + 256*256*256*256*256 * c + + 256*256*256*256 * d + + 256*256*256 * e + + 256*256 * f + + 256 * g + + h else return 0 end @@ -1830,7 +1846,7 @@ if not modules then modules = { } end modules ['l-number'] = { -- this module will be replaced when we have the bit library local tostring = tostring -local format, floor, insert, match = string.format, math.floor, string.match +local format, floor, match, rep = string.format, math.floor, string.match, string.rep local concat, insert = table.concat, table.insert local lpegmatch = lpeg.match @@ -1900,27 +1916,37 @@ function number.clearbit(x, p) end -function number.tobitstring(n) +function number.tobitstring(n,m) if n == 0 then - return "00000000" + if m then + rep("00000000",m) + else + return "00000000" + end else - tc = 0 - t = {} + local t = { } while n > 0 do - table.insert(t,1,n % 2 > 0 and 1 or 0) - n = math.floor(n/2) - tc = tc + 1 - end - while tc % 8 > 0 do - table.insert(t,1,0) - tc = tc + 1 - end - n = table.concat(t) - return n + insert(t,1,n % 2 > 0 and 1 or 0) + n = floor(n/2) + end + local nn = 8 - #t % 8 + if nn > 0 and nn < 8 then + for i=1,nn do + insert(t,1,0) + end + end + if m then + m = m * 8 - #t + if m > 0 then + insert(t,1,rep("0",m)) + end + end + return concat(t) end end + end -- of closure do -- create closure to overcome 200 locals limit @@ -8638,6 +8664,15 @@ function xml.collected(root,pattern,reverse) -- e return wrap(function() end) end +-- handy + +function xml.inspect(collection,pattern) + pattern = pattern or "." + for e in xml.collected(collection,pattern or ".") do + report_lpath("pattern %q\n\n%s\n",pattern,xml.tostring(e)) + end +end + end -- of closure -- cgit v1.2.3