cbdevnet / midimonster

Multi-protocol control & translation software (ArtNet, MIDI, OSC, sACN, ...)
https://midimonster.net/
BSD 2-Clause "Simplified" License
500 stars 49 forks source link

Lua interpreter extensions may fail to load if not linked against liblua themselves #102

Open bcslaam opened 2 years ago

bcslaam commented 2 years ago

My config wont parse because it gets this:

Failed to load source file fsgc2ir.lua for instance gc: error loading module 'socket.core' from file '/usr/lib/arm-linux-gnueabihf/lua/5.3/socket/core.so':
    /usr/lib/arm-linux-gnueabihf/lua/5.3/socket/core.so: undefined symbol: lua_gettop

Running Raspberry Pi4 with Raspbian latest. Aim is to use TouchOSC to control multiple aspects of my studio I have lua 5.1, 5.2 and 5.3 installed as well as luasocket library. Is there any other libraries I need? I tried installing the socket library with luarocks but it comes up with this error:

pi@raspberrypi:~ $ sudo luarocks install luasocket
Installing https://luarocks.org/luasocket-3.0rc1-2.src.rock
gcc -O2 -fPIC -I/usr/include/lua5.1 -c src/mime.c -o src/mime.o -DLUA_COMPAT_APIINTCASTS -DLUASOCKET_DEBUG -DLUASOCKET_API=__attribute__((visibility("default"))) -DUNIX_API=__attribute__((visibility("default"))) -DMIME_API=__attribute__((visibility("default")))
src/mime.c:7:10: fatal error: lua.h: No such file or directory
 #include "lua.h"
          ^~~~~~~
compilation terminated.

Error: Build error: Failed compiling object src/mime.o

so I installed all the libraries the standard way including socket:

sudo apt-get install luasocket
sudo apt-get install luasocket-dev
bcslaam commented 2 years ago

here's my config, osc to artnet was working fine. It was since I introduced osc to lua to address a globalcache device that it no longer parses:

[backend artnet]
bind = 0.0.0.0

[osc touch]
bind = 127.0.0.1 8000

