From 5e2a1bc9e56003349e533f7e5841041ba5c04e28 Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 4 Oct 2005 02:02:15 +0000 Subject: starting to commit gridflow 0.8.0 ... if you know how to use "cvs import" please mail me and i'll use it for 0.8.1 svn path=/trunk/; revision=3646 --- externals/gridflow/base/flow_objects.rb | 1476 +++++++++++++++++++++++++++++++ 1 file changed, 1476 insertions(+) create mode 100644 externals/gridflow/base/flow_objects.rb (limited to 'externals/gridflow/base/flow_objects.rb') diff --git a/externals/gridflow/base/flow_objects.rb b/externals/gridflow/base/flow_objects.rb new file mode 100644 index 00000000..6ea06c56 --- /dev/null +++ b/externals/gridflow/base/flow_objects.rb @@ -0,0 +1,1476 @@ +=begin + $Id: flow_objects.rb,v 1.1 2005-10-04 02:02:13 matju Exp $ + + GridFlow + Copyright (c) 2001,2002,2003,2004 by Mathieu Bouchard + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + See file ../COPYING for further informations on licensing terms. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +=end + +module GridFlow + +#-------- fClasses for: control + misc + +# a dummy class that gives access to any stuff global to GridFlow. +FObject.subclass("gridflow",1,1) { + def _0_profiler_reset + GridFlow.fobjects.each {|o,*| o.total_time = 0 } + GridFlow.profiler_reset2 if GridFlow.respond_to? :profiler_reset2 + end + def _0_profiler_dump + ol = [] + total=0 + post "-"*32 + post "microseconds percent pointer constructor" + GridFlow.fobjects.each {|o,*| ol.push o } + + # HACK: BitPacking is not a real fobject + # !@#$ is this still necessary? + ol.delete_if {|o| not o.respond_to? :total_time } + + ol.sort! {|a,b| a.total_time <=> b.total_time } + ol.each {|o| total += o.total_time } + total=1 if total<1 + total_us = 0 + ol.each {|o| + ppm = o.total_time * 1000000 / total + us = (o.total_time*1E6/GridFlow.cpu_hertz).to_i + total_us += us + post "%12d %2d.%04d %08x %s", us, + ppm/10000, ppm%10000, o.object_id, o.args + } + post "-"*32 + post "sum of accounted microseconds: #{total_us}" + if GridFlow.respond_to? :memcpy_calls then + post "memcpy calls: #{GridFlow.memcpy_calls} "+ + "; bytes: #{GridFlow.memcpy_bytes}"+ + "; time: #{GridFlow.memcpy_time}" + end + if GridFlow.respond_to? :malloc_calls then + post "malloc calls: #{GridFlow.malloc_calls} "+ + "; bytes: #{GridFlow.malloc_bytes}"+ + "; time: #{GridFlow.malloc_time}" + end + post "-"*32 + end + def _0_formats + post "-"*32 + GridFlow.fclasses.each {|k,v| + next if not /#in:/ =~ k + modes = case v.flags + when 2; "#out" + when 4; "#in" + when 6; "#in/#out" + end + post "%s %s: %s", modes, k, v.description + if v.respond_to? :info then + post "-> %s", v.info + end + } + post "-"*32 + end + # security issue if patches shouldn't be allowed to do anything they want + def _0_eval(*l) + s = l.map{|x|x.to_i.chr}.join"" + post "ruby: %s", s + post "returns: %s", eval(s).inspect + end + add_creator "@global" + GridFlow.bind "gridflow", "gridflow" rescue Exception +} +FObject.subclass("fps",1,1) { + def initialize(*options) + super + @history = [] # list of delays between incoming messages + @last = 0.0 # when was last time + @duration = 0.0 # how much delay since last summary + @period = 1 # minimum delay between summaries + @detailed = false + @mode = :real + options.each {|o| + case o + when :detailed; @detailed=true + when :real,:user,:system,:cpu; @mode=o + end + } + def @history.moment(n=1) + sum = 0 + each {|x| sum += x**n } + sum/length + end + end + def method_missing(*a) end # ignore non-bangs + def _0_period x; @period=x end + def publish + @history.sort! + n=@history.length + fps = @history.length/@duration + if not @detailed then send_out 0, fps; return end + send_out 0, fps, + 1000*@history.min, + 500*(@history[n/2]+@history[(n-1)/2]), + 1000*@history.max, + 1000/fps, + 1000*(@history.moment(2) - @history.moment(1)**2)**0.5 + end + def _0_bang + t = case @mode + when :real; Time.new.to_f + when :user; Process.times.utime + when :system; Process.times.stime + when :cpu; GridFlow.rdtsc/GridFlow.cpu_hertz + end + @history.push t-@last + @duration += t-@last + @last = t + return if @duration<@period + fps = @history.length/@duration + publish if fps>0.001 + @history.clear + @duration = 0 + end +} + +# to see what the messages look like when they get on the Ruby side. +FObject.subclass("rubyprint",1,0) { + def initialize(*a) + super + @time = !!(a.length and a[0]==:time) + end + + def method_missing(s,*a) + s=s.to_s + pre = if @time then sprintf "%10.6f ", Time.new.to_f else "" end + case s + when /^_0_/; post "%s","#{pre}#{s[3..-1]}: #{a.inspect}" + else super + end + end +} +FObject.subclass("printargs",0,0) { + def initialize(*a) super; post a.inspect end +} +GridObject.subclass("#print",1,0) { + install_rgrid 0, true + attr_accessor :name + def initialize(name=nil) + super # don't forget super!!! + if name then @name = name.to_s+": " else @name="" end + @base=10; @format="d"; @trunc=70; @maxrows=50 + end + def end_hook; end # other hijackability + def format + case @nt + when :float32; '%6.6f' + when :float64; '%14.14f' + else "%#{@columns}#{@format}" end + end + def _0_base(x) + @format = (case x + when 2; "b" + when 8; "o" + when 10; "d" + when 16; "x" + else raise "base #{x} not supported" end) + @base = x + end + def _0_trunc(x) + x=x.to_f + (0..240)===x or raise "out of range (not in 0..240 range)" + @trunc = x + end + def _0_maxrows(x) @maxrows = x.to_i end + def make_columns udata + min = udata.min + max = udata.max + @columns = "" # huh? + @columns = [ + sprintf(format,min).length, + sprintf(format,max).length].max + end + def unpack data + ps = GridFlow.packstring_for_nt @nt + data.unpack ps + end + def _0_rgrid_begin + @dim = inlet_dim 0 + @nt = inlet_nt 0 + @data = "" + end + def _0_rgrid_flow(data) @data << data end + def _0_rgrid_end + head = "#{name}Dim[#{@dim.join','}]" + head << "(#{@nt})" if @nt!=:int32 + head << ": " + if @dim.length > 3 then + post head+" (not printed)" + elsif @dim.length < 2 then + udata = unpack @data + make_columns udata + post trunc(head + dump(udata)) + elsif @dim.length == 2 then + post head + udata = unpack @data + make_columns udata + sz = udata.length/@dim[0] + rown = 1 + for row in 0...@dim[0] do + post trunc(dump(udata[sz*row,sz])) + rown += 1 + (post "..."; break) if rown>@maxrows + end + elsif @dim.length == 3 then + post head + make_columns unpack(@data) + sz = @data.length/@dim[0] + sz2 = sz/@dim[1] + rown = 1 + for row in 0...@dim[0] + column=0; str="" + for col in 0...@dim[1] + str << "(" << dump(unpack(@data[sz*row+sz2*col,sz2])) << ")" + break if str.length>@trunc + end + post trunc(str) + rown += 1 + (post "..."; break) if rown>@maxrows + end + end + @data,@dim,@nt = nil + end_hook + end + def dump(udata,sep=" ") + f = format + udata.map{|x| sprintf f,x }.join sep + end + def trunc s + if s.length>@trunc then s[0...@trunc]+" [...]" else s end + end +} +GridPack = +GridObject.subclass("#pack",1,1) { + install_rgrid 0 + class<=16 and raise "too many inlets" + super + @data=[0]*n + @cast=cast + @ps =GridFlow.packstring_for_nt cast + end + def initialize2 + return if self.class.ninlets>1 + add_inlets @data.length-1 + end + def _0_cast(cast) + @ps = GridFlow.packstring_for_nt cast + @cast = cast + end + def self.define_inlet i + module_eval " + def _#{i}_int x; @data[#{i}]=x; _0_bang; end + def _#{i}_float x; @data[#{i}]=x; _0_bang; end + " + end + (0...15).each {|x| define_inlet x } + def _0_bang + send_out_grid_begin 0, [@data.length], @cast + send_out_grid_flow 0, @data.pack(@ps), @cast + end + self +} + +# the install_rgrids in the following are hacks so that +# outlets can work. (install_rgrid is supposed to be for receiving) +# maybe GF-0.8 doesn't need that. +GridPack.subclass("@two", 2,1) { install_rgrid 0 } +GridPack.subclass("@three",3,1) { install_rgrid 0 } +GridPack.subclass("@four", 4,1) { install_rgrid 0 } +GridPack.subclass("@eight",8,1) { install_rgrid 0 } +GridObject.subclass("#unpack",1,0) { + install_rgrid 0, true + def initialize(n) + @n=n + n>=10 and raise "too many outlets" + super + end + def initialize2; add_outlets @n end + def _0_rgrid_begin + inlet_dim(0)==[@n] or raise "expecting Dim[#{@n}], got Dim#{@dim}" + inlet_set_factor 0,@n + end + def _0_rgrid_flow data + @ps = GridFlow.packstring_for_nt inlet_nt(0) + duh = data.unpack(@ps) + i=duh.size-1 + until i<0 do send_out i,duh[i]; i-=1 end + end + def _0_rgrid_end; end +} + +GridObject.subclass("#export_symbol",1,1) { + install_rgrid 0 + def _0_rgrid_begin; @data="" end + def _0_rgrid_flow data; @data << data; end + def _0_rgrid_end + send_out 0, :symbol, @data.unpack("I*").pack("c*").intern + end +} +GridObject.subclass("unix_time",1,3) { + install_rgrid 0 + def _0_bang + t = Time.new + tt = t.to_s + send_out_grid_begin 0, [tt.length], :uint8 + send_out_grid_flow 0, tt, :uint8 + send_out 1, t.to_i + send_out 2, t.to_f-t.to_f.floor + end +} +### test with "shell xlogo &" -> [exec] +FObject.subclass("exec",1,0) { + def _0_shell(*a) system(a.map!{|x| x.to_s }.join(" ")) end +} +FObject.subclass("renamefile",1,0) { + def initialize; end + def _0_list(a,b) File.rename(a.to_s,b.to_s) end +} +FObject.subclass("ls",1,1) { + def _0_symbol(s) send_out 0, :list, *Dir.new(s.to_s).map {|x| x.intern } end +} + +#-------- fClasses for: math + +FPatcher.subclass("gfmessagebox",1,1) { + def initialize(*a) @a=a end + def _0_float(x) send_out 0, *@a.map {|y| if y=="$1".intern then x else y end } end + def _0_symbol(x) send_out 0, *@a.map {|y| if y=="$1".intern then x else y end } end +} + +FPatcher.subclass("@!",1,1) { + @fobjects = ["# +","#type","gfmessagebox list $1 #"] + @wires = [-1,0,1,0, 1,0,2,0, 2,0,0,1, -1,0,0,0, 0,0,-1,0] + def initialize(sym) + super + @fobjects[0].send_in 0, case sym + when :rand; "op rand"; when :sqrt; "op sqrt" + when :abs; "op abs-"; when :sq; "op sq-" + else raise "bork BORK bork" end + end +} +FPatcher.subclass("@fold",2,1) { + @fobjects = ["#fold +","gfmessagebox seed $1"] + @wires = [-1,0,0,0, -1,1,1,0, 1,0,0,1, 0,0,-1,0] + def initialize(op,seed=0) super; o=@fobjects[0] + o.send_in 0, :op, op; o.send_in 0, :seed, seed end +} +FPatcher.subclass("@scan",2,1) { + @fobjects = ["#scan +","gfmessagebox seed $1"] + @wires = [-1,0,0,0, -1,1,1,0, 1,0,0,1, 0,0,-1,0] + def initialize(op,seed=0) super; o=@fobjects[0] + o.send_in 0, :op, op; o.send_in 0, :seed, seed end +} +FPatcher.subclass("@inner",3,1) { + @fobjects = ["#inner","gfmessagebox seed $1"] + @wires = [-1,0,0,0, -1,1,1,0, 1,0,0,0, 0,0,-1,0, -1,2,0,1] + def initialize(op=:*,fold=:+,seed=0,r=0) super; o=@fobjects[0] + o.send_in 0, :op, op; o.send_in 0, :fold, fold + o.send_in 0, :seed, seed; o.send_in 1, r end +} +FPatcher.subclass("@convolve",2,1) { + @fobjects = ["#convolve"] + @wires = [-1,0,0,0, -1,2,0,1, 0,0,-1,0] + def initialize(op=:*,fold=:+,seed=0,r=0) super; o=@fobjects[0] + o.send_in 0, :op, op; o.send_in 0, :fold, fold + o.send_in 0, :seed, seed; o.send_in 1, r end +} + +#-------- fClasses for: video + +FPatcher.subclass("@scale_to",2,1) { + @fobjects = [ + "@for {0 0} {42 42} {1 1}","@ *","@ /", + "@store","#dim","@redim {2}","#finished", + ] + @wires = [] + for i in 1..3 do @wires.concat [i-1,0,i,0] end + @wires.concat [3,0,-1,0, 4,0,5,0, 5,0,1,1, 6,0,0,0, + -1,0,4,0, -1,0,3,1, -1,0,6,0, -1,1,0,1, -1,1,2,1] + def initialize(size) + (size.length==2 and Numeric===size[0] and Numeric===size[1]) or + raise "expecting {height width}" + super + send_in 1, size + end +} + +# told me to: +# RGBtoYUV : @fobjects = ["#inner ( 3 3 # 66 -38 112 128 -74 -94 25 112 -18 )", +# "@ >> 8","@ + {16 128 128}"] +# YUVtoRGB : @fobjects = ["@ - ( 16 128 128 )", +# "#inner ( 3 3 # 298 298 298 0 -100 516 409 -208 0 )","@ >> 8"] + +FPatcher.subclass("#rotate",2,1) { + @fobjects = ["@inner * + 0","@ >> 8"] + @wires = [-1,0,0,0, 0,0,1,0, 1,0,-1,0] + def update_rotator + rotator = (0...@axis[2]).map {|i| + (0...@axis[2]).map {|j| + if i==j then 256 else 0 end + } + } + th = @angle * Math::PI / 18000 + scale = 1<<8 + (0...2).each {|i| + (0...2).each {|j| + rotator[@axis[i]][@axis[j]] = + (scale*Math.cos(th+(j-i)*Math::PI/2)).to_i + } + } + @fobjects[0].send_in 2, + @axis[2], @axis[2], "#".intern, *rotator.flatten + end + def _0_axis(from,to,total) + total>=0 or raise "total-axis number incorrect" + from>=0 and from=0 and to 0 + (send_out 0, x; x += step) while x < stop + elsif step < 0 + (send_out 0, x; x += step) while x > stop + end + end + def _0_float(x) self.start=x; _0_bang end + alias _1_float stop= + alias _2_float stop= +} +FObject.subclass("oneshot",2,1) { + def initialize(state=true) @state=state!=0 end + def method_missing(sel,*a) + m = /^_0_(.*)$/.match(sel.to_s) or return super + send_out 0, m[1].intern, *a if @state + @state=false + end + def _1_int(state) @state=state!=0 end + alias _1_float _1_int + def _1_bang; @state=true end +} +FObject.subclass("inv+",2,1) { + def initialize(b=0) @b=b end; def _1_float(b) @b=b end + def _0_float(a) send_out 0, :float, @b-a end +} +FObject.subclass("inv*",2,1) { + def initialize(b=0) @b=b end; def _1_float(b) @b=b end + def _0_float(a) send_out 0, :float, @b/a end +} +FObject.subclass("range",1,1) { + def initialize(*a) @a=a end + def initialize2 + add_inlets @a.length + add_outlets @a.length + end + def _0_float(x) i=0; i+=1 until @a[i]==nil or x<@a[i]; send_out i,x end + def method_missing(sel,*a) + m = /^(_\d+_)(.*)/.match(sel.to_s) or return super + m[2]=="float" or return super + @a[m[1].to_i-1] = a[0] + post "setting a[#{m[1].to_i-1}] = #{a[0]}" + end +} + +#-------- fClasses for: GUI + +module Gooey # to be included in any FObject class + def initialize(*) + super + @selected=false + @bg = "#ffffff" # white background + @bgb = "#000000" # black border + @bgs = "#0000ff" # blue border when selected + @fg = "#000000" # black foreground + @rsym = "#{self.class}#{self.object_id}".intern # unique id for use in Tcl + @can = nil # the canvas number + @canvas = nil # the canvas string + @y,@x = 0,0 # position on canvas + @sy,@sx = 16,16 # size on canvas + @font = "Courier -12" + @vis = nil + end + attr_reader :canvas + attr_reader :selected + def canvas=(can) + @can = can if Integer===can + @canvas = case can + when String; can + when Integer; ".x%x.c"%(4*can) + else raise "huh?" + end + end + def initialize2(*) GridFlow.bind self, @rsym.to_s end + def pd_displace(can,x,y) self.canvas||=can; @x+=x; @y+=y; pd_show(can) end + def pd_activate(can,*) self.canvas||=can end + def quote(text) # for tcl (isn't completely right ?) + text=text.gsub(/[\{\}]/) {|x| "\\"+x } + "{#{text}}" + end + def pd_vis(can,vis) + self.canvas||=can; @vis=vis!=0; update end + def update; pd_show @can if @vis end + def pd_getrect(can) + self.canvas||=can + @x,@y = get_position(can) + # the extra one-pixel on each side was for #peephole only + # not sure what to do with this + [@x-1,@y-1,@x+@sx+1,@y+@sy+1] + end + def pd_click(can,x,y,shift,alt,dbl,doit) return 0 end + def outline; if selected then @bgs else "#000000" end end + def pd_select(can,sel) + self.canvas||=can + @selected=sel!=0 + GridFlow.gui %{ #{canvas} itemconfigure #{@rsym} -outline #{outline} \n } + end + def pd_delete(can) end + def pd_show(can) + self.canvas||=can + @x,@y = get_position can if can + end + def highlight(color,ratio) # doesn't use self + c = /^#(..)(..)(..)/.match(color)[1..3].map {|x| x.hex } + c.map! {|x| [255,(x*ratio).to_i].min } + "#%02x%02x%02x" % c + end +end + +class Display < FObject; include Gooey + attr_accessor :text + def initialize() + super + @sel = nil; @args = [] # contents of last received message + @text = "..." + @sy,@sx = 16,80 # default size of the widget + @bg,@bgs,@fg = "#6774A0","#00ff80","#ffff80" + end + def _0_set_size(sy,sx) @sy,@sx=sy,sx end + def atom_to_s a + case a + when Float; sprintf("%.5f",a).gsub(/\.?0+$/, "") + else a.to_s + end + end + def method_missing(sel,*args) + m = /^(_\d+_)(.*)/.match(sel.to_s) or return super + @sel,@args = m[2].intern,args + @text = case @sel + when nil; "..." + when :float; atom_to_s @args[0] + else @sel.to_s + ": " + @args.map{|a| atom_to_s a }.join(' ') + end + update + end + def pd_show(can) + super + return if not canvas or not @vis # can't show for now... + GridFlow.gui %{ + set canvas #{canvas} + $canvas delete #{@rsym}TEXT + set y #{@y+2} + foreach line [split #{quote @text} \\n] { + $canvas create text #{@x+2} $y -fill #{@fg} -font #{quote @font}\ + -text $line -anchor nw -tag #{@rsym}TEXT + set y [expr $y+14] + } + foreach {x1 y1 x2 y2} [$canvas bbox #{@rsym}TEXT] {} + set sx [expr $x2-$x1+1] + set sy [expr $y2-$y1+3] + $canvas delete #{@rsym} + $canvas create rectangle #{@x} #{@y} \ + [expr #{@x}+$sx] [expr #{@y}+$sy] -fill #{@bg} \ + -tags #{@rsym} -outline #{outline} + $canvas lower #{@rsym} #{@rsym}TEXT + pd \"#{@rsym} set_size $sy $sx;\n\"; + } + end + def pd_delete(can) + if @vis + GridFlow.gui %{ #{canvas} delete #{@rsym} #{@rsym}TEXT \n} + end + super + end + def delete; super end + def _0_grid(*foo) # big hack! + # hijacking a [#print] + gp = FObject["#print"] + @text = "" + overlord = self + gp.instance_eval { @overlord = overlord } + def gp.post(fmt,*args) @overlord.text << sprintf(fmt,*args) << "\n" end + def gp.end_hook + @overlord.instance_eval{@text.chomp!} + @overlord.update + end + #gp.send_in 0, :trunc, 70 + gp.send_in 0, :maxrows, 20 + gp.send_in 0, :grid, *foo + end + + install "display", 1, 1 + gui_enable if GridFlow.bridge_name =~ /puredata/ +end + +class GridEdit < GridObject; include Gooey + def initialize(grid) + super + @store = GridStore.new + @store.connect 0,self,2 + @fin = GridFinished.new + @fin.connect 0,self,3 + @bg,@bgs,@fg = "#609068","#0080ff","#ff80ff" + @bghi = highlight(@bg,1.25) # "#80C891" # highlighted @bg + #@bghihi = highlight(@bghi,1.5) # very highlighted @bg + @cellsy,@cellsx = 16,48 + @i,@j = nil,nil # highlighted cell dex + send_in 0, grid + end + def _0_cell_size(sy,sx) @cellsy,@cellsx=sy,sx; update end + def _0_float(*a) @store.send_in 1,:float,*a; @store.send_in 0; update end + def _0_list (*a) @store.send_in 1, :list,*a; @store.send_in 0; update end + def _0_grid (*a) @store.send_in 1, :grid,*a; @fin.send_in 0, :grid,*a end + def _3_bang; @store.send_in 0; update end + def edit_start(i,j) + edit_end if @i + @i,@j=i,j + GridFlow.gui %{ + set canvas #{canvas} + $canvas itemconfigure #{@rsym}CELL_#{@i}_#{@j} -fill #{@bghi} + } + end + def edit_end + GridFlow.gui %{ + set canvas #{canvas} + $canvas itemconfigure #{@rsym}CELL_#{@i}_#{@j} -fill #{@bg} + } + unfocus @can + end + def _2_rgrid_begin + @data = [] + @dim = inlet_dim 2 + @nt = inlet_nt 2 + post "_2_rgrid_begin: dim=#{@dim.inspect} nt=#{@nt.inspect}" + send_out_grid_begin 0, @dim, @nt + end + def _2_rgrid_flow data + ps = GridFlow.packstring_for_nt @nt + @data[@data.length,0] = data.unpack(ps) + post "_2_rgrid_flow: data=#{@data.inspect}" + send_out_grid_flow 0, data + end + def _2_rgrid_end + post "_2_rgrid_end" + end + def pd_click(can,x,y,shift,alt,dbl,doit) + post "pd_click: %s", [can,x,y,shift,alt,dbl,doit].inspect + return 0 if not doit!=0 + i = (y-@y-1)/@cellsy + j = (x-@x-1)/@cellsx + post "%d,%d", i,j + ny = @dim[0] || 1 + nx = @dim[1] || 1 + if (0...ny)===i and (0...nx)===j then + focus @can,x,y + edit_start i,j + end + return 0 + end + def pd_key(key) + post "pd_key: %s", [key].inspect + if key==0 then unfocus @can; return end + end + def pd_motion(dx,dy) + post "pd_motion: %s", [dx,dy].inspect + ny = @dim[0] || 1 + nx = @dim[1] || 1 + k = @i*nx+@j + post "@data[#{k}]=#{@data[k]} before" + @data[k]-=dy + @store.send_in 1, :put_at, [@i,@j] + @store.send_in 1, @data[k] + @store.send_in 0 + post "@data[#{k}]=#{@data[k]} after" + update + end + def pd_show(can) + super + return if not can + ny = @dim[0] || 1 + nx = @dim[1] || 1 + @sy = 2+@cellsy*ny + @sx = 2+@cellsx*nx + g = %{ + set canvas #{canvas} + $canvas delete #{@rsym} #{@rsym}CELL + $canvas create rectangle #{@x} #{@y} #{@x+@sx} #{@y+@sy} \ + -fill #{@bg} -tags #{@rsym} -outline #{outline} + } + ny.times {|i| + nx.times {|j| + y1 = @y+1+i*@cellsy; y2 = y1+@cellsy + x1 = @x+1+j*@cellsx; x2 = x1+@cellsx + v = @data[i*nx+j] + g << %{ + $canvas create rectangle #{x1} #{y1} #{x2} #{y2} -fill #{@bg} \ + -tags {#{@rsym}CELL #{@rsym}CELL_#{i}_#{j}} -outline #{outline} + $canvas create text #{x2-4} #{y1+2} -text "#{v}" -anchor ne -fill #ffffff \ + -tags {#{@rsym}CELL_#{i}_#{j}_T} + } + } + } + GridFlow.gui g + end + install "#edit", 2, 1 + install_rgrid 2, true + gui_enable if GridFlow.bridge_name =~ /puredata/ +end + +class Peephole < FPatcher; include Gooey + @fobjects = ["#dim","#export_list","#downscale_by 1 smoothly","#out","#scale_by 1", + proc{Demux.new(2)}] + @wires = [-1,0,0,0, 0,0,1,0, -1,0,5,0, 2,0,3,0, 4,0,3,0, 5,0,2,0, 5,1,4,0, 3,0,-1,0] + def initialize(sy=32,sx=32,*args) + super + @fobjects[1].connect 0,self,2 + post "Peephole#initialize: #{sx} #{sy} #{args.inspect}" + @scale = 1 + @down = false + @sy,@sx = sy,sx # size of the widget + @fy,@fx = 0,0 # size of last frame after downscale + @bg,@bgs = "#A07467","#00ff80" + end + def pd_show(can) + super + return if not can + if not @open + GridFlow.gui %{ + pd \"#{@rsym} open [eval list [winfo id #{@canvas}]] 1;\n\"; + } + @open=true + end + # round-trip to ensure this is done after the open + GridFlow.gui %{ + pd \"#{@rsym} set_geometry #{@y} #{@x} #{@sy} #{@sx};\n\"; + } + GridFlow.gui %{ + set canvas #{canvas} + $canvas delete #{@rsym} + $canvas create rectangle #{@x} #{@y} #{@x+@sx} #{@y+@sy} \ + -fill #{@bg} -tags #{@rsym} -outline #{outline} + } + set_geometry_for_real_now + end + def set_geometry_for_real_now + @fy,@fx=@sy,@sx if @fy<1 or @fx<1 + @down = (@fx>@sx or @fy>@sx) + if @down then + @scale = [(@fy+@sy-1)/@sy,(@fx+@sx-1)/@sx].max + @scale=1 if @scale<1 # what??? + @fobjects[2].send_in 1, @scale + sy2 = @fy/@scale + sx2 = @fx/@scale + else + @scale = [@sy/@fy,@sx/@fx].min + @fobjects[4].send_in 1, @scale + sy2 = @fy*@scale + sx2 = @fx*@scale + end + begin + @fobjects[5].send_in 1, (if @down then 0 else 1 end) + x2=@y+(@sy-sy2)/2 + y2=@x+(@sx-sx2)/2 + @fobjects[3].send_in 0, :set_geometry, + x2, y2, sy2, sx2 + rescue StandardError => e + post "peeperr: %s", e.inspect + end + post "set_geometry_for_real_now (%d,%d) (%d,%d) (%d,%d) (%d,%d) (%d,%d)", + @x+1,@y+1,@sx,@sy,@fx,@fy,sx2,sy2,x2,y2 + end + def _0_open(wid,use_subwindow) + post "%s", [wid,use_subwindow].inspect + @use_subwindow = use_subwindow==0 ? false : true + if @use_subwindow then + @fobjects[3].send_in 0, :open,:x11,:here,:embed_by_id,wid + end + end + def _0_set_geometry(y,x,sy,sx) + @sy,@sx = sy,sx + @y,@x = y,x + set_geometry_for_real_now + end + def _0_fall_thru(flag) # never worked ? + post "fall_thru: #{flag}" + @fobjects[3].send_in 0, :fall_thru, flag + end + # note: the numbering here is a FPatcher gimmick... -1,0 goes to _1_. + def _1_position(y,x,b) + s=@scale + if @down then y*=s;x*=s else y*=s;x*=s end + send_out 0,:position,y,x,b + end + def _2_list(sy,sx,chans) + @fy,@fx = sy,sx + set_geometry_for_real_now + end + def _0_paint() + post "paint()" + @fobjects[3].send_in 0, "draw" + end + def delete + post "deleting peephole" + GridFlow.gui %{ #{canvas} delete #{@rsym} \n} + @fobjects[3].send_in 0, :close + super + end + def method_missing(s,*a) + #post "%s: %s", s.to_s, a.inspect + super rescue NameError + end + + install "#peephole", 1, 1 + gui_enable if GridFlow.bridge_name =~ /puredata/ + #GridFlow.addtomenu "#peephole" # was this IMPD-specific ? +end + +#-------- fClasses for: Hardware + +if const_defined? :USB + +class<1 + @usb=USB.new(r[0]) + if_num=nil + r[0].config.each {|config| + config.interface.each {|interface| + if_num = interface.bInterfaceNumber + } + } + # post "Interface # %i\n", if_num + @usb.set_configuration 1 + @usb.claim_interface if_num + @usb.set_altinterface 0 rescue ArgumentError + end + # libdelcom had this: + # uint8 recipient, deviceModel, major, minor, dataL, dataM; + # uint16 length; uint8[8] extension; + def _0_send_command(major,minor,dataL,dataM,extension="\0\0\0\0\0\0\0\0") + raise "closed" if not @usb + raise "extension.length!=8" if extension.length!=8 + @usb.control_msg( + 0x000000c8, 0x00000012, + minor*0x100+major, + dataM*0x100+dataL, + extension, 5000) + end + def delete; @usb.close; end + install "delcomusb", 1, 1 +end + +# Klippeltronics +FObject.subclass("multio",1,1) { + Vendor,Product=0xDEAD,0xBEEF + def self.find + r=[] + USB.busses.each {|dir,bus| + bus.each {|dev| + post "dir=%s, vendor=%x, product=%x", + dir, dev.idVendor, dev.idProduct + r<1 + $iobox=@usb=USB.new(r[0]) + if_num=nil + r[0].config.each {|config| + config.interface.each {|interface| + #post "interface=%s", interface.to_s + if_num = interface.bInterfaceNumber + } + } + # post "Interface # %i\n", if_num + # @usb.set_configuration 0 + @usb.claim_interface if_num + @usb.set_altinterface 0 rescue ArgumentError + end + #@usb.control_msg(0b10100001,0x01,0,0,"",1000) + #@usb.control_msg(0b10100001,0x01,0,1," ",0) + def delete; @usb.close; end +} +end # if const_defined? :USB + +# requires Ruby 1.8.0 because of bug in Ruby 1.6.x +FObject.subclass("joystick_port",0,1) { + def initialize(port) + raise "sorry, requires Ruby 1.8" if RUBY_VERSION<"1.8" + @f = File.open(port.to_s,"r+") + @status = nil + @clock = Clock.new self + @clock.delay 0 + @f.nonblock=true + end + def delete; @clock.unset; @f.close end + def call + loop{ + begin + event = @f.read(8) + rescue Errno::EAGAIN + @clock.delay 0 + return + end + return if not event + return if event.length<8 + send_out 0, *event.unpack("IsCC") + } + end +} + +# plotter control (HPGL) +FObject.subclass("plotter_control",1,1) { + def puts(x) + x<<"\n" + x.each_byte {|b| send_out 0, b } + send_out 0 + end + def _0_pu; puts "PU;" end + def _0_pd; puts "PD;" end + def _0_pa x,y; puts "PA#{x},#{y};" end + def _0_sp c; puts "SP#{c};"; end + def _0_ip(*v) puts "IP#{v.join','};" end + def _0_other(command,*v) puts "#{command.to_s.upcase}#{v.join','};" end + def _0_print(*text) puts "LB#{text.join(' ')}\003;" end + def _0_print_from_ascii(*codes) + _0_print codes.map{|code| code.chr }.join("") + end +} + +(begin require "linux/ParallelPort"; true; rescue LoadError; false end) and +FObject.subclass("parallel_port",1,3) { + def initialize(port,manually=0) + @f = File.open(port.to_s,"r+") + @f.extend Linux::ParallelPort + @status = nil + @flags = nil + @manually = manually!=0 + @clock = (if @manually then nil else Clock.new self end) + @clock.delay 0 if @clock + end + def delete; @clock.unset unless @manually; @f.close end + def _0_int(x) @f.write x.to_i.chr; @f.flush end + alias _0_float _0_int + def call + flags = @f.port_flags + send_out 2, flags if @flags != flags + @flags = flags + status = @f.port_status + send_out 1, status if @status != status + @status = status + @clock.delay 20 if @clock + end + def _0_bang + @status = @flags = nil + call + end + # outlet 0 reserved (future use) +} + +(begin require "linux/SoundMixer"; true; rescue LoadError; false end) and +FObject.subclass("SoundMixer",1,1) { + # BUG? i may have the channels (left,right) backwards + def initialize(filename) + super + @file = File.open filename.to_s, 0 + @file.extend Linux::SoundMixer + $sm = self + end + @@vars = Linux::SoundMixer.instance_methods.grep(/=/) + @@vars_h = {} + @@vars.each {|attr| + attr.chop! + eval %{ def _0_#{attr}(x) @file.#{attr} = x[0]*256+x[1] end } + @@vars_h[attr]=true + } + def _0_get(sel=nil) + if sel then + sels=sel.to_s + sel=sels.intern + raise if not @@vars_h.include? sel.to_s + begin + x = @file.send sel + send_out 0, sel, "(".intern, (x>>8)&255, x&255, ")".intern + rescue + send_out 0, sel, "(".intern, -1, -1, ")".intern + end + else + @@vars.each {|var| _0_get var } + end + end +} + +# experimental +FObject.subclass("rubyarray",2,1) { + def initialize() @a=[]; @i=0; end + def _0_float i; @i=i; send_out 0, *@a[@i]; end + def _1_list(*l) @a[@i]=l; end + def _0_save(filename,format=nil) + f=File.open(filename.to_s,"w") + if format then + @a.each {|x| f.puts(format.to_s%x) } + else + @a.each {|x| f.puts(x.join(",")) } + end + f.close + end + def _0_load(filename) + f=File.open(filename.to_s,"r") + @a.clear + f.each {|x| @a.push x.split(",").map {|y| Float(y) rescue y.intern }} + f.close + end +} + +end # module GridFlow -- cgit v1.2.1