Reading Carla patchbay into BWise blocks and Tcldot

A first little report on some preparations and a night work to read the Jack connection information (Linux Audio) from a saved "Carla" state and putting it into a BWise connected block form.

I used the first procedure from A little XML parser to read and somewhat verify the integrity of the XML data.

#
# read the (test) "Carla" input file with as the last part the "patchbay" 
# XML information describing the Jack (audio) connections
# as "source/target" pairs with additional pin names
#
set xmltext ""
set xmlf [open test.carxp]
while {[eof $xmlf] == 0} {
    append xmltext "[gets $xmlf]\n"
}
close $xmlf


# Use [RS]'s "xml2list" procedure to read all the connections in "xmlo"
#
set count 0; set xmlo ""
foreach i [lindex [lrange [
    xml2list [string range $xmltext [string first "<Patchbay>" $xmltext] [
       expr [string first "</Patchbay>" $xmltext] + [string length "</Patchbay>"]]]
   ] 1 end] 1] { 
   if {[lindex [lindex [lindex $i 2] 1] 0] == "Target" 
    && [lindex [lindex [lindex $i 2] 0] 0] == "Source"} {
      append xmlo "[lindex [lindex [lindex [lindex [lindex $i 2] 0] end] 0] end],[lindex [lindex [lindex [lindex [lindex $i 2] 1] end] 0] end]\n"
      incr count
   }
}


# Jack(d) named audio connection can contain most characters (no . and ! I think)
# BWise block and pin names want only alnums and _s
#
proc stringtoblockname { {str}  } {
        set o ""
           foreach i [split $str {}] {
              if {[string is alnum $i]  || $i == "_"} {
                 append o $i
              } {
                  append o "_"
              }
           }
           return [string tolower $o]
        }

# Read through the xmlo lines with 4 names for a connection 
# (2 blocks, 2 pins) and create array entries per unique 
# block name and list all the connected pins (in or out)
array unset xmlins
array unset xmlouts
foreach i [split $xmlo '\n'] {
   if {$i != "" } {
      lappend xmlouts([lindex [split [lindex [split $i ','] 0] ':'] 0]) [lindex [split [lindex [split $i ','] 0] ':'] 1]
      lappend  xmlins([lindex [split [lindex [split $i ','] 1] ':'] 0]) [lindex [split [lindex [split $i ','] 1] ':'] 1] 
   }
}


# Create BWise blocks from the above gathered info
# simply all on a row, but with the correct number of 
# pins and simplified block names
# and a special "testxml" additional canvas tag
set ix 50
foreach i [lsort -uni [concat [array names xmlins] [array names xmlouts]]] {
   set ins {}; set outs {}
   if [info exists xmlins($i) ] {
      foreach j [lsort -unique $xmlins($i)] {
         lappend ins [stringtoblockname $j]
       } 
   }
   if [info exist xmlouts($i)] {
      foreach j [lsort -unique $xmlouts($i)] {
         lappend outs [stringtoblockname $j]
      }
   }
   if {[llength $ins] > [llength $outs]} { 
      set height [expr 17+ 18 * [llength $ins]]
   } {
      set height [expr 17+ 18 * [llength $outs]]
   }
   eval newblock [stringtoblockname $i] $ix 50 40 $height "\{$ins\}" "\{$outs\}" testxml
   set ix [expr $ix + 50]
}


# and connect the blocks according to the given XML spec
#
foreach i [split $xmlo '\n'] {
   if {$i != "" } {
      connect {} [stringtoblockname [lindex [split [lindex [split $i ','] 0] ':'] 0]] [stringtoblockname [lindex [split [lindex [split $i ','] 0] ':'] 1]] [stringtoblockname [lindex [split [lindex [split $i ','] 1] ':'] 0]] [stringtoblockname [lindex [split [lindex [split $i ','] 1] ':'] 1]]
   }
}

After executing the above code with the test.carxp file as input (which is a proper audio processing graph I tested with Carla and the other programs for audio processing actually running), and dragging the processing blocks turned into bwise blocks into place, I got this:

Image tclcarla2

There are two major issues with this: BWise doesn't allow multiple output pins as it is. And there are more than one connection to individual input pins at the moment, which probably will cause unrecoverable errors in BWise. o I can't use the more fancy block functionality straight away at the moment, a little scheduler and so on rewriting will be needed for that. I could fairly easily change the network topology above and write a new output file, or restart the jackd based processing programs with a new jack_connect to reflect the new topology. that shouldn't be overly hard.

Now lets include the automatic placement of Graphviz and Tcldot in the picture.

# read the package
package require Tcldot
# define a new graph
set g [dotnew digraph rankdir LR]
# set the style of it's constituting nodes
$g setnodeattribute style filled color white shape box
# point the renderer to the BWise canvas for output
set c $mc
# create the nodes from the above used array variables
foreach i [lsort -uni [concat [array names xmlins] [array names xmlouts]]] { 
   $g addnode $i
}
# Add the edges between the nodes from the list of connections we had
foreach i [split $xmlo '\n'] {
   if {$i != "" } {
      $g addedge [lindex [split [lindex [split $i ','] 0] ':'] 0] [lindex [split [lindex [split $i ','] 1] ':'] 0] }
}
# and render the resulting graph to the canvas
eval [$g render]

Now we can see the graph on top of the above created blocks before they were dragged into position:

Image tclcarla1

A few handy tricks for working with the bwise blocks.

To increase the canvas scroll size:

   $mc conf -scrollregion {0 0 4000 3000}

Selecting all the block with tag from above, to be able delete them with the "Del Sel" button:

   foreach i [tag_and {block testxml}] {cbbox [block_name_fromid $i]}

An example of a real DSP graph consisting of Linux processes under the Jack audio processing library:

proc stringtodotname { {str}  } {
                set o ""
                   foreach ipro [split $str {}] {
                      if {[string is alnum $i]  || $i == "_"} {
                         append o $i
                      } {
                        if {$i == " "} {
                        } {
                          append o "_"
                        }
                      }
                   }
                   return [string tolower [string trim $o]]
                }

foreach i [$g listnodes] { 
   $i setattributes href "Screendumps/[stringtodotname [$i showname]].png" 
}
set fo [open test6.dot w]
$g write $fo ; close $fo
exec dot -Tsvg test6.dot -Gbgcolor="#eeffcc" -o test6.svg

Here's the resulting "svg" html page: http://www.theover.org/test/test6.svg