/*f/1 = f 0.0 1.0
/*f/2 = f 0.0 1.0
/*f/3 = f 0.0 1.0
/*f/4 = f 0.0 1.0
/*f/5 = f 0.0 1.0
/*f/6 = f 0.0 1.0
/*f/7 = f 0.0 1.0
/*f/8 = f 0.0 1.0
/*f/9 = f 0.0 1.0
/*f/10 = f 0.0 1.0

[artnet net1]
destination = 192.168.1.100

[lua gc]
script = fsgc2ir.lua

[map]
touch./crp1f/{1..10} > net1.{001..010}
touch./crp2f/{1..10} > net1.{011..020}
touch./crp3f/{1..10} > net1.{021..030}
touch./crp4f/{1..10} > net1.{031..040}
touch./crp5f/{1..10} > net1.{041..050}
touch./crp6f/{1..10} > net1.{051..060}
touch./trp7f/{1..10} > net1.{061..070}
touch./trp8f/{1..10} > net1.{071..080}
touch./trp9f/{1..10} > net1.{081..090}
touch./trp10f/{1..10} > net1.{091..100}
touch./trp11f/{1..10} > net1.{101..110}
touch./trp12f/{1..10} > net1.{111..120}

touch./vidpager/{0..15} > gc.input{1..16}
touch./daw1/1 > gc.output1
touch./daw2/1 > gc.output2
touch./daw3/1 > gc.output3
touch./daw4/1 > gc.output4
touch./ws/1 > gc.output5
touch./wr/1 > gc.output6
touch./av/1 > gc.output7
touch./output8/1 > gc.output8
touch./output9/1 > gc.output9
touch./proj/1 > gc.output10
touch./output11/1 > gc.output11
touch./output12/1 > gc.output12
touch./output13/1 > gc.output13
touch./output14/1 > gc.output14
touch./output15/1 > gc.output15
touch./bmcard/1 > gc.output16
bcslaam commented 2 years ago

here is the main top part of my lua script, the osc side is a button (exclusive, off or on, using radio buttons). It carries on with all the ir codes so its repetitious beyond:

print(os.getenv("HOME"))
local socket = require("socket")

host = "192.168.1.70"
port = 4998

print("Attempting connection to host '" ..host.. "' and port " ..port.. "...")
c = assert(socket.connect(host, port))

print("Connection OK")

function power(value)
    if value > 0.9 then
        c:send("sendir,1:1,0,38000,1,1,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,64,21,21,21,21,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655")
    end
end

function input1(value)
    if value > 0.9 then
        c:send("sendir,1:1,0,38000,1,1,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655")
    end
end

function input2(value)
    if value > 0.9 then
        c:send("sendir,1:1,0,38000,1,1,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655")
    end
end

and so on....

bcslaam commented 2 years ago

I have decided to change to Ubuntu 21.10 on the RPi4 because I need 64bit I have installed mm and lua5.3 and lua-socket but I am still getting this:

lua Failed to load source file fsgc2ir.lua for instance gc: error loading module 'socket.core' from file '/usr/lib/aarch64-linux-gnu/lua/5.3/socket/core.so':
    /usr/lib/aarch64-linux-gnu/lua/5.3/socket/core.so: undefined symbol: lua_gettop
core/cfg    Failed to configure instance gc
bcslaam commented 2 years ago

someone please help, this is driving me nuts

cbdevnet commented 2 years ago

Hey, sorry for taking so long - I currently can't dedicate as much time to my open source projects as I would like to. Thank you for providing a lot of valuable information on the environment, that will definitely help in reproducing the situation in question!

I think this may be a deeper problem with the way Lua extensions are implemented, as they may expect to be able to resolve the lua_ API symbols in the host interpreter. This is something the MIDIMonster can't provide in this way, as the Lua backend providing the interpreter environment is itself a runtime shared object.

I'm sorry to say that this will probably require some deeper analysis. I currently can not give you a definite timeline for getting this resolved, other than that I will look into it and will update you here

bcslaam commented 2 years ago

I appreciate you looking at it. Sorry to hear it is a deep issue. I really thought it was just something I was missing.

I was just hacking around trying to get lua installed because I'm a novice in linux, and I still think its not quite right. I can run lua from console by itself, so I got that part, but for mm, under what user should it be installed, what folders, what libraries? I did everything with sudo when installing. Really, I didn't even get past first base to run lua in mm. Surely some other people have got lua to work with mm.

Remember we talked about global cache devices, and since you got one you gave me an example of the lua script. I just copied it and adapted to my IPs and ir codes. Is my script right, did you update yours? You hadn't tested it at that stage. I would have no idea how to derive one myself, I just copied yours.

And also just installing lua5.3 (its at 5.4 now but I discovered mm only looks for a 5.3 folder) doesnt seem enough, there seems to be additional libraries needed like socket, socket-dev, readline, readline-dev. So many different methods of installing and conflicting opinions.

Can you put a definitive install for lua in linux (ubuntu arm64) specifically for mm use and those who use the mm installer.sh, somewhere on the documentation? Including all the libraries. Although you've got less time for mm there will always be a need for it I think, albeit elite but still...its a legacy!

bcslaam commented 2 years ago

Well I think I have installed lua 5.3.5 properly using luarocks https://github.com/luarocks/luarocks/wiki/Using-LuaRocks

and then used luarocks to install the lua socket library. Apparently the advantage of luarocks is that to install a particular library it will also find and install all dependencies.

I am still getting the same lua_gettop error though.

lua Failed to load source file fsgc2ir.lua for instance gc: error loading module 'socket.core' from file '/usr/local/lib/lua/5.3/socket/core.so':
    /usr/local/lib/lua/5.3/socket/core.so: undefined symbol: lua_gettop
core/cfg    Failed to configure instance gc

**notice how the file location of this error now differs from the one before in my first ubuntu 21.10 attempt.

So...no-one else here has successfully used lua with mm? If you have, please chime in with how you installed it and the main part of your script.

cbdevnet commented 2 years ago

Just as a quick note - MM is by no means a dead project and it is still very much in active development and support. It's just that currently my work and family life takes a bit of a precedence to unpaid passion projects :)

bcslaam commented 2 years ago

I appreciate any time you or someone else here can share to point me in the right direction. It is for my work as a sole operator. Perhaps there's another way?

Can I use the Python backend instead? I notice it has a socket or serial library. Please note:

  1. I dont need to receive a data response, its only sending a command one way without requiring an answer.
  2. My global cache device uses ethernet and is not usb. It uses TCP.
  3. I could forget about socket, not use the gc device, and use Serial instead of ethernet by using a usb to serial cable plugged into the Pi and telnet my commands with no two way communication to make it simple. Could Python work this way?
  4. I am just trying to remote control (via TouchOSC) a hdmi matrix that has IR or serial control. It also has web control via browser but I'd imagine that's impossible for MM.
bcslaam commented 2 years ago

BTW you should put a Donate button on the website. If you do I will be amoungst the first to donate.

cbdevnet commented 2 years ago

Using python may be a viable idea if that is an option for you, it has lower-level socket features integrated in the language as well as access to some more powerful MM APIs. There is even an (admittedly, very basic) sample of handling sockets in the Python backend docs.

A backend for sending more generic HTTP requests to automate controlling browser-based devices is in the works, but not yet finished (see also #72).

I'll try to set up your use case as a sample with Python later, I'll update you here. I also have some GlobalCache devices here, so I can directly test :)

Accepting donations is a bit of a pain (both in general and in Germany specifically), but there are soft plans for integrating the MIDIMonster features into a more graphical environment and selling that at some point.

cbdevnet commented 2 years ago

For your specific use case, an example config using Python might be as follows (this just maps my mouse keys to two commands, but you get the picture)

globalcache.cfg

[python gc]
module = globalcache

[evdev in]
input = TPPS

[map]
in.EV_KEY.BTN_LEFT > gc.globalcache.input1
in.EV_KEY.BTN_RIGHT > gc.globalcache.input2

globalcache.py

import socket
import midimonster

DEVICE_IP="127.0.0.1"
DEVICE_PORT=4998

def socket_handler(sock):
    data = sock.recv(1024)
    print("Received %d bytes from socket: %s" % (len(data), data))
    if(len(data) == 0):
        # Unmanage the socket if it has been closed
        print("Remote has closed the connection")
        midimonster.manage(None, sock)
        sock.close()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((DEVICE_IP, DEVICE_PORT))
midimonster.manage(socket_handler, s)

def input1(value):
    if value > 0.9:
        s.send(bytes("sendir,1:1,0,38000,1,1,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))

def input2(value):
    if value > 0.9:
        s.send(bytes("sendir,1:1,0,38000,1,1,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
bcslaam commented 2 years ago

Thanks @cbdevnet I worked from your example but havent been succesfull yet. MM crashes as soon as I run it, once I included the python backend. It's pretty much a copy of yours, I just substituted in my DEVICE values, Here is my current config:

[backend artnet]
bind = 0.0.0.0

[osc touch]
bind = 0.0.0.0 8000

/*/1 = f 0.0 1.0
/*/2 = f 0.0 1.0
/*/3 = f 0.0 1.0
/*/4 = f 0.0 1.0
/*/5 = f 0.0 1.0
/*/6 = f 0.0 1.0
/*/7 = f 0.0 1.0
/*/8 = f 0.0 1.0
/*/9 = f 0.0 1.0
/*/10 = f 0.0 1.0

[artnet net1]
destination = 192.168.1.100

[python gc]
module = mm2gc

[map]
touch./crp1f/{1..10} > net1.{001..010}
touch./crp2f/{1..10} > net1.{011..020}
touch./crp3f/{1..10} > net1.{021..030}
touch./crp4f/{1..10} > net1.{031..040}
touch./crp5f/{1..10} > net1.{041..050}
touch./crp6f/{1..10} > net1.{051..060}
touch./trp7f/{1..10} > net1.{061..070}
touch./trp8f/{1..10} > net1.{071..080}
touch./trp9f/{1..10} > net1.{081..090}
touch./trp10f/{1..10} > net1.{091..100}
touch./trp11f/{1..10} > net1.{101..110}
touch./trp12f/{1..10} > net1.{111..120}

touch./vinput{1..16} > gc.mm2gc.vin{1..16}
touch./voutput{1..16} > gc.mm2gc.vout{1.16}
touch./vpower > gc.mm2gc.vpow

and here is my mm2gc.py script:

import socket
import midimonster

DEVICE_IP="192.168.1.70"
DEVICE_PORT=4998

def socket_handler(sock):
    data = sock.recv(1024)
    print("Received %d bytes from socket: %s" % (len(data), data))
    if(len(data) == 0):
        # Unmanage the socket if it has been closed
        print("Remote has closed the connection")
        midimonster.manage(None, sock)
        sock.close()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((DEVICE_IP, DEVICE_PORT))
midimonster.manage(socket_handler, s)

def vpow(value):
    if value > 0.9:
        s.send(bytes("sendir,1:1,0,38000,1,1,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,64,21,21,21,21,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))

def vin1(value):
    if value > 0.9:
        s.send(bytes("sendir,1:1,0,38000,1,1,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))

def vin2(value):
    if value > 0.9:
        s.send(bytes("sendir,1:1,0,38000,1,1,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))

and so on...

Can you see whats making MM crash? I tried the DEVICE_PORT number in quotes.

I assume "s.connect((DEVICE_IP, DEVICE_PORT))" remains as is, and is not "s.connect((192.168.1.70, 4998))"?

I am running MM on Windows 10 now because on the RPi mulitouch screen is only supported on Android (Lineage19.0). There's no android version of mm that I know of. Thus my change to Windows for mm and I'm preferring it since I'm familiar with it. I have it working on Windows with Artnet and my pre python config. But as soon as Python backend is called its crashing at start.

I installed Python 64bit windows installable v3.9. Should this be the embeded version instead or should the python39.dll be in the mm directory? I havent been able to find any info on how MM wants python3.x to be installed in Windows 10. Any suggestions? All my firewall rules are ok. My python script just ends at the last gc command. Is there any code that needs to go at the end of the script to close it off?

Additionally, I will also need to send commands directly from RS232 port out of the pc to another switching device. Can you start me off on a python script for serial commands with no globalcache protocols, it's just COM1 at 9600 bauds one way. Or would Lua be better for serial commands?

Much appreciated

Spacelord09 commented 2 years ago

Hey @bcslaam, can you provide your MIDIMonster Log that we can debug your issue further?

bcslaam commented 2 years ago

Hi @Spacelord09 thanks for your reply. I couldn't find any documentation on creating log file so I appended "2> log.txt" to the end of my bat command and got the output

Registered backend artnet Registered backend loopback Registered backend lua Registered backend maweb Registered backend mqtt Registered backend openpixelcontrol Registered backend osc Registered backend rtpmidi Registered backend sacn Registered backend visca Registered backend wininput Registered backend winmidi Reading configuration file bens_midimonster.cfg artnet Interface 0 bound to 0.0.0.0 port 6454 No such backend python Failed to parse master configuration file bens_midimonster.cfg artnet Backend shut down loopback Backend shut down lua Backend shut down maweb Backend shut down mqtt Backend shut down openpixelcontrol Backend shut down osc Backend shut down rtpmidi Backend shut down sacn Backend shut down visca Backend shut down wininput Backend shut down winmidi Backend shut down

As a result I checked and there is no python dll in the backend folder. Which brings me back to the quesion of:

How do I install Python for MM in Windows? There is no documentation on this in the Knowledge base

I have downloaded the embeded version of Python 3.9 and the folder has a lot in it. Including python3.dll and python39.dll Do I just put one of these dll in the backend folder and leave out the rest of the files in the python folder?

Edit: I just tried putting python3.dll and python39.dll in the backend folder and got the same output. Also tried putting the whole python embed folder in there. Tried creating a symlink.

I've got a feeling you are going to tell me that python backend isn't available for Windows :( As I dont see the dll in older Windows zips of mm either. If that is the case I'd be prepared to compile if you can give me info on how to specifically for MM. I found this: https://docs.python.org/3/faq/windows.html#how-can-i-embed-python-into-a-windows-application

If Python backend in MM is impossible for Windows then is there anyway to get MM to run on Android (Lineage 19.0 on RPi) with Python backend?

Spacelord09 commented 2 years ago

Hello @bcslaam, You are right! Unfortunately, the Python backend is currently only supported on Linux and OSX. You can also find this information in our readme in the table at the top. Building the Python Backend for windows is currently not possible.

Why is your PI running on Android? If you're going to flash it with any flavor of Linux(preferred Raspberry Pi OS ) you can get your MM to work as expected.

bcslaam commented 2 years ago

Ok, I will move MM to OSX so I can keep my multitouch OSC RPi in Android. I have a High Sierra machine with some headroom for this. Will report back. What's your suggestion for sending to a serial port (not globalcache)? Will the shortfalls in Lua discovered earlier in this thread be a problem? Is python the only way for serial port commands that require carriage return. Two way coms not needed.

Oh, unless you think I can get MM with python running on Android?

bcslaam commented 2 years ago

Now in OSX High Sierra, I have installed homebrew, dlib, pyenv and python 3.9.2, running mm gives this:

MIDIMonster v0.6
Failed to load plugin ./backends/python.so: dlopen(./backends/python.so, 2): Library not loaded: /usr/local/opt/python@3.9/Frameworks/Python.framework/Versions/3.9/Python
  Referenced from: /Users/ben/backends/python.so
  Reason: image not found
Failed to load plugin ./backends/artnet.so: dlopen(./backends/artnet.so, 2): Symbol not found: ____chkstk_darwin
  Referenced from: ./backends/artnet.so (which was built for Mac OS X 10.15)
  Expected in: /usr/lib/libSystem.B.dylib
 in ./backends/artnet.so
Failed to load plugin ./backends/osc.so: dlopen(./backends/osc.so, 2): Symbol not found: ____chkstk_darwin
  Referenced from: ./backends/osc.so (which was built for Mac OS X 10.15)
  Expected in: /usr/lib/libSystem.B.dylib
 in ./backends/osc.so
Registered backend loopback
Reading configuration file ./bens_midimonster.cfg
Cannot configure unknown backend artnet
Failed to parse master configuration file ./bens_midimonster.cfg
loopback    Backend shut down
MIDIMonster v0.6
Usage:
    ./midimonster <configfile>
logout

Does this indicate I should be using OSX 10.15 Catalina? What Libraries do I need to install with brew to get python, artnet and osc backends working?

cbdevnet commented 2 years ago

Windows support for the Python backend is an open issue (#66), which unfortunately does not have a good indication of success so far.

To get MM to run on OSX, installing the following packages via brew

should allow you to build the entire project. To do that, you can leverage the CI script (as the OSX build process requires a few special variables for Apple-reasons) using ./assets/ci.sh --target=build-osx

Serial port sending using python is very similar, it might even work with Lua (at least on Linux/OSX) natively, as it does not require specialized APIs.

bcslaam commented 2 years ago

I installed Catalina OS and all the libraries you recommended using brew then used the mm OSX bundle available on the site and placed the backend folder, mm exec and custom cfg at the root of my user folder. It runs fine for osc to artnet without all the python stuff, but when I add my lines for python backend in my config I get this:

MIDIMonster v0.6
Registered backend python
Registered backend artnet
Registered backend ola
Registered backend osc
Registered backend lua
Registered backend openpixelcontrol
Registered backend jack
Registered backend visca
Registered backend rtpmidi
Registered backend mqtt
Registered backend sacn
Registered backend maweb
Registered backend loopback
Reading configuration file ./bens_midimonster.cfg
artnet  Interface 0 bound to 0.0.0.0 port 6454
python  Initializing main python interpreter
Created python instance gc
Created osc instance touch
Created artnet instance net1
osc Matched pattern /vinput1 for /vinput1
osc Matched pattern /vinput2 for /vinput2
osc Matched pattern /vinput3 for /vinput3
osc Matched pattern /vinput4 for /vinput4
osc Matched pattern /vinput5 for /vinput5
osc Matched pattern /vinput6 for /vinput6
osc Matched pattern /vinput7 for /vinput7
osc Matched pattern /vinput8 for /vinput8
osc Matched pattern /vinput9 for /vinput9
osc Matched pattern /vinput10 for /vinput10
osc Matched pattern /vinput11 for /vinput11
osc Matched pattern /vinput12 for /vinput12
osc Matched pattern /vinput13 for /vinput13
osc Matched pattern /vinput14 for /vinput14
osc Matched pattern /vinput15 for /vinput15
osc Matched pattern /vinput16 for /vinput16
core/cfg    Failed to detect glob type for spec 1.16
Failed to parse glob 1 in mm2gc.vout{1.16} internally
Failed to map channel touch./voutput{1..16} to gc.mm2gc.vout{1.16}
Failed to parse master configuration file ./bens_midimonster.cfg
python  Backend shut down
artnet  Backend shut down
ola Backend shut down
osc Backend shut down
lua Backend shut down
openpixelcontrol    Backend shut down
jack    Backend shut down
visca   Backend shut down
rtpmidi Backend shut down
mqtt    Backend shut down
sacn    Backend shut down
maweb   Backend shut down
loopback    Backend shut down
MIDIMonster v0.6
Usage:
    ./midimonster <configfile>

my config file:

[backend artnet]
bind = 0.0.0.0

[python gc]
module = mm2gc

[osc touch]
bind = 0.0.0.0 8000

/*/1 = f 0.0 1.0
/*/2 = f 0.0 1.0
/*/3 = f 0.0 1.0
/*/4 = f 0.0 1.0
/*/5 = f 0.0 1.0
/*/6 = f 0.0 1.0
/*/7 = f 0.0 1.0
/*/8 = f 0.0 1.0
/*/9 = f 0.0 1.0
/*/10 = f 0.0 1.0

/vinput1 = f 1 16
/vinput2 = f 1 16
/vinput3 = f 1 16
/vinput4 = f 1 16
/vinput5 = f 1 16
/vinput6 = f 1 16
/vinput7 = f 1 16
/vinput8 = f 1 16
/vinput9 = f 1 16
/vinput10 = f 1 16
/vinput11 = f 1 16
/vinput12 = f 1 16
/vinput13 = f 1 16
/vinput14 = f 1 16
/vinput15 = f 1 16
/vinput16 = f 1 16
/voutput1 = f 1 16
/voutput2 = f 1 16
/voutput3 = f 1 16
/voutput4 = f 1 16
/voutput5 = f 1 16
/voutput6 = f 1 16
/voutput7 = f 1 16
/voutput8 = f 1 16
/voutput9 = f 1 16
/voutput10 = f 1 16
/voutput11 = f 1 16
/voutput12 = f 1 16
/voutput13 = f 1 16
/voutput14 = f 1 16
/voutput15 = f 1 16
/voutput16 = f 1 16
/vpower = f 0.0 1.0

[artnet net1]
destination = 192.168.1.100

[map]
touch./vinput{1..16} > gc.mm2gc.vin{1..16}
touch./voutput{1..16} > gc.mm2gc.vout{1.16}
touch./vpower > gc.mm2gc.vpow
touch./crp1f/{1..10} > net1.{001..010}
touch./crp2f/{1..10} > net1.{011..020}
touch./crp3f/{1..10} > net1.{021..030}
touch./crp4f/{1..10} > net1.{031..040}
touch./crp5f/{1..10} > net1.{041..050}
touch./crp6f/{1..10} > net1.{051..060}
touch./trp7f/{1..10} > net1.{061..070}
touch./trp8f/{1..10} > net1.{071..080}
touch./trp9f/{1..10} > net1.{081..090}
touch./trp10f/{1..10} > net1.{091..100}
touch./trp11f/{1..10} > net1.{101..110}
touch./trp12f/{1..10} > net1.{111..120}

and my python script is unchanged.

What is the reason for the errors:

core/cfg    Failed to detect glob type for spec 1.16
Failed to parse glob 1 in mm2gc.vout{1.16} internally
Failed to map channel touch./voutput{1..16} to gc.mm2gc.vout{1.16}
cbdevnet commented 2 years ago

You're missing a dot in the channel glob specification. gc.mm2gc.vout{1.16} should probably be gc.mm2gc.vout{1..16} (two dots between 1 and 16).

bcslaam commented 2 years ago

Aah yes thanks for finding the typo. After much trial and error I have my config and python script parsing. I had a few things wrong as you probably know. So I'm almost there.

Now it seems the message its sending the global cache device isn't right. global cache is reporting back:

Received 17 bytes from socket: b'unknowncommand 3\r'

Assuming the gc string syntax is correct, is there anything else wrong with the message python sends? Will the gc be getting additional characters due to the code? Like brackets, spaces etc Note that is requires a carriage return witch according to its return message is \r and we have \r", "utf-8"

Edit2: gc string syntax is prooven via gc test utility, and it works with the utf-8 bit in the python version so thats not the problem. The osc message is twofold. One when pressing and the other when releasing. I have tracked the input into mm and released several seconds later but gc is only returning success for the first message (ie the vinput). It's like pythjon can only send one message at a time. Please advise?

bcslaam commented 2 years ago

I have success using python instead of Lua. I assume in terms of Lua, the issue in the thread title still holds. Thanks for your help. If you think it would be beneficial I can briefly document my case in the Projects section later when its finished. Please feel free to split this thread up or delete OT bits.

cbdevnet commented 2 years ago

Hey @bcslaam, great to hear it's making progress! Yes, I would absolutely think that the use case is interesting for others, so if you're willing to document it a bit, you're very much welcome to add it to the knowledgebase at https://github.com/control8r/midimonster-knowledge-base/tree/master/source/usecases !

We always like having more users tell us about their ideas and solutions, and hoperfully it will inspire and help others :)

bcslaam commented 2 years ago

Hi, sorry spoke too soon. My mm config is parsing fine but python script always just sends the message for vin1 and vout1 and it doesnt follow the input from mm (because my python script is wrong I think). My config:

[backend artnet]
bind = 0.0.0.0

[backend osc]
detect = on

[python gc]
module = mm2gc

[osc touch]
bind = 0.0.0.0 8000

/*/0 = f 0.0 1.0
/*/1 = f 0.0 1.0
/*/2 = f 0.0 1.0
/*/3 = f 0.0 1.0
/*/4 = f 0.0 1.0
/*/5 = f 0.0 1.0
/*/6 = f 0.0 1.0
/*/7 = f 0.0 1.0
/*/8 = f 0.0 1.0
/*/9 = f 0.0 1.0
/*/10 = f 0.0 1.0
/*/11 = f 0.0 1.0
/*/12 = f 0.0 1.0
/*/13 = f 0.0 1.0
/*/14 = f 0.0 1.0
/*/15 = f 0.0 1.0
/*/16 = f 0.0 1.0
/vinput = i 0 15
/voutput = i 0 15

