Rebuilding Grid Library Functions - Double square bracket

Hi,

I am currently trying to rebuild the library functions which are part of the monome-grid node package (grid.js). I am not yet clear about what I will rearly need in the end but in any case this is a good exercise to learn about grid programming and especially the bitmask functions. Now I am stuck with the following:

The function m_map (see below) can either accept a one …

m_map(0, 0, [6, 8, 8, 8, 8, 8, 8, 32])

… or a two-dimensional array:

m_map(0, 0, [
        [0, 0, 0, 0, 0, 0, 0, 0],
        [0, 1, 0, 1, 0, 1, 0, 1],
        [0, 1, 0, 1, 0, 1, 0, 1],
        [0, 1, 0, 1, 0, 1, 0, 1],
        [0, 1, 0, 1, 0, 1, 0, 1],
        [0, 1, 0, 1, 0, 1, 0, 1],
        [0, 1, 0, 1, 0, 1, 0, 1],
        [0, 1, 0, 1, 0, 1, 0, 1]
])

Problem is, that in the former case (could not yet test the second one) I will get the following output (in Sonic Pi’s protocol window):

OSC -> localhost, 48408, /grid/led/map, [[0, 0, 6, 8, 8, 8, 8, 8, 8, 32]]

… which won’t work because of the double square brackets. Won’t work means, that serialosc does not get correct parameters and will not set any leds.

I tried different things to concatenate the osc output correctly so Sonic Pi’s osc command will work, but I did not succeed yet. Here is the function:

define :m_map do | x_offset, y_offset, arr |
  state = []
  arr.each_with_index do | y, i |
    if y.is_a? Integer
      state[i] = y
    else
      state[i] = 0
      arr[i].each_with_index do | x, j |
        # puts x
        state[i] += arr[i][j] << x
      end
    end
  end
  m = x_offset, y_offset, state # here is the problem
  osc "/grid/led/map", m.flatten
end

Any help would be very much appreciated!

Try using:

  osc "/grid/led/map", *m.flatten

The * will unpack the elements of the flattened m into separate arguments to osc, which should remove one dimension of the array, giving:

OSC -> localhost, 48408, /grid/led/map, [0, 0, 6, 8, 8, 8, 8, 8, 8, 32]

Is that what you want?

2 Likes

Hi @emlyn,

perfect. Exactly what I needed. Thanks a lot!

:smile:

2 Likes

Hi,

just for those who are interested and also want to use a Monome (mine is on the way :wink: ):

I build a library with a set of functions which

  1. set the leds (osc_) according to methods serialosc supports (set, map, row, col) and
  2. store the grid state (if needed on several pages)

I am aware of the fact that I probably have some complicated, clumsy or just false ideas which shine through the code due to my lack of experience. But on the other hand: I am constantly learning and am quite glad what I have so far compared to what I knew a few months ago.

I also think that meanwhile I reached a point where it possibly would be better to not write code running in one of SP’s buffer but write an extension to the Sonic Pi core code in proper Ruby. (I probably will soon run into problems of when and how to load the code in the write order, name space issues and possibly also performance bottlenecks). I feel like a baby with a mind of a 18 year old that has not yet the means to express that.

So I will go on with my tiny and somewhat clumsy baby steps bearing in mind, that in the end I want to use this to make music and consider the coding progress as an gratifying and useful byproduct :wink:

Here is a preview of the code (just the code, no documentation, which is - I know - somehow impertinent) with the intention to show those who are interested the progress and maybe get some feedback and advice:

# grid-08.rb

set :host, "localhost"
set :port, 47120
use_osc get(:host), get(:port)

define :delay do | d = 0.0625|
  sleep d
end

#
# Initialize PAGES array -
# a representation of the the grid in separate pages
#

set :num_pages, 5
set :grid_size, 8

pages = []

get(:num_pages).times do
  y = []
  8.times do
    x = []
    get(:grid_size).times do
      x.push(0)
    end
    y.push(x)
  end
  pages.push(y)
end

set :pages, pages

#
# Page helper functions
#

define :pages_print do
  pages.length.times do | p |
    row = ""
    puts "Page #{p}: ----------------"
    pages[0].length.times do | y |
      row += pages[p][y].to_s
      puts pages[p][y].to_s
    end
    puts "------------------------"
  end
end

# set single item of page p
# @param s {number} single state value
define :page_set do | p, s, x, y |
  page = pages[p]
  page[y][x] = s
  pages[p] = page
  set :pages, pages
end

#page_set(1, 1, 7, 7)

define :page_all do | p, s |
  page = pages[p]
  page = s
  pages[p] = page
  set :pages, pages
end

