Skip to content

Instantly share code, notes, and snippets.

@aisot

aisot/main.lua Secret

Last active February 22, 2023 10:10
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 aisot/c16e612aad2a15e165eff54cd7e35315 to your computer and use it in GitHub Desktop.
Save aisot/c16e612aad2a15e165eff54cd7e35315 to your computer and use it in GitHub Desktop.
[OSC]MIDI受信ピアノ VCIで使用しているLuaスクリプト
-- [Piano receiving OSC]
-- main.lua MIT License by aisot
-- Version 2023.02.20
-- MIDI OSC を受信して vci.message を送信
local Mome = require("metry-osc-midi-emit")
local isReceiveEnabled = vci.osc.IsReceiveEnabled()
vci.assets.SetText("Text1",
"OSC ReceiveEnabled : " .. tostring(isReceiveEnabled))
vci.assets.SetText("Text2", "")
-- 複数のMIDI OSC受信アイテムがある場合、Useしたアイテムがvci.messageへの送信を担当する
onUse = Mome:addEventStartEmit(onUse)
-- 受信したvci.message からMIDIを受信してピアノを動かす
local prefix = "pianola_"
local KeyItemsObj = {}
local KeyItemsRot = {}
for key_num = 1, 88 do
local item_name = prefix .. key_num
local itemObj = vci.assets.GetTransform(item_name)
KeyItemsObj[key_num] = itemObj
KeyItemsRot[key_num] = itemObj.GetLocalRotation()
end
-- 鍵盤の色と回転をリセットする onUse時などに呼ばれる
function Mome:onOscToVciMsgStart()
for key_num = 1, 88 do
KeyItemsObj[key_num].SetLocalRotation(KeyItemsRot[key_num])
vci.assets.material.Reset(prefix .. key_num);
end
end
function onMsgMidiNoteOn(sender, name, data)
local channel, note_num, velocity = unpack(data)
text = "NoteOn:" .. channel .. "," .. note_num .. "," .. velocity
vci.assets.SetText("Moniter", text)
if note_num < 21 or note_num > 108 then return end
if not (channel == 0) then return end
local key_num = note_num - 21 + 1
local mat_name = prefix .. key_num
local itemObj = KeyItemsObj[key_num]
local item_rot = KeyItemsRot[key_num]
local rot = Quaternion.AngleAxis(-2, Vector3.left);
itemObj.SetLocalRotation(item_rot * rot)
local color = Color.__new(1.5, 0.01, 0.01);
vci.assets.material.SetColor(mat_name, color)
end
vci.message.On("/midi/noteon", onMsgMidiNoteOn)
function onMsgMidiNoteOff(sender, name, data)
local channel, note_num, velocity = unpack(data)
text = "NoteOff:" .. channel .. "," .. note_num .. "," .. velocity
vci.assets.SetText("Moniter", text)
if note_num < 21 or note_num > 108 then return end
if not (channel == 0) then return end
local key_num = note_num - 21 + 1
local mat_name = prefix .. key_num
KeyItemsObj[key_num].SetLocalRotation(KeyItemsRot[key_num])
vci.assets.material.Reset(mat_name);
end
vci.message.On("/midi/noteoff", onMsgMidiNoteOff)
function onMsgMidiControlChange(sender, name, data)
local channel, number, value = unpack(data)
text = "ControlChange:" .. channel .. "," .. number .. "," .. value
vci.assets.SetText("Moniter", text)
end
vci.message.On("/midi/controlchange", onMsgMidiControlChange)
function onMsgMidiPitchbend(sender, name, data)
local channel, msb, lsb = unpack(data)
local text = "Pitchbend:" .. channel .. "," .. msb .. "," .. lsb
vci.assets.SetText("Moniter", text)
end
vci.message.On("/midi/pitchbend", onMsgMidiPitchbend)
-- metry-osc-midi-emit.lua MIT License by aisot
-- Version 2023.02.20
-- MIDI OSC を受信して vci.message を送信
local moMidiEmit = {}
local MIDI = require("metry-osc-midi")
local instanceId = vci.assets.GetInstanceId()
local isReceiveEnabled = vci.osc.IsReceiveEnabled()
local isMidiMsgEmit = false
-- MIDI OSC受信アイテムが複数ある場合、二重送信を防止する(最後に出したアイテムが送信する)
function moMidiEmit:onInit(isMidiMsgEmit) end
vci.message.On("/oscToMsgStart", function(sender, name, receiveInstantID)
isMidiMsgEmit = (instanceId == receiveInstantID)
print("MidiMsgEmit : " .. tostring(isMidiMsgEmit))
--vci.assets.SetText("Text2", "MidiMsgEmit : " .. tostring(isMidiMsgEmit))
end)
vci.message.Emit("/oscToMsgStart", instanceId)
-- イベント関数にoscToVciMsgStartEmitを追加する
-- onUse = moMidiEmit:addEventStartEmit(onUse)
function moMidiEmit:addEventStartEmit(eventFunction)
return function(...)
if eventFunction then eventFunction(...) end
vci.message.Emit("/oscToMsgStart", instanceId)
end
end
-- OSCから受信したMIDIを自身を含む他のVCIに向けにvci.messageを送信
function MIDI:onNoteOn(...)
if vci.assets.IsMine and isMidiMsgEmit then
vci.message.Emit("/midi/noteon", {...})
end
end
function MIDI:onNoteOff(...)
if vci.assets.IsMine and isMidiMsgEmit then
vci.message.Emit("/midi/noteoff", {...})
end
end
function MIDI:onControlChange(...)
if vci.assets.IsMine and isMidiMsgEmit then
vci.message.Emit("/midi/controlchange", {...})
end
end
function MIDI:onPitchbend(...)
if vci.assets.IsMine and isMidiMsgEmit then
vci.message.Emit("/midi/pitchbend", {...})
end
end
function MIDI:onRawMidi(...)
if vci.assets.IsMine and isMidiMsgEmit then
vci.message.Emit("/midi/rawmidi", {...})
end
end
return moMidiEmit
-- metry-osc-midi.lua MIT License by aisot
-- Version 2023.02.19
-- MIDI OSC 受信する
local moMidi = {}
local isEnabled = vci.osc.IsReceiveEnabled()
if (isEnabled == false) then return moMidi end
local String = vci.osc.types.String
local Int = vci.osc.types.Int32
local Floart = vci.osc.types.Float32
local Blob = vci.osc.types.BlobAsUtf8
local III = {Int, Int, Int}
local I = {Int}
local nilError = function(s)
print(s .. " - Data in OSC is nil.")
return -1
end
---------------------------------------------------------
-- NoteOn
-- /midi/noteon/ INT32 INT32 INT32
---------------------------------------------------------
function moMidi:onNoteOn(channel, pitch, velocity)
print("onNoteOn:" .. channel .. "," .. pitch .. "," .. velocity)
end
local function noteOn(...)
if ... == nil then return nilError("noteOn") end
moMidi:onNoteOn(...)
end
vci.osc.RegisterMethod("/midi/noteon/", noteOn, III)
vci.osc.RegisterMethod("/midi/noteon", noteOn, III)
---------------------------------------------------------
-- NoteOff
-- /midi/noteoff/ INT32 INT32 INT32
---------------------------------------------------------
function moMidi:onNoteOff(channel, pitch, velocity)
print("onNoteOff:" .. channel .. "," .. pitch .. "," .. velocity)
end
local function noteOff(...)
if ... == nil then return nilError("noteOff") end
moMidi:onNoteOff(...)
end
vci.osc.RegisterMethod("/midi/noteoff/", noteOff, III)
vci.osc.RegisterMethod("/midi/noteoff", noteOff, III)
---------------------------------------------------------
-- ControlChange
-- /midi/controlchange INT32 INT32 INT32
---------------------------------------------------------
function moMidi:onControlChange(channel, number, value)
print("moMidi:onControllerChange:" .. channel .. "," .. number .. "," ..
value)
end
local function ControlChange(...)
if ... == nil then return nilError("controllerChange") end
moMidi:onControlChange(...)
end
vci.osc.RegisterMethod("/midi/controlchange", ControlChange, III)
---------------------------------------------------------
-- Pitchbend - ch msb lsb
-- /midi/pitchbend INT32 INT32 INT32
--------------------------------------------------------
function moMidi:onPitchbend(channel, msb, lsb)
print("moMidi:onPitchbend:" .. channel .. "," .. msb .. "," .. lsb)
end
local function pitchbend(...)
if ... == nil then return nilError("pitchbend") end
moMidi:onPitchbend(...)
end
vci.osc.RegisterMethod("/midi/pitchbend", pitchbend, III)
---------------------------------------------------------
-- Raw midi
-- /rawmidi INT32 INT32 INT32
---------------------------------------------------------
function moMidi:onRawMidi(event, data1, data2)
print("moMidi:onRawMidi:" .. event .. "," .. data1 .. "," .. data2)
end
local function rawMidi(event, data1, data2)
if event == nil then return nilError("rawMidi") end
-- print("rawMidi:" .. event .. "," .. data1 .. "," .. data2)
-- noteOff
if event >= 0x80 and event <= 0x8F then
local channel, pitch, velocity = event - 0x80, data1, data2
moMidi:onNoteOff(channel, pitch, velocity)
-- noteOn
elseif event >= 0x90 and event <= 0x9F then
local channel, pitch, velocity = event - 0x90, data1, data2
moMidi:onNoteOn(channel, pitch, velocity)
-- Control Change
elseif event >= 0xB0 and event <= 0xBF then
local channel, msb, lsb = event - 0xB0, data1, data2
moMidi:onControlChange(channel, msb, lsb);
-- Pitch Wheel
elseif event >= 0xE0 and event <= 0xEF then
local channel, msb, lsb = event - 0xE0, data1, data2
moMidi:onPitchbend(channel, msb, lsb)
else
moMidi:onRawMidi(event, data1, data2)
end
end
vci.osc.RegisterMethod("/rawmidi", rawMidi, III)
---------------------------------------------------------
-- OSC/PAR(https://oscpilot.com/pages/osc-par)
-- /TrackName/note_[1-127] INT32
-- /midi/[1-16]/note_[1-127] INT32
---------------------------------------------------------
for pitch = 0, 127 do
for channel = 0, 15 do
local func = function(velocity)
if velocity == 0 then
moMidi:onNoteOff(channel, pitch, velocity)
else
moMidi:onNoteOn(channel, pitch, velocity)
end
end
if channel == 0 then
-- default TrackName OSC address
vci.osc.RegisterMethod("/TrackName/note_" .. pitch, func, I)
end
local chName = channel + 1
vci.osc.RegisterMethod("/midi/" .. chName .. "/note_" .. pitch, func, I)
end
end
return moMidi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment