Skip to content

Instantly share code, notes, and snippets.

@lv7777
Created November 12, 2017 11:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lv7777/9e916d6ecd89534f8aead5179af9079e to your computer and use it in GitHub Desktop.
Save lv7777/9e916d6ecd89534f8aead5179af9079e to your computer and use it in GitHub Desktop.
音madミラーっぽい効果を追加
----------------------------------------------------------------------------------------------------
--
-- MIDIFileReader
--
-- 以下のようなテーブルを作成します
--
-- MFR
-- [track]
-- [note]
-- .channel : チャンネル番号
-- .notenum : ノート番号
-- .noteon : ノートオン時のデルタタイム
-- .noteoff : ノートオフ時のデルタタイム
-- .noteontime : ノートオン時の経過秒
-- .noteofftime : ノートオフ時の経過秒
-- .velocity : ベロシティ
-- .pitch : ピッチベンド
-- [index]
-- .time : 変化するデルタタイム
-- .ttime : timeを秒に変換したもの
-- .pitch : ピッチ(半音単位)
-- .trackname : トラックエンド時のデルタタイム
-- .trackend : トラックエンド時のデルタタイム
-- .bpm
-- [index]
-- .bpm : 変化後のBPM値
-- .time : 変化するデルタタイム
-- .ttime : timeを秒に変換したもの
-- .beat
-- [index]
-- .beat : 変化後の拍子(分子)
-- .denom : 変化後の拍子(分母)
-- .time : 変化するデルタタイム
-- .ttime : timeを秒に変換したもの
-- .beatx
-- [measure]
-- .time : 小節の先頭の時間(デルタタイム)
-- .beat : 拍子(分子)
-- .denom : 拍子(分母)
-- .totalbeat : 今までの累計拍数
-- .ttime : timeを秒に変換したもの
-- .lyric
-- [index] : テキスト系イベント
-- .track : データのあるトラック
-- .time : イベントのあるデルタタイム
-- .text : 歌詞
-- .ttime : timeを秒に変換したもの
-- .index : ソート用
-- .marker
-- [index] : テキスト系イベント
-- .track : データのあるトラック
-- .time : イベントのあるデルタタイム
-- .text : マーカー
-- .ttime : timeを秒に変換したもの
-- .index : ソート用
-- .text
-- [index] : テキスト系イベント
-- .track : データのあるトラック
-- .time : イベントのあるデルタタイム
-- .text : テキスト
-- .index : ソート用
-- .resolution : 分解能(四分音符のデルタタイム)
-- .time : 現在の時間(拡張スクリプトにより付加)
--
-- MFR.getTime(dtime)
-- デルタタイムを秒に変換します
--
-- MFR.getDTime(time)
-- 秒をデルタタイムに変換します
--
-- MFR.getBeat(time)
-- 秒をビートに変換します
--
-- MFR.getMeasure(time)
-- 秒を小節に変換します
--
-- MFR.getBPM(time)
-- 現在のBPMを取得します
--
-- MFR.getFirstNote(track,time)
-- timeにより指定された時間に鳴っている音のうち、
-- もっともインデックスが小さいものを返します
-- テーブルのインデックスが各トラック番号になります
--
-- MFR.getNoteonTable(track,time)
-- 以下のような構造を持つテーブルの配列を返します
--
-- track : トラック番号
-- data : データの位置(note[]に対応)
-- notenum : ノート番号
-- velocity : ベロシティ
--
-- MFR.getPassedNoteCount(track,time)
-- time以前に鳴ったノートの個数を返します
--
-- MFR.getFirstPitch(track,time)
-- timeにより指定された時間に適用されている
-- ピッチベンドのインデックスを返します
-- テーブルのインデックスが各トラック番号になります
--
-- MFR.getLyricTable(time)
-- 指定時間における最新の歌詞テーブルを取得します
-- 戻り値2つ目にMFR.lyricに対応するインデックスが返ります
--
-- MFR.getLyric(time)
-- 指定時間における最新の歌詞を取得します
--
-- MFR.getInfo()
-- 簡単な情報をstringで取得します
--
-- 共通事項
-- trackで数値が指定された場合、そのトラック内での情報、
-- nilの場合全トラックの情報をテーブルで返します
--
-- デルタタイムとは、フレームのようなMIDIにおける単位時間のようなものです
-- MFR.resolutionが四分音符のデルタタイム長となります
--
-- テキスト系データは、デルタタイムを基準に昇順のソートをします
-- 同時間の場合はトラックの昇順、同時間同トラックはイベント順です
--
----------------------------------------------------------------------------------------------------
--------------------------------------------------
@MIDIファイル読み込み
--------------------------------------------------
--track3:毎初期,0,1,0,1
--file:
--file:
init = obj.track3
if (obj.time==0 or init~=0 or MFR==nil)then
MIDIFileReader = package.loadlib(obj.getinfo("script_path").."MIDIFileReader.dll", "MIDIFileReader")
if(MIDIFileReader == nil)then
return
end
MFR = MIDIFileReader(file)
local eot = 0
for t=1,#MFR do
if(eot<MFR[t].trackend)then
eot = MFR[t].trackend
end
end
MFR.trackend = eot
local beat = MFR.beat
local beatx = {}
local b = 0
local bc = 1
local res = MFR.resolution
local totalbeat = 0
for i=1,MFR.trackend do
beatx[i] = { time=b, beat=beat[bc].beat, denom=beat[bc].denom, totalbeat=totalbeat }
totalbeat = totalbeat + beat[bc].beat
if(beat[bc]~=nil)then
b = b+(beat[bc].beat/beat[bc].denom)*res*4*4/beat[bc].denom
if(beat[bc+1]~=nil and b>=beat[bc+1].time)then
bc = bc+1
end
else b = b+res*4
end
if(b>MFR.trackend)then break end
end
MFR.beatx = beatx
function MFR.getTime(dtime)
local time = 0
local i = 1
local m = MFR
local res = MFR.resolution
while(m.bpm[i+1]~=nil and dtime>m.bpm[i+1].time) do
dt = m.bpm[i+1].time - m.bpm[i].time
bpm = m.bpm[i].bpm
time = time + 60/bpm*dt/res
i = i+1
end
dt = dtime-m.bpm[i].time
bpm = m.bpm[i].bpm
return time + 60/bpm*dt/res
end
function MFR.getDTime(time)
time = time or MFR.time or obj.time
return MFR.getBeat(time)*MFR.resolution
end
function MFR.getBeat(time)
time = time or MFR.time or obj.time
local i = 1
local m = MFR
local res = MFR.resolution
while(m.bpm[i+1]~=nil) do
if(time<m.bpm[i+1].ttime)then
break
end
i = i+1
end
return m.bpm[i].time/res + ((time - m.bpm[i].ttime)*m.bpm[i].bpm/60)
end
function MFR.getBeat_d(dtime)
local beat = 0
local i = 1
local m = MFR
local res = MFR.resolution
while(m.bpm[i+1]~=nil and dtime>m.bpm[i+1].time) do
dt = m.bpm[i+1].time - m.bpm[i].time
beat = beat + dt/res
i = i+1
end
dt = dtime-m.bpm[i].time
beat = beat + dt/res
return beat
end
function MFR.getMeasure(time)
time = time or MFR.time or obj.time
local beatx = MFR.beatx
local beat = MFR.getBeat(time)
local bi,bd = math.modf(beat)
local measure = #MFR.beatx
-- search measure(int)
-- todo : linear search -> fast
for m=1,#beatx do
if(time<beatx[m].ttime)then
measure = m -- lua index, over run
break
end
end
local mi = measure+1
if(#beatx<mi)then
mi = #MFR.beatx
end
local mbeat = beatx[mi].beat
local totalbeat = beatx[mi].totalbeat
return measure + ((bi+bd)-totalbeat)/mbeat
end
function MFR.getBPM(time)
time = time or MFR.time or obj.time
local i = 1
local m = MFR
while(m.bpm[i+1]~=nil and time>m.bpm[i+1].ttime) do
i = i+1
end
return m.bpm[i].bpm
end
function MFR.getBPM_d(dtime)
local i = 1
local m = MFR
while(m.bpm[i+1]~=nil and dtime>m.bpm[i+1].time) do
i = i+1
end
return m.bpm[i].bpm
end
--------------------------------------------------
-- テキスト系イベントのデータソート
local function TextEventComp(v1,v2) -- ソート用関数
if(v1.time==v2.time)then
if(v1.track==v2.track)then -- 同時間 同トラック
return v1.index < v2.index
else -- 同時間
return v1.track < v2.track
end
else --
return v1.time < v2.time
end
end
table.sort(MFR.lyric, TextEventComp)
table.sort(MFR.marker, TextEventComp)
table.sort(MFR.text, TextEventComp)
-- めんどくさいので予め計算しておく
local gt = MFR.getTime
for t=1,#MFR do
-- note
local td = MFR[t]
for d=1,#td do
MFR[t][d].noteontime = gt(td[d].noteon)
MFR[t][d].noteofftime = gt(td[d].noteoff)
end
-- pitch
local tp = MFR[t].pitch
for p=1,#tp do
MFR[t].pitch[p].ttime = gt(tp[p].time)
end
end
local function setTime(t)
for i=1,#t do
t[i].ttime = gt(t[i].time)
end
end
setTime(MFR.bpm)
setTime(MFR.beat)
setTime(MFR.beatx)
setTime(MFR.lyric)
setTime(MFR.marker)
setTime(MFR.text)
--------------------------------------------------
function MFR.getFirstNote(track,time)
local m = MFR
local gt = m.getTime
local floor = math.floor
local ln = track or #m
local isTable = track==nil
local ret
local ri = 1
if(isTable)then ret = {} end
time = time or MFR.time or obj.time
local range = 64
for t=(track or 1),ln do
local td = m[t]
local tn = #td
local Teot = gt(td.trackend)
local l,r = 1,tn
-- local p = floor(time/Teot*tn)
local p = floor(tn/2)
local first = 0
if(tn<=0)then
first = 0
r = -1
elseif(td[tn].noteontime<=time)then -- 最後のノーツ
if(tn>1)then
p = tn
while(td[p].noteontime<=time and time<=td[p].noteofftime)do
p = p-1
end
first = p+1
if(tn<first)then
first = tn
end
else
first = tn
end
r = -1
end
if(tn<p)then p=tn end
--debug_print("----- "..t.." -------------------------")
while(l<=r)do
if(p<=0)then first = 0 break end
local ndt = td[p].noteon
-- p.noteon < time
if(td[p].noteontime<=time)then
local ppt = p-1
local pnt = p+1
-- 和音時の前の発音
while(td[ppt]~=nil and td[p].noteon<td[ppt].noteoff)do ppt = ppt-1 end
-- 和音時の次の発音
while(td[pnt]~=nil and td[p].noteon==td[pnt].noteon)do pnt = pnt+1 end
if(td[pnt]==nil)then pnt=pnt-1 end
-- p.noteon < time < p+1.noteon
if(time<=td[pnt].noteontime)then
p = ppt+1 - range
if(p<1)then p=1 end
while(td[p]~=nil and p<pnt-1)do
--DebugLog("[%03d/%03d] %.3f <= %.3f <= %.3f", p,pnt, td[p].noteontime,time,td[p].noteofftime)
if(td[p].noteontime<=time and time<=td[p].noteofftime)then
break
end
p = p+1
end
first = p break
-- p.noteon < p+1.noteon < time
else l = p+1
end
-- time < p.noteon
else r = p-1
end
p = floor((l+r)/2)
end
--debug_print(first)
if(isTable)then
ret[ri] = first
ri = ri+1
else ret = first break
end
end
return ret
end
function MFR.getNoteonTable(track,time)
local m = MFR
local floor = math.floor
local l = track or #m
time = time or MFR.time or obj.time
local notelist = {}
local notelisti = 1
local start = m.getFirstNote(track,time)
local isTable = track==nil
for t=(track or 1),l do
local td = m[t]
if(td==nil)then break end
local tn = #td
local sn
if(isTable)then sn = start[t]
else sn = start
end
if(sn>0)then
for n=sn,tn do
local nst = td[n].noteontime
local net = td[n].noteofftime
if(nst<=time and time<=net)then
notelist[notelisti] = { track=t, data=n, notenum=td[n].notenum, velocity=td[n].velocity }
notelisti = notelisti+1
elseif(nst>time)then
break
end
end
end
end
return notelist
end
function MFR.getPassedNoteCount(track,time)
local m = MFR
local l = track or #m
time = time or MFR.time or obj.time
local notelist = {}
local totalnote = 0
local start = m.getFirstNote(track,time)
local isTable = track==nil
if(time>=0)then -- 現在のノート
for t=(track or 1),l do
local td = m[t]
if(td==nil)then break end
local tn = #td
local sn
if(isTable)then sn = start[t]
else sn = start
end
local pass = 0
if(sn>0)then
pass = tn
for n=sn,tn do
if(time<td[n].noteontime)then
pass = n-1
break
end
end
end
notelist[t] = pass
totalnote = totalnote + pass
end
else -- 演奏全体でのノート
for t=(track or 1),l do
notelist[t] = #MFR[t]
totalnote = totalnote + notelist[t]
end
end
notelist.total = totalnote
if(isTable)then
return notelist
else
return notelist[track]
end
end
function MFR.getFirstPitch(track,time)
local m = MFR
local gt = m.getTime
local floor = math.floor
local ln = track or #m
local isTable = track==nil
local ret
if(isTable)then ret = {} end
time = time or MFR.time or obj.time
local range = 64
for t=(track or 1),ln do
local td = m[t].pitch
local tn = #td
local first = 0
if(tn<=0)then -- データがない
first = 0
elseif(td[tn].ttime<=time)then -- 最後のノーツ
local p = tn
while(td[p].time==td[tn].time)do
p = p-1
if(p<0)then
p = -1
break
end
end
first = p+1
else
-- todo : linear -> fast
for p=1,tn do
if(time<td[p].ttime)then
first = p-1
break
end
end
end
if(isTable)then
ret[t] = first
else ret = first break
end
end
return ret
end
function MFR.getLyricTable(time)
time = time or MFR.time or obj.time
local n = #MFR.lyric
local p
for i=1,n do
local d = MFR.lyric[i]
if(time<d.ttime)then
return p,i-1
end
p = d
end
-- no or last lyric
return p,n
end
function MFR.getLyric(time)
return MFR.getLyricTable(time).text
end
function MFR.getInfo()
local info = ""
local note = MFR.getPassedNoteCount()
local allnote = MFR.getPassedNoteCount(nil,-1)
local function add(f,...)
info = info .. string.format(f,...)
end
local fn = file:sub(-1 * file:reverse():find("\\")+1)
add(fn.."\n")
add("BPM : %8.3f\n",MFR.getBPM())
add("Measure : %8.3f\n",MFR.getMeasure())
add("Note : %5d / %5d\n",note.total,allnote.total)
return info
end
end
-- 毎フレーム実行
if(MFR~=nil)then
MFR.time = nil
obj.load("figure","四角形")
--obj.draw(0,0,0,0,0)
--obj.setoption("draw_state",true)
obj.alpha = 0
obj.setoption("focus_mode","fixed_size")
end
--------------------------------------------------
@mad_mirror2
--------------------------------------------------
--file:
--file:
obj.load("image", file)
if((MFR.getPassedNoteCount().total)%2==1)then
debug_print("奇数")
obj.effect("反転","左右反転",1)
else
obj.effect("反転","左右反転",0)
debug_print("偶数")
end
--------------------------------------------------
@表示 ピアノロール
--------------------------------------------------
--track0:幅,0,2048,640,1
--track1:高さ,0,2048,480,1
--track2:速度,0,2000,100
--track3:トラック,0,32,0,1
--dialog:色/col,color=nil;再生位置表示/chk,isPlayline=1;中心位置,PlaylineX=0;ノートオフ透明度,Noteoffalpha=30;減衰/chk,isDecay=0;小節線/chk,isBeatline=0;小節線 フォント,beat_font="MS ゴシック";小節線 文字サイズ,beat_size=16;小節線 文字位置,beat_ypos=100;小節線 透明度,measure_alpha=75;拍線 透明度,beat_alpha=90;オクターブ線 透明度,octaveline_alpha=90;音階線 透明度,noteline_alpha=100;マーカー サイズ,marker_size=16;
if(MFR==nil)then return end
local getTime = MFR.getTime
local drawpoly = obj.drawpoly
local screen_w = obj.track0
local screen_h = obj.track1
local speed = obj.track2
local track = obj.track3
local time = MFR.time or obj.time
time = -time
Noteoffalpha = Noteoffalpha or 100
Noteoffalpha = Noteoffalpha *0.01
PlaylineX = PlaylineX or 0
div = div or 1
beat_font = beat_font or "MS ゴシック"
--beat_size = beat_size or 16
beat_ypos = beat_ypos or 100
measure_alpha = measure_alpha or 100
beat_alpha = beat_alpha or 100
octaveline_alpha= octaveline_alpha or 100
noteline_alpha = noteline_alpha or 100
measure_alpha = 1-measure_alpha *0.01
beat_alpha = 1-beat_alpha *0.01
octaveline_alpha= 1-octaveline_alpha *0.01
noteline_alpha = 1-noteline_alpha *0.01
local function getDigit(num)
local d=1
while(num>=10)do
num = num*0.1
d = d+1
end
return d
end
local function gettx(t)
return t*speed+time*speed + PlaylineX
end
local function getx(dtime)
return gettx(getTime(dtime))
end
local function draw(notenum,noteon,noteoff)
local plx = PlaylineX
local w = screen_w/2
local h = screen_h/0x80
local cy = -screen_h/2
local y = cy + (0x80-1-notenum)*h
local x0,x1 = gettx(noteon), gettx(noteoff)
local y0,y1 = y,y+h
local alpha = Noteoffalpha
if(not(x1<-w or w<x0))then
if(x0<=plx and plx<=x1)then
if(isDecay==0)then
alpha = 1
else
alpha = (1-Noteoffalpha)*(1-(plx-x0)/(x1-x0)) + Noteoffalpha
end
end
drawpoly(
x0,y0,0, x1,y0,0, x1,y1,0, x0,y1,0,
0,0, 0,0, 0,0, 0,0, alpha
)
end
if(w<x0)then return true end -- 手抜き高速化
end
colchange = color==nil
col = color or 0xffffff
obj.setoption("drawtarget","tempbuffer",screen_w,screen_h)
-- 小節線
if(isBeatline==1)then
local load = obj.load
local draw = obj.draw
local beat = MFR.beat
local beatx = MFR.beatx
local eot = MFR.trackend
local res = MFR.resolution
local bs = 0
local bn = #beatx
local h = screen_h*0.5
local bx = 1
if(beat_size~=nil)then
obj.setfont(beat_font,beat_size)
for b=0,bn do
if(beatx[b+1]==nil)then break end
local d = getDigit(b)
local x = getx(beatx[b+1].time)
if(x+beat_size*d>-screen_w/2)then
load("text",b)
draw(x+obj.w/2+2,(screen_h-obj.h)*beat_ypos*0.005)
if(x-beat_size*d>screen_w/2)then
break
end
else
bs = b
end
end
end
obj.load("figure","四角形",0xffffff)
for b=bs,bn do
if(beatx[b+1]==nil)then break end
local x = getx(beatx[b+1].time)
drawpoly(
x , -h, 0, x+1, -h, 0, x+1, h, 0, x , h, 0,
0,0, 0,0, 0,0, 0,0, measure_alpha
)
if(x+1>screen_w/2)then
break
end
local bx = beatx[b+1]
for bb=1,bx.denom-1 do
local x = getx(bx.time+bb/bx.denom*res*bx.denom)
drawpoly(
x , -h, 0, x+1, -h, 0, x+1, h, 0, x , h, 0,
0,0, 0,0, 0,0, 0,0, beat_alpha
)
end
end
-- 音程
local w = screen_w/2
local h = screen_h/0x80
local cy=-screen_h/2
for i=1,(0x80-1) do
local y = cy + (0x80-1-i)*h
local alpha = noteline_alpha
if((i+1)%12==0)then
alpha = octaveline_alpha
end
drawpoly(-w, y , 0, w, y , 0, w, y+1, 0, -w, y+1, 0, 0,0, 0,0, 0,0, 0,0, alpha)
end
-- マーカー
if(marker_size~=nil)then
obj.setfont(beat_font,marker_size)
local marker = MFR.marker
local len = string.len
for i=1,#marker do
local x = getx(marker[i].time)
local ForeW = len(marker[i].text)*marker_size
local ForeX = x+ForeW
if(-w<ForeX and ForeX<w)then
load("text",marker[i].text)
draw(x+obj.w/2+2,(screen_h-obj.h-beat_size*1.5)*(beat_ypos/200))
end
end
end
end
-- 再生位置
if(isPlayline==1)then
x = PlaylineX
w = 1
local h = screen_h/2
obj.load("figure","四角形",0x808080)
obj.drawpoly(x ,-h,0, x+w,-h,0, x+w, h,0, x , h,0)
end
-- ノート
if(#MFR<track)then
obj.load("tempbuffer")
return
end
obj.load("figure","四角形",col)
w,h = obj.getpixel()
local m = MFR
if(track==0)then track = nil end
local l = track or #m
local notelist = m.getFirstNote(track, -time-(screen_w/2+PlaylineX)/speed )
for t=(track or 1),l do
local td = m[t]
local tn = #m[t]
if(tn>0)then
if(colchange)then
obj.effect("単色化","color",HSV((t-1)/16*360,50,100))
end
if(track~=nil)then n = notelist
else n = notelist[t]
end
if(n<1)then n = 1 end
for n=n,tn do
if( draw(td[n].notenum, td[n].noteontime, td[n].noteofftime) )then break end
end
end -- ( #m[t]>0 )
end
obj.load("tempbuffer")
--------------------------------------------------
@表示 ピアノロール3D
--------------------------------------------------
--track0:サイズ,0,512,32,1
--track1:幅,0,10000,3000
--track2:速度,0,2000,500
--track3:トラック,0,32,0,1
--dialog:色/col,color=nil;再生位置表示/chk,isPlayline=1;中心位置,PlaylineX=0;ノートオフ透明度,Noteoffalpha=50;減衰/chk,isDecay=0;トラックのパディング,paddingZ=32;
if(MFR==nil)then return end
local size = obj.track0
local screen_w = obj.track1
local screen_h = size*0x80
local speed = obj.track2
local track = obj.track3
local tnh = #MFR/2
local time = MFR.time or obj.time
time = -time
Noteoffalpha = Noteoffalpha or 100
Noteoffalpha = Noteoffalpha*0.01
PlaylineX = PlaylineX or 0
local function getx(dtime)
return MFR.getTime(dtime)*speed+time*speed + PlaylineX
end
local function draw(notenum,noteon,noteoff, track)
local plx = PlaylineX
local w = screen_w/2
local h = screen_h/0x80
local cy = -screen_h/2
local y = cy + (0x80-1-notenum)*h
local x0,x1 = getx(noteon), getx(noteoff)
local y0,y1 = y,y+h
local z0,z1 = (-tnh+track-1)*(size+paddingZ),(-tnh+track)*(size+paddingZ)-paddingZ
local alpha = Noteoffalpha
local ws = obj.getpixel()
local drawpoly = obj.drawpoly
if(not(x1<-w or w<x0))then
if(x0<=plx and plx<=x1)then
if(isDecay==0)then
alpha = 1
else
alpha = (1-Noteoffalpha)*(1-(plx-x0)/(x1-x0)) + Noteoffalpha
end
end
local u0 = (1-alpha)*ws
drawpoly(x0,y0,z0, x1,y0,z0, x1,y1,z0, x0,y1,z0, u0,u0, u0,u0, u0,u0, u0,u0) -- front
drawpoly(x1,y0,z1, x0,y0,z1, x0,y1,z1, x1,y1,z1, u0,u0, u0,u0, u0,u0, u0,u0) -- back
drawpoly(x0,y0,z1, x1,y0,z1, x1,y0,z0, x0,y0,z0, u0,u0, u0,u0, u0,u0, u0,u0) -- top
drawpoly(x0,y1,z0, x1,y1,z0, x1,y1,z1, x0,y1,z1, u0,u0, u0,u0, u0,u0, u0,u0) -- bottom
drawpoly(x0,y0,z1, x0,y0,z0, x0,y1,z0, x0,y1,z1, u0,u0, u0,u0, u0,u0, u0,u0) -- left
drawpoly(x1,y0,z0, x1,y0,z1, x1,y1,z1, x1,y1,z0, u0,u0, u0,u0, u0,u0, u0,u0) -- right
end
if(w<x0)then return true end -- 手抜き高速化
end
obj.setoption("focus_mode","fixed_size")
obj.setoption("draw_state",true)
obj.setoption("antialias",0)
colchange = color==nil
col = color or 0xffffff
-- 再生位置
if(isPlayline==1)then
x = PlaylineX
w = 1
local h = size*0x40
local z = (size+paddingZ)*tnh - paddingZ
obj.load("figure","四角形",0xffffff)
obj.drawpoly(
x,-h,-z, x,-h, z, x, h, z, x, h,-z,
0,0, 0,0, 0,0, 0,0, 0.25
)
end
-- ノート
if(#MFR<track)then return end
obj.setoption("culling",1)
obj.load("figure","四角形",col)
local w,h = obj.getpixel()
local m = MFR
if(track==0)then track = nil end
local l = track or #m
local tl= track or 1
local notelist = m.getFirstNote(track, -time-(screen_w/2+PlaylineX)/speed-1 )
obj.effect("グラデーション", "no_color",1, "幅",h)
for t=(track or l),tl,-1 do
local td = m[t]
local tn = #m[t]
if(tn>0)then
if(colchange)then
obj.effect("単色化","color",HSV((t-1)/16*360,50,100))
end
if(track~=nil)then n = notelist
else n = notelist[t]
end
if(n<1)then n = 1 end
for n=n,tn do
if( draw(td[n].notenum, td[n].noteon, td[n].noteoff ,t) )then
break
end
end
end -- ( #m[t]>0 )
end
--------------------------------------------------
@表示 鍵盤
--------------------------------------------------
--track0:モード,1,2,1,1
--track1:トラック,0,32,0,1
--dialog:画像ファイル,path="keybord.png";キー 上限,KEYTOP=96;キー 下限,KEYBOT=24;
if(MFR==nil)then return end
local keymap = {0,1,0,1,0,0,1,0,1,0,1,0}
local keyis = {1,1,0,1,1,1,0}
local function getKeyn(bot,top)
bot_s = bot%12
white = 0
black = 0
for n=bot,top do
i = (n+bot_s)%12 +1
if(keymap[i]==0)then white = white +1
else black = black +1
end
end
return white,black
end
local function getWhiteKeyIndex(keynum)
local n = 7
local p = 0
for i=1,keynum%12 do
if(keymap[i]==0)then
p = p+1
end
end
return math.floor(keynum/12)*n + p
end
local floor = math.floor
local mode = obj.track0
local track = obj.track1
KEYTOP = KEYTOP or 127
KEYBOT = KEYBOT or 0
if(KEYBOT>KEYTOP)then KEYBOT,KEYTOP = KEYTOP,KEYBOT end
KEYTOP = math.min(KEYTOP,127)
KEYBOT = math.max(KEYBOT, 0)
obj.load("image",obj.getinfo("script_path").."texture\\"..path)
local w,h = obj.getpixel()
keyw,keyh = w/2,h/2
local white,black = getKeyn(KEYBOT,KEYTOP)
local isTrack
if(track>0)then isTrack = track
else isTrack = nil end -- 念のため
noteonlist = MFR.getNoteonTable()
function isNoteon(track,keynum)
if(noteonlist~=nil)then
for i=1,#noteonlist do
if((track==nil or noteonlist[i].track==track) and noteonlist[i].notenum==keynum)then
return true
end
end
end
return false
end
local function draw(keynum, col, isTrack, track )
local keycol = keymap[(keynum%12)+1]
if(keycol~=col)then return end
keycol = keycol*keyw
local gwhi = getWhiteKeyIndex
local index = gwhi(keynum) - gwhi(KEYBOT)
local cx = -bufw/2
if(track~=nil)then cy = -bufh/2 + (track-0.5)*keyh
else cy = 0 end
x0 = cx + index*(keyw-1) - math.floor(keycol/2)
x1 = x0+keyw
y0,y1 = cy-keyh/2,cy+keyh/2
u0,u1 = keycol,keycol+keyw
v0,v1 = 0,keyh
if( isNoteon(isTrack,keynum) )then
v0 = v0+keyh
v1 = v1+keyh
end
obj.drawpoly(x0,y0,0, x1,y0,0, x1,y1,0, x0,y1,0, u0,v0, u1,v0, u1,v1, u0,v1)
end
---------- 鍵盤作成
bufw = math.ceil((keyw-1)*white+2)
bufh = keyh
if(mode==2)then bufh = keyh*track end
obj.setoption("drawtarget","tempbuffer",bufw,bufh)
if (mode==1)then
for x=KEYBOT,KEYTOP do draw(x,0,isTrack) end -- 白鍵
for x=KEYBOT,KEYTOP do draw(x,1,isTrack) end -- 黒鍵
elseif (mode==2)then
for t=1,track do
for x=KEYBOT,KEYTOP do draw(x,0,t, t) end -- 白鍵
for x=KEYBOT,KEYTOP do draw(x,1,t, t) end -- 黒鍵
end
end
obj.load("tempbuffer")
--------------------------------------------------
@表示 鍵盤(等間隔)
--------------------------------------------------
--track0:モード,1,2,1,1
--track1:トラック,0,32,0,1
--dialog:画像ファイル,path="keybord.png";オクターブ 上限,OctBottom=2;オクターブ 下限,OctTop=7;
if(MFR==nil)then return end
local keymap = {0,1,0,1,0,0,1,0,1,0,1,0}
local keypwhite = {1,0,2,0,3,4,0,5,0,6,0,7}
local keypblack = {0,1,0,2,0,0,3,0,4,0,5,0}
local keyp = {keypwhite, keypblack}
local keyn = {12,7,5}
local noteonlist= MFR.getNoteonTable()
-- 指定キーがノート音か
-- track = 0 で全パート探索
function isNoteon(track,keynum)
if(noteonlist~=nil)then
for i=1,#noteonlist do
if((track==0 or noteonlist[i].track==track) and noteonlist[i].notenum==keynum)then
return true
end
end
end
return false
end
-- 白鍵 = 0 / 黒鍵 = 1
local function getKeyColor(keynum)
return keymap[keynum%keyn[1]+1]
end
-- オクターブ
local function getKeyOct(keynum)
return math.floor(keynum/keyn[1])
end
-- オクターブでの左端からの同色鍵盤の位置
local function getKeyOctPos(keynum)
local c = getKeyColor(keynum)
return keyp[c+1][keynum%keyn[1]+1]
end
-- 音程
local function getKeyTone(keynum)
return keynum%keyn[1]
end
local function Round(v)
local p = v%1
local d = v-p
if(p<0.5)then
return d
else
return d+1
end
end
local floor = math.floor
local mode = obj.track0
local track = obj.track1
-- キー範囲
OctTop = OctTop or 9
OctBottom = OctBottom or -1
if(OctTop<OctBottom)then OctBottom,OctTop = OctTop,OctBottom end
OctTop = math.min(OctTop, 9)
OctBottom = math.max(OctBottom,-1)
local KeyTop = math.min((OctTop+1)*12-1,127)
local KeyBottom = math.max(OctBottom*12, 0)
obj.load("image",obj.getinfo("script_path").."texture\\"..path)
local w,h = obj.getpixel()
local keyw,keyh = w/2,h/2
local octw = (keyw-1)*keyn[2]
local octx = octw/keyw
local isTrack = track>0
local bufw = (OctTop-OctBottom+1)*octw + 1
local bufh = keyh
if(mode==2)then bufh = keyh*track end
local cx = -bufw/2
local dcy1 = 0
local bdx = (keyw - octw/keyn[1])/2 - 1
obj.setoption("drawtarget","tempbuffer",bufw,bufh)
local function draw(keynum, col, track)
local oct = getKeyOct(keynum)
local tone = getKeyTone(keynum)
local keycol = getKeyColor(keynum)
if(keycol~=col)then return end
local cy = dcy1
if(mode==2)then
cy = -bufh/2 + (track-0.5)*keyh
end
local doct = oct-OctBottom
local oi = doct*keyn[2]
if(col==0)then -- white
local index = oi + getKeyOctPos(keynum)-1
x0 = cx + index*(keyw-1)
else -- black
local op = getKeyTone(keynum)/keyn[1]
x0 = cx + Round( (doct+op)*(octw) - bdx )
end
x1 = x0+keyw
y0,y1 = cy-keyh/2,cy+keyh/2
u0,u1 = keycol*keyw,(keycol+1)*keyw
v0,v1 = 0,keyh
if( isNoteon(track,keynum) )then
v0 = v0+keyh
v1 = v1+keyh
end
obj.drawpoly(x0,y0,0, x1,y0,0, x1,y1,0, x0,y1,0, u0,v0, u1,v0, u1,v1, u0,v1)
end
---------- 鍵盤作成
if (mode==1)then
for x=KeyBottom,KeyTop do draw(x,0,track) end -- 白鍵
for x=KeyBottom,KeyTop do draw(x,1,track) end -- 黒鍵
elseif (mode==2)then
for t=1,track do
for x=KeyBottom,KeyTop do draw(x,0,t) end -- 白鍵
for x=KeyBottom,KeyTop do draw(x,1,t) end -- 黒鍵
end
end
obj.load("tempbuffer")
w,h = obj.getpixel()
obj.ox = -(w%2)/2
obj.oy = -(h%2)/2
--------------------------------------------------
@表示 動画再生(速度指定)
--------------------------------------------------
--track0:開始位置,0,1000,0,0.01
--track1:再生速度,-2000,2000,100,0.01
--track2:待機位置,-1,1000,0,0.01
--track3:トラック,0,32,2,1
--check0:アルファチャンネルを読み込む,0
--file:
if(MFR==nil)then return end
if(file==nil)then return end
local T_start = obj.track0
local speed = obj.track1*0.01
local T_wait = obj.track2
local track = obj.track3
local alpha
if(obj.check0)then
alpha = 1 -- アルファあり
else alpha = 0 -- アルファなし
end
-- 動画の時間を取得
local totaltime,framerate = obj.load("movie",file)
if(T_wait>totaltime)then T_wait = totaltime end
local value = 0
if(track==0 or MFR[track]~=nil)then
local m = MFR
local gt = m.getTime
local time = MFR.time or obj.time
if(track==0)then
track = 1
l = #m
else
l = track
end
for t=track,l do
local td = m[t]
local noten = #m[t]
local eot_time = gt(td.trackend)
local v = 0
local n = MFR.getFirstNote(t)
for n=n,noten do
local nont = td[n].noteontime
local nofft = td[n].noteofftime
if(time<nont)then break end
v = time-nont
end
if(value<v)then value = v end
end
if(value<0)then value = 0 end
end
-- 値の調整
time = T_start+value*speed
if(time<0)then time = 0 end
if(totaltime<time)then
if(T_wait>=0)then time = T_wait
else time = totaltime
end
end
obj.load("movie", file, time, alpha)
-- あとなんか自分でやりたかったらこれ使って
MFR_value = value
--------------------------------------------------
@表示 動画再生(フレーム指定)
--------------------------------------------------
--track0:開始位置,0,10000,0,1
--track1:終了位置,0,10000,100,1
--track2:待機位置,-1,10000,0,1
--track3:トラック,0,32,2,1
--check0:アルファチャンネルを読み込む,0
--file:
if(MFR==nil)then return end
if(file==nil)then return end
local F_start = obj.track0
local F_end = obj.track1
local F_wait = obj.track2
local track = obj.track3
if(obj.check0)then
alpha = 1 -- アルファあり
else alpha = 0 -- アルファなし
end
-- 動画の時間を取得
local totaltime,framerate = obj.load("movie",file)
if(F_start>F_end)then
F_start,F_end = F_end,F_start
end
if(F_end>totaltime*framerate)then
F_end = totaltime*framerate
end
if(F_wait<0)then F_wait = F_end end
local value = 0
if(track==0 or MFR[track]~=nil)then
local m = MFR
local gt = m.getTime
local time = MFR.time or obj.time
if(track==0)then
track = 1
l = #m
else
l = track
end
for t=track,l do
local td = m[t]
local noten = #m[t]
local eot_time = gt(td.trackend)
local v = 0
local n = MFR.getFirstNote(t)
for n=n,noten do
local nont = td[n].noteontime
local nofft = td[n].noteofftime
if(time<nont)then break end
v = (time-nont)/(nofft-nont)
end
if(value<v)then value = v end
end
if(value<0)then value = 0 end
end
-- 値の調整
time = (F_start+(F_end-F_start)*(value))/framerate
if(value>1)then
time = F_wait/framerate
end
obj.load("movie", file, time, alpha)
-- あとなんか自分でやりたかったらこれ使って
MFR_value = value
--------------------------------------------------
@表示 歌詞
--------------------------------------------------
--track0:イン,0,10,0.5,0.01
--track1:アウト,0,10,0.5,0.01
--track2:表示秒,0,100,10,0.01
--check0:次歌詞データまで表示させ続ける,0
--dialog:フォント,font="MS UI Gothic";サイズ,size=34;装飾[0-4],decoration=0;色1/col,col1=0xffffff;色2/col,col2=0x000000;表示速度,rate=0;基準位置[1-9],pos=4;
-- [ | | ] "view" sec [ next lyric ]
-- in out
-- | vtime | ntime
local time = MFR.time or obj.time
local intime = obj.track0
local outtime = obj.track1
local viewtime = obj.track2
local isNext = obj.check0
-- 表示時間
local vdata,i = MFR.getLyricTable(time)
if(vdata==nil)then return end
local ndata = MFR.lyric[i+1]
local vtime = vdata.ttime
local ltime = time-vtime
local ntime = vtime + viewtime
if(ndata)then -- 次歌詞が存在
ntime = ndata.ttime
end
local dtime = ntime-vtime
if(isNext)then -- 次データまで
viewtime= dtime
end
dtime = math.min(viewtime,dtime)
-- 表示時間がインアウトより短い
local p = (intime+outtime)/dtime
local ratio = intime/(intime+outtime)
if(1<p)then
intime = intime*p
outtime = outtime*p
end
-- フォント設定
if(col2==nil)then decoration = 0 end
font = font or "MS UI Gothic"
size = size or 34
decoration = decoration or 0
col1 = col1 or 0xffffff
col2 = col2 or 0x000000
rate = rate or 0
pos = pos or 5
if(pos<1 or 9<pos)then pos = 5
else pos = math.floor(pos)
end
-- テキスト読み込み
obj.setfont(font,size,decoration,col1,col2)
obj.load("text",vdata.text,rate,ltime)
-- 座標調整
local px = {0.5,0,-0.5, 0.5,0,-0.5, 0.5,0,-0.5}
local py = {0.5,0.5,0.5, 0,0,0, -0.5,-0.5,-0.5}
obj.ox = obj.w*px[pos]
obj.oy = obj.h*py[pos]
if(ltime/dtime<ratio)then -- イン
local v = (1/intime)*ltime
obj.alpha = math.min(v,1)
else -- アウト
local v = (1/outtime)*(dtime-ltime)
obj.alpha = math.min(math.max(v,0),1)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment