Event Highlighting

I'm playing around with a Tidal editor and trying to get feedforward-style context highlights working. Right now I'm running a Tidal boot file that contains the following editor target:

let editorTarget =
      Target {oName = "editor",
              oAddress = "127.0.0.1",
              oPort = editorPort, -- From an ENV variable
              oLatency = 0.02,
              oSchedule = Pre BundleStamp,
              oWindow = Nothing,
              oHandshake = False,
              oBusPort = Nothing
             }
             
    editorShape =
      OSCContext "/editor/highlights"

Then, I'm passing it into my config with:

tidal <- startStream (defaultConfig {cVerbose = True, cFrameTimespan = 1/20}) 
                       [(superdirtTarget, [superdirtShape]),
                        (editorTarget, [editorShape])]

Sure enough, this produces a stream of OSC messages with the pattern ID and the location of a highlighted range. However, it's not obvious to me how you go about matching highlights with individual mininotation strings. Any tips? Is there something else I should be doing?

Like, if I have the pattern d1 $ s "sn bd" # (rotR 0.5 $ n "15 16") and get a message to highlight the range [1, 3], how do I know which symbol to highlight?

My guess is relying on the order that events with the same timestamp come in, but that doesn't seem reliable since UDP makes no promises about dropped packets, etc.

Hey @archaic.tech

These numbers will tell you the column/row of the position within the mininotation. There should be four numbers to give you the start/stop. I think the row is always 1, because mininotation doesn't normally go over more than one row.

This is not so useful by itself, as you don't know which mininotation string it's referring to, and therefore whm00ere in the pattern should be highlighted. For example:
mat

d1 $ sound "bd sd"

The first event should give the numbers ((1,1),(3,1)), to highlight the 'bd ', from column 1 to 3.

To make this more useful you have to tell tidal where each mininotation string is in the original pattern. Here's my (not quite working) attempt at doing that with javascript.

var indexToColRow = function (index, string) {
  const sub = string.substr(0, index);
  const row = (sub.match(/\n/gs) || []).length;
  const col = ((sub.match(/[^\n]+$/gs) || [''])[0].length);
  return([col,row])
}
var mungePattern = function(pat) {
  return pat.replace(/"[^"]+"/sg, function(match, index) {const [col, row] = indexToColRow(index, match); return `(deltaContext ${col} ${row} ${match}})`});
}

With that

mungePattern('d1 $ sound "bd sn" \n  # speed "2 3"')

returns

d1 $ sound (deltaContext 7 0 "bd sn"}) 
  # speed (deltaContext 5 0 "2 3"})"

I.e. it tries to add the row and column to the source positions in the pattern, which should then be reflected in the highlights you get back.

However there's something wrong with my javascript as those aren't the right col / row values! Not sure what's going on as the 'indexToColRow' function seems to work on its own.

Anyway hope that makes some sense, I'm pretty tired atm.. But this is how feedforward does it. There's a big assumption that double quotes are only used to delimit mininotation. That's generally the case.. But it will create confusing errors if you don't match your double quotes. It's a big hack really!

2 Likes

Thinking about it a second more.. tidal-listener could take care of this munging on the haskell side, using the existing 'deltaMini' function.

That makes a lot of sense, thanks! I hadn't realized that there was an extra step of injecting new metadata code, but that makes sense. I'm happy to keep tweaking your Javascript example and figuring out how to get it working.

I found this interesting so I did some digging and opened Reimplementing event highlighting in tidal-listener · Issue #1047 · tidalcycles/Tidal · GitHub to share my thoughts and spark a new discussion.

4 Likes