[artnet net1]
destination = 192.168.1.100

[map]
touch./vpower/1 > gc.mm2gc.vpow
touch./vinput > gc.mm2gc.vin
touch./voutput > gc.mm2gc.vout
touch./crp1f/{1..10} > net1.{001..010}
touch./crp2f/{1..10} > net1.{011..020}
touch./crp3f/{1..10} > net1.{021..030}
touch./crp4f/{1..10} > net1.{031..040}
touch./crp5f/{1..10} > net1.{041..050}
touch./crp6f/{1..10} > net1.{051..060}
touch./trp7f/{1..10} > net1.{061..070}
touch./trp8f/{1..10} > net1.{071..080}
touch./trp9f/{1..10} > net1.{081..090}
touch./trp10f/{1..10} > net1.{091..100}
touch./trp11f/{1..10} > net1.{101..110}
touch./trp12f/{1..10} > net1.{111..120}

and my python script I need help with:

import socket
import midimonster

DEVICE_IP="192.168.1.70"
DEVICE_PORT=4998

def socket_handler(sock):
    data = sock.recv(1024)
    print("Received %d bytes from socket: %s" % (len(data), data))
    if(len(data) == 0):
        # Unmanage the socket if it has been closed
        print("Remote has closed the connection")
        midimonster.manage(None, sock)
        sock.close()

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((DEVICE_IP, DEVICE_PORT))
midimonster.manage(socket_handler, s)