##| k = [[0, 0, 0, 0, 0, 0, 0, 1],
##|      [0, 0, 0, 0, 0, 0, 1, 1],
##|      [0, 0, 0, 0, 0, 1, 1, 1],
##|      [0, 0, 0, 0, 1, 1, 1, 1],
##|      [0, 0, 0, 1, 1, 1, 1, 1],
##|      [0, 0, 1, 1, 1, 1, 1, 1],
##|      [0, 1, 1, 1, 1, 1, 1, 1],
##|      [1, 1, 1, 1, 1, 1, 1, 1]
##|      ]
##| page_all(0, k)

define :page_row do | p, s, x |
  page = pages[p]
  page[x] = s
  pages[p] = page
  set :pages, pages
end

#page_row(0, [1, 1, 1, 1, 1, 1, 1, 1], 0)

define :page_col do | p, s, y |
  page = pages[p]
  get(:grid_size).times do | i |
    page[i][y] = s[i]
  end
  pages[p] = page
  set :pages, pages
end

#page_col(1, [1, 1, 1, 1, 1, 1, 1, 1], 7)

define :page_update do | p, s, x=nil, y=nil |
  if x != nil and y == nil
    page_row(p, x, s)
  elsif x == nil and y != nil
    page_col(p, s, y)
  elsif x != nil and y != nil
    page_all(p, s)
  else
    page_set(p, s, x, y)
  end
end

define :osc_set do | x, y, s, page=0 |
  osc "/grid/led/set", x, y, s
end

# Set all of device's leds to off or on
define :osc_all do | s |
  osc "/grid/led/all", s
end

osc_all(0)

define :osc_map do | x_offset, y_offset, arr, page=0 |
  state = []
  arr.each_with_index do | y, i |
    # arr 1-dimensional with decimal bitmask
    if y.is_a? Integer
      state[i] = y
    else
      # arr is 2-dimensional with 0 and 1
      bin = ""
      arr[i].each do | x |
        bin += x.to_s
      end
      dec = bin.reverse.to_i(2)
      state.push(dec)
    end
  end
  osc "/grid/led/map", x_offset, y_offset, *state
end

##| m = [[1, 1, 1, 1, 1, 1, 1, 1],
##|      [1, 0, 0, 0, 0, 0, 0, 0],
##|      [1, 0, 0, 0, 0, 0, 0, 0],
##|      [1, 0, 0, 0, 0, 0, 0, 0],
##|      [1, 0, 0, 0, 0, 0, 0, 0],
##|      [1, 0, 0, 0, 0, 0, 0, 0],
##|      [1, 0, 0, 0, 0, 0, 0, 0],
##|      [1, 1, 1, 1, 1, 1, 1, 1]]
##| osc_map(0, 0, m)
# osc_map(0, 0, [128, 192, 224, 240, 248, 252, 254, 255])

define :osc_row do | x_offset, y, s, page=0 |
  state = []
  if s.is_a? Integer
    state = s
  else
    state = s.join.reverse.to_i(2)
  end
  osc "/grid/led/row", x_offset, y, state
  page_update(0, state, nil, y)
end

#osc_row(0, 0, [0,1,1,1,0,0,1,1])
#osc_row(0, 0, 192)

define :osc_col do | x, y_offset, s, page=0|
  state = []
  if s.is_a? Integer
    state = s
  else
    state = s.join.reverse.to_i(2)
  end
  osc "/grid/led/col", x, y_offset, state
end

#osc_col(5, 0, [0,1,1,1,1,1,1,1])
#osc_col(5, 0, 254)

define :toggle do | x, y, page = nil |
  state = get(:pages)[0][y][x]
  if state == 1
    osc_set(x, y, 0, p)
    state = 0
  elsif state == 0
    osc_set(x, y, 1, p)
    state = 1
  end
  if page == nil
    # if no page given update all pages
    get(:num_pages).times do | p |
      page_set(p, state, x, y)
    end
  else
    # update only given page
    page_set(page, state, x, y)
  end
  return state
end

# /// Testing //////////////////////////////////////////

live_loop :listen do
  use_real_time
  data  = sync "/osc/monome/grid/key"
  #data  = sync k
  x = data[0]
  y = data[1]
  s = data[2]
  
  if data[2] == 1
    if y == 7
      case x
      when 0
        t = toggle(x, y)
        if t
          current_page = 1
        end
      when 1
        t = toggle(x, y)
        if t
          current_page = 2
        end
      when 2
        t = toggle(x, y)
        if t
          current_page = 3
        end
      when 3
        t = toggle(x, y)
        if t
          current_page = 4
        end
      end
    end
    pages_print()
    puts current_page
  end
end

#page_set(1, 1, 7, 0)

PS.: The immediate objective is to port this application from Open Sound Control to the Monome.