From 2e29fb02c09bb79fea450ea7fac327a910b76f84 Mon Sep 17 00:00:00 2001 From: samba Date: Tue, 16 Jul 2024 23:55:41 +0200 Subject: [PATCH] impl lua mod/functions context --- examples/lua/devices/integra7/integra7.lua | 58 ++++++++++ manual.in.md | 35 +++--- manual.md | 35 +++--- .../tests/eventFunctionInstrumentinfo.sheet | 25 +++++ .../tests/integra7-instrumentDef.sheet | 30 ++++++ rendertests/tests/modinstrumentinfo.lua | 19 +++- rendertests/tests/modinstrumentinfo.sheet | 2 +- src/CMakeLists.txt | 1 + src/compiler/lua/luaContext.cpp | 101 ++++++++++++++++++ src/compiler/lua/luaContext.h | 26 +++++ src/compiler/modification/EventFunction.cpp | 10 +- src/compiler/modification/LuaMod.cpp | 82 ++------------ src/lua/ALuaObject.h | 7 +- 13 files changed, 318 insertions(+), 113 deletions(-) create mode 100644 examples/lua/devices/integra7/integra7.lua create mode 100644 rendertests/tests/eventFunctionInstrumentinfo.sheet create mode 100644 rendertests/tests/integra7-instrumentDef.sheet create mode 100644 src/compiler/lua/luaContext.cpp create mode 100644 src/compiler/lua/luaContext.h diff --git a/examples/lua/devices/integra7/integra7.lua b/examples/lua/devices/integra7/integra7.lua new file mode 100644 index 00000000..08ee5a20 --- /dev/null +++ b/examples/lua/devices/integra7/integra7.lua @@ -0,0 +1,58 @@ +-- +-- creates integra7 parameter sysex messages +-- +-- the parameter (node) id. As placeholder for the partId can `xxx` be used. For exampe `PRM-_PRF-_FPxxx-NEFP_OUT_ASGN` +-- the value +-- specifies the part id. If not set, will be determined using its related instrument channel(s), assuming that the channel never changes. + + +require "/lua/devices/integra7/_model" +require "lua/com/com" + +parameters = { + -- { name="parameterId"}, + -- { name="value"}, + -- { name="partId", default=-1 }, +} + +local function get_partids(params) + if params.partIdsFromInstrument ~= nil then + return params.partIdsFromInstrument + end + if isnumber(params.partId) then + return { tonumber(params.partId) } + end + local function get_id_from_instrument() + + end +end + +function execute(params, timeinfo) + local part_ids = get_partids(params); + local value = tonumber(params.value) + local node_id = string.format(NODE_ID_TEMPLATE, part_nr) + + local nodeinfo = Get_Node(node_id) + if nodeinfo == nil then + error("no node found for id:" .. node_id) + end + nodeinfo.node:setvalue(value) + local sysex = Create_SysexMessage(nodeinfo) + return { + { + ["type"] = "sysex", + ["sysexData"] = sysex, + } + } +end + +local function get_partids_from_instrument(events) + +end + +function perform(events, params, timeinfo) + params.partIdsFromInstrument = get_partids_from_instrument(events) + local midiMessage = execute(params, timeinfo) + table.insert(events, midiMessage[1]) + return events +end \ No newline at end of file diff --git a/manual.in.md b/manual.in.md index 87ebd4a0..e98150a6 100644 --- a/manual.in.md +++ b/manual.in.md @@ -986,7 +986,7 @@ function perform(events, params, timeinfo) end ``` -The perform function has 3 arguments: +The perform function has 4 arguments: ### `events` argument This table contains all input events. @@ -1059,20 +1059,7 @@ This table contains all input events. -- a table of byte values (excluding F0 and F7) -- only relevant if type is "sysex" - sysexData = { byte values }, - - -- some information about the related instrument - instrument = { - name = string, - pan = 0..100, - volume = 0..100, - midiChannel = 0..15, -- optional - midiLsb = 0..127, -- optional - midiMsb = 0..127, -- optional - midiPc = 0..127, -- optional - children: {} -- further instrument children see instrumentSection (https://www.werckme.org/manual#instrumentsection) - } - + sysexData = { byte values } } ... } @@ -1096,6 +1083,24 @@ Contains a table with informations about the current musical time. } ``` +### `context` argument +Contains an interface with some context related functions. + +#### getCurrentInstrument +returns information about the current instrument +```lua +{ + name = string, + pan = 0..100, + volume = 0..100, + midiChannel = 0..15, -- optional + midiLsb = 0..127, -- optional + midiMsb = 0..127, -- optional + midiPc = 0..127, -- optional + children: {} -- further instrument children see instrumentSection (https://www.werckme.org/manual#instrumentsection) +} +``` + ### return value Returns a table containing events. See [events](#events-argument) diff --git a/manual.md b/manual.md index a096e897..d94a66d5 100644 --- a/manual.md +++ b/manual.md @@ -986,7 +986,7 @@ function perform(events, params, timeinfo) end ``` -The perform function has 3 arguments: +The perform function has 4 arguments: ### `events` argument This table contains all input events. @@ -1059,20 +1059,7 @@ This table contains all input events. -- a table of byte values (excluding F0 and F7) -- only relevant if type is "sysex" - sysexData = { byte values }, - - -- some information about the related instrument - instrument = { - name = string, - pan = 0..100, - volume = 0..100, - midiChannel = 0..15, -- optional - midiLsb = 0..127, -- optional - midiMsb = 0..127, -- optional - midiPc = 0..127, -- optional - children: {} -- further instrument children see instrumentSection (https://www.werckme.org/manual#instrumentsection) - } - + sysexData = { byte values } } ... } @@ -1096,6 +1083,24 @@ Contains a table with informations about the current musical time. } ``` +### `context` argument +Contains an interface with some context related functions. + +#### getCurrentInstrument +returns information about the current instrument +```lua +{ + name = string, + pan = 0..100, + volume = 0..100, + midiChannel = 0..15, -- optional + midiLsb = 0..127, -- optional + midiMsb = 0..127, -- optional + midiPc = 0..127, -- optional + children: {} -- further instrument children see instrumentSection (https://www.werckme.org/manual#instrumentsection) +} +``` + ### return value Returns a table containing events. See [events](#events-argument) diff --git a/rendertests/tests/eventFunctionInstrumentinfo.sheet b/rendertests/tests/eventFunctionInstrumentinfo.sheet new file mode 100644 index 00000000..b4376f95 --- /dev/null +++ b/rendertests/tests/eventFunctionInstrumentinfo.sheet @@ -0,0 +1,25 @@ + +using "./modinstrumentinfo.lua"; + +device: _setName=MyDevice _isType=midi _useDevice="FLUID Synth"; +instrumentDef: _setName=piano _onDevice=MyDevice _ch=0 _pc=1 _cc=8; + +instrumentDef: _setName=p1 _onDevice=MyDevice _ch=1 _pc=100; +instrumentDef: _setName=p2 _onDevice=MyDevice _ch=2 _pc=12; +instrumentSection: mySection p1 p2; + +[ +instrument: piano; +{ + /call: modinstrumentinfo/ + c d e f | g a b c' +} +] + +[ +instrument: mySection; +{ + /call: modinstrumentinfo/ + c, d, e, f, | g, a, b, c +} +] diff --git a/rendertests/tests/integra7-instrumentDef.sheet b/rendertests/tests/integra7-instrumentDef.sheet new file mode 100644 index 00000000..8decbaba --- /dev/null +++ b/rendertests/tests/integra7-instrumentDef.sheet @@ -0,0 +1,30 @@ +using "/chords/default.chords"; +using "../../examples/lua/devices/integra7/integra7.lua"; +using "../../examples/lua/mods/myArpeggio.lua"; + +tempo: 150; +device: MyDevice midi _useDevice="DIN 3"; +instrumentDef:guitar _onDevice=MyDevice _pc=0 _ch=6 _bankMsb=89 _bankLsb=64 _pc=97; +instrumentConf: guitar + mod myArpeggio + mod integra7 +; + +[ +type: template; +name: chords; +instrument: guitar; +{ + 1 :(x3) + |: + 1 :(x3)| +} +] + +[ +type: accomp; +{ + /template: chords/ + C | F | G7 :| +} +] \ No newline at end of file diff --git a/rendertests/tests/modinstrumentinfo.lua b/rendertests/tests/modinstrumentinfo.lua index 82569169..f84975c3 100644 --- a/rendertests/tests/modinstrumentinfo.lua +++ b/rendertests/tests/modinstrumentinfo.lua @@ -7,6 +7,9 @@ local function checkinstrument (instrument) if instrument.name == nil then return false end + if #instrument.name == 0 then + return false + end if instrument.children ~= nil then for _, child in pairs(instrument.children) do return checkinstrument(child) @@ -18,9 +21,19 @@ local function checkinstrument (instrument) return true end -function perform(events, params, timeinfo) - if checkinstrument(events[1].instrument) == false then - return {} +function perform(events, params, timeinfo, context) + local instrument = context:getCurrentInstrument() + if checkinstrument(instrument) == false then + error("instrument check failed") end return events +end + +function execute(params, timeinfo, context) + local instrument = context:getCurrentInstrument() + dump(instrument) + if checkinstrument(instrument) == false then + error("instrument check failed") + end + return {} end \ No newline at end of file diff --git a/rendertests/tests/modinstrumentinfo.sheet b/rendertests/tests/modinstrumentinfo.sheet index 588c9266..3fa8ac2f 100644 --- a/rendertests/tests/modinstrumentinfo.sheet +++ b/rendertests/tests/modinstrumentinfo.sheet @@ -23,4 +23,4 @@ instrument: mySection; /mod: modinstrumentinfo/ c, d, e, f, | g, a, b, c } -] \ No newline at end of file +] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c5f9b7dd..8c237cb1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,6 +54,7 @@ SET (SRC_FETZER_LIB compiler/SheetNavigator.cpp compiler/EventInformationServer.cpp compiler/lua/luaTimeInfo.cpp + compiler/lua/luaContext.cpp documentModel/objects/Event.cpp documentModel/objects/ChordDef.cpp documentModel/objects/Track.cpp diff --git a/src/compiler/lua/luaContext.cpp b/src/compiler/lua/luaContext.cpp new file mode 100644 index 00000000..90094a67 --- /dev/null +++ b/src/compiler/lua/luaContext.cpp @@ -0,0 +1,101 @@ +#include "luaContext.h" +#include +#include +#include + +static const char *LUA_CONTEXT_PROPETRY_CURRENT_INSTRUMENT = "getCurrentInstrument"; +static const char *LUA_EVENT_PROPETRY_INSTRUMENT = "instrument"; +static const char *LUA_INSTRUMENT_PROPERTY_CHILDREN = "children"; +static const char *LUA_INSTRUMENT_PROPERTY_NAME = "name"; +static const char *LUA_INSTRUMENT_PROPERTY_VOLUME = "volume"; +static const char *LUA_INSTRUMENT_PROPERTY_PAN = "pan"; +static const char *LUA_INSTRUMENT_PROPERTY_MIDI_CHANNEL = "midiChannel"; +static const char *LUA_INSTRUMENT_PROPERTY_MIDI_MSB = "midiMsb"; +static const char *LUA_INSTRUMENT_PROPERTY_MIDI_LSB = "midiLsb"; +static const char *LUA_INSTRUMENT_PROPERTY_MIDI_PC = "midiPc"; + +namespace lua +{ + + static void pushInstrument(lua_State *L, compiler::IContext &ctx, compiler::AInstrumentDefPtr instrument) + { + lua_createtable(L, 4, 0); + if (!instrument) + { + return; + } + auto top = lua_gettop(L); + // + lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_NAME); + lua_pushstring(L, instrument->uname.c_str()); + lua_settable(L, top); + // + lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_VOLUME); + lua_pushnumber(L, instrument->volume); + lua_settable(L, top); + // + lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_PAN); + lua_pushnumber(L, instrument->pan); + lua_settable(L, top); + // + auto instrumentSection = std::dynamic_pointer_cast(instrument); + if (instrumentSection) + { + lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_CHILDREN); + lua_createtable(L, instrumentSection->instrumentNames.size(), 0); + auto childrenTop = lua_gettop(L); + int index = 1; + for (const auto &uname : instrumentSection->instrumentNames) + { + auto instrumentDef = ctx.getInstrumentDef(uname); + lua_pushinteger(L, index++); + pushInstrument(L, ctx, instrumentDef); + lua_settable(L, childrenTop); + } + lua_settable(L, top); + return; + } + // + auto midiInstrument = std::dynamic_pointer_cast(instrument); + if (!midiInstrument) + { + return; + } + lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_MIDI_CHANNEL); + lua_pushinteger(L, midiInstrument->channel); + lua_settable(L, top); + // + lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_MIDI_MSB); + lua_pushinteger(L, midiInstrument->bankMsb); + lua_settable(L, top); + // + lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_MIDI_LSB); + lua_pushinteger(L, midiInstrument->bankLsb); + lua_settable(L, top); + // + lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_MIDI_PC); + lua_pushinteger(L, midiInstrument->pc); + lua_settable(L, top); + } + + static int getCurrentInstrument(lua_State *L) + { + using namespace lua; + auto luaContext = ALuaObject::getObject(L, -1); + auto top = lua_gettop(L); + // instrument + auto& context = luaContext->context; + auto instrument = context.currentInstrumentDef(); + pushInstrument(L, context, instrument); + return 1; + } + + static const luaL_Reg libfs[] = { + {"getCurrentInstrument", getCurrentInstrument}, + {NULL, NULL}}; + + void LuaContext::push(lua_State *L) + { + Base::push(L, libfs, 1); + } +} diff --git a/src/compiler/lua/luaContext.h b/src/compiler/lua/luaContext.h new file mode 100644 index 00000000..33fb1645 --- /dev/null +++ b/src/compiler/lua/luaContext.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +struct lua_State; + +namespace compiler +{ + class IContext; +} + +namespace lua +{ + + class LuaContext : public lua::ALuaObject + { + public: + typedef lua::ALuaObject Base; + LuaContext(compiler::IContext& context) : context(context) + { + } + void push(lua_State *L); + compiler::IContext &context; + virtual ~LuaContext() = default; + }; +} diff --git a/src/compiler/modification/EventFunction.cpp b/src/compiler/modification/EventFunction.cpp index 440556e9..72a2c627 100644 --- a/src/compiler/modification/EventFunction.cpp +++ b/src/compiler/modification/EventFunction.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -31,8 +32,13 @@ namespace compiler { lua_getglobal(L, LUA_EVENTFUNCTION_FENTRY); pushParameters(L, ALuaWithParameter::parameters); - lua::LuaTimeInfo(ctx->getTimeInfo()).push(L); - call(2, 1); + + lua::LuaTimeInfo ltimeInfo(ctx->getTimeInfo()); + ltimeInfo.push(L); + lua::LuaContext luaCtx(*ctx.get()); + luaCtx.push(L); + + call(3, 1); auto events = popEvents(ctx); outEvents.swap(events); } diff --git a/src/compiler/modification/LuaMod.cpp b/src/compiler/modification/LuaMod.cpp index 19284647..4657b91e 100644 --- a/src/compiler/modification/LuaMod.cpp +++ b/src/compiler/modification/LuaMod.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,6 @@ static const char *LUA_EVENT_TYPE_UNKNOWN = "unknown"; static const char *LUA_EVENT_PROPETRY_VELOCITY = "velocity"; static const char *LUA_EVENT_PROPETRY_DURATION = "duration"; static const char *LUA_EVENT_PROPETRY_TYING = "isTied"; -static const char *LUA_EVENT_PROPETRY_INSTRUMENT = "instrument"; static const char *LUA_EVENT_PROPETRY_OFFSET = "offset"; static const char *LUA_EVENT_PROPETRY_CC_NR = "ccNr"; static const char *LUA_EVENT_PROPETRY_CC_VALUE = "ccValue"; @@ -34,14 +34,6 @@ static const char *LUA_EVENT_PROPETRY_TOAL_TIED_DURATION = "totalTiedDuration"; static const char *LUA_EVENT_PROPERTY_TIED_DURATION = "tiedDuration"; static const char* LUA_EVENT_PROPERTY_TRACK_ID = "trackId"; static const char* LUA_EVENT_PROPERTY_VOICE_ID = "voiceId"; -static const char* LUA_INSTRUMENT_PROPERTY_NAME = "name"; -static const char* LUA_INSTRUMENT_PROPERTY_VOLUME = "volume"; -static const char* LUA_INSTRUMENT_PROPERTY_PAN = "pan"; -static const char* LUA_INSTRUMENT_PROPERTY_MIDI_CHANNEL = "midiChannel"; -static const char* LUA_INSTRUMENT_PROPERTY_MIDI_MSB = "midiMsb"; -static const char* LUA_INSTRUMENT_PROPERTY_MIDI_LSB = "midiLsb"; -static const char* LUA_INSTRUMENT_PROPERTY_MIDI_PC = "midiPc"; -static const char* LUA_INSTRUMENT_PROPERTY_CHILDREN = "children"; namespace compiler { @@ -57,7 +49,6 @@ namespace compiler void push(lua_State *L); void pushPitches(lua_State *L); void pushTags(lua_State *L); - void pushInstrument(lua_State *L, AInstrumentDefPtr instrument); void pushPitchBendValue(lua_State *L, int top, const documentModel::Event &event); const char *getTypename() const; }; @@ -78,10 +69,6 @@ namespace compiler lua_pushstring(L, LUA_EVENT_PITCH_PROPETRY_TAGS); pushTags(L); lua_settable(L, top); - // instrument - lua_pushstring(L, LUA_EVENT_PROPETRY_INSTRUMENT); - pushInstrument(L, ctx->currentInstrumentDef()); - lua_settable(L, top); // offset lua::setTableValue(L, LUA_EVENT_PROPETRY_OFFSET, top, event->offset / com::PPQ); @@ -159,66 +146,6 @@ namespace compiler lua_settable(L, top); } } - void LuaEvent::pushInstrument(lua_State *L, AInstrumentDefPtr instrument) - { - lua_createtable(L, event->tags.size(), 0); - if (!instrument) - { - return; - } - auto top = lua_gettop(L); - // - lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_NAME); - lua_pushstring(L, instrument->uname.c_str()); - lua_settable(L, top); - // - lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_VOLUME); - lua_pushnumber(L, instrument->volume); - lua_settable(L, top); - // - lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_PAN); - lua_pushnumber(L, instrument->pan); - lua_settable(L, top); - // - auto instrumentSection = std::dynamic_pointer_cast(instrument); - if (instrumentSection) - { - lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_CHILDREN); - lua_createtable(L, instrumentSection->instrumentNames.size(), 0); - auto childrenTop = lua_gettop(L); - int index = 1; - for(const auto& uname : instrumentSection->instrumentNames) - { - auto instrumentDef = ctx->getInstrumentDef(uname); - lua_pushinteger(L, index++); - pushInstrument(L, instrumentDef); - lua_settable(L, childrenTop); - } - lua_settable(L, top); - return; - } - // - auto midiInstrument = std::dynamic_pointer_cast(instrument); - if (!midiInstrument) - { - return; - } - lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_MIDI_CHANNEL); - lua_pushinteger(L, midiInstrument->channel); - lua_settable(L, top); - // - lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_MIDI_MSB); - lua_pushinteger(L, midiInstrument->bankMsb); - lua_settable(L, top); - // - lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_MIDI_LSB); - lua_pushinteger(L, midiInstrument->bankLsb); - lua_settable(L, top); - // - lua_pushstring(L, LUA_INSTRUMENT_PROPERTY_MIDI_PC); - lua_pushinteger(L, midiInstrument->pc); - lua_settable(L, top); - } const char *LuaEvent::getTypename() const { using namespace documentModel; @@ -435,8 +362,11 @@ namespace compiler lua_getglobal(L, LUA_MODIFICATION_FENTRY); pushEvents(ctx, events); pushParameters(L, ALuaWithParameter::parameters); - lua::LuaTimeInfo(ctx->getTimeInfo()).push(L); - call(3, 1); + lua::LuaTimeInfo ltimeInfo(ctx->getTimeInfo()); + ltimeInfo.push(L); + lua::LuaContext luaCtx(*ctx.get()); + luaCtx.push(L); + call(4, 1); auto processedEvents = popEvents(ctx); events.swap(processedEvents); } diff --git a/src/lua/ALuaObject.h b/src/lua/ALuaObject.h index 8a08f4af..bb3cca74 100644 --- a/src/lua/ALuaObject.h +++ b/src/lua/ALuaObject.h @@ -42,7 +42,12 @@ namespace lua { throw std::runtime_error("invalid cast for ALuaObject"); } - return dynamic_cast(obj); + TObject *target = dynamic_cast(obj); + if (target == nullptr) + { + throw std::runtime_error("unexpected lua reference error"); + } + return target; } template