How about a Sonic Monome?

I can hardly wait … ! :+1:t4::pray:t4::stuck_out_tongue::grinning:

1 Like

Is there some progress in the grid interface (Launchpad , …)?
Or was it choosen to drop it from the plans?

@Buce - Sam may have other comments, but as far as I understand it, all recent development effort has been focused on a small handful of things: startup stability (no easy task when there are a multitude of different software components and hardware configurations involved), and recently, completely rebuilding the MIDI sub-system. New features such as the grid UI are still on the wish-list, but as always, it comes down to a question of priorities vs resources…

Hi @buce,

@ethancrawford is right - unfortunately since this topic started Sonic Pi lost its major source of funding and I had to work hard to figure out how I could create my own funding streams in order to enable continued development and maintenance. This meant that most of my time was directed towards finding funding and pretty much any time I had left had for development had to be prioritised on fixing boot errors and maintaining compatibility with new OS versions.

In an ideal world, we’d have societies that could fund projects in such a way that the developers can focus on what they’re typically good at - continued development and innovation rather than forcing the developers to pivot and learn how to be good enough at business (creating and running a company is a whole new set of skills to learn before we even talking about keeping it afloat).

Luckily I’ve managed to keep going through all this and I’m in a better position to start growing Sonic Pi again rather than just maintaining it. However, there’s still the rest of the virus pandemic and now Brexit for me to face and weather the oncoming storms…

Still, it’s definitely on the TODO list so it’s just a matter of time…

2 Likes

Thanks to help from this thread and this thread at lines.co, I’ve interfaced my monome grid with Sonic Pi. First, you follow the Prerequisites to install the Python stuff needed, which is easy. The rest of the tutorial is quite challenging if you don’t already know Python well enough, and it also contains a bit of deprecated code. Writing Python scripts that send OSC messages tailored for use in Sonic Pi would vary so greatly with the musical situation—let alone the differences between musicians—that I just have the grid persistently report its 128 on/off states, then maintain a current snapshot of the grid as 1’s and 0’s in a Sonic Pi array. You then use the grid’s button states in any way you wish to imagine without bothering with working in a separate app in Python and coordinating your Python with your Sonic Pi code. I think there’s no musical application in Sonic Pi that you could do in Python in this situation that doesn’t have a way to do exactly the same thing all within Sonic Pi, so there’s no reason to get fancy with incoming OSC messages and involved processing of them. You just access the on/off states of the 128 buttons.

I can’t attach files, so the Python code I boiled it down to specifically for Sonic Pi + grid is here:

#! /usr/bin/env python3

# in Terminal do:
# cd '' && '/usr/local/bin/python3'  '<path to this file>'  && echo Exit status: $? && exit 1

import aiosc
import asyncio
import monome

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

    def on_grid_ready(self):
        self.step = [[0 for col in range(self.grid.width)] for row in range(8)]

        asyncio.ensure_future(self.play())
        
    async def play(self):
        while True:
            self.draw()

            await asyncio.sleep(0.1)

    def draw(self):
        brightness = 11
        buffer = monome.GridBuffer(self.grid.width, self.grid.height)

        # display steps
        for x in range(self.grid.width):
            for y in range(8):
                buffer.led_level_set(x, y, self.step[y][x] * brightness)

        # update grid
        buffer.render(self.grid)

    def on_grid_key(self, col, row, s):
        if s == 1 and row < 8:
            self.step[row][col] ^= 1 # toggle step
            self.draw()

            # Send the step info to Sonic Pi.
            print("row, col, val is", row, col, self.step[row][col])
            asyncio.ensure_future(aiosc.send(('127.0.0.1', 4560), '/grid', row, col, self.step[row][col]))


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()

While the Python script is running, your grid buttons turn on and off properly and send OSC messages reporting their state to Sonic Pi on its default port. I also wrote this Ruby code to use in Sonic Pi to maintain an 8x12 array whose 1’s and 0’s reflect your grid’s state in real time:

#
# loop that fetches and processes OSC messages from monome grid.
#

use_osc "localhost", 4560

ROW = 0
COL = 1
VALUE = 2

initializeGrid = true

if initializeGrid == true
  $grid = Array.new(8){Array.new(16, 0)}
  set "/osc*/grid", [0, 0, 0]
end

gridButton = Array.new(3, 0)

live_loop :gridListener do
  use_real_time
  gridButton = get "/osc*/grid"
  $grid[gridButton[ROW]][gridButton[COL]] = gridButton[VALUE]
  sleep 0.1
end

con #1: iI you press grid buttons faster than the gridListener loop can respond, the $grid array won’t properly reflect the grid’s state. The loop sleeps for 0.1 (at default BPM), which is 100ms, I guess, so if you play the grid like a keyboard, that’s too much latency and you’ll lose stuff. When I set the sleep to 0.01 (10ms), that’s more like a MIDI controller’s latency, and works better, but CPU usage goes up even more, Sonic Pi complains about keeping up, and the cue log flies by even faster, in case that matters to you.

con #2: Look at that initializeGrid = true. If you leave it set to true, then every time you reload, $grid gets wiped even though your grid’s state hasn’t changed. You have to set it to true, start Sonic Pi playing, then change the true to false so that subsequent reloads don’t mess things up. Then you have to set it to true after you stop Sonic Pi, and physically turn any lit grid buttons off.

If anyone has ways to improve this, please post. I’ve been using the grid’s buttons as flags to control flow in Sonic Pi when you want to make several changes at once, but in real time, without having to make a bunch of error-prone edits, then hit reload. I also have variables, such as port, channel, and BPM, whose values get set depending on buttons’ states.

Hi, does the code for this still exist prototype_grid* still exist, or is it not worth sharing as no longer able to build with all changes since (now on 4.4 I think)?
(I tried to find related branches in repos but couldn’t see - thought it would be interested to see the approach employed by the master :pray:)

Assume this is some clever thing you were able to ‘spike’ using that fancy phoenix elixir concoction. Fascinating stuff!

No, this never made it past the experimental stage. It unfortunately got parked at the time I lost my funding and had to fight hard to find a way to survive financially.

However, it’s likely to return now I have the Phoenix live view stuff up and running. (The prototype was originally built using C++ and Qt). I’m currently working on learning Elixir web development which is going really well so hopefully this will be easy to build and add some point in the future.

1 Like