def vpow(value):
    if value > 0.9:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,64,21,21,21,21,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))

def vin(value):
    if value == 0:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 1:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 2:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 3:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 4:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 5:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,64,21,21,21,21,21,64,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 6:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,64,21,21,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 7:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 8:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,21,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 9:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,21,21,21,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 10:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 11:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 12:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 13:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 14:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,21,21,21,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 15:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))

def vout(value):
    if value == 0:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,64,21,21,21,21,21,64,21,21,21,64,21,64,21,21,21,21,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 1:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 2:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 3:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,21,21,64,21,21,21,21,21,21,21,64,21,21,21,21,21,64,21,21,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 4:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,21,21,21,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 5:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 6:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 7:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 8:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 9:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,64,21,21,21,64,21,64,21,21,21,64,21,64,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 10:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 11:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,21,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,64,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 12:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,21,21,64,21,64,21,21,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 13:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,21,21,64,21,21,21,21,21,21,21,64,21,21,21,64,21,64,21,21,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 14:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,64,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,64,21,1517,341,85,21,3655\r", "utf-8"))
    elif value == 15:
        s.send(bytes("sendir,4:1,1,38000,1,69,341,170,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,64,21,21,21,64,21,21,21,21,21,21,21,64,21,64,21,21,21,64,21,21,21,64,21,1517,341,85,21,3655\r", "utf-8"))

the sample script you gave was using discrete button that give a floating point value. But I need to use radio buttons that give an interger, which I have defined correctly I hope. It's just the syntax of the python script.