Hi all!

I have two 40h laying around and am thinking of getting a norns, and doing my research beforehand.

Any ideas around combining two 64/40h into one 128? Dan told me it is not supported as such, but would be a script-level change.

Yes, I’ve been working on a new version of midigrid and I am currently using two 64* button launchpad mini’s as a 128. I’ve been on a bit of a development hiatus though. I would like to support dual 64 grids, but I’m not sure what the best way to attack this is, and it’s right at the bottom of the feature list TBH.

What’s your coding ability?

Coding ability is moderate when it comes to this type of stuff - I decided to build a neotrellis_monome_teensy (still trying to get it to talk to serialosc on the PC), but still it would be fun to play around with the two 40h’s as well. Right now it is a bit on the backburner here as well (sorry for the late response), because I’m still waiting for the Fates PCB to arrive.

Hey @artfwo,
the pip version of pymonome library no longer works, it doesn’t have the add_handler function that the git version has. Just thought I’d let you know, keep up the great work!

What version is installed by pip exactly? I’ve just checked pypi and it has version 0.10 which is identical to git master.

pip version 20.1.1

sorry, forgot to mention the problem was with the aiosc module which I believe is 1.4 but the pip version is 1.3

I might be doing something wrong…

//edit
Just double checked and its definitely 1.4… sorry to waste your time.

I’m trying to get the Python grid studies working with a 40h on the latest Ubuntu Studio (Groovy), with Python 3.8 and the latest versions of the study files and Pymonome.

It recognises button presses, but I can’t get the LEDs working. I’m guessing the code only works with varibright models and I’m not sure what needs changing…any thoughts…?

(I’ve seen a note about varibright translation being done via serialosc; it’s on the latest version, 141.)

I have a 40h - I’ve previously got pymonome code working with it - not sure if it was the studies that you’re looking at but one thing to check is that you may need to set the led level to 15 for the LEDs to come on

I’m not at home at the moment but I can check some of your code on my 40h in a few days if you’re still stuck.

1 Like

…thanks, useful to know it can be made to work. I was using 15, but I’ll do some more experimenting…

Both pymonome and serialosc independently support varibright → monobright translation.

Does you grid work with other apps and implementations (max/pd)? Have you tried using monobright methods in your code, i.e. led_set instead of led_level_set?

Thanks for the reply…I found it worked straight away with my monobright walnut 128, so I’ve switched to using that. :+1:

n00b here, especially Python n00b. I just got my grid, went through serialosc docs and Grid Studies. I can press buttons on my grid and control the printout and led behavior in on_grid_key in the Grid Studies. Now I want to send an osc message to a port on the localhost when I press a button, and this is where I’m in over my head. The studies don’t seem to deal with that. I did install osc4py3 for OSC communications, put its import statements into the first grid study in a way that looked logical, and do its osc_send function right after the grid study prints the key info. OSC Data Monitor shows no activity on the port, so I conclude trying to do this with educated guesses didn’t work out.

Am I on the right track by using the first grid study to send OSC? Do I need to add on a package like osc4py3, or is there already some way that serialosc can be made to send an OSC message? I don’t actually comprehend from the serialosc docs how it could be used to send a message to another port on the localhost.

More detail: the problem is that I don’t understand the syntax of the Python in Grid Studies. I tried to mesh the code for osc4py3 from the section called 1.3.1.2 Sending OSC Messages like this:

#! /usr/bin/env python3

import asyncio
import monome

# Import needed modules from osc4py3
from osc4py3.as_eventloop import *
from osc4py3 import oscbuildparse

# Start theosc4py3 system.
osc_startup()

# Make client channels to send packets.
osc_udp_client("127.0.0.1", 4560, "SonicPi")

# Build a message with autodetection of data types, and send it.
msg = oscbuildparse.OSCMessage("/flag1", None, ["text", 672, 8.871])

class GridStudies(monome.GridApp):
    def __init__(self):
        super().__init__()

    def on_grid_key(self, x, y, s):
        print("key:", x, y, s)
        osc_send(msg, "SonicPi")
        self.grid.led_level_set(x, y, s*15)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    grid_studies = GridStudies()

    def serialosc_device_added(id, type, port):
        print('connecting to {} ({})'.format(id, type))
        asyncio.ensure_future(grid_studies.grid.connect('127.0.0.1', port))

    serialosc = monome.SerialOsc()
    serialosc.device_added_event.add_handler(serialosc_device_added)

    loop.run_until_complete(serialosc.connect())
    loop.run_forever()

except I now realize there should be a osc_process() somewhere (I think).

you can use aiosc for sending OSC in asyncio event loops. pymonome is built on top of aiosc, so it should already be installed on your system.

to send osc using aiosc, modify your grid key handler like this:

import aiosc
...
class GridStudies(monome.GridApp):
...
    def on_grid_key(self, x, y, s):
        print("key:", x, y, s)
        asyncio.ensure_future(aiosc.send(('127.0.0.1', 4560), '/flag1', 'text', 672, 8.871))
        self.grid.led_level_set(x, y, s*15)

or create a wrapper for the Sonic Pi client as follows:

class GridStudies(monome.GridApp):
    def __init__(self, sonic_pi):
        super().__init__()
        self.sonic_pi = sonic_pi

    def on_grid_key(self, x, y, s):
        self.sonic_pi.flag1(...)

class SonicPi(aiosc.OSCProtocol):
    def flag1(self, *args):
        self.send('/flag1', *args)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()

    coro = loop.create_datagram_endpoint(SonicPi, local_addr=('127.0.0.1', 0), remote_addr=('127.0.0.1', 4560))
    transport, sonic_pi = loop.run_until_complete(coro)

    grid_studies = GridStudies(sonic_pi)
    ....
2 Likes

This is fantastic, thank you so much for spoonfeeding. Looking at this part of the Python Tutorial, I see my minimal experience with object oriented programming was making the Grid Studies code almost impossible for me to follow. All I really need to do (for now) is send simple OSC messages to one port so that simply hacking if statements into on_grid_key() based on key values will provide all the control of Sonic Pi that I can currently imagine. In that case, spending the hours it would take to comprehend Python classes would hardly pay off because I’ll surely have forgotten it all by the next time I need to know it.

I’ve verified that Sonic Pi receives the OSC messages. OSCDataMonitor, on the other hand, does not, which is unfortunate because it has been such a good tool in previous applications. For interest, I’ve attached a screenshot showing the data coming through in Sonic Pi and Terminal, but nothing in OSCDataMonitor:

It’s usually not possible for 2 applications to listen on the same port, so if Sonic Pi is launched first, it will occupy the port and OSC Data Monitor will not get any messages (and should fail to open the socket, i wonder why it didn’t).

If you really want to have 2 receiving apps, so you can monitor the messages - run OSC Data Monitor on a separate port and send the messages to both.

Yes, thanks, I just verified that OSC Data Monitor works when Sonic Pi isn’t running.

Except for grid-studies-1.py, I get an invalid syntax error near the top of each Grid Studies file at the line asyncio.async(self.play()). The caret in the terminal points to the ‘a’ in “async” if that helps. Am I missing something?

Right, that’s deprecated syntax in recent Python versions. Use asyncio.ensure_future(self.play()) instead.

1 Like

thanks @artfwo, just ran into this asyncio.ensure_future(self.play()) issue myself.

I’m noticing that I can’t set the leds to anything but off or full brightness in python but that I can in SuperCollider.
python: led_level_set(8, 5, 9) sets to full bright
sc: ~m.levset(8, 5, 8) sets to half bright

looking through monome.py there is a check for varibright but I haven’t figured out how to check within a script