Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- make global functions local for faster lookup
- local table = table
- local append, concat = table.insert, table.concat
- local string = string
- local sub, gsub, lower = string.sub, string.gsub, string.lower
- local find, match, gmatch = string.find, string.match, string.gmatch
- local ipairs, pairs = ipairs, pairs
- local function file_search(filter, dir_path)
- local function c_in(value, tab)
- for _, v in pairs(tab) do
- if v == value then return true end
- end
- return false
- end
- function string:split(sep)
- local sep, fields = sep or ":", {}
- local pattern = string.format("([^%s]+)", sep)
- self:gsub(pattern, function(c) fields[#fields+1] = c end)
- return fields
- end
- local fs = require 'lfs'
- local filter = string.lower(filter) or "*"
- local dir_path = dir_path or fs.currentdir()
- local extensions = filter:split(";")
- local files = {}
- for _, path in ipairs(dir_path:split(";")) do
- for f in fs.dir(path) do
- if f ~= "." and f ~= ".." then
- local attr = fs.attributes(path..'\\'..f)
- if attr.mode == "file" then
- if filter=="*" or
- c_in(lower(f:match('%.%w*$')), extensions) then
- append(files, {path = path..'\\', name = f})
- end
- elseif attr.mode == "directory" then
- local subf = file_search(filter, path..'\\'..f)
- for _, v in ipairs(subf) do
- append(files, {path = v.path, name = v.name})
- end
- end
- end
- end
- end
- return files
- end
- local function processMeasure(measure)
- local note_lookup_table = {
- ['1000'] = '4', ['0100'] = '2',
- ['0010'] = '8', ['0001'] = '6',
- ['1100'] = '1', ['1010'] = '7',
- ['1001'] = 'B', ['0110'] = 'A',
- ['0101'] = '3', ['0011'] = '9',
- ['1110'] = '<81>', ['0111'] = '<83>',
- ['1101'] = '<61>', ['1011'] = '<8B>',
- ['1111'] = '<19>', ['0000'] = '0',
- }
- local beat_notes = {''} -- reserve beat_notes[1] for opening tag if necessary
- local note_count = 0
- for note in measure:gmatch('%d%d%d%d') do
- append(beat_notes, note_lookup_table[note])
- append(beat_notes, '') -- for possible note padding
- note_count = note_count + 1
- end
- if note_count == 4 then
- for i=3, 9, 2 do beat_notes[i] = '0' end -- add appropriate note padding
- elseif note_count == 8 then
- elseif note_count == 12 then
- for i=3, 25, 2 do beat_notes[i] = '0' end
- beat_notes[1] = '['; append(beat_notes, ']')
- elseif note_count == 16 then
- beat_notes[1] = '('; append(beat_notes, ')')
- elseif note_count == 24 then
- beat_notes[1] = '['; append(beat_notes, ']')
- elseif note_count == 32 then
- for i=3, 65, 2 do beat_notes[i] = '0' end
- beat_notes[1] = '{'; append(beat_notes, '}')
- elseif note_count == 48 then
- for i=3, 97, 2 do beat_notes[i] = '000' end
- beat_notes[1] = '`'; append(beat_notes, '\'')
- elseif note_count == 64 then
- beat_notes[1] = '{'; append(beat_notes, '}')
- elseif note_count == 96 then
- for i=3, 193, 2 do beat_notes[i] = '0' end
- beat_notes[1] = '`'; append(beat_notes, '\'')
- elseif note_count == 192 then
- beat_notes[1] = '`'; append(beat_notes, '\'')
- else
- return nil -- invalid note count
- end
- return concat(beat_notes) .. '\n'
- end
- -------------------------------------------------------------------------------------------------
- local function smToDwi(full_path)
- -- open sm file to read contents into string
- local sm_file
- do
- local tmp = io.open(full_path)
- sm_file = tmp:read('*a')
- tmp:close()
- end
- function string:getFieldContents(field)
- local _, idx = self:find('#'..field..':')
- local str = self:match('%b:;', idx)
- return str:sub(2, #str - 1)
- end
- local changebpm = sm_file:getFieldContents('BPMS')
- local start_bpm
- do -- separate first bpm and bpm changes
- start_bpm = changebpm:match('%d+%.?%d*%s*=%s*(%d+%.?%d*)')
- local _, idx = changebpm:find('%d+%.?%d*%s*=%s*%d+%.?%d*%s*,')
- if idx then changebpm = changebpm:sub(idx + 1)
- else changebpm = '' end
- end
- if changebpm then -- multiply all measures by 4 to convert to beats
- changebpm = changebpm:gsub('(%d+%.?%d*)(%s*=%s*%d+%.?%d*,?)', function(beat, bpm)
- return string.format('%.3f', beat * 4)..bpm
- end)
- end
- -- process common .sm file fields
- local file_contents = {}
- append(file_contents, '#TITLE:' .. sm_file:getFieldContents('TITLE') .. ';\n')
- append(file_contents, '#ARTIST:' .. sm_file:getFieldContents('ARTIST') .. ';\n')
- append(file_contents, '#FILE:' .. sm_file:getFieldContents('MUSIC') .. ';\n')
- append(file_contents, '#BPM:' .. start_bpm .. ';\n')
- append(file_contents, '#GAP:' .. tonumber(sm_file:getFieldContents('OFFSET')) * -1000 .. ';\n')
- append(file_contents, '#SAMPLESTART:' .. sm_file:getFieldContents('SAMPLESTART') .. ';\n')
- append(file_contents, '#SAMPLELENGTH:' .. sm_file:getFieldContents('SAMPLELENGTH') .. ';\n\n')
- if changebpm then
- append(file_contents, '#CHANGEBPM:' .. changebpm .. ';\n')
- end
- append(file_contents, '#SINGLE:MANIAC:1:\n')
- sm_file = sm_file:match(':.+$') -- extract start of note data to end of file
- for measure in sm_file:gmatch('.-[,;]') do
- append(file_contents, processMeasure(measure))
- end
- do -- save converted file
- local contents = concat(file_contents)
- local dwi_file = io.open(full_path:gsub('%.%w*$', '.dwi'), 'w')
- dwi_file:write(contents..'\n')
- dwi_file:close()
- end
- end
- -------------------------------------------------------------------------------------------------
- for _, file in ipairs(file_search('.sm;.ssc;.ds')) do
- smToDwi(file.path .. file.name)
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement