Created
November 12, 2017 11:47
-
-
Save lv7777/9e916d6ecd89534f8aead5179af9079e to your computer and use it in GitHub Desktop.
音madミラーっぽい効果を追加
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------------------------------------------------------------------------------------- | |
-- | |
-